├── .gitignore ├── .rspec ├── .travis.yml ├── Gemfile ├── LICENSE.txt ├── README.md ├── Rakefile ├── lib ├── uber.rb └── uber │ ├── api.rb │ ├── api │ ├── activities.rb │ ├── deliveries.rb │ ├── me.rb │ ├── partners.rb │ ├── places.rb │ ├── price_estimates.rb │ ├── products.rb │ ├── promotions.rb │ ├── reminders.rb │ ├── requests.rb │ └── time_estimates.rb │ ├── api_request.rb │ ├── arguments.rb │ ├── base.rb │ ├── client.rb │ ├── error.rb │ ├── models │ ├── activity.rb │ ├── delivery.rb │ ├── delivery │ │ ├── delivery.rb │ │ ├── quote.rb │ │ ├── rating.rb │ │ ├── rating_tag.rb │ │ ├── receipt.rb │ │ └── region.rb │ ├── estimate.rb │ ├── map.rb │ ├── partner.rb │ ├── partner │ │ ├── partner.rb │ │ ├── payment.rb │ │ └── trip.rb │ ├── place.rb │ ├── price.rb │ ├── product.rb │ ├── promotion.rb │ ├── receipt.rb │ ├── reminder.rb │ ├── request.rb │ ├── time.rb │ └── user.rb │ ├── parse_json.rb │ ├── rate_limit.rb │ ├── token.rb │ ├── utils.rb │ └── version.rb ├── spec ├── lib │ ├── api │ │ ├── activities_spec.rb │ │ ├── deliveries_spec.rb │ │ ├── me_spec.rb │ │ ├── partners_spec.rb │ │ ├── places_spec.rb │ │ ├── price_estimates_spec.rb │ │ ├── products_spec.rb │ │ ├── promotions_spec.rb │ │ ├── reminders_spec.rb │ │ ├── requests_spec.rb │ │ └── time_estimates_spec.rb │ └── rate_limit_spec.rb ├── spec_helper.rb └── support │ └── client_helpers.rb └── uber-ruby.gemspec /.gitignore: -------------------------------------------------------------------------------- 1 | *.gem 2 | *.rbc 3 | .bundle 4 | .config 5 | .yardoc 6 | Gemfile.lock 7 | InstalledFiles 8 | _yardoc 9 | coverage 10 | doc/ 11 | lib/bundler/man 12 | pkg 13 | rdoc 14 | spec/reports 15 | test/tmp 16 | test/version_tmp 17 | tmp 18 | -------------------------------------------------------------------------------- /.rspec: -------------------------------------------------------------------------------- 1 | --format documentation 2 | --color 3 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: ruby 2 | rvm: 3 | - 1.9.3 4 | - 2.0 5 | - 2.1 6 | - 2.2.2 7 | - 2.4.1 8 | - ruby-head 9 | - jruby-9.0.3.0 10 | matrix: 11 | allow_failures: 12 | - rvm: 1.9.3 13 | - rvm: ruby-head 14 | - rvm: jruby-9.0.3.0 15 | fast_finish: true 16 | before_install: gem install bundler -v 1.11.2 17 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | # Specify your gem's dependencies in uber-ruby.gemspec 4 | gemspec 5 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014 Dingding Ye 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # The Uber Ruby Gem 3 | 4 | ![travis AnkurGel](https://travis-ci.org/AnkurGel/uber-ruby.svg?branch=master) 5 | 6 | > A Ruby interface to the Uber API. 7 | 8 | 9 | ## Installation 10 | 11 | Add this line to your application's Gemfile: 12 | 13 | gem 'uber-ruby', require: 'uber' 14 | 15 | And then execute: 16 | 17 | $ bundle 18 | 19 | Or install it yourself as: 20 | 21 | $ gem install uber-ruby 22 | 23 | ## Configuration 24 | 25 | ```ruby 26 | client = Uber::Client.new do |config| 27 | config.server_token = "YOUR_SERVER_TOKEN" 28 | config.client_id = "YOUR_CLIENT_ID" 29 | config.client_secret = "YOUR_CLIENT_SECRET" 30 | end 31 | ``` 32 | 33 | ### Sandbox mode 34 | The Uber API Sandbox provides development endpoints for testing the functionality of an application without making calls to the production Uber platform. All requests made to the Sandbox environment will be ephemeral. 35 | 36 | ```ruby 37 | client = Uber::Client.new do |config| 38 | config.server_token = "YOUR_SERVER_TOKEN" 39 | config.client_id = "YOUR_CLIENT_ID" 40 | config.client_secret = "YOUR_CLIENT_SECRET" 41 | config.sandbox = true 42 | end 43 | # More info here https://developer.uber.com/docs/sandbox#section-product-types 44 | ``` 45 | 46 | ## Debug mode 47 | Add `config.debug = true` to log HTTP request-response headers while making API requests. 48 | 49 | ## Usage 50 | 51 | ### Request Products 52 | 53 | ```ruby 54 | client = Uber::Client.new do |config| 55 | config.server_token = "YOUR_SERVER_TOKEN" 56 | end 57 | client.products(latitude: lat, longitude: lon) 58 | ``` 59 | 60 | ### Request price estimations 61 | 62 | ```ruby 63 | client = Uber::Client.new do |config| 64 | config.server_token = "YOUR_SERVER_TOKEN" 65 | end 66 | client.price_estimations(start_latitude: slat, start_longitude: slon, 67 | end_latitude: dlat, end_longitude: dlon) 68 | ``` 69 | 70 | ### Request time estimations 71 | 72 | ```ruby 73 | client = Uber::Client.new do |config| 74 | config.server_token = "YOUR_SERVER_TOKEN" 75 | end 76 | client.time_estimations(start_latitude: slat, start_longitude: slon) 77 | ``` 78 | 79 | ### Retrieve user info 80 | 81 | ```ruby 82 | client = Uber::Client.new do |config| 83 | config.server_token = "YOUR_SERVER_TOKEN" 84 | config.client_id = "YOUR_CLIENT_ID" 85 | config.client_secret = "YOUR_CLIENT_SECRET" 86 | config.bearer_token = "USER_ACCESS_TOKEN" 87 | end 88 | client.me 89 | ``` 90 | 91 | ### Retrieve user activities 92 | 93 | ```ruby 94 | client = Uber::Client.new do |config| 95 | config.server_token = "YOUR_SERVER_TOKEN" 96 | config.client_id = "YOUR_CLIENT_ID" 97 | config.client_secret = "YOUR_CLIENT_SECRET" 98 | config.bearer_token = "USER_ACCESS_TOKEN" 99 | end 100 | client.history 101 | ``` 102 | 103 | ### Request a ride 104 | 105 | ```ruby 106 | client = Uber::Client.new do |config| 107 | config.client_id = "YOUR_CLIENT_ID" 108 | config.client_secret = "YOUR_CLIENT_SECRET" 109 | config.bearer_token = "USER_ACCESS_TOKEN" 110 | end 111 | 112 | client.trip_request(product_id: product_id, start_latitude: start_lat, start_longitude: start_lng, end_latitude: end_lat, end_longitude: end_lng) 113 | ``` 114 | 115 | ### Simulate a ride request with surge 116 | 117 | ```ruby 118 | client = Uber::Client.new do |config| 119 | config.client_id = "YOUR_CLIENT_ID" 120 | config.client_secret = "YOUR_CLIENT_SECRET" 121 | config.bearer_token = "USER_ACCESS_TOKEN" 122 | end 123 | 124 | # Only available in sandbox environment 125 | # Use this to simulate a surge 126 | # More info here https://developer.uber.com/docs/sandbox#section-product-types 127 | client.apply_surge 'product_id', 2.0 128 | 129 | client.trip_request(product_id: product_id, start_latitude: start_lat, start_longitude: start_lng, end_latitude: end_lat, end_longitude: end_lng, surge_confirmation_id: surge_id) 130 | ``` 131 | 132 | ### Simulate a ride request with no drivers available 133 | 134 | ```ruby 135 | client = Uber::Client.new do |config| 136 | config.client_id = "YOUR_CLIENT_ID" 137 | config.client_secret = "YOUR_CLIENT_SECRET" 138 | config.bearer_token = "USER_ACCESS_TOKEN" 139 | end 140 | 141 | # Only available in sandbox environment 142 | # Use this to simulate a request with no drivers available 143 | # More info here https://developer.uber.com/docs/sandbox#section-product-types 144 | client.apply_availability 'product_id', false 145 | 146 | client.trip_request(product_id: product_id, start_latitude: start_lat, start_longitude: start_lng, end_latitude: end_lat, end_longitude: end_lng) 147 | ``` 148 | 149 | ### Update the status of a ride request 150 | 151 | ```ruby 152 | client = Uber::Client.new do |config| 153 | config.client_id = "YOUR_CLIENT_ID" 154 | config.client_secret = "YOUR_CLIENT_SECRET" 155 | config.bearer_token = "USER_ACCESS_TOKEN" 156 | end 157 | 158 | # Only available in sandbox environment 159 | # Use this to simulate the status change of a ride request 160 | # More info here https://developer.uber.com/docs/sandbox#section-request 161 | 162 | client.trip_update('request_id', 'accepted') 163 | ``` 164 | 165 | ### Retrieve a ride request details 166 | 167 | ```ruby 168 | client = Uber::Client.new do |config| 169 | config.client_id = "YOUR_CLIENT_ID" 170 | config.client_secret = "YOUR_CLIENT_SECRET" 171 | config.bearer_token = "USER_ACCESS_TOKEN" 172 | end 173 | 174 | client.trip_details 'request_id' 175 | ``` 176 | 177 | ### Cancel a ride request 178 | 179 | ```ruby 180 | client = Uber::Client.new do |config| 181 | config.client_id = "YOUR_CLIENT_ID" 182 | config.client_secret = "YOUR_CLIENT_SECRET" 183 | config.bearer_token = "USER_ACCESS_TOKEN" 184 | end 185 | 186 | client.trip_cancel 'request_id' 187 | ``` 188 | 189 | ### Generate ride receipt 190 | Generates the receipt for a completed request. 191 | 192 | ```ruby 193 | client = Uber::Client.new do |config| 194 | config.client_id = "YOUR_CLIENT_ID" 195 | config.client_secret = "YOUR_CLIENT_SECRET" 196 | config.bearer_token = "USER_ACCESS_TOKEN" 197 | end 198 | 199 | client.trip_receipt 'request_id' #=> Generates Uber::Receipt 200 | # or 201 | receipt = client.ride_receipt 'request_id' 202 | receipt.total_charged #=> "$5.92" 203 | ``` 204 | 205 | ### Retrieve addresses 206 | Retrieves address information of _home_ or _work_. 207 | 208 | ```ruby 209 | client = Uber::Client.new do |config| 210 | config.client_id = "YOUR_CLIENT_ID" 211 | config.client_secret = "YOUR_CLIENT_SECRET" 212 | config.bearer_token = "USER_ACCESS_TOKEN" 213 | end 214 | 215 | place = client.place 'home' 216 | place.address #=> returns fully qualified address of location 217 | ``` 218 | 219 | ### Update addresses 220 | Updates address information of _home_ or _work_. 221 | ```ruby 222 | client = Uber::Client.new do |config| 223 | config.client_id = "YOUR_CLIENT_ID" 224 | config.client_secret = "YOUR_CLIENT_SECRET" 225 | config.bearer_token = "USER_ACCESS_TOKEN" 226 | end 227 | 228 | place = client.place_update 'home', 'my address' 229 | place.address #=> retuns fully qualified address of location 230 | ``` 231 | 232 | ### Retrieve a reminder 233 | This allows you to get the status of an existing ride reminder. 234 | **Note**: It only supports _server_token_. 235 | ```ruby 236 | client = Uber::Client.new do |config| 237 | config.client_id = "YOUR_CLIENT_ID" 238 | config.client_secret = "YOUR_CLIENT_SECRET" 239 | client.server_token = "YOUR_SERVER_TOKEN" 240 | end 241 | client.reminder 'reminder_id' 242 | #=> Uber::Reminder 243 | ``` 244 | 245 | ### Add a reminder 246 | This allows developers to set a reminder for a future trip. You can pass object of `Time` or _unixtime_ in `reminder_time` and `event.time`. 247 | ```ruby 248 | reminder = client.add_reminder({reminder_time: Time.local(2016, 9, 8, 23, 23, 23), 249 | phone_number: '+91-9999999999', 250 | trip_branding: {link_text: 'My first reminder'}, 251 | event: {time: Time.now + 234234}, 252 | reminder_id: 'rem1' }) 253 | reminder.event.time 254 | #=> 2016-09-11 11:02:06 UTC 255 | reminder.reminder_time 256 | #=> 2016-09-08 17:53:23 UTC 257 | reminder.reminder_status 258 | #=> "pending" 259 | ``` 260 | 261 | ### Update a reminder 262 | This allows you to update an existing reminder. 263 | ```ruby 264 | reminder = client.add_reminder('rem1', {reminder_time: Time.local(2016, 9, 10, 23, 23, 23), 265 | phone_number: '+91-9999999999', 266 | trip_branding: {link_text: 'My edited reminder'}, 267 | event: {time: Time.now + 234234}, 268 | reminder_id: 'rem1' }) 269 | reminder.trip_branding.link_text 270 | #=> "My edited reminder" 271 | 272 | ``` 273 | 274 | ### Delete a reminder 275 | This allows you to remove any reminder in the pending state from being sent. 276 | ```ruby 277 | reminder.delete_reminder 'rem1' 278 | #=> Uber::Reminder 279 | ``` 280 | 281 | ## Drivers API 282 | [Drivers API](https://developer.uber.com/docs/drivers/introduction) lets you build services and solutions that make the driver experience more productive and rewarding. With the driver's permission, you can use trip data, earnings, ratings and more to shape the future of the on-demand economy. 283 | 284 | We provide this under namespace of `client.partners` 285 | 286 | ### Driver details 287 | It returns the profile of the authenticated driver. 288 | > OAuth 2.0 bearer token with a partner.accounts scope. 289 | 290 | ```ruby 291 | driver = client.partners.me 292 | driver.first_name #=> 'John' 293 | driver.last_name #=> 'Driver' 294 | driver.promo_code #=> 'join_john_on_uber' 295 | ``` 296 | More details can be found [here](https://developer.uber.com/docs/drivers/references/api/v1/partners-me-get). 297 | 298 | ### Earnings details 299 | It returns an array of payments for the given driver. Payments are available at this endpoint in near real-time. 300 | > OAuth 2.0 bearer token with scope partner.payments 301 | 302 | ```ruby 303 | earnings = client.partners.payments 304 | # client.partners.earnings is also supported 305 | earnings.count #=> 5 306 | earnings.payments #=> Array of Uber::Partner::Payment 307 | payment = earnings.payments.first 308 | payment.category #=> 'fare' 309 | payment.cash_collected #=> 7.63 310 | payment.currency_code #=> 'USD' 311 | payment.event_time #=> 2016-11-12 10:29:28 UTC 312 | 313 | # Using params: 314 | earnings = client.partners.payments(:offset => 1, :limit => 2) 315 | ``` 316 | More details can be found [here](https://developer.uber.com/docs/drivers/references/api/v1/partners-payments-get). 317 | 318 | ### Trips details 319 | It returns an array of trips for the authenticated driver. 320 | > OAuth 2.0 bearer token with the partner.trips. 321 | 322 | ```ruby 323 | trips = client.partners.trips 324 | trips.count #=> 1 325 | trips.offset #=> 0 326 | trips.trips #=> Array of Uber::Partner::Trip 327 | trip = trips.trips.first 328 | trip.distance #=> 0 329 | trip.status #=> 'driver_canceled' 330 | trip.duration #=> 0 331 | ``` 332 | More details can be found [here](https://developer.uber.com/docs/drivers/references/api/v1/partners-trips-get). 333 | 334 | ## Deliveries API 335 | [Deliveries API]() lets you and your customer track the exact location of your delivery from any device. 336 | > OAuth 2.0 bearer token with the delivery scope 337 | 338 | We provide this under namespace of `client.deliveries`. Besides OAuth, you can get bearer token with `delivery` scope via __client_credentials__ workflow, follow this [guide](https://developer.uber.com/docs/deliveries/guides/authentication#client-credentials-flow). 339 | 340 | ```ruby 341 | client = Uber::Client.new do |config| 342 | config.server_token = "YOUR_SERVER_TOKEN" 343 | config.client_id = "YOUR_CLIENT_ID" 344 | config.client_secret = "YOUR_CLIENT_SECRET" 345 | config.bearer_token = "USER_ACCESS_TOKEN" 346 | end 347 | ``` 348 | 349 | 350 | ### List deliveries 351 | It retrieves a list of all deliveries 352 | 353 | 354 | ```ruby 355 | deliveries = client.deliveries.list #=> Array of Uber::Delivery::Delivery 356 | ``` 357 | More details can be found [here](https://developer.uber.com/docs/deliveries/references/api/v1/deliveries-get) 358 | 359 | ### Create a delivery 360 | It allows a delivery to be requested given the delivery information and quote ID 361 | 362 | ```ruby 363 | delivery = client.deliveries.add_delivery({quote_id: 'KEBjNGUxNjhlZmNmMD...', .. }) 364 | delivery.quote_id #=> 'KEBjNGUxNjhlZmNmMD...' 365 | ``` 366 | More details and parameters can be found [here](https://developer.uber.com/docs/deliveries/references/api/v1/deliveries-post) 367 | 368 | ### Create delivery quote 369 | Generate a delivery quote, given a pickup and dropoff location. On-demand and scheduled delivery quotes will be returned. 370 | 371 | ```ruby 372 | quotes = client.deliveries.add_quote({ "pickup" => { "location" => { ... } }, 373 | "dropoff" => { "location" => { ... } } ) 374 | # returns array of Uber::Delivery::Quote containing all On-demand and scheduled delivery quotes 375 | quotes.size #=> 4 376 | quotes[0].fee #=> 5.42 377 | ``` 378 | More details can be found [here](https://developer.uber.com/docs/deliveries/references/api/v1/deliveries-quote-post) 379 | 380 | ### Retrieve a delivery information 381 | Get the status of an ongoing delivery 382 | 383 | ```ruby 384 | delivery = client.deliveries.retrieve('8b58bc58-7352-4278-b569-b5d24d8e3f76') #=> Uber::Delivery::Delivery 385 | delivery.currency_code #=> "USD" 386 | delivery.delivery_id #=> '8b58bc58-7352-4278-b569-b5d24d8e3f76' 387 | delivery.fee #=> 5.0 388 | ``` 389 | More details can be found [here](https://developer.uber.com/docs/deliveries/references/api/v1/deliveries-delivery_id-get) 390 | 391 | ### Retrieve receipt for a delivery 392 | ```ruby 393 | receipt = client.deliveries.receipt('8b58bc58-7352-4278-b569-b5d24d8e3f76') #=> Uber::Delivery::Receipt 394 | receipt.delivery_id #=> '8b58bc58-7352-4278-b569-b5d24d8e3f76' 395 | receipt.total_fee #=> 6.17 396 | receipt.charges #=> hash of charges 397 | ``` 398 | More details can be found [here](https://developer.uber.com/docs/deliveries/references/api/v1/deliveries-delivery_id-receipt-get) 399 | 400 | ### Get delivery ratings 401 | Retrieve the available ratings for a delivery. 402 | 403 | ```ruby 404 | ratings = client.deliveries.ratings('8b58bc58-7352-4278-b569-b5d24d8e3f76') 405 | # Array of Uber::Delivery::Rating 406 | ratings.size #=> 2 407 | ratings[0].waypoint #=> 'pickup' 408 | ``` 409 | More details can be found [here](https://developer.uber.com/docs/deliveries/references/api/v1/deliveries-delivery_id-ratings-get) 410 | 411 | ### Submit a rating 412 | Submit a rating for a delivery. 413 | 414 | ```ruby 415 | status = client.deliveries.add_rating('8b58bc58-7352-4278-b569-b5d24d8e3f76', 416 | {"waypoint"=>"dropoff", 417 | "rating_type"=>"binary", 418 | "rating_value"=>0, 419 | "tags"=>["courier_not_on_time", "delivery_in_good_condition"], 420 | "comments"=>"Courier was not professionally dressed."}) 421 | # Returns the status code, with no content 422 | status #=> 204 423 | ``` 424 | More details can be found [here](https://developer.uber.com/docs/deliveries/references/api/v1/deliveries-delivery_id-ratings-post) 425 | 426 | ### Get rating tags 427 | Retrieve the available rating tags for a delivery 428 | 429 | ```ruby 430 | tags = client.deliveries.rating_tags('8b58bc58-7352-4278-b569-b5d24d8e3f76') 431 | # Array of Uber::Deliery::RatingTag 432 | tags.size #=> 2 433 | tags[0].waypoint #=> 'pickup' 434 | tags.tags #=> Array of rating tags for delivery 435 | ``` 436 | More details can be found [here](https://developer.uber.com/docs/deliveries/references/api/v1/deliveries-delivery_id-rating_tags-get) 437 | 438 | ### Cancel a delivery 439 | Cancel an existing delivery. 440 | 441 | ```ruby 442 | status = client.deliveries.cancel('8b58bc58-7352-4278-b569-b5d24d8e3f76') 443 | status #=> 204 444 | ``` 445 | More details can be found [here](https://developer.uber.com/docs/deliveries/references/api/v1/deliveries-delivery_id-cancel-post) 446 | 447 | ### Get service regions 448 | Returns all regions where UberRUSH is available. 449 | 450 | ```ruby 451 | regions = client.deliveries.regions 452 | # Array of Uber::Delivery::Region 453 | regions[0].city #=> 'San Francisco' 454 | ``` 455 | More details can be found [here](https://developer.uber.com/docs/deliveries/references/api/v1/deliveries-regions-get) 456 | 457 | ## Contributors 458 | 459 | * [Arun Thampi](https://github.com/arunthampi) 460 | * [Ankur Goel](https://github.com/AnkurGel) 461 | 462 | ## Contributing 463 | 464 | 1. Fork it ( http://github.com/sishen/uber-ruby/fork ) 465 | 2. Create your feature branch (`git checkout -b my-new-feature`) 466 | 3. Commit your changes (`git commit -am 'Add some feature'`) 467 | 4. Push to the branch (`git push origin my-new-feature`) 468 | 5. Create new Pull Request 469 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require "bundler/gem_tasks" 2 | require "rspec/core/rake_task" 3 | 4 | RSpec::Core::RakeTask.new(:spec) 5 | 6 | task default: "spec" 7 | -------------------------------------------------------------------------------- /lib/uber.rb: -------------------------------------------------------------------------------- 1 | require 'uber/base' 2 | require 'uber/utils' 3 | require 'uber/api' 4 | require 'uber/arguments' 5 | require 'uber/error' 6 | require 'uber/token' 7 | require 'uber/client' 8 | -------------------------------------------------------------------------------- /lib/uber/api.rb: -------------------------------------------------------------------------------- 1 | require 'uber/api/products' 2 | require 'uber/api/price_estimates' 3 | require 'uber/api/time_estimates' 4 | require 'uber/api/activities' 5 | require 'uber/api/me' 6 | require 'uber/api/promotions' 7 | require 'uber/api/reminders.rb' 8 | require 'uber/api/requests' 9 | require 'uber/api/places' 10 | require 'uber/api/partners' 11 | require 'uber/api/deliveries' 12 | 13 | module Uber 14 | module API 15 | include Uber::Utils 16 | include Uber::API::Products 17 | include Uber::API::PriceEstimates 18 | include Uber::API::TimeEstimates 19 | include Uber::API::Activities 20 | include Uber::API::Me 21 | include Uber::API::Promotions 22 | include Uber::API::Places 23 | include Uber::API::Reminders 24 | include Uber::API::Requests 25 | end 26 | end 27 | -------------------------------------------------------------------------------- /lib/uber/api/activities.rb: -------------------------------------------------------------------------------- 1 | require 'uber/arguments' 2 | require 'uber/api_request' 3 | require 'uber/models/activity' 4 | 5 | module Uber 6 | module API 7 | module Activities 8 | def history(*args) 9 | arguments = Uber::Arguments.new(args) 10 | perform_with_object(:get, "/v1.2/history", arguments.options, Activity) 11 | end 12 | end 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /lib/uber/api/deliveries.rb: -------------------------------------------------------------------------------- 1 | require 'uber/arguments' 2 | require 'uber/api_request' 3 | require 'uber/models/delivery' 4 | 5 | module Uber 6 | module API 7 | module Deliveries 8 | include Uber::Utils 9 | 10 | def list(*args) 11 | arguments = Uber::Arguments.new(args) 12 | perform_with_objects(:get, "/v1/deliveries", arguments.options, Delivery::Delivery, self.client) 13 | end 14 | 15 | def add_delivery(*args) 16 | arguments = Uber::Arguments.new(args) 17 | perform_with_object(:post, "/v1/deliveries", arguments.options, Delivery::Delivery, self.client) 18 | end 19 | 20 | def add_quote(*args) 21 | arguments = Uber::Arguments.new(args) 22 | perform_with_objects(:post, "/v1/deliveries/quote", arguments.options, Delivery::Quote, self.client) 23 | end 24 | 25 | def retrieve(delivery_id) 26 | perform_with_object(:get, "/v1/deliveries/#{delivery_id}", {}, Delivery::Delivery, self.client) 27 | end 28 | 29 | def receipt(delivery_id) 30 | delivery_id = delivery_id.is_a?(Delivery::Delivery) ? delivery_id.delivery_id : delivery_id 31 | perform_with_object(:get, "/v1/deliveries/#{delivery_id}/receipt", {}, Delivery::Receipt, self.client) 32 | end 33 | 34 | def ratings(delivery_id) 35 | delivery_id = delivery_id.is_a?(Delivery::Delivery) ? delivery_id.delivery_id : delivery_id 36 | perform_with_objects(:get, "/v1/deliveries/#{delivery_id}/ratings", {}, Delivery::Rating, self.client) 37 | end 38 | 39 | def add_rating(delivery_id, *args) 40 | delivery_id = delivery_id.is_a?(Delivery::Delivery) ? delivery_id.delivery_id : delivery_id 41 | arguments = Uber::Arguments.new(args) 42 | perform_without_object(:post, "/v1/deliveries/#{delivery_id}/rating", arguments.options, self.client) 43 | end 44 | 45 | def rating_tags(delivery_id) 46 | delivery_id = delivery_id.is_a?(Delivery::Delivery) ? delivery_id.delivery_id : delivery_id 47 | perform_with_objects(:get, "/v1/deliveries/#{delivery_id}/rating_tags", {}, Delivery::RatingTag, self.client) 48 | end 49 | 50 | def cancel(delivery_id) 51 | delivery_id = delivery_id.is_a?(Delivery::Delivery) ? delivery_id.delivery_id : delivery_id 52 | perform_without_object(:post, "/v1/deliveries/#{delivery_id}/cancel", {}, self.client) 53 | end 54 | 55 | def regions 56 | perform_with_objects(:get, "/v1/deliveries/regions", {}, Delivery::Region, self.client) 57 | end 58 | end 59 | end 60 | end -------------------------------------------------------------------------------- /lib/uber/api/me.rb: -------------------------------------------------------------------------------- 1 | require 'uber/arguments' 2 | require 'uber/api_request' 3 | require 'uber/models/user' 4 | 5 | module Uber 6 | module API 7 | module Me 8 | def me(*args) 9 | arguments = Uber::Arguments.new(args) 10 | perform_with_object(:get, "/v1/me", arguments.options, User) 11 | end 12 | end 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /lib/uber/api/partners.rb: -------------------------------------------------------------------------------- 1 | require 'uber/arguments' 2 | require 'uber/api_request' 3 | require 'uber/models/partner' 4 | 5 | module Uber 6 | module API 7 | module Partners 8 | include Uber::Utils 9 | def me 10 | perform_with_object(:get, "v1/partners/me", {}, Uber::Partner::Partner, self.client) 11 | end 12 | 13 | def payments(*args) 14 | arguments = Uber::Arguments.new(args) 15 | perform_with_object(:get, "/v1/partners/payments", arguments.options, Uber::Partner::PaymentActivity, self.client) 16 | end 17 | 18 | def trips(*args) 19 | arguments = Uber::Arguments.new(args) 20 | perform_with_object(:get, "/v1/partners/trips", arguments.options, Uber::Partner::TripActivity, self.client) 21 | end 22 | 23 | alias_method :earnings, :payments 24 | end 25 | end 26 | end 27 | -------------------------------------------------------------------------------- /lib/uber/api/places.rb: -------------------------------------------------------------------------------- 1 | require 'uber/arguments' 2 | require 'uber/api_request' 3 | require 'uber/models/place' 4 | 5 | module Uber 6 | module API 7 | module Places 8 | def place(place_id) 9 | perform_with_object(:get, "/v1/places/#{place_id}", {}, Place) 10 | end 11 | 12 | def place_update(place_id, address) 13 | perform_with_object(:put, "/v1/places/#{place_id}", {address: address}, Place) 14 | end 15 | 16 | alias_method :place_detail, :place 17 | end 18 | end 19 | end -------------------------------------------------------------------------------- /lib/uber/api/price_estimates.rb: -------------------------------------------------------------------------------- 1 | require 'uber/arguments' 2 | require 'uber/api_request' 3 | require 'uber/models/price' 4 | 5 | module Uber 6 | module API 7 | module PriceEstimates 8 | def price_estimations(*args) 9 | arguments = Uber::Arguments.new(args) 10 | perform_with_objects(:get, "/v1/estimates/price", arguments.options, Price) 11 | end 12 | end 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /lib/uber/api/products.rb: -------------------------------------------------------------------------------- 1 | require 'uber/arguments' 2 | require 'uber/api_request' 3 | require 'uber/models/product' 4 | 5 | module Uber 6 | module API 7 | module Products 8 | def products(*args) 9 | arguments = Uber::Arguments.new(args) 10 | perform_with_objects(:get, "/v1/products", arguments.options, Product) 11 | end 12 | 13 | def apply_surge(product_id, surge_multiplier) 14 | perform_with_object(:put, "/v1/sandbox/products/#{product_id}", {surge_multiplier: surge_multiplier}, Product) 15 | end 16 | 17 | def apply_availability(product_id, value) 18 | perform_with_object(:put, "/v1/sandbox/products/#{product_id}", {drivers_available: value}, Product) 19 | end 20 | end 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /lib/uber/api/promotions.rb: -------------------------------------------------------------------------------- 1 | require 'uber/arguments' 2 | require 'uber/api_request' 3 | require 'uber/models/promotion' 4 | 5 | module Uber 6 | module API 7 | module Promotions 8 | def promotion(*args) 9 | arguments = Uber::Arguments.new(args) 10 | perform_with_object(:get, "/v1/promotions", arguments.options, Promotion) 11 | end 12 | end 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /lib/uber/api/reminders.rb: -------------------------------------------------------------------------------- 1 | require 'uber/arguments' 2 | require 'uber/api_request' 3 | require 'uber/models/reminder' 4 | 5 | module Uber 6 | module API 7 | module Reminders 8 | 9 | def reminder(reminder_id) 10 | perform_with_object(:get, "/v1/reminders/#{reminder_id}", {}, Reminder) 11 | end 12 | 13 | def add_reminder(*args) 14 | arguments = sanitize_time(Uber::Arguments.new(args)) 15 | perform_with_object(:post, "/v1/reminders", arguments.options, Reminder) 16 | end 17 | 18 | def update_reminder(reminder_id, *args) 19 | arguments = sanitize_time(Uber::Arguments.new(args)) 20 | perform_with_object(:patch, "/v1/reminders/#{reminder_id}", arguments.options, Reminder) 21 | end 22 | 23 | def delete_reminder(reminder_id) 24 | perform_with_object(:delete, "/v1/reminders/#{reminder_id}", {}, Reminder) 25 | end 26 | 27 | alias_method :reminder_detail, :reminder 28 | 29 | private 30 | def sanitize_time(arguments) 31 | options = arguments.options 32 | options[:reminder_time] = to_unix_time(options[:reminder_time]) 33 | options[:event][:time] = to_unix_time(options[:event][:time]) if options[:event] 34 | arguments 35 | end 36 | 37 | def to_unix_time(attr) 38 | attr && attr.instance_of?(::Time) ? attr.to_i : attr 39 | end 40 | 41 | end 42 | end 43 | end 44 | -------------------------------------------------------------------------------- /lib/uber/api/requests.rb: -------------------------------------------------------------------------------- 1 | require 'uber/arguments' 2 | require 'uber/api_request' 3 | require 'uber/models/request' 4 | require 'uber/models/receipt' 5 | require 'uber/models/estimate' 6 | require 'uber/models/map' 7 | 8 | module Uber 9 | module API 10 | module Requests 11 | def trip_estimate(*args) 12 | arguments = Uber::Arguments.new(args) 13 | perform_with_object(:post, "v1/requests/estimate", arguments.options, Estimate) 14 | end 15 | 16 | def trip_request(*args) 17 | arguments = Uber::Arguments.new(args) 18 | perform_with_object(:post, "v1/requests", arguments.options, Request) 19 | end 20 | 21 | def trip_details(request_id) 22 | perform_with_object(:get, "v1/requests/#{request_id}", {}, Request) 23 | end 24 | 25 | def trip_map(request_id) 26 | perform_with_object(:get, "v1/requests/#{request_id}/map", {}, Map) 27 | end 28 | 29 | def trip_update(request_id, status) 30 | perform_with_object(:put, "v1/sandbox/requests/#{request_id}", {status: status}, Request) 31 | end 32 | 33 | def trip_cancel(request_id) 34 | perform_with_object(:delete, "v1/requests/#{request_id}", {}, Request) 35 | end 36 | 37 | def trip_receipt(request_id) 38 | perform_with_object(:get, "v1.2/requests/#{request_id}/receipt", {}, Receipt) 39 | end 40 | 41 | alias_method :ride_receipt, :trip_receipt 42 | end 43 | end 44 | end 45 | -------------------------------------------------------------------------------- /lib/uber/api/time_estimates.rb: -------------------------------------------------------------------------------- 1 | require 'uber/arguments' 2 | require 'uber/api_request' 3 | require 'uber/models/time' 4 | 5 | module Uber 6 | module API 7 | module TimeEstimates 8 | def time_estimations(*args) 9 | arguments = Uber::Arguments.new(args) 10 | perform_with_objects(:get, "/v1/estimates/time", arguments.options, Time) 11 | end 12 | end 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /lib/uber/api_request.rb: -------------------------------------------------------------------------------- 1 | module Uber 2 | class ApiRequest 3 | attr_accessor :client, :request_method, :path, :options 4 | alias_method :verb, :request_method 5 | 6 | # @param client [Uber::Client] 7 | # @param request_method [String, Symbol] 8 | # @param path [String] 9 | # @param options [Hash] 10 | # @return [Uber::ApiRequest] 11 | def initialize(client, request_method, path, options = {}) 12 | @client = client 13 | @request_method = request_method.to_sym 14 | @path = path 15 | @options = options 16 | end 17 | 18 | # @return [Hash] 19 | def perform 20 | @client.send(@request_method, @path, @options).body 21 | end 22 | 23 | # @param klass [Class] 24 | # @param request [Uber::ApiRequest] 25 | # @return [Object] 26 | def perform_with_object(klass) 27 | klass.new(perform) 28 | end 29 | 30 | # @param klass [Class] 31 | # @return [Array] 32 | def perform_with_objects(klass) 33 | ((perform.values.find { |v| v.is_a?(Array) }) || []).collect do |element| 34 | klass.new(element) 35 | end 36 | end 37 | 38 | # @return status_code [Integer] 39 | def perform_without_object 40 | @client.send(@request_method, @path, @options).status 41 | end 42 | end 43 | end 44 | -------------------------------------------------------------------------------- /lib/uber/arguments.rb: -------------------------------------------------------------------------------- 1 | module Uber 2 | class Arguments < Array 3 | attr_reader :options 4 | 5 | # Initializes a new Arguments object 6 | # 7 | # @return [Uber::Arguments] 8 | def initialize(args) 9 | @options = args.last.is_a?(::Hash) ? args.pop : {} 10 | super(args.flatten) 11 | end 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /lib/uber/base.rb: -------------------------------------------------------------------------------- 1 | module Uber 2 | class Base 3 | attr_reader :attrs 4 | alias_method :to_h, :attrs 5 | 6 | # Initializes a new object 7 | # 8 | # @param attrs [Hash] 9 | # @return [Uber::Base] 10 | def initialize(attrs = {}) 11 | return if attrs.nil? || attrs.empty? 12 | attrs.each do |key, value| 13 | if respond_to?(:"#{key}=") 14 | send(:"#{key}=", value) 15 | end 16 | end 17 | end 18 | 19 | # Fetches an attribute of an object using hash notation 20 | # 21 | # @param method [String, Symbol] Message to send to the object 22 | def [](method) 23 | send(method.to_sym) 24 | rescue NoMethodError 25 | nil 26 | end 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /lib/uber/client.rb: -------------------------------------------------------------------------------- 1 | require 'uber/version' 2 | require 'uber/error' 3 | require 'base64' 4 | require 'faraday' 5 | require 'faraday/request/multipart' 6 | require 'uber/parse_json' 7 | 8 | module Uber 9 | class Client 10 | include Uber::API 11 | 12 | attr_accessor :server_token, :client_id, :client_secret 13 | attr_accessor :bearer_token 14 | attr_accessor :sandbox 15 | attr_accessor :debug 16 | 17 | attr_writer :connection_options, :middleware 18 | ENDPOINT = 'https://api.uber.com' 19 | SANDBOX_ENDPOINT = 'https://sandbox-api.uber.com' 20 | 21 | def initialize(options = {}) 22 | options.each do |key, value| 23 | send(:"#{key}=", value) 24 | end 25 | yield(self) if block_given? 26 | validate_credential_type! 27 | end 28 | 29 | def bearer_token=(token) 30 | @bearer_token = Token.new(access_token: token, token_type: Token::BEARER_TYPE) 31 | end 32 | 33 | def connection_options 34 | @connection_options ||= { 35 | :builder => middleware, 36 | :headers => { 37 | :accept => 'application/json', 38 | :user_agent => user_agent, 39 | }, 40 | :request => { 41 | :open_timeout => 10, 42 | :timeout => 30, 43 | }, 44 | } 45 | end 46 | 47 | # @return [Boolean] 48 | def user_token? 49 | !!(client_id && client_secret) 50 | end 51 | 52 | # @return [String] 53 | def user_agent 54 | @user_agent ||= "Uber Ruby Gem #{Uber::Version}" 55 | end 56 | 57 | def middleware 58 | @middleware ||= Faraday::RackBuilder.new do |faraday| 59 | # Encodes as "application/x-www-form-urlencoded" if not already encoded 60 | faraday.request :url_encoded 61 | # Parse JSON response bodies 62 | faraday.response :parse_json 63 | faraday.response :logger if self.debug 64 | # Use instrumentation if available 65 | faraday.use :instrumentation if defined?(FaradayMiddleware::Instrumentation) 66 | # Set default HTTP adapter 67 | faraday.adapter Faraday.default_adapter 68 | end 69 | end 70 | 71 | # Perform an HTTP GET request 72 | def get(path, params = {}) 73 | headers = request_headers(:get, path, params) 74 | request(:get, path, params, headers) 75 | end 76 | 77 | # Perform an HTTP POST request 78 | def post(path, params = {}) 79 | headers = params.values.any? { |value| value.respond_to?(:to_io) } ? request_headers(:post, path, params, {}) : request_headers(:post, path, params) 80 | request(:post, path, params.to_json, headers) 81 | end 82 | 83 | # Perform an HTTP PUT request 84 | def put(path, params = {}) 85 | headers = params.values.any? { |value| value.respond_to?(:to_io) } ? request_headers(:post, path, params, {}) : request_headers(:put, path, params) 86 | request(:put, path, params.to_json, headers) 87 | end 88 | 89 | # Perform an HTTP DELETE request 90 | def delete(path, params = {}) 91 | headers = request_headers(:delete, path, params) 92 | request(:delete, path, params, headers) 93 | end 94 | 95 | # Perform an HTTP PATCH request 96 | def patch(path, params={}) 97 | headers = params.values.any? { |value| value.respond_to?(:to_io) } ? request_headers(:post, path, params, {}) : request_headers(:patch, path, params) 98 | request(:patch, path, params.to_json, headers) 99 | end 100 | 101 | # @return [Boolean] 102 | def bearer_token? 103 | !!bearer_token 104 | end 105 | 106 | # @return [Hash] 107 | def credentials 108 | { 109 | server_token: server_token, 110 | client_id: client_id, 111 | client_secret: client_secret 112 | } 113 | end 114 | 115 | # @return [Boolean] 116 | def credentials? 117 | credentials.values.all? 118 | end 119 | 120 | def partners 121 | @partners ||= Uber::Partner::Client.new self 122 | end 123 | 124 | def deliveries 125 | @deliveries ||= Uber::Delivery::Client.new self 126 | end 127 | private 128 | 129 | # Ensures that all credentials set during configuration are 130 | # of a valid type. Valid types are String and Symbol. 131 | # 132 | # @raise [Uber::Error::ConfigurationError] Error is raised when 133 | # supplied uber credentials are not a String or Symbol. 134 | def validate_credential_type! 135 | credentials.each do |credential, value| 136 | next if value.nil? 137 | fail(Uber::Error::ConfigurationError.new("Invalid #{credential} specified: #{value.inspect} must be a string or symbol.")) unless value.is_a?(String) || value.is_a?(Symbol) 138 | end 139 | end 140 | 141 | # Returns a Faraday::Connection object 142 | # 143 | # @return [Faraday::Connection] 144 | def connection 145 | @connection ||= Faraday.new(self.sandbox ? SANDBOX_ENDPOINT : ENDPOINT, connection_options) 146 | end 147 | 148 | def request(method, path, params = {}, headers = {}) 149 | connection.send(method.to_sym, path, params) { |request| request.headers.update(headers) }.env 150 | rescue Faraday::Error::TimeoutError, Timeout::Error => error 151 | raise(Uber::Error::RequestTimeout.new(error)) 152 | rescue Faraday::Error::ClientError, JSON::ParserError => error 153 | fail(Uber::Error.new(error)) 154 | end 155 | 156 | def request_headers(method, path, params = {}, signature_params = params) 157 | headers = {} 158 | headers[:accept] = '*/*' 159 | headers[:content_type] = 'application/json; charset=UTF-8' 160 | if bearer_token? 161 | headers[:authorization] = bearer_auth_header 162 | else 163 | headers[:authorization] = server_auth_header 164 | end 165 | headers 166 | end 167 | 168 | def bearer_auth_header 169 | token = bearer_token.is_a?(Uber::Token) && bearer_token.bearer? ? bearer_token.access_token : bearer_token 170 | "Bearer #{token}" 171 | end 172 | 173 | def server_auth_header 174 | "Token #{@server_token}" 175 | end 176 | end 177 | 178 | module Partner 179 | class Client 180 | include Uber::API::Partners 181 | attr_reader :client 182 | def initialize(client) 183 | @client = client 184 | end 185 | end 186 | end 187 | module Delivery 188 | class Client 189 | include Uber::API::Deliveries 190 | attr_reader :client 191 | def initialize(client) 192 | @client = client 193 | end 194 | end 195 | end 196 | 197 | end 198 | -------------------------------------------------------------------------------- /lib/uber/error.rb: -------------------------------------------------------------------------------- 1 | require 'uber/rate_limit' 2 | 3 | module Uber 4 | # Custom error class for rescuing from all Uber errors 5 | class Error < StandardError 6 | attr_reader :code, :rate_limit 7 | 8 | module Code 9 | AUTHENTICATION_PROBLEM = 32 10 | MALFORMED_REQUEST = 400 11 | UNAUTHORIZED_REQUEST = 401 12 | REQUEST_FORBIDDEN = 403 13 | RESOURCE_NOT_FOUND = 404 14 | UNACCEPTABLE_CONTENT_TYPE = 406 15 | INVALID_REQUEST = 422 16 | RATE_LIMIT_EXCEEDED = 429 17 | INTERVAL_ERROR = 500 18 | end 19 | Codes = Code # rubocop:disable ConstantName 20 | 21 | class << self 22 | # Create a new error from an HTTP response 23 | # 24 | # @param response [Faraday::Response] 25 | # @return [Uber::Error] 26 | def from_response(response) 27 | message, code = parse_error(response.body) 28 | new(message, response.response_headers, code) 29 | end 30 | 31 | # @return [Hash] 32 | def errors 33 | @errors ||= { 34 | 400 => Uber::Error::BadRequest, 35 | 401 => Uber::Error::Unauthorized, 36 | 403 => Uber::Error::Forbidden, 37 | 404 => Uber::Error::NotFound, 38 | 406 => Uber::Error::NotAcceptable, 39 | 422 => Uber::Error::UnprocessableEntity, 40 | 429 => Uber::Error::RateLimited, 41 | 500 => Uber::Error::InternalServerError 42 | } 43 | end 44 | 45 | private 46 | 47 | def parse_error(body) 48 | if body.nil? 49 | ['', nil] 50 | elsif body[:error] 51 | [body[:error], nil] 52 | elsif body[:errors] 53 | extract_message_from_errors(body) 54 | end 55 | end 56 | 57 | def extract_message_from_errors(body) 58 | first = Array(body[:errors]).first 59 | if first.is_a?(Hash) 60 | [first[:message].chomp, first[:code]] 61 | else 62 | [first.chomp, nil] 63 | end 64 | end 65 | end 66 | 67 | # Initializes a new Error object 68 | # 69 | # @param exception [Exception, String] 70 | # @param rate_limit [Hash] 71 | # @param code [Integer] 72 | # @return [Uber::Error] 73 | def initialize(message = '', rate_limit = {}, code = nil) 74 | super(message) 75 | @rate_limit = Uber::RateLimit.new(rate_limit) 76 | @code = code 77 | end 78 | 79 | class ClientError < self; end 80 | 81 | # Raised when Uber requests are timed-out 82 | class RequestTimeout < ClientError; end 83 | 84 | class ConfigurationError < ::ArgumentError; end 85 | 86 | # Raised when Uber returns the HTTP status code 400 87 | class BadRequest < ClientError; end 88 | 89 | # Raised when Uber returns the HTTP status code 401 90 | class Unauthorized < ClientError; end 91 | 92 | # Raised when Uber returns the HTTP status code 403 93 | class Forbidden < ClientError; end 94 | 95 | # Raised when Uber returns the HTTP status code 404 96 | class NotFound < ClientError; end 97 | 98 | # Raised when Uber returns the HTTP status code 406 99 | class NotAcceptable < ClientError; end 100 | 101 | # Raised when Uber returns the HTTP status code 422 102 | class UnprocessableEntity < ClientError; end 103 | 104 | # Raised when Uber returns the HTTP status code 429 105 | class RateLimited < ClientError; end 106 | 107 | # Raised when Uber returns a 5xx HTTP status code 108 | class ServerError < self; end 109 | 110 | # Raised when Uber returns the HTTP status code 500 111 | class InternalServerError < ServerError; end 112 | end 113 | end 114 | -------------------------------------------------------------------------------- /lib/uber/models/activity.rb: -------------------------------------------------------------------------------- 1 | module Uber 2 | class Activity < Base 3 | attr_accessor :offset, :limit, :count, :histories 4 | 5 | def history=(values) 6 | @histories = values.map { |value| History.new(value) } 7 | end 8 | end 9 | 10 | class History < Base 11 | attr_accessor :request_time, :product_id, :status, :distance, :start_time, :end_time, :start_city, :request_id 12 | alias_method :uuid, :request_id 13 | 14 | def request_time=(value) 15 | @request_time = ::Time.at(value) 16 | end 17 | 18 | def start_time=(value) 19 | @start_time = ::Time.at(value) 20 | end 21 | 22 | def end_time=(value) 23 | @end_time = ::Time.at(value) 24 | end 25 | 26 | def start_city=(value) 27 | @start_city = City.new(value) 28 | end 29 | end 30 | 31 | class Location < Base 32 | attr_accessor :address, :latitude, :longitude 33 | end 34 | 35 | class City < Base 36 | attr_accessor :display_name, :latitude, :longitude 37 | end 38 | end 39 | -------------------------------------------------------------------------------- /lib/uber/models/delivery.rb: -------------------------------------------------------------------------------- 1 | require 'uber/models/delivery/delivery' 2 | require 'uber/models/delivery/quote' 3 | require 'uber/models/delivery/rating' 4 | require 'uber/models/delivery/rating_tag' 5 | require 'uber/models/delivery/receipt' 6 | require 'uber/models/delivery/region' -------------------------------------------------------------------------------- /lib/uber/models/delivery/delivery.rb: -------------------------------------------------------------------------------- 1 | module Uber 2 | module Delivery 3 | class Delivery < Base 4 | attr_accessor :courier, :created_at, :currency_code, :delivery_id, 5 | :dropoff, :fee, :items, :order_reference_id, :pickup, :quote_id, 6 | :status, :tracking_url, :batch 7 | 8 | def created_at 9 | @created_at && ::Time.at(@created_at) 10 | end 11 | end 12 | end 13 | end -------------------------------------------------------------------------------- /lib/uber/models/delivery/quote.rb: -------------------------------------------------------------------------------- 1 | module Uber 2 | module Delivery 3 | class Quote < Base 4 | attr_accessor :quote_id, :estimated_at, :expires_at, :fee, :currency_code, 5 | :pickup_eta, :dropoff_eta 6 | 7 | def estimated_at 8 | @estimated_at && ::Time.at(@estimated_at) 9 | end 10 | 11 | def expires_at 12 | @expires_at && ::Time.at(@expires_at) 13 | end 14 | end 15 | end 16 | end -------------------------------------------------------------------------------- /lib/uber/models/delivery/rating.rb: -------------------------------------------------------------------------------- 1 | module Uber 2 | module Delivery 3 | class Rating < Base 4 | attr_accessor :waypoint, :rating_type, :rating_value, :tags, :comments 5 | end 6 | end 7 | end -------------------------------------------------------------------------------- /lib/uber/models/delivery/rating_tag.rb: -------------------------------------------------------------------------------- 1 | module Uber 2 | module Delivery 3 | class RatingTag < Base 4 | attr_accessor :waypoint, :tags 5 | end 6 | end 7 | end -------------------------------------------------------------------------------- /lib/uber/models/delivery/receipt.rb: -------------------------------------------------------------------------------- 1 | module Uber 2 | module Delivery 3 | class Receipt < Base 4 | attr_accessor :charges, :charge_adjustments, :delivery_id, :currency_code, :total_fee 5 | end 6 | end 7 | end -------------------------------------------------------------------------------- /lib/uber/models/delivery/region.rb: -------------------------------------------------------------------------------- 1 | module Uber 2 | module Delivery 3 | class Region < Base 4 | attr_accessor :city, :country, :type, :features 5 | end 6 | end 7 | end -------------------------------------------------------------------------------- /lib/uber/models/estimate.rb: -------------------------------------------------------------------------------- 1 | module Uber 2 | class Estimate < Base 3 | attr_accessor :pickup_estimate, :price, :trip, :errors 4 | 5 | def price=(value) 6 | @price = value.nil? ? nil : Price.new(value) 7 | end 8 | 9 | def trip=(value) 10 | @trip = value.nil? ? nil : Trip.new(value) 11 | end 12 | 13 | def humanized_estimate 14 | unless pickup_estimate.nil? 15 | pickup_estimate.to_i == 1 ? "#{pickup_estimate} minute" : "#{pickup_estimate} minutes" 16 | end 17 | end 18 | end 19 | 20 | class Price < Base 21 | attr_accessor :surge_confirmation_href, :surge_confirmation_id, :high_estimate, :low_estimate, :minimum, :surge_multiplier, :display, :currency_code 22 | end 23 | 24 | class Trip < Base 25 | attr_accessor :distance_unit, :duration_estimate, :distance_estimate 26 | end 27 | 28 | end 29 | 30 | -------------------------------------------------------------------------------- /lib/uber/models/map.rb: -------------------------------------------------------------------------------- 1 | module Uber 2 | class Map < Base 3 | attr_accessor :request_id, :href 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /lib/uber/models/partner.rb: -------------------------------------------------------------------------------- 1 | require 'uber/models/partner/partner' 2 | require 'uber/models/partner/payment' 3 | require 'uber/models/partner/trip' -------------------------------------------------------------------------------- /lib/uber/models/partner/partner.rb: -------------------------------------------------------------------------------- 1 | module Uber 2 | module Partner 3 | class Partner < Base 4 | attr_accessor :driver_id, :first_name, :last_name, :phone_number, :email, :picture, 5 | :rating, :promo_code, :activation_status 6 | end 7 | end 8 | end -------------------------------------------------------------------------------- /lib/uber/models/partner/payment.rb: -------------------------------------------------------------------------------- 1 | module Uber 2 | module Partner 3 | 4 | class PaymentActivity < Base 5 | attr_accessor :offset, :limit, :count, :payments 6 | 7 | def payments=(values) 8 | @payments = values.map { |value| Uber::Partner::Payment.new value } 9 | end 10 | end 11 | 12 | class Payment < Base 13 | attr_accessor :category, :breakdown, :rider_fees, :event_time, :trip_id, :cash_collected, 14 | :amount, :driver_id, :partner_id, :currency_code 15 | 16 | def event_time 17 | ::Time.at @event_time 18 | end 19 | end 20 | 21 | end 22 | 23 | end -------------------------------------------------------------------------------- /lib/uber/models/partner/trip.rb: -------------------------------------------------------------------------------- 1 | module Uber 2 | module Partner 3 | 4 | class TripActivity < Base 5 | attr_accessor :count, :limit, :offset, :trips 6 | 7 | def trips=(values) 8 | @trips = values.map { |value| Uber::Partner::Trip.new value } 9 | end 10 | end 11 | 12 | class Trip < Base 13 | attr_accessor :dropoff, :vehicle_id, :distance, :start_city, :status_changes, :pickup, 14 | :driver_id, :status, :duration, :trip_id 15 | 16 | def status_changes=(values) 17 | @status_changes = values.map { |value| Uber::Partner::StatusChange.new value } 18 | end 19 | end 20 | 21 | class StatusChange < Base 22 | attr_accessor :status, :timestamp 23 | 24 | def time 25 | ::Time.at @timestamp if @timestamp 26 | end 27 | end 28 | end 29 | end -------------------------------------------------------------------------------- /lib/uber/models/place.rb: -------------------------------------------------------------------------------- 1 | module Uber 2 | class Place < Base 3 | attr_accessor :address 4 | end 5 | end -------------------------------------------------------------------------------- /lib/uber/models/price.rb: -------------------------------------------------------------------------------- 1 | module Uber 2 | class Price < Base 3 | attr_accessor :product_id, :currency_code, :display_name, :estimate, :low_estimate, :high_estimate, :surge_multiplier, :duration, :distance 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /lib/uber/models/product.rb: -------------------------------------------------------------------------------- 1 | module Uber 2 | class Product < Base 3 | attr_accessor :product_id, :description, :display_name, :capacity, :image, 4 | :cash_enabled, :shared, :price_details 5 | 6 | [:cash_enabled, :shared].each do |m| 7 | define_method("#{m}?") { instance_variable_get("@#{m}") } 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /lib/uber/models/promotion.rb: -------------------------------------------------------------------------------- 1 | module Uber 2 | class Promotion < Base 3 | attr_accessor :display_text, :localized_value, :type 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /lib/uber/models/receipt.rb: -------------------------------------------------------------------------------- 1 | module Uber 2 | class Receipt < Base 3 | attr_accessor :request_id, :subtotal, :total_charged, :total_owed, 4 | :total_fare, :currency_code, :duration, :distance, :distance_label 5 | 6 | def distance=(value) 7 | @distance = value.to_f if value 8 | end 9 | end 10 | end -------------------------------------------------------------------------------- /lib/uber/models/reminder.rb: -------------------------------------------------------------------------------- 1 | module Uber 2 | class Reminder < Base 3 | attr_accessor :event, :product_id, :reminder_id, :reminder_time, :reminder_status, :trip_branding 4 | 5 | def event=(value) 6 | @event = value && Event.new(value) 7 | end 8 | 9 | def trip_branding=(value) 10 | @trip_branding = value && TripBranding.new(value) 11 | end 12 | 13 | def reminder_time 14 | @reminder_time && ::Time.at(@reminder_time) 15 | end 16 | 17 | class Event < Base 18 | attr_accessor :name, :location, :latitude, :longitude, :time 19 | 20 | def time 21 | @time && ::Time.at(@time) 22 | end 23 | end 24 | 25 | class TripBranding < Base 26 | attr_accessor :link_text, :partner_deeplink 27 | end 28 | end 29 | 30 | end -------------------------------------------------------------------------------- /lib/uber/models/request.rb: -------------------------------------------------------------------------------- 1 | module Uber 2 | class Request < Base 3 | attr_accessor :request_id, :status, :vehicle, :driver, :location, 4 | :pickup, :destination, :eta, :surge_multiplier, :meta, :errors 5 | 6 | def driver=(value) 7 | @driver = value.nil? ? nil : Driver.new(value) 8 | end 9 | 10 | def vehicle=(value) 11 | @vehicle = value.nil? ? nil : Vehicle.new(value) 12 | end 13 | 14 | def location=(value) 15 | @location = value.nil? ? nil : Location.new(value) 16 | end 17 | 18 | def pickup=(value) 19 | @pickup = value.nil? ? nil : Location.new(value) 20 | end 21 | 22 | def destination=(value) 23 | @destination = value.nil? ? nil : Location.new(value) 24 | end 25 | 26 | def errors=(values) 27 | @errors = values.map { |v| RequestError.new(v) } 28 | end 29 | 30 | def vehicle_name 31 | vehicle.nil? ? nil : "#{vehicle.make} #{vehicle.model}" 32 | end 33 | 34 | def vehicle_image_url 35 | vehicle.nil? ? nil : "#{vehicle.picture_url}" 36 | end 37 | 38 | def driver_image_url 39 | driver.nil? ? nil : "#{driver.picture_url}" 40 | end 41 | 42 | def humanized_eta 43 | unless eta.nil? 44 | eta.to_i == 1 ? "#{eta} minute" : "#{eta} minutes" 45 | end 46 | end 47 | end 48 | 49 | class RequestError < Base 50 | attr_accessor :status, :code, :title 51 | end 52 | 53 | class Driver < Base 54 | attr_accessor :phone_number, :rating, :picture_url, :name 55 | end 56 | 57 | class Vehicle < Base 58 | attr_accessor :make, :model, :license_plate, :picture_url 59 | end 60 | 61 | class Location < Base 62 | attr_accessor :latitude, :longitude, :bearing, :eta 63 | end 64 | end 65 | -------------------------------------------------------------------------------- /lib/uber/models/time.rb: -------------------------------------------------------------------------------- 1 | module Uber 2 | class Time < Base 3 | attr_accessor :product_id, :display_name, :estimate 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /lib/uber/models/user.rb: -------------------------------------------------------------------------------- 1 | module Uber 2 | class User < Base 3 | attr_accessor :first_name, :last_name, :email, :picture, :promo_code, :mobile_verified, :uuid 4 | 5 | def mobile_verified? 6 | !!self.mobile_verified 7 | end 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /lib/uber/parse_json.rb: -------------------------------------------------------------------------------- 1 | require 'faraday' 2 | require 'json' 3 | 4 | module Uber 5 | module Response 6 | class ParseJson < Faraday::Response::Middleware 7 | WHITESPACE_REGEX = /\A^\s*$\z/ 8 | 9 | def parse(body) 10 | case body 11 | when WHITESPACE_REGEX, nil 12 | nil 13 | else 14 | JSON.parse(body, :symbolize_names => true) 15 | end 16 | end 17 | 18 | def on_complete(response) 19 | response.body = parse(response.body) if respond_to?(:parse) && !unparsable_status_codes.include?(response.status) 20 | end 21 | 22 | def unparsable_status_codes 23 | [204, 301, 302, 304] 24 | end 25 | end 26 | end 27 | end 28 | 29 | Faraday::Response.register_middleware :parse_json => Uber::Response::ParseJson 30 | -------------------------------------------------------------------------------- /lib/uber/rate_limit.rb: -------------------------------------------------------------------------------- 1 | module Uber 2 | class RateLimit 3 | attr_reader :attrs 4 | 5 | def initialize(attrs = {}) 6 | return if attrs.nil? || attrs.empty? 7 | @attrs = attrs 8 | end 9 | 10 | # @return [Integer] 11 | def limit 12 | limit = @attrs['x-rate-limit-limit'] 13 | limit.to_i if limit 14 | end 15 | 16 | # @return [Integer] 17 | def remaining 18 | remaining = @attrs['x-rate-limit-remaining'] 19 | remaining.to_i if remaining 20 | end 21 | 22 | # @return [Time] 23 | def reset_at 24 | reset = @attrs['x-rate-limit-reset'] 25 | ::Time.at(reset.to_i) if reset 26 | end 27 | 28 | # @return [Integer] 29 | def reset_in 30 | [(reset_at - ::Time.now).ceil, 0].max if reset_at 31 | end 32 | end 33 | end 34 | -------------------------------------------------------------------------------- /lib/uber/token.rb: -------------------------------------------------------------------------------- 1 | require 'uber/base' 2 | 3 | module Uber 4 | class Token < Uber::Base 5 | attr_accessor :access_token, :token_type 6 | alias_method :to_s, :access_token 7 | 8 | BEARER_TYPE = 'bearer' 9 | 10 | # @return [Boolean] 11 | def bearer? 12 | token_type == BEARER_TYPE 13 | end 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /lib/uber/utils.rb: -------------------------------------------------------------------------------- 1 | require 'uber/arguments' 2 | require 'uber/api_request' 3 | 4 | module Uber 5 | module Utils 6 | # @param request_method [Symbol] 7 | # @param path [String] 8 | # @param options [Hash] 9 | # @param klass [Class] 10 | def perform_with_object(request_method, path, options, klass, client=self) 11 | request = Uber::ApiRequest.new(client, request_method, path, options) 12 | request.perform_with_object(klass) 13 | end 14 | 15 | # @param request_method [Symbol] 16 | # @param path [String] 17 | # @param options [Hash] 18 | # @param klass [Class] 19 | def perform_with_objects(request_method, path, options, klass, client=self) 20 | request = Uber::ApiRequest.new(client, request_method, path, options) 21 | request.perform_with_objects(klass) 22 | end 23 | 24 | # @param request_method [Symbol] 25 | # @param path [String] 26 | # @param options [Hash] 27 | def perform_without_object(request_method, path, options, client=self) 28 | request = Uber::ApiRequest.new(client, request_method, path, options) 29 | request.perform_without_object 30 | end 31 | end 32 | end 33 | -------------------------------------------------------------------------------- /lib/uber/version.rb: -------------------------------------------------------------------------------- 1 | module Uber 2 | class Version 3 | MAJOR = 0 4 | MINOR = 10 5 | PATCH = 0 6 | 7 | class << self 8 | # @return [String] 9 | def to_s 10 | [MAJOR, MINOR, PATCH].compact.join('.') 11 | end 12 | end 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /spec/lib/api/activities_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | require 'uber' 3 | 4 | describe Uber::API::Activities do 5 | let!(:client) { setup_client } 6 | 7 | before do 8 | stub_uber_request(:get, 'v1.2/history', 9 | # From: https://developer.uber.com/docs/v12-history 10 | { 11 | "offset" => 0, 12 | "limit" => 1, 13 | "count" => 5, 14 | "history" => [ 15 | { 16 | "request_time" => 1401884467, 17 | "product_id" => "edf5e5eb-6ae6-44af-bec6-5bdcf1e3ed2c", 18 | "status" => "completed", 19 | "distance" => 0.0279562, 20 | "start_time" => 1401884646, 21 | "end_time" => 1401884732, 22 | "start_city" => { 23 | "latitude" => 37.7749295, 24 | "display_name" => "San Francisco", 25 | "longitude" => -122.4194155 26 | }, 27 | "request_id" => "37d57a99-2647-4114-9dd2-c43bccf4c30b" 28 | } 29 | ] 30 | } 31 | ) 32 | end 33 | 34 | it "should return the user's activities" do 35 | activity = client.history 36 | 37 | expect(activity.offset).to eql 0 38 | expect(activity.limit).to eql 1 39 | expect(activity.count).to eql 5 40 | 41 | expect(activity.histories.size).to eql 1 42 | 43 | expect(activity.histories[0].request_time.to_i).to eql 1401884467 44 | expect(activity.histories[0].product_id).to eql "edf5e5eb-6ae6-44af-bec6-5bdcf1e3ed2c" 45 | expect(activity.histories[0].status).to eql "completed" 46 | expect(activity.histories[0].distance).to eql 0.0279562 47 | expect(activity.histories[0].start_time.to_i).to eql 1401884646 48 | expect(activity.histories[0].end_time.to_i).to eql 1401884732 49 | expect(activity.histories[0].request_id).to eql "37d57a99-2647-4114-9dd2-c43bccf4c30b" 50 | expect(activity.histories[0].uuid).to eql "37d57a99-2647-4114-9dd2-c43bccf4c30b" 51 | expect(activity.histories[0].start_city.display_name).to eql "San Francisco" 52 | expect(activity.histories[0].start_city.latitude).to eql 37.7749295 53 | expect(activity.histories[0].start_city.longitude).to eql -122.4194155 54 | end 55 | end 56 | -------------------------------------------------------------------------------- /spec/lib/api/deliveries_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | require 'uber' 3 | 4 | describe Uber::API::Deliveries do 5 | let!(:client) { setup_client } 6 | 7 | describe 'on requesting deliveries' do 8 | before do 9 | stub_uber_request(:get, 'v1/deliveries', 10 | { 11 | "count" => 172, 12 | "next_page" => "status=completed&limit=10&offset=10", 13 | "previous_page" => "", 14 | "deliveries" => [ 15 | {"courier"=> 16 | {"location"=> 17 | {"latitude"=>40.7619629893, "longitude"=>-74.0014480227, "bearing"=>33}, 18 | "name"=>"Rob", 19 | "phone"=>"+18622564699", 20 | "picture_url"=> 21 | "https://d297l2q4lq2ras.cloudfront.net/nomad/2014/10/16/18/479x479_id_dba13493-27db-4d39-a322-8cb5eca67b54.jpeg", 22 | "vehicle"=> 23 | {"license_plate"=>"RUSHNYC", 24 | "make"=>"Acura", 25 | "model"=>"ZDX", 26 | "picture_url"=>nil}}, 27 | "created_at"=>1441147296, 28 | "currency_code"=>"USD", 29 | "delivery_id"=>"8b58bc58-7352-4278-b569-b5d24d8e3f76", 30 | "dropoff"=> 31 | {"contact"=> 32 | {"company_name"=>"Gizmo Shop", 33 | "email"=>"contact@uber.com", 34 | "first_name"=>"Calvin", 35 | "last_name"=>"Lee", 36 | "phone"=>{"number"=>"+14081234567", "sms_enabled"=>false}, 37 | "send_email_notifications"=>true, 38 | "send_sms_notifications"=>true}, 39 | "eta"=>30, 40 | "location"=> 41 | {"address"=>"530 W 113th Street", 42 | "address_2"=>"Floor 2", 43 | "city"=>"New York", 44 | "country"=>"US", 45 | "postal_code"=>"10025", 46 | "state"=>"NY"}, 47 | "signature_required"=>false, 48 | "special_instructions"=>nil}, 49 | "fee"=>5.0, 50 | "items"=> 51 | [{"height"=>5, 52 | "is_fragile"=>false, 53 | "length"=>14.5, 54 | "price"=>1, 55 | "quantity"=>1, 56 | "title"=>"Shoes", 57 | "weight"=>2, 58 | "width"=>7}, 59 | {"height"=>5, 60 | "is_fragile"=>false, 61 | "length"=>25, 62 | "quantity"=>1, 63 | "title"=>"Guitar", 64 | "weight"=>10, 65 | "width"=>12}], 66 | "order_reference_id"=>"SDA124KA", 67 | "pickup"=> 68 | {"contact"=> 69 | {"company_name"=>"Gizmo Shop", 70 | "email"=>"contact@uber.com", 71 | "first_name"=>"Calvin", 72 | "last_name"=>"Lee", 73 | "phone"=>{"number"=>"+14081234567", "sms_enabled"=>false}, 74 | "send_email_notifications"=>true, 75 | "send_sms_notifications"=>true}, 76 | "eta"=>4, 77 | "location"=> 78 | {"address"=>"636 W 28th Street", 79 | "address_2"=>"Floor 2", 80 | "city"=>"New York", 81 | "country"=>"US", 82 | "postal_code"=>"10001", 83 | "state"=>"NY"}, 84 | "special_instructions"=>"Go to pickup counter in back of shop."}, 85 | "quote_id"=> 86 | "KEBiNmI4MWQ0NDIzNjUyNjE1ZmM5YzlkNDQ5NDA4MzhlNTg5MWZlNzQ5YTNmZTRkYzQxZTgxMzc4YjlkZjU0Yjc2Fbamsd4KFeavsd4KFYD1sgwcFdD/0oQDFYfw48EFABwVyoCThQMVp/qvwQUAGANVU0QA", 87 | "status"=>"en_route_to_pickup", 88 | "tracking_url"=>"https://trip.uber.com/v2/share/-JazZXXuBl", 89 | "batch"=> 90 | {"batch_id"=>"963233d3-e8ad-4ed9-aae7-95446ffee22f", 91 | "count"=>2, 92 | "deliveries"=> 93 | ["8b58bc58-7352-4278-b569-b5d24d8e3f76", 94 | "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"]} 95 | } 96 | ] 97 | } 98 | ) 99 | end 100 | it 'should return list of all deliveries' do 101 | deliveries = client.deliveries.list 102 | expect(deliveries.size).to eql 1 103 | 104 | expect(deliveries[0].courier.class).to eql Hash 105 | expect(deliveries[0].created_at).to eql ::Time.at(1441147296) 106 | expect(deliveries[0].currency_code).to eql 'USD' 107 | expect(deliveries[0].delivery_id).to eql '8b58bc58-7352-4278-b569-b5d24d8e3f76' 108 | expect(deliveries[0].dropoff.class).to eql Hash 109 | expect(deliveries[0].fee).to eql 5.0 110 | expect(deliveries[0].items.class).to eql Array 111 | expect(deliveries[0].order_reference_id).to eql 'SDA124KA' 112 | expect(deliveries[0].pickup.class).to eql Hash 113 | expect(deliveries[0].quote_id).to eql 'KEBiNmI4MWQ0NDIzNjUyNjE1ZmM5YzlkNDQ5NDA4MzhlNTg5MWZlNzQ5YTNmZTRkYzQxZTgxMzc4YjlkZjU0Yjc2Fbamsd4KFeavsd4KFYD1sgwcFdD/0oQDFYfw48EFABwVyoCThQMVp/qvwQUAGANVU0QA' 114 | expect(deliveries[0].status).to eql 'en_route_to_pickup' 115 | expect(deliveries[0].tracking_url).to eql 'https://trip.uber.com/v2/share/-JazZXXuBl' 116 | expect(deliveries[0].batch.class).to eql Hash 117 | end 118 | end 119 | 120 | describe 'on requesting a particular delivery' do 121 | before do 122 | stub_uber_request(:get, "v1/deliveries/8b58bc58-7352-4278-b569-b5d24d8e3f76", 123 | { 124 | "courier"=> 125 | {"location"=> 126 | {"latitude"=>40.7619629893, "longitude"=>-74.0014480227, "bearing"=>33}, 127 | "name"=>"Rob", 128 | "phone"=>"+18622564699", 129 | "picture_url"=> 130 | "https://d297l2q4lq2ras.cloudfront.net/nomad/2014/10/16/18/479x479_id_dba13493-27db-4d39-a322-8cb5eca67b54.jpeg", 131 | "vehicle"=> 132 | {"license_plate"=>"RUSHNYC", 133 | "make"=>"Acura", 134 | "model"=>"ZDX", 135 | "picture_url"=>nil}}, 136 | "created_at"=>1441147296, 137 | "currency_code"=>"USD", 138 | "delivery_id"=>"8b58bc58-7352-4278-b569-b5d24d8e3f76", 139 | "dropoff"=> 140 | {"contact"=> 141 | {"company_name"=>"Gizmo Shop", 142 | "email"=>"contact@uber.com", 143 | "first_name"=>"Calvin", 144 | "last_name"=>"Lee", 145 | "phone"=>{"number"=>"+14081234567", "sms_enabled"=>false}, 146 | "send_email_notifications"=>true, 147 | "send_sms_notifications"=>true}, 148 | "eta"=>30, 149 | "location"=> 150 | {"address"=>"530 W 113th Street", 151 | "address_2"=>"Floor 2", 152 | "city"=>"New York", 153 | "country"=>"US", 154 | "postal_code"=>"10025", 155 | "state"=>"NY"}, 156 | "signature_required"=>false, 157 | "special_instructions"=>nil}, 158 | "fee"=>5.0, 159 | "items"=> 160 | [{"height"=>5, 161 | "is_fragile"=>false, 162 | "length"=>14.5, 163 | "price"=>1, 164 | "quantity"=>1, 165 | "title"=>"Shoes", 166 | "weight"=>2, 167 | "width"=>7}, 168 | {"height"=>5, 169 | "is_fragile"=>false, 170 | "length"=>25, 171 | "quantity"=>1, 172 | "title"=>"Guitar", 173 | "weight"=>10, 174 | "width"=>12}], 175 | "order_reference_id"=>"SDA124KA", 176 | "pickup"=> 177 | {"contact"=> 178 | {"company_name"=>"Gizmo Shop", 179 | "email"=>"contact@uber.com", 180 | "first_name"=>"Calvin", 181 | "last_name"=>"Lee", 182 | "phone"=>{"number"=>"+14081234567", "sms_enabled"=>false}, 183 | "send_email_notifications"=>true, 184 | "send_sms_notifications"=>true}, 185 | "eta"=>4, 186 | "location"=> 187 | {"address"=>"636 W 28th Street", 188 | "address_2"=>"Floor 2", 189 | "city"=>"New York", 190 | "country"=>"US", 191 | "postal_code"=>"10001", 192 | "state"=>"NY"}, 193 | "special_instructions"=>"Go to pickup counter in back of shop."}, 194 | "quote_id"=> 195 | "KEBiNmI4MWQ0NDIzNjUyNjE1ZmM5YzlkNDQ5NDA4MzhlNTg5MWZlNzQ5YTNmZTRkYzQxZTgxMzc4YjlkZjU0Yjc2Fbamsd4KFeavsd4KFYD1sgwcFdD/0oQDFYfw48EFABwVyoCThQMVp/qvwQUAGANVU0QA", 196 | "status"=>"en_route_to_pickup", 197 | "tracking_url"=>"https://trip.uber.com/v2/share/-JazZXXuBl", 198 | "batch"=> 199 | {"batch_id"=>"963233d3-e8ad-4ed9-aae7-95446ffee22f", 200 | "count"=>2, 201 | "deliveries"=> 202 | ["8b58bc58-7352-4278-b569-b5d24d8e3f76", 203 | "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"]} 204 | }) 205 | end 206 | 207 | it 'should give detail about that delivery' do 208 | delivery = client.deliveries.retrieve("8b58bc58-7352-4278-b569-b5d24d8e3f76") 209 | 210 | expect(delivery.courier.class).to eql Hash 211 | expect(delivery.created_at).to eql ::Time.at(1441147296) 212 | expect(delivery.currency_code).to eql 'USD' 213 | expect(delivery.delivery_id).to eql '8b58bc58-7352-4278-b569-b5d24d8e3f76' 214 | expect(delivery.dropoff.class).to eql Hash 215 | expect(delivery.fee).to eql 5.0 216 | expect(delivery.items.class).to eql Array 217 | expect(delivery.order_reference_id).to eql 'SDA124KA' 218 | expect(delivery.pickup.class).to eql Hash 219 | expect(delivery.quote_id).to eql 'KEBiNmI4MWQ0NDIzNjUyNjE1ZmM5YzlkNDQ5NDA4MzhlNTg5MWZlNzQ5YTNmZTRkYzQxZTgxMzc4YjlkZjU0Yjc2Fbamsd4KFeavsd4KFYD1sgwcFdD/0oQDFYfw48EFABwVyoCThQMVp/qvwQUAGANVU0QA' 220 | expect(delivery.status).to eql 'en_route_to_pickup' 221 | expect(delivery.tracking_url).to eql 'https://trip.uber.com/v2/share/-JazZXXuBl' 222 | expect(delivery.batch.class).to eql Hash 223 | end 224 | end 225 | 226 | describe 'on creating a delivery' do 227 | before do 228 | stub_uber_request(:post, "v1/deliveries", 229 | {"courier"=>nil, 230 | "created_at"=>1441146983, 231 | "currency_code"=>"USD", 232 | "delivery_id"=>"b32d5374-7cee-4bc0-b588-f3820ab9b98c", 233 | "dropoff"=> 234 | {"contact"=> 235 | {"company_name"=>"Gizmo Shop", 236 | "email"=>"contact@uber.com", 237 | "first_name"=>"Calvin", 238 | "last_name"=>"Lee", 239 | "phone"=>{"number"=>"+14081234567", "sms_enabled"=>false}, 240 | "send_email_notifications"=>true, 241 | "send_sms_notifications"=>true}, 242 | "eta"=>20, 243 | "location"=> 244 | {"address"=>"530 W 113th Street", 245 | "address_2"=>"Floor 2", 246 | "city"=>"New York", 247 | "country"=>"US", 248 | "postal_code"=>"10025", 249 | "state"=>"NY"}, 250 | "signature_required"=>false, 251 | "special_instructions"=>nil}, 252 | "fee"=>5, 253 | "items"=> 254 | [{"height"=>5, 255 | "is_fragile"=>false, 256 | "length"=>14.5, 257 | "price"=>1, 258 | "quantity"=>1, 259 | "title"=>"Shoes", 260 | "weight"=>2, 261 | "width"=>7}, 262 | {"height"=>5, 263 | "is_fragile"=>false, 264 | "length"=>25, 265 | "quantity"=>1, 266 | "title"=>"Guitar", 267 | "weight"=>10, 268 | "width"=>12}], 269 | "order_reference_id"=>"SDA124KA", 270 | "pickup"=> 271 | {"contact"=> 272 | {"company_name"=>"Gizmo Shop", 273 | "email"=>"contact@uber.com", 274 | "first_name"=>"Calvin", 275 | "last_name"=>"Lee", 276 | "phone"=>{"number"=>"+14081234567", "sms_enabled"=>false}, 277 | "send_email_notifications"=>true, 278 | "send_sms_notifications"=>true}, 279 | "eta"=>5, 280 | "location"=> 281 | {"address"=>"636 W 28th Street", 282 | "address_2"=>"Floor 2", 283 | "city"=>"New York", 284 | "country"=>"US", 285 | "postal_code"=>"10001", 286 | "state"=>"NY"}, 287 | "special_instructions"=>"Go to pickup counter in back of shop."}, 288 | "quote_id"=> 289 | "KEBjNGUxNjhlZmNmMDA4ZGJjNmJlY2EwOGJlN2M0ZjdmZjI2Y2VkZDdmMmQ2MDJlZDJjMTc4MzM2ODU2YzRkMzU4FYihsd4KFbiqsd4KFYD1sgwcFdD/0oQDFYfw48EFABwVyoCThQMVp/qvwQUAGANVU0QA", 290 | "status"=>"processing", 291 | "tracking_url"=>nil, 292 | "batch"=> 293 | {"batch_id"=>"963233d3-e8ad-4ed9-aae7-95446ffee22f", 294 | "count"=>2, 295 | "deliveries"=> 296 | ["8b58bc58-7352-4278-b569-b5d24d8e3f76", 297 | "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"]} 298 | }, 299 | body: { 300 | "dropoff"=> 301 | {"contact"=> 302 | {"company_name"=>"Gizmo Shop", 303 | "email"=>"contact@uber.com", 304 | "first_name"=>"Calvin", 305 | "last_name"=>"Lee", 306 | "phone"=>{"number"=>"+14081234567", "sms_enabled"=>false}, 307 | "send_email_notifications"=>true, 308 | "send_sms_notifications"=>true}, 309 | "eta"=>20, 310 | "location"=> 311 | {"address"=>"530 W 113th Street", 312 | "address_2"=>"Floor 2", 313 | "city"=>"New York", 314 | "country"=>"US", 315 | "postal_code"=>"10025", 316 | "state"=>"NY"}, 317 | "signature_required"=>false, 318 | "special_instructions"=>nil}, 319 | "items"=> 320 | [{"height"=>5, 321 | "is_fragile"=>false, 322 | "length"=>14.5, 323 | "price"=>1, 324 | "quantity"=>1, 325 | "title"=>"Shoes", 326 | "weight"=>2, 327 | "width"=>7}, 328 | {"height"=>5, 329 | "is_fragile"=>false, 330 | "length"=>25, 331 | "quantity"=>1, 332 | "title"=>"Guitar", 333 | "weight"=>10, 334 | "width"=>12}], 335 | "order_reference_id"=>"SDA124KA", 336 | "pickup"=> 337 | {"contact"=> 338 | {"company_name"=>"Gizmo Shop", 339 | "email"=>"contact@uber.com", 340 | "first_name"=>"Calvin", 341 | "last_name"=>"Lee", 342 | "phone"=>{"number"=>"+14081234567", "sms_enabled"=>false}, 343 | "send_email_notifications"=>true, 344 | "send_sms_notifications"=>true}, 345 | "location"=> 346 | {"address"=>"636 W 28th Street", 347 | "address_2"=>"Floor 2", 348 | "city"=>"New York", 349 | "country"=>"US", 350 | "postal_code"=>"10001", 351 | "state"=>"NY"}, 352 | "special_instructions"=>"Go to pickup counter in back of shop."}, 353 | "quote_id"=> 354 | "KEBjNGUxNjhlZmNmMDA4ZGJjNmJlY2EwOGJlN2M0ZjdmZjI2Y2VkZDdmMmQ2MDJlZDJjMTc4MzM2ODU2YzRkMzU4FYihsd4KFbiqsd4KFYD1sgwcFdD/0oQDFYfw48EFABwVyoCThQMVp/qvwQUAGANVU0QA" 355 | }.to_json, 356 | status_code: 200 357 | ) 358 | end 359 | it 'should return newly created delivery' do 360 | delivery = client.deliveries.add_delivery({ 361 | "dropoff"=> 362 | {"contact"=> 363 | {"company_name"=>"Gizmo Shop", 364 | "email"=>"contact@uber.com", 365 | "first_name"=>"Calvin", 366 | "last_name"=>"Lee", 367 | "phone"=>{"number"=>"+14081234567", "sms_enabled"=>false}, 368 | "send_email_notifications"=>true, 369 | "send_sms_notifications"=>true}, 370 | "eta"=>20, 371 | "location"=> 372 | {"address"=>"530 W 113th Street", 373 | "address_2"=>"Floor 2", 374 | "city"=>"New York", 375 | "country"=>"US", 376 | "postal_code"=>"10025", 377 | "state"=>"NY"}, 378 | "signature_required"=>false, 379 | "special_instructions"=>nil}, 380 | "items"=> 381 | [{"height"=>5, 382 | "is_fragile"=>false, 383 | "length"=>14.5, 384 | "price"=>1, 385 | "quantity"=>1, 386 | "title"=>"Shoes", 387 | "weight"=>2, 388 | "width"=>7}, 389 | {"height"=>5, 390 | "is_fragile"=>false, 391 | "length"=>25, 392 | "quantity"=>1, 393 | "title"=>"Guitar", 394 | "weight"=>10, 395 | "width"=>12}], 396 | "order_reference_id"=>"SDA124KA", 397 | "pickup"=> 398 | {"contact"=> 399 | {"company_name"=>"Gizmo Shop", 400 | "email"=>"contact@uber.com", 401 | "first_name"=>"Calvin", 402 | "last_name"=>"Lee", 403 | "phone"=>{"number"=>"+14081234567", "sms_enabled"=>false}, 404 | "send_email_notifications"=>true, 405 | "send_sms_notifications"=>true}, 406 | "location"=> 407 | {"address"=>"636 W 28th Street", 408 | "address_2"=>"Floor 2", 409 | "city"=>"New York", 410 | "country"=>"US", 411 | "postal_code"=>"10001", 412 | "state"=>"NY"}, 413 | "special_instructions"=>"Go to pickup counter in back of shop."}, 414 | "quote_id"=> 415 | "KEBjNGUxNjhlZmNmMDA4ZGJjNmJlY2EwOGJlN2M0ZjdmZjI2Y2VkZDdmMmQ2MDJlZDJjMTc4MzM2ODU2YzRkMzU4FYihsd4KFbiqsd4KFYD1sgwcFdD/0oQDFYfw48EFABwVyoCThQMVp/qvwQUAGANVU0QA" 416 | }) 417 | expect(delivery.delivery_id).to eql "b32d5374-7cee-4bc0-b588-f3820ab9b98c" 418 | end 419 | end 420 | 421 | describe 'on adding quote' do 422 | before do 423 | stub_uber_request(:post, 'v1/deliveries/quote', 424 | {"quotes"=> 425 | [{"quote_id"=> 426 | "CwACAAAAQGU0NTYwYjUyNjY4YzBjNDBiNDFjYzA4ZDdlNzE0OWM3ZmYxZjY0NTJkNDQ1NjE2NDg3NDI1ZmFkZjZiYTI1ODcIAANXHm3xCAAEVx5wSQgABQBSs-AMAAYIAAEYXJdJCAAC0_FrQwAMAAcIAAEYWt-7CAAC0_BeNAALAAgAAAADVVNEAA==", 427 | "estimated_at"=>1461612017, 428 | "expires_at"=>1461612617, 429 | "fee"=>5.42, 430 | "currency_code"=>"USD", 431 | "pickup_eta"=>6, 432 | "dropoff_eta"=>13}, 433 | {"quote_id"=> 434 | "CwACAAAAQDNkMWZhMDg0ZWJiNzkwMTA4MGNmNzlkMTdlN2U1MGE2YzI1NTQ0Yzc4ZmIwOTIyNzUwMDc0ZDNjNGFhZjRlYjMIAANXHm3xCAAEVx5wSQgABQBCOSAMAAYIAAEYXJdJCAAC0_FrQwAMAAcIAAEYWt-7CAAC0_BeNAALAAgAAAADVVNECgAJAAABVE84wIAKAAoAAAFUT2-vAAoACwAAAVRPLXXgAA==", 435 | "estimated_at"=>1461612017, 436 | "expires_at"=>1461612617, 437 | "start_time"=>1461618000, 438 | "end_time"=>1461621600, 439 | "fee"=>4.34, 440 | "currency_code"=>"USD", 441 | "ready_by_time"=>1461617260}, 442 | {"quote_id"=> 443 | "CwACAAAAQGViOWFkM2E5NTBkZDlmOWI1NjI4ODc0NTljMjc3OWFlZWY1YmVkODVhMzc4MGQ4N2RlNTI3NDAzNWU3NTIxYzUIAANXHm3xCAAEVx5wSQgABQBCOSAMAAYIAAEYXJdJCAAC0_FrQwAMAAcIAAEYWt-7CAAC0_BeNAALAAgAAAADVVNECgAJAAABVE9vrwAKAAoAAAFUT6adgAoACwAAAVRPZGRgAA==", 444 | "estimated_at"=>1461612017, 445 | "expires_at"=>1461612617, 446 | "start_time"=>1461621600, 447 | "end_time"=>1461625200, 448 | "fee"=>4.34, 449 | "currency_code"=>"USD", 450 | "ready_by_time"=>1461620860}, 451 | {"quote_id"=> 452 | "CwACAAAAQDljOGJkZmVjZjg0NDgwNGJhY2UyNDAzYTU4NjA3OTc5MjA3NmIxMmJmMjNhOTM3YWQ0NGM3NGMwYzNjNTM4OTQIAANXHm3xCAAEVx5wSQgABQBCOSAMAAYIAAEYXJdJCAAC0_FrQwAMAAcIAAEYWt-7CAAC0_BeNAALAAgAAAADVVNECgAJAAABVE-mnYAKAAoAAAFUT92MAAoACwAAAVRPm1LgAA==", 453 | "estimated_at"=>1461612017, 454 | "expires_at"=>1461612617, 455 | "start_time"=>1461625200, 456 | "end_time"=>1461628800, 457 | "fee"=>4.34, 458 | "currency_code"=>"USD", 459 | "ready_by_time"=>1461624460}] 460 | }, 461 | body: { 462 | "pickup" => { 463 | "location" => { 464 | "address"=>"636 W 28th Street", 465 | "address_2"=>"Floor 2", 466 | "city"=>"New York", 467 | "country"=>"US", 468 | "postal_code"=>"10001", 469 | "state"=>"NY" 470 | } 471 | }, 472 | "dropoff" => { 473 | "location" => { 474 | "address"=>"530 W 113th Street", 475 | "address_2"=>"Floor 2", 476 | "city"=>"New York", 477 | "country"=>"US", 478 | "postal_code"=>"10025", 479 | "state"=>"NY" 480 | } 481 | } 482 | }.to_json, 483 | status_code: 201 484 | ) 485 | end 486 | 487 | it 'should return on-demand and scheduled delivery quotes' do 488 | quotes = client.deliveries.add_quote({ 489 | "pickup" => { 490 | "location" => { 491 | "address"=>"636 W 28th Street", 492 | "address_2"=>"Floor 2", 493 | "city"=>"New York", 494 | "country"=>"US", 495 | "postal_code"=>"10001", 496 | "state"=>"NY" 497 | } 498 | }, 499 | "dropoff" => { 500 | "location" => { 501 | "address"=>"530 W 113th Street", 502 | "address_2"=>"Floor 2", 503 | "city"=>"New York", 504 | "country"=>"US", 505 | "postal_code"=>"10025", 506 | "state"=>"NY" 507 | } 508 | } 509 | }) 510 | expect(quotes.size).to eql 4 511 | 512 | expect(quotes[0].quote_id).to eql 'CwACAAAAQGU0NTYwYjUyNjY4YzBjNDBiNDFjYzA4ZDdlNzE0OWM3ZmYxZjY0NTJkNDQ1NjE2NDg3NDI1ZmFkZjZiYTI1ODcIAANXHm3xCAAEVx5wSQgABQBSs-AMAAYIAAEYXJdJCAAC0_FrQwAMAAcIAAEYWt-7CAAC0_BeNAALAAgAAAADVVNEAA==' 513 | expect(quotes[0].estimated_at).to eql Time.at(1461612017) 514 | expect(quotes[0].expires_at).to eql Time.at(1461612617) 515 | expect(quotes[0].fee).to eql 5.42 516 | expect(quotes[0].currency_code).to eql 'USD' 517 | expect(quotes[0].pickup_eta).to eql 6 518 | expect(quotes[0].dropoff_eta).to eql 13 519 | end 520 | end 521 | 522 | describe 'on requesting receipt' do 523 | before do 524 | stub_uber_request(:get, 'v1/deliveries/78aa3783-e845-4a85-910c-be30dd0c712b/receipt', 525 | {"charges"=>[{"amount"=>9.79, "name"=>"Trip fare"}], 526 | "charge_adjustments"=> 527 | [{"amount"=>-1, "name"=>"Uber Credit"}, 528 | {"amount"=>-2.62, "name"=>"Batch Discount"}], 529 | "delivery_id"=>"78aa3783-e845-4a85-910c-be30dd0c712b", 530 | "currency_code"=>"USD", 531 | "total_fee"=>6.17}) 532 | end 533 | it 'should return delivery receipt with details' do 534 | receipt = client.deliveries.receipt('78aa3783-e845-4a85-910c-be30dd0c712b') 535 | expect(receipt.charges.class).to eql Array 536 | expect(receipt.charge_adjustments.class).to eql Array 537 | expect(receipt.delivery_id).to eql '78aa3783-e845-4a85-910c-be30dd0c712b' 538 | expect(receipt.currency_code).to eql 'USD' 539 | expect(receipt.total_fee).to eql 6.17 540 | end 541 | end 542 | 543 | describe 'on requesting ratings of a delivery' do 544 | before do 545 | stub_uber_request(:get, 'v1/deliveries/8b58bc58-7352-4278-b569-b5d24d8e3f76/ratings', 546 | {"ratings"=> 547 | [{"waypoint"=>"pickup", 548 | "rating_type"=>"binary", 549 | "rating_value"=>0, 550 | "tags"=>["courier_unprofessional", "courier_remained_at_curbside"], 551 | "comments"=>"Courier was not professionally dressed."}, 552 | {"waypoint"=>"dropoff", 553 | "rating_type"=>"binary", 554 | "rating_value"=>0, 555 | "tags"=>["courier_not_on_time", "delivery_in_good_condition"], 556 | "comments"=>"Courier was not professionally dressed."}] 557 | }) 558 | end 559 | it 'should return all avilable ratings for that delivery' do 560 | ratings = client.deliveries.ratings('8b58bc58-7352-4278-b569-b5d24d8e3f76') 561 | 562 | expect(ratings.size).to eql 2 563 | expect(ratings[0].waypoint).to eql 'pickup' 564 | expect(ratings[0].rating_type).to eql 'binary' 565 | expect(ratings[0].rating_value).to eql 0 566 | expect(ratings[0].tags).to eql ["courier_unprofessional", "courier_remained_at_curbside"] 567 | expect(ratings[0].comments).to eql 'Courier was not professionally dressed.' 568 | end 569 | end 570 | 571 | describe 'on adding a rating to a delivery' do 572 | before do 573 | stub_uber_request(:post, 'v1/deliveries/8b58bc58-7352-4278-b569-b5d24d8e3f76/rating', 574 | nil, 575 | body: {"waypoint"=>"dropoff", 576 | "rating_type"=>"binary", 577 | "rating_value"=>0, 578 | "tags"=>["courier_not_on_time", "delivery_in_good_condition"], 579 | "comments"=>"Courier was not professionally dressed."}.to_json, 580 | status_code: 204 581 | ) 582 | end 583 | 584 | it 'should create rating and return nothing' do 585 | status = client.deliveries.add_rating('8b58bc58-7352-4278-b569-b5d24d8e3f76', 586 | {"waypoint"=>"dropoff", 587 | "rating_type"=>"binary", 588 | "rating_value"=>0, 589 | "tags"=>["courier_not_on_time", "delivery_in_good_condition"], 590 | "comments"=>"Courier was not professionally dressed."}) 591 | expect(status).to eql 204 592 | end 593 | end 594 | 595 | describe 'on request delivery rating tags' do 596 | before do 597 | stub_uber_request(:get, 'v1/deliveries/8b58bc58-7352-4278-b569-b5d24d8e3f76/rating_tags', 598 | {"rating_tags"=> 599 | [{"waypoint"=>"pickup", 600 | "tags"=> 601 | ["courier_remained_at_curbside", 602 | "courier_missing_delivery_bag", 603 | "courier_unprofessional", 604 | "courier_late_to_pickup", 605 | "courier_late_to_dropoff", 606 | "inaccurate_eta", 607 | "courier_missed_pickup_instructions"]}, 608 | {"waypoint"=>"dropoff", 609 | "tags"=> 610 | ["courier_on_time", 611 | "courier_not_on_time", 612 | "delivery_in_good_condition", 613 | "delivery_in_bad_condition", 614 | "courier_good_service", 615 | "courier_bad_service"]}] 616 | }) 617 | end 618 | it 'should return all available rating tags for the delivery' do 619 | tags = client.deliveries.rating_tags('8b58bc58-7352-4278-b569-b5d24d8e3f76') 620 | 621 | expect(tags.size).to eql 2 622 | expect(tags[0].waypoint).to eql 'pickup' 623 | expect(tags[0].tags.class).to eql Array 624 | expect(tags[0].tags).to eql ["courier_remained_at_curbside", "courier_missing_delivery_bag", 625 | "courier_unprofessional", "courier_late_to_pickup", 626 | "courier_late_to_dropoff", "inaccurate_eta", 627 | "courier_missed_pickup_instructions"] 628 | end 629 | end 630 | 631 | describe 'on canceling the delivery' do 632 | before do 633 | stub_uber_request(:post, 'v1/deliveries/8b58bc58-7352-4278-b569-b5d24d8e3f76/cancel', nil, 634 | body: {}.to_json, status_code: 204) 635 | end 636 | it 'should cancel the delivery request and return status code' do 637 | status = client.deliveries.cancel('8b58bc58-7352-4278-b569-b5d24d8e3f76') 638 | expect(status).to eql 204 639 | end 640 | end 641 | 642 | describe 'on requesting regions' do 643 | before do 644 | stub_uber_request(:get, 'v1/deliveries/regions', 645 | {"regions"=> 646 | [{"city"=>"San Francisco", 647 | "country"=>"USA", 648 | "type"=>"FeatureCollection", 649 | "features"=> 650 | [{"type"=>"Feature", 651 | "properties"=>{}, 652 | "geometry"=> 653 | {"type"=>"Polygon", 654 | "coordinates"=> 655 | [[[-122.52330780029295, 37.80815648152641], 656 | [-122.38357543945312, 37.81385247479046], 657 | [-122.33379364013672, 37.69197100839692], 658 | [-122.50888824462889, 37.67920120945425], 659 | [-122.52330780029295, 37.80815648152641]]]}} 660 | ] 661 | }] 662 | }) 663 | end 664 | it 'should return all regions where UberRUSH is available' do 665 | regions = client.deliveries.regions 666 | expect(regions.size).to eql 1 667 | expect(regions[0].city).to eql 'San Francisco' 668 | expect(regions[0].country).to eql 'USA' 669 | expect(regions[0].type).to eql 'FeatureCollection' 670 | expect(regions[0].features.class).to eql Array 671 | end 672 | end 673 | end 674 | -------------------------------------------------------------------------------- /spec/lib/api/me_spec.rb: -------------------------------------------------------------------------------- 1 | require "spec_helper" 2 | require "uber" 3 | 4 | describe Uber::API::Me do 5 | let!(:client) { setup_client } 6 | 7 | before do 8 | stub_uber_request(:get, "v1/me", 9 | # From: https://developer.uber.com/v1/endpoints/#user-profile 10 | { 11 | "first_name" => "Uber", 12 | "last_name" => "Developer", 13 | "email" => "developer@uber.com", 14 | "picture" => "https://cloudfront.net/deadbeef.jpg", 15 | "promo_code" => "teypo", 16 | "uuid" => "91d81273-45c2-4b57-8124-d0165f8240c0", 17 | "mobile_verified" => true 18 | }) 19 | end 20 | 21 | it "should return the user profile" do 22 | profile = client.me 23 | expect(profile.first_name).to eql "Uber" 24 | expect(profile.last_name).to eql "Developer" 25 | expect(profile.email).to eql "developer@uber.com" 26 | expect(profile.picture).to eql "https://cloudfront.net/deadbeef.jpg" 27 | expect(profile.promo_code).to eql "teypo" 28 | expect(profile.uuid).to eql "91d81273-45c2-4b57-8124-d0165f8240c0" 29 | expect(profile.mobile_verified).to be true 30 | expect(profile.mobile_verified?).to be true 31 | end 32 | end 33 | -------------------------------------------------------------------------------- /spec/lib/api/partners_spec.rb: -------------------------------------------------------------------------------- 1 | require "spec_helper" 2 | require "uber" 3 | 4 | 5 | describe Uber::API::Partners do 6 | let!(:client) { setup_client } 7 | 8 | describe "profile" do 9 | before do 10 | stub_uber_request(:get, 'v1/partners/me', 11 | {"driver_id" => "3ag923b1-ff5d-4422-80da-a5cefdca3cea", 12 | "first_name" => "John", 13 | "last_name" => "Driver", 14 | "phone_number" => "+12345678901", 15 | "email" => "john@example.com", 16 | "picture" => "https://subdomain.cloudfront.net/default.jpeg", 17 | "rating" => 4.9, 18 | "promo_code" => "join_john_on_uber", 19 | "activation_status" => "active" 20 | } 21 | ) 22 | end 23 | it 'should give profile of authenticated driver' do 24 | driver = client.partners.me 25 | expect(driver).to be_instance_of Uber::Partner::Partner 26 | expect(driver.driver_id).to eql "3ag923b1-ff5d-4422-80da-a5cefdca3cea" 27 | expect(driver.first_name).to eql 'John' 28 | expect(driver.last_name).to eql 'Driver' 29 | expect(driver.phone_number).to eql "+12345678901" 30 | expect(driver.email).to eql 'john@example.com' 31 | expect(driver.rating).to eql 4.9 32 | expect(driver.picture).to eql "https://subdomain.cloudfront.net/default.jpeg" 33 | expect(driver.promo_code).to eql "join_john_on_uber" 34 | expect(driver.activation_status).to eql 'active' 35 | end 36 | 37 | end 38 | 39 | describe "payments" do 40 | describe 'without options' do 41 | before do 42 | stub_uber_request(:get, 'v1/partners/payments', 43 | {"offset" => 0, 44 | "limit" => 2, 45 | "count" => 123, 46 | "payments" => [{"category" => "fare", 47 | "breakdown" => {"other" => 6.83, 48 | "toll" => 2, 49 | "service_fee" => -1.2}, 50 | "rider_fees" => {"split_fare" => 0.5}, 51 | "event_time" => 1465224550, 52 | "trip_id" => "c72787af", 53 | "cash_collected" => 7.63, 54 | "amount" => 7.63, 55 | "driver_id" => "8LaCLRbV", 56 | "partner_id" => "8LaCLRbV", 57 | "currency_code" => "USD"}, 58 | {"category" => "device_payment", 59 | "breakdown" => {"other" => 0}, 60 | "event_time" => 1465646574, 61 | "trip_id" => nil, 62 | "cash_collected" => 0, 63 | "amount" => -5, 64 | "driver_id" => "8LaCLRbV", 65 | "rider_fees" => {}, 66 | "partner_id" => "8LaCLRbV", 67 | "currency_code" => "USD"}] 68 | } 69 | ) 70 | end 71 | 72 | it 'should return information about payments' do 73 | payments = client.partners.payments 74 | expect(payments).to be_instance_of Uber::Partner::PaymentActivity 75 | expect(payments.payments).to be_instance_of Array 76 | expect(payments.payments.length).to eql 2 77 | expect(payments.payments.length).to eql [payments.count, payments.limit].min 78 | expect(payments.offset).to eql 0 79 | expect(payments.limit).to eql 2 80 | expect(payments.count).to eql 123 81 | payment = payments.payments.first 82 | expect(payment).to be_instance_of Uber::Partner::Payment 83 | expect(payment.category).to eql 'fare' 84 | expect(payment.event_time).to eql Time.at(1465224550) 85 | expect(payment.trip_id).to eql 'c72787af' 86 | expect(payment.cash_collected).to eql 7.63 87 | expect(payment.amount).to eql 7.63 88 | expect(payment.driver_id).to eql '8LaCLRbV' 89 | expect(payment.partner_id).to eql '8LaCLRbV' 90 | expect(payment.currency_code).to eql 'USD' 91 | end 92 | end 93 | 94 | describe 'with options' do 95 | before do 96 | stub_uber_request(:get, 'v1/partners/payments?limit=1&offset=1', 97 | {"offset" => 1, 98 | "limit" => 1, 99 | "count" => 123, 100 | "payments" => [{"category" => "device_payment", 101 | "breakdown" => {"other" => 0}, 102 | "event_time" => 1465646574, 103 | "trip_id" => nil, 104 | "cash_collected" => 0, 105 | "amount" => -5, 106 | "driver_id" => "8LaCLRbV", 107 | "rider_fees" => {}, 108 | "partner_id" => "8LaCLRbV", 109 | "currency_code" => "USD"}] 110 | } 111 | ) 112 | end 113 | 114 | it 'should return information about payments with correct limits' do 115 | payments = client.partners.payments(:limit => 1, :offset => 1) 116 | expect(payments).to be_instance_of Uber::Partner::PaymentActivity 117 | expect(payments.payments).to be_instance_of Array 118 | expect(payments.payments.length).to eql 1 119 | expect(payments.payments.length).to eql [payments.count, payments.limit].min 120 | expect(payments.offset).to eql 1 121 | expect(payments.limit).to eql 1 122 | expect(payments.count).to eql 123 123 | payment = payments.payments.first 124 | expect(payment).to be_instance_of Uber::Partner::Payment 125 | expect(payment.category).to eql 'device_payment' 126 | expect(payment.event_time).to eql Time.at(1465646574) 127 | expect(payment.trip_id).to eql nil 128 | expect(payment.cash_collected).to eql 0 129 | expect(payment.amount).to eql -5 130 | expect(payment.driver_id).to eql '8LaCLRbV' 131 | expect(payment.partner_id).to eql '8LaCLRbV' 132 | expect(payment.currency_code).to eql 'USD' 133 | end 134 | end 135 | end 136 | 137 | describe "trips" do 138 | describe 'without options' do 139 | before do 140 | stub_uber_request(:get, 'v1/partners/trips', 141 | {"count" => 1, 142 | "limit" => 10, 143 | "offset" => 0, 144 | "trips" => [{"dropoff" => {"timestamp" => 1455912051}, 145 | "vehicle_id" => "e6d1e6e8-fb19-49b5-b0a9-690672dab458", 146 | "distance" => 0, 147 | "start_city" => {"latitude" => 37.7749, 148 | "display_name" => "San Francisco", 149 | "longitude" => -122.4194}, 150 | "status_changes" => [{"status" => "accepted", 151 | "timestamp" => 1455910811}, 152 | {"status" => "driver_arrived", 153 | "timestamp" => 1455910831}, 154 | {"status" => "trip_began", 155 | "timestamp" => 1455910832}, 156 | {"status" => "completed", 157 | "timestamp" => 1455912051}], 158 | "pickup" => {"timestamp" => 1455910832}, 159 | "driver_id" => "8GhJMmFh8fxRCsIlzf8kY12cJx97COSXldXaCHRLfha_7UM8jyR3SVJyGSaV-eFlXpf2Fa6rAo15bQ_gkHq-5lS5D9CaCmHRTjycmUxiaC0ee1iTlJ1v7R5GydCONS46IA==", 160 | "status" => "completed", 161 | "duration" => 1220, 162 | "trip_id" => "e33f756b-16e9-4cb4-96d4-ef0d0e5c9838"}]} 163 | ) 164 | end 165 | 166 | it 'should return information about trips' do 167 | trips = client.partners.trips 168 | expect(trips).to be_instance_of Uber::Partner::TripActivity 169 | expect(trips.trips).to be_instance_of Array 170 | expect(trips.trips.length).to eql 1 171 | expect(trips.trips.length).to eql [trips.count, trips.limit].min 172 | expect(trips.count).to eql 1 173 | expect(trips.limit).to eql 10 174 | expect(trips.offset).to eql 0 175 | 176 | trip = trips.trips.first 177 | expect(trip).to be_instance_of Uber::Partner::Trip 178 | expect(trip.dropoff[:timestamp]).to eql 1455912051 179 | expect(trip.vehicle_id).to eql "e6d1e6e8-fb19-49b5-b0a9-690672dab458" 180 | expect(trip.distance).to eql 0 181 | expect(trip.start_city[:latitude]).to eql 37.7749 182 | expect(trip.start_city[:display_name]).to eql 'San Francisco' 183 | expect(trip.start_city[:longitude]).to eql -122.4194 184 | expect(trip.pickup[:timestamp]).to eql 1455910832 185 | expect(trip.driver_id).to eql "8GhJMmFh8fxRCsIlzf8kY12cJx97COSXldXaCHRLfha_7UM8jyR3SVJyGSaV-eFlXpf2Fa6rAo15bQ_gkHq-5lS5D9CaCmHRTjycmUxiaC0ee1iTlJ1v7R5GydCONS46IA==" 186 | expect(trip.status).to eql 'completed' 187 | expect(trip.duration).to eql 1220 188 | expect(trip.trip_id).to eql "e33f756b-16e9-4cb4-96d4-ef0d0e5c9838" 189 | 190 | status_change = trip.status_changes.first 191 | expect(status_change).to be_instance_of Uber::Partner::StatusChange 192 | expect(status_change.status).to eq 'accepted' 193 | expect(status_change.timestamp).to eq 1455910811 194 | expect(status_change.time).to eq ::Time.at(1455910811) 195 | end 196 | 197 | end 198 | 199 | describe 'with options' do 200 | before do 201 | stub_uber_request(:get, 'v1/partners/trips?offset=1&limit=1', 202 | {"count" => 1, 203 | "limit" => 1, 204 | "offset" => 1, 205 | "trips" => [{"dropoff" => {"timestamp" => 1455912051}, 206 | "vehicle_id" => "e6d1e6e8-fb19-49b5-b0a9-690672dab458", 207 | "distance" => 0, 208 | "start_city" => {"latitude" => 37.7749, 209 | "display_name" => "San Francisco", 210 | "longitude" => -122.4194}, 211 | "status_changes" => [{"status" => "accepted", 212 | "timestamp" => 1455910811}, 213 | {"status" => "driver_arrived", 214 | "timestamp" => 1455910831}, 215 | {"status" => "trip_began", 216 | "timestamp" => 1455910832}, 217 | {"status" => "completed", 218 | "timestamp" => 1455912051}], 219 | "pickup" => {"timestamp" => 1455910832}, 220 | "driver_id" => "8GhJMmFh8fxRCsIlzf8kY12cJx97COSXldXaCHRLfha_7UM8jyR3SVJyGSaV-eFlXpf2Fa6rAo15bQ_gkHq-5lS5D9CaCmHRTjycmUxiaC0ee1iTlJ1v7R5GydCONS46IA==", 221 | "status" => "completed", 222 | "duration" => 1220, 223 | "trip_id" => "e33f756b-16e9-4cb4-96d4-ef0d0e5c9838"}]} 224 | ) 225 | end 226 | 227 | it 'should return information about trips with limits' do 228 | trips = client.partners.trips(:offset => 1, :limit => 1) 229 | expect(trips.count).to eql 1 230 | expect(trips.limit).to eql 1 231 | expect(trips.offset).to eql 1 232 | expect(trips.trips.length).to eql [trips.limit, trips.count].min 233 | end 234 | 235 | end 236 | end 237 | end 238 | 239 | 240 | -------------------------------------------------------------------------------- /spec/lib/api/places_spec.rb: -------------------------------------------------------------------------------- 1 | require "spec_helper" 2 | require "uber" 3 | 4 | describe Uber::API::Places do 5 | let!(:client) { setup_client } 6 | 7 | before do 8 | stub_uber_request(:get, 'v1/places/home', {address: 'Mumbai, India'}) 9 | end 10 | 11 | it 'should return information about place' do 12 | place_request = client.place('home') 13 | expect(place_request.class).to eql Uber::Place 14 | expect(place_request.address).to eql 'Mumbai, India' 15 | end 16 | 17 | describe 'update' do 18 | before do 19 | stub_uber_request(:put, 'v1/places/work', {address: 'Mumbai, Maharashtra, India'}, body: {address: 'Mumbai, India'}.to_json) 20 | end 21 | 22 | it 'should save and return correct address' do 23 | place_request = client.place_update('work', 'Mumbai, India') 24 | expect(place_request.class).to eql Uber::Place 25 | expect(place_request.address).to eql 'Mumbai, Maharashtra, India' 26 | end 27 | end 28 | 29 | end -------------------------------------------------------------------------------- /spec/lib/api/price_estimates_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | require 'uber' 3 | 4 | describe Uber::API::PriceEstimates do 5 | let!(:client) { setup_client } 6 | 7 | before do 8 | stub_uber_request(:get, 'v1/estimates/price?start_latitude=0.0&start_longitude=0.5&end_latitude=0.0&end_longitude=0.6', 9 | # From: https://developer.uber.com/v1/endpoints/#price-estimates 10 | { 11 | "prices" => [ 12 | { 13 | "product_id" => "08f17084-23fd-4103-aa3e-9b660223934b", 14 | "currency_code" => "USD", 15 | "display_name" => "UberBLACK", 16 | "estimate" => "$23-29", 17 | "low_estimate" => 23, 18 | "high_estimate" => 29, 19 | "surge_multiplier" => 1, 20 | "duration" => 640, 21 | "distance" => 5.34 22 | }, 23 | { 24 | "product_id" => "9af0174c-8939-4ef6-8e91-1a43a0e7c6f6", 25 | "currency_code" => "USD", 26 | "display_name" => "UberSUV", 27 | "estimate" => "$36-44", 28 | "low_estimate" => 36, 29 | "high_estimate" => 44, 30 | "surge_multiplier" => 1.25, 31 | "duration" => 640, 32 | "distance" => 5.34 33 | }, 34 | { 35 | "product_id" => "aca52cea-9701-4903-9f34-9a2395253acb", 36 | "currency_code" => nil, 37 | "display_name" => "uberTAXI", 38 | "estimate" => "Metered", 39 | "low_estimate" => nil, 40 | "high_estimate" => nil, 41 | "surge_multiplier" => 1, 42 | "duration" => 640, 43 | "distance" => 5.34 44 | }, 45 | { 46 | "product_id" => "a27a867a-35f4-4253-8d04-61ae80a40df5", 47 | "currency_code" => "USD", 48 | "display_name" => "uberX", 49 | "estimate" => "$15", 50 | "low_estimate" => 15, 51 | "high_estimate" => 15, 52 | "surge_multiplier" => 1, 53 | "duration" => 640, 54 | "distance" => 5.34 55 | } 56 | ] 57 | } 58 | ) 59 | end 60 | 61 | it "should return time estimates for various products" do 62 | estimates = client.price_estimations(start_latitude: 0.0, start_longitude: 0.5, end_latitude: 0.0, end_longitude: 0.6) 63 | expect(estimates.size).to eql 4 64 | 65 | expect(estimates[0].product_id).to eql "08f17084-23fd-4103-aa3e-9b660223934b" 66 | expect(estimates[0].display_name).to eql "UberBLACK" 67 | expect(estimates[0].currency_code).to eql "USD" 68 | expect(estimates[0].estimate).to eql "$23-29" 69 | expect(estimates[0].low_estimate).to eql 23 70 | expect(estimates[0].high_estimate).to eql 29 71 | expect(estimates[0].surge_multiplier).to eql 1 72 | expect(estimates[0].duration).to eql 640 73 | expect(estimates[0].distance).to eql 5.34 74 | 75 | expect(estimates[1].product_id).to eql "9af0174c-8939-4ef6-8e91-1a43a0e7c6f6" 76 | expect(estimates[1].display_name).to eql "UberSUV" 77 | expect(estimates[1].currency_code).to eql "USD" 78 | expect(estimates[1].estimate).to eql "$36-44" 79 | expect(estimates[1].low_estimate).to eql 36 80 | expect(estimates[1].high_estimate).to eql 44 81 | expect(estimates[1].surge_multiplier).to eql 1.25 82 | expect(estimates[1].duration).to eql 640 83 | expect(estimates[1].distance).to eql 5.34 84 | 85 | expect(estimates[2].product_id).to eql "aca52cea-9701-4903-9f34-9a2395253acb" 86 | expect(estimates[2].display_name).to eql "uberTAXI" 87 | expect(estimates[2].currency_code).to eql nil 88 | expect(estimates[2].estimate).to eql "Metered" 89 | expect(estimates[2].low_estimate).to eql nil 90 | expect(estimates[2].high_estimate).to eql nil 91 | expect(estimates[2].surge_multiplier).to eql 1 92 | expect(estimates[2].duration).to eql 640 93 | expect(estimates[2].distance).to eql 5.34 94 | 95 | expect(estimates[3].product_id).to eql "a27a867a-35f4-4253-8d04-61ae80a40df5" 96 | expect(estimates[3].display_name).to eql "uberX" 97 | expect(estimates[3].currency_code).to eql "USD" 98 | expect(estimates[3].estimate).to eql "$15" 99 | expect(estimates[3].low_estimate).to eql 15 100 | expect(estimates[3].high_estimate).to eql 15 101 | expect(estimates[3].surge_multiplier).to eql 1 102 | expect(estimates[3].duration).to eql 640 103 | expect(estimates[3].distance).to eql 5.34 104 | end 105 | end 106 | -------------------------------------------------------------------------------- /spec/lib/api/products_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | require 'uber' 3 | 4 | describe Uber::API::Products do 5 | let!(:client) { setup_client } 6 | 7 | describe '#products' do 8 | context 'with a valid response' do 9 | before do 10 | stub_uber_request(:get, "v1/products", 11 | # From: https://developer.uber.com/v1/endpoints/#product-types 12 | { 13 | "products" => [ 14 | { 15 | "capacity" => 4, 16 | "description" => "The low-cost Uber", 17 | "price_details" => { 18 | "distance_unit" => "mile", 19 | "cost_per_minute" => 0.26, 20 | "service_fees" => [ 21 | { 22 | "fee" => 1.0, 23 | "name" => "Safe Rides Fee" 24 | } 25 | ], 26 | "minimum" => 5.0, 27 | "cost_per_distance" => 1.3, 28 | "base" => 2.2, 29 | "cancellation_fee" => 5.0, 30 | "currency_code" => "USD" 31 | }, 32 | "image" => "http://d1a3f4spazzrp4.cloudfront.net/car.jpg", 33 | "display_name" => "uberX", 34 | "product_id" => "a1111c8c-c720-46c3-8534-2fcdd730040d", 35 | "shared" => true, 36 | "cash_enabled" => true 37 | }, 38 | { 39 | "capacity" => 6, 40 | "description" => "low-cost rides for large groups", 41 | "price_details" => { 42 | "distance_unit" => "mile", 43 | "cost_per_minute" => 0.45, 44 | "service_fees" => [ 45 | { 46 | "fee" => 1.0, 47 | "name" => "Safe Rides Fee" 48 | } 49 | ], 50 | "minimum" => 8.0, 51 | "cost_per_distance" => 2.15, 52 | "base" => 5.0, 53 | "cancellation_fee" => 5.0, 54 | "currency_code" => "USD" 55 | }, 56 | "image" => "http://d1a3f4spazzrp4.cloudfront.net/car.jpg", 57 | "display_name" => "uberXL", 58 | "product_id" => "821415d8-3bd5-4e27-9604-194e4359a449", 59 | "shared" => true, 60 | "cash_enabled" => true 61 | }, 62 | { 63 | "capacity" => 4, 64 | "description" => "The original Uber", 65 | "price_details" => { 66 | "distance_unit" => "mile", 67 | "cost_per_minute" => 0.65, 68 | "service_fees" => [], 69 | "minimum" => 15.0, 70 | "cost_per_distance" => 3.75, 71 | "base" => 8.0, 72 | "cancellation_fee" => 10.0, 73 | "currency_code" => "USD" 74 | }, 75 | "image" => "http://d1a3f4spazzrp4.cloudfront.net/car.jpg", 76 | "display_name" => "UberBLACK", 77 | "product_id" => "d4abaae7-f4d6-4152-91cc-77523e8165a4", 78 | "shared" => false, 79 | "cash_enabled" => true 80 | }, 81 | { 82 | "capacity" => 6, 83 | "description" => "Room for everyone", 84 | "price_details" => { 85 | "distance_unit" => "mile", 86 | "cost_per_minute" => 0.9, 87 | "service_fees" => [], 88 | "minimum" => 25.0, 89 | "cost_per_distance" => 3.75, 90 | "base" => 15.0, 91 | "cancellation_fee" => 10.0, 92 | "currency_code" => "USD" 93 | }, 94 | "image" => "http://d1a3f4spazzrp4.cloudfront.net/car.jpg", 95 | "display_name" => "UberSUV", 96 | "product_id" => "8920cb5e-51a4-4fa4-acdf-dd86c5e18ae0", 97 | "shared" => true, 98 | "cash_enabled" => false 99 | }, 100 | { 101 | "capacity" => 4, 102 | "description" => "Taxi without the hassle", 103 | "price_details" => nil, 104 | "image" => "http://d1a3f4spazzrp4.cloudfront.net/car.jpg", 105 | "display_name" => "uberTAXI", 106 | "product_id" => "3ab64887-4842-4c8e-9780-ccecd3a0391d", 107 | "shared" => false, 108 | "cash_enabled" => false 109 | } 110 | ] 111 | } 112 | ) 113 | end 114 | 115 | it 'should list all the products' do 116 | products = client.products 117 | expect(products.size).to eql 5 118 | 119 | expect(products[0].capacity).to eql 4 120 | expect(products[0].description).to eql "The low-cost Uber" 121 | expect(products[0].display_name).to eql "uberX" 122 | expect(products[0].product_id).to eql "a1111c8c-c720-46c3-8534-2fcdd730040d" 123 | expect(products[0].image).to eql "http://d1a3f4spazzrp4.cloudfront.net/car.jpg" 124 | expect(products[0].price_details.class).to be Hash 125 | expect(products[0].shared).to be true 126 | expect(products[0].cash_enabled).to be true 127 | expect(products[0].shared?).to be true 128 | expect(products[0].cash_enabled?).to be true 129 | 130 | expect(products[1].capacity).to eql 6 131 | expect(products[1].description).to eql "low-cost rides for large groups" 132 | expect(products[1].display_name).to eql "uberXL" 133 | expect(products[1].product_id).to eql "821415d8-3bd5-4e27-9604-194e4359a449" 134 | expect(products[1].image).to eql "http://d1a3f4spazzrp4.cloudfront.net/car.jpg" 135 | expect(products[1].price_details.class).to be Hash 136 | expect(products[1].shared).to be true 137 | expect(products[1].cash_enabled).to be true 138 | 139 | expect(products[2].capacity).to eql 4 140 | expect(products[2].description).to eql "The original Uber" 141 | expect(products[2].display_name).to eql "UberBLACK" 142 | expect(products[2].product_id).to eql "d4abaae7-f4d6-4152-91cc-77523e8165a4" 143 | expect(products[2].image).to eql "http://d1a3f4spazzrp4.cloudfront.net/car.jpg" 144 | expect(products[2].price_details.class).to be Hash 145 | expect(products[2].shared).to be false 146 | expect(products[2].cash_enabled).to be true 147 | 148 | expect(products[3].capacity).to eql 6 149 | expect(products[3].description).to eql "Room for everyone" 150 | expect(products[3].display_name).to eql "UberSUV" 151 | expect(products[3].product_id).to eql "8920cb5e-51a4-4fa4-acdf-dd86c5e18ae0" 152 | expect(products[3].image).to eql "http://d1a3f4spazzrp4.cloudfront.net/car.jpg" 153 | expect(products[3].price_details.class).to be Hash 154 | expect(products[3].shared).to be true 155 | expect(products[3].cash_enabled).to be false 156 | 157 | expect(products[4].capacity).to eql 4 158 | expect(products[4].description).to eql "Taxi without the hassle" 159 | expect(products[4].display_name).to eql "uberTAXI" 160 | expect(products[4].product_id).to eql "3ab64887-4842-4c8e-9780-ccecd3a0391d" 161 | expect(products[4].image).to eql "http://d1a3f4spazzrp4.cloudfront.net/car.jpg" 162 | expect(products[4].price_details).to be nil 163 | expect(products[4].shared).to be false 164 | expect(products[4].cash_enabled).to be false 165 | expect(products[4].shared?).to be false 166 | expect(products[4].cash_enabled?).to be false 167 | end 168 | end 169 | end 170 | 171 | describe '#apply_surge' do 172 | let!(:sandbox_client) { setup_client(sandbox: true) } 173 | 174 | before do 175 | stub_uber_request(:put, "v1/sandbox/products/deadbeef", 176 | # From: https://developer.uber.com/docs/v1-requests-cancel 177 | nil, 178 | body: {surge_multiplier: 2.0}, 179 | status_code: 204, 180 | sandbox: true) 181 | end 182 | 183 | it 'should update the surge of the product in the sandbox' do 184 | request = sandbox_client.apply_surge('deadbeef', 2.0) 185 | expect(request.class).to eql Uber::Product 186 | end 187 | end 188 | 189 | describe '#apply_availability' do 190 | let!(:sandbox_client) { setup_client(sandbox: true) } 191 | 192 | before do 193 | stub_uber_request(:put, "v1/sandbox/products/deadbeef", 194 | # From: https://developer.uber.com/docs/v1-requests-cancel 195 | nil, 196 | body: {drivers_available: false}, 197 | status_code: 204, 198 | sandbox: true) 199 | end 200 | 201 | it 'should update the drivers availability of the product in the sandbox' do 202 | request = sandbox_client.apply_availability('deadbeef', false) 203 | expect(request.class).to eql Uber::Product 204 | end 205 | end 206 | end 207 | -------------------------------------------------------------------------------- /spec/lib/api/promotions_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | require 'uber' 3 | 4 | describe Uber::API::Promotions do 5 | let!(:client) { setup_client } 6 | 7 | before do 8 | stub_uber_request(:get, 'v1/promotions?end_latitude=0.0&end_longitude=0.6&start_latitude=0.0&start_longitude=0.5', 9 | # From: https://developer.uber.com/v1/endpoints/#promotions 10 | { 11 | "display_text" => "Free ride up to $30", 12 | "localized_value" => "$30", 13 | "type" => "trip_credit" 14 | } 15 | ) 16 | end 17 | 18 | it "should return available promotion" do 19 | promotion = client.promotion(start_latitude: 0.0, start_longitude: 0.5, 20 | end_latitude: 0.0, end_longitude: 0.6) 21 | 22 | expect(promotion.display_text).to eql "Free ride up to $30" 23 | expect(promotion.localized_value).to eql "$30" 24 | expect(promotion.type).to eql "trip_credit" 25 | end 26 | end 27 | 28 | -------------------------------------------------------------------------------- /spec/lib/api/reminders_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | require 'uber' 3 | 4 | describe Uber::API::Reminders do 5 | let!(:client) { setup_client } 6 | 7 | describe "get reminder" do 8 | before do 9 | # From: https://developer.uber.com/docs/rides/api/v1-reminders-get 10 | stub_uber_request(:get, 'v1/reminders/48ee034e-311d-41ea-9794-02fc8dcd8696', 11 | {"reminder_status"=>"pending", "reminder_id"=>"48ee034e-311d-41ea-9794-02fc8dcd8696", "reminder_time"=>1473296851, 12 | "event"=>{"latitude"=>nil, "time"=>1473507651, "name"=>nil, "longitude"=>nil, "location"=>nil}, "product_id"=>{}} 13 | ) 14 | end 15 | 16 | it "should return details about reminder" do 17 | reminder = client.reminder('48ee034e-311d-41ea-9794-02fc8dcd8696') 18 | expect(reminder).to be_instance_of Uber::Reminder 19 | expect(reminder.event).to be_instance_of Uber::Reminder::Event 20 | expect(reminder.reminder_id).to eq "48ee034e-311d-41ea-9794-02fc8dcd8696" 21 | end 22 | 23 | it "should also respond to reminder_detail" do 24 | reminder = client.reminder_detail('48ee034e-311d-41ea-9794-02fc8dcd8696') 25 | expect(reminder).to be_instance_of Uber::Reminder 26 | expect(reminder.event).to be_instance_of Uber::Reminder::Event 27 | expect(reminder.reminder_id).to eq "48ee034e-311d-41ea-9794-02fc8dcd8696" 28 | end 29 | end 30 | 31 | describe "add reminder" do 32 | before do 33 | # From: https://developer.uber.com/docs/rides/api/v1-reminders-post 34 | @time_now = Time.at(1473275408) 35 | stub_uber_request(:post, 'v1/reminders', 36 | { 37 | reminder_time: 1473377003, 38 | phone_number: '+91-9999999999', 39 | event: {time: 1473509642}, 40 | trip_branding: {link_text: 'My first reminder'}, 41 | reminder_id: 'rem1', 42 | reminder_status: 'pending', 43 | product_id: {} 44 | }, 45 | body: { 46 | reminder_time: 1473377003, 47 | phone_number: '+91-9999999999', 48 | trip_branding: {link_text: 'My first reminder'}, 49 | event: {time: 1473509642}, 50 | reminder_id: 'rem1' 51 | }.to_json, 52 | status_code: 200) 53 | end 54 | it 'should return reminder with details' do 55 | allow(Time).to receive(:now).and_return(@time_now) 56 | reminder = client.add_reminder({reminder_time: Time.utc(2016, 9, 8, 23, 23, 23), 57 | phone_number: '+91-9999999999', 58 | trip_branding: {link_text: 'My first reminder'}, 59 | event: {time: Time.now + 234234}, 60 | reminder_id: 'rem1' }) 61 | expect(reminder).to be_instance_of Uber::Reminder 62 | expect(reminder.reminder_status).to eq 'pending' 63 | expect(reminder.event).to be_instance_of Uber::Reminder::Event 64 | expect(reminder.trip_branding).to be_instance_of Uber::Reminder::TripBranding 65 | expect(reminder.reminder_time).to eq Time.utc(2016, 9, 8, 23, 23, 23) 66 | expect(reminder.event.time).to eq @time_now + 234234 67 | expect(reminder.reminder_id).to eq 'rem1' 68 | end 69 | end 70 | 71 | describe "update reminder" do 72 | before do 73 | # From: https://developer.uber.com/docs/rides/api/v1-reminders-patch 74 | @time_now = Time.at(1473275408) 75 | stub_uber_request(:patch, 'v1/reminders/rem1', 76 | { 77 | reminder_time: 1473549803, 78 | phone_number: '+91-9999999999', 79 | trip_branding: {link_text: 'My first reminder'}, 80 | event: {time: 1473509642}, 81 | reminder_id: 'rem1', 82 | reminder_status: 'pending', 83 | product_id: {} 84 | }, 85 | body: { reminder_time: 1473549803 }.to_json 86 | ) 87 | end 88 | it 'should return updated reminder' do 89 | allow(Time).to receive(:now).and_return(@time_now) 90 | reminder = client.update_reminder('rem1', {reminder_time: Time.utc(2016, 9, 10, 23, 23, 23)}) 91 | expect(reminder).to be_instance_of Uber::Reminder 92 | expect(reminder.reminder_status).to eq 'pending' 93 | expect(reminder.reminder_time).to eq Time.utc(2016, 9, 10, 23, 23, 23) 94 | expect(reminder.event.time).to eq @time_now + 234234 95 | expect(reminder.reminder_id).to eq 'rem1' 96 | end 97 | end 98 | 99 | describe "delete reminder" do 100 | before do 101 | # From: https://developer.uber.com/docs/rides/api/v1-reminders-delete 102 | stub_uber_request(:delete, 'v1/reminders/my_reminder', nil, {status_code: 204}) 103 | end 104 | it 'should successfully delete the reminder' do 105 | reminder = client.delete_reminder 'my_reminder' 106 | expect(reminder).to be_instance_of Uber::Reminder 107 | end 108 | end 109 | end 110 | -------------------------------------------------------------------------------- /spec/lib/api/requests_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | require 'uber' 3 | 4 | describe Uber::API::Requests do 5 | let!(:client) { setup_client } 6 | 7 | describe '#trip_estimate' do 8 | context 'with a valid response' do 9 | before do 10 | stub_uber_request(:post, "v1/requests/estimate", 11 | # From: https://developer.uber.com/docs/v1-requests-estimate 12 | { 13 | "price" => { 14 | "surge_confirmation_href" => "https:\/\/api.uber.com\/v1\/surge-confirmations\/7d604f5e", 15 | "high_estimate" => 6, 16 | "surge_confirmation_id"=> "7d604f5e", 17 | "minimum"=> 5, 18 | "low_estimate"=> 5, 19 | "surge_multiplier"=> 1.2, 20 | "display"=> "$5-6", 21 | "currency_code"=> "USD" 22 | }, 23 | "trip" => { 24 | "distance_unit"=> "mile", 25 | "duration_estimate"=> 540, 26 | "distance_estimate"=> 2.1 27 | }, 28 | "pickup_estimate" => 2, 29 | }, 30 | body: {product_id: 'deadbeef', start_latitude: 0.0, start_longitude: 0.5, end_latitude: 0.0, end_longitude: 0.6}.to_json, 31 | status_code: 200) 32 | end 33 | 34 | it 'should submit a request estimate' do 35 | request = client.trip_estimate(product_id: 'deadbeef', start_latitude: 0.0, start_longitude: 0.5, end_latitude: 0.0, end_longitude: 0.6) 36 | expect(request.pickup_estimate).to eql 2 37 | 38 | expect(request.price.surge_confirmation_href).to eql 'https://api.uber.com/v1/surge-confirmations/7d604f5e' 39 | expect(request.price.high_estimate).to eql 6 40 | expect(request.price.surge_confirmation_id).to eql '7d604f5e' 41 | expect(request.price.minimum).to eql 5 42 | expect(request.price.low_estimate).to eql 5 43 | expect(request.price.surge_multiplier).to eql 1.2 44 | expect(request.price.display).to eql '$5-6' 45 | expect(request.price.currency_code).to eql 'USD' 46 | 47 | expect(request.trip.distance_unit).to eql 'mile' 48 | expect(request.trip.duration_estimate).to eql 540 49 | expect(request.trip.distance_estimate).to eql 2.1 50 | end 51 | end 52 | end 53 | 54 | describe '#trip_request' do 55 | context 'with a valid response' do 56 | before do 57 | stub_uber_request(:post, "v1/requests", 58 | # From: https://developer.uber.com/v1/endpoints/#request 59 | { 60 | "status" => "accepted", 61 | "driver" => { 62 | "phone_number" => "(555)555-5555", 63 | "rating" => 5, 64 | "picture_url" => "https://d1w2poirtb3as9.cloudfront.net/img.jpeg", 65 | "name" => "Bob" 66 | }, 67 | "eta" => 4, 68 | "location" => { 69 | "latitude" => 37.776033, 70 | "longitude" => -122.418143, 71 | "bearing" => 33 72 | }, 73 | "vehicle" => { 74 | "make" => "Bugatti", 75 | "model" => "Veyron", 76 | "license_plate" => "I<3Uber", 77 | "picture_url" => "https://d1w2poirtb3as9.cloudfront.net/car.jpeg", 78 | }, 79 | "surge_multiplier" => 1.0, 80 | "request_id" => "b2205127-a334-4df4-b1ba-fc9f28f56c96" 81 | }, 82 | body: {product_id: 'deadbeef', start_latitude: 0.0, start_longitude: 0.5, end_latitude: 0.0, end_longitude: 0.6}.to_json, 83 | status_code: 201) 84 | end 85 | 86 | it 'should submit a request for a ride' do 87 | request = client.trip_request(product_id: 'deadbeef', start_latitude: 0.0, start_longitude: 0.5, end_latitude: 0.0, end_longitude: 0.6) 88 | expect(request.status).to eql 'accepted' 89 | expect(request.eta).to eql 4 90 | expect(request.surge_multiplier).to eql 1.0 91 | expect(request.request_id).to eql 'b2205127-a334-4df4-b1ba-fc9f28f56c96' 92 | 93 | expect(request.driver.phone_number).to eql '(555)555-5555' 94 | expect(request.driver.rating).to eql 5 95 | expect(request.driver.picture_url).to eql 'https://d1w2poirtb3as9.cloudfront.net/img.jpeg' 96 | expect(request.driver.name).to eql 'Bob' 97 | 98 | expect(request.location.latitude).to eql 37.776033 99 | expect(request.location.longitude).to eql -122.418143 100 | expect(request.location.bearing).to eql 33 101 | 102 | expect(request.vehicle.make).to eql 'Bugatti' 103 | expect(request.vehicle.model).to eql 'Veyron' 104 | expect(request.vehicle.license_plate).to eql 'I<3Uber' 105 | expect(request.vehicle.picture_url).to eql 'https://d1w2poirtb3as9.cloudfront.net/car.jpeg' 106 | end 107 | 108 | context 'with a sandbox API' do 109 | let!(:sandbox_client) { setup_client(sandbox: true) } 110 | 111 | before do 112 | stub_uber_request(:post, "v1/requests", 113 | # From: https://developer.uber.com/v1/endpoints/#request 114 | { 115 | "status" => "accepted", 116 | "driver" => { 117 | "phone_number" => "(555)555-5555", 118 | "rating" => 5, 119 | "picture_url" => "https://d1w2poirtb3as9.cloudfront.net/img.jpeg", 120 | "name" => "Bob" 121 | }, 122 | "eta" => 4, 123 | "location" => { 124 | "latitude" => 37.776033, 125 | "longitude" => -122.418143, 126 | "bearing" => 33 127 | }, 128 | "vehicle" => { 129 | "make" => "Bugatti", 130 | "model" => "Veyron", 131 | "license_plate" => "I<3Uber", 132 | "picture_url" => "https://d1w2poirtb3as9.cloudfront.net/car.jpeg", 133 | }, 134 | "surge_multiplier" => 1.0, 135 | "request_id" => "b2205127-a334-4df4-b1ba-fc9f28f56c96" 136 | }, 137 | body: {product_id: 'deadbeef', start_latitude: 0.0, start_longitude: 0.5, end_latitude: 0.0, end_longitude: 0.6}.to_json, 138 | status_code: 201, 139 | sandbox: true) 140 | end 141 | 142 | it 'should submit a request for a ride' do 143 | request = sandbox_client.trip_request(product_id: 'deadbeef', start_latitude: 0.0, start_longitude: 0.5, end_latitude: 0.0, end_longitude: 0.6) 144 | expect(request.status).to eql 'accepted' 145 | expect(request.eta).to eql 4 146 | expect(request.surge_multiplier).to eql 1.0 147 | expect(request.request_id).to eql 'b2205127-a334-4df4-b1ba-fc9f28f56c96' 148 | 149 | expect(request.driver.phone_number).to eql '(555)555-5555' 150 | expect(request.driver.rating).to eql 5 151 | expect(request.driver.picture_url).to eql 'https://d1w2poirtb3as9.cloudfront.net/img.jpeg' 152 | expect(request.driver.name).to eql 'Bob' 153 | 154 | expect(request.location.latitude).to eql 37.776033 155 | expect(request.location.longitude).to eql -122.418143 156 | expect(request.location.bearing).to eql 33 157 | 158 | expect(request.vehicle.make).to eql 'Bugatti' 159 | expect(request.vehicle.model).to eql 'Veyron' 160 | expect(request.vehicle.license_plate).to eql 'I<3Uber' 161 | expect(request.vehicle.picture_url).to eql 'https://d1w2poirtb3as9.cloudfront.net/car.jpeg' 162 | end 163 | end 164 | end 165 | 166 | context 'with a "processing" response' do 167 | before do 168 | stub_uber_request(:post, "v1/requests", 169 | # From: https://developer.uber.com/v1/endpoints/#request 170 | { 171 | :status => "processing", 172 | :request_id => "cad219b7-9cfa-4861-b59b-1e1184429b33", 173 | :driver => nil, 174 | :eta => 7, 175 | :location => nil, 176 | :vehicle => nil, 177 | :surge_multiplier => 1.0 178 | }, 179 | body: {product_id: 'deadbeef', start_latitude: 0.0, start_longitude: 0.5, end_latitude: 0.0, end_longitude: 0.6}.to_json, 180 | status_code: 409) 181 | end 182 | 183 | it 'should submit a request for a ride' do 184 | request = client.trip_request(product_id: 'deadbeef', start_latitude: 0.0, start_longitude: 0.5, end_latitude: 0.0, end_longitude: 0.6) 185 | expect(request.status).to eql 'processing' 186 | expect(request.eta).to eql 7 187 | expect(request.surge_multiplier).to eql 1.0 188 | expect(request.request_id).to eql 'cad219b7-9cfa-4861-b59b-1e1184429b33' 189 | 190 | expect(request.driver).to be_nil 191 | expect(request.location).to be_nil 192 | expect(request.vehicle).to be_nil 193 | end 194 | end 195 | 196 | context 'with a 409 conflict with surge response' do 197 | before do 198 | stub_uber_request(:post, "v1/requests", 199 | # From: https://developer.uber.com/v1/endpoints/#request 200 | { 201 | "meta" => { 202 | "surge_confirmation" => { 203 | "href" => "https://api.uber.com/v1/surge-confirmations/e100a670", 204 | "surge_confirmation_id" => "e100a670" 205 | } 206 | }, 207 | "errors" =>[ 208 | { 209 | "status" => 409, 210 | "code" => "surge", 211 | "title" => "Surge pricing is currently in effect for this product." 212 | } 213 | ] 214 | }, 215 | body: {product_id: 'deadbeef', start_latitude: 0.0, start_longitude: 0.5, end_latitude: 0.0, end_longitude: 0.6}.to_json, 216 | status_code: 409) 217 | end 218 | 219 | it 'should submit a request for a ride' do 220 | request = client.trip_request(product_id: 'deadbeef', start_latitude: 0.0, start_longitude: 0.5, end_latitude: 0.0, end_longitude: 0.6) 221 | expect(request.errors.size).to eql 1 222 | 223 | expect(request.errors[0].status).to eql 409 224 | expect(request.errors[0].code).to eql 'surge' 225 | expect(request.errors[0].title).to eql "Surge pricing is currently in effect for this product." 226 | 227 | expect(request.meta[:surge_confirmation][:href]).to eql "https://api.uber.com/v1/surge-confirmations/e100a670" 228 | expect(request.meta[:surge_confirmation][:surge_confirmation_id]).to eql "e100a670" 229 | end 230 | end 231 | end 232 | 233 | describe '#trip_details' do 234 | before do 235 | stub_uber_request(:get, "v1/requests/deadbeef", 236 | # From: https://developer.uber.com/v1/endpoints/#request-details 237 | { 238 | "status" => "accepted", 239 | "driver" => { 240 | "phone_number" => "(555)555-5555", 241 | "rating" => 5, 242 | "picture_url" => "https://d1w2poirtb3as9.cloudfront.net/img.jpeg", 243 | "name" => "Bob" 244 | }, 245 | "eta" => 4, 246 | "location" => { 247 | "latitude" => 37.776033, 248 | "longitude" => -122.418143, 249 | "bearing" => 33 250 | }, 251 | "pickup" => { 252 | "latitude" => 0.0, 253 | "longitude" => 0.5, 254 | "eta" => 5 255 | }, 256 | "destination" => { 257 | "latitude" => 0.0, 258 | "longitude" => 0.6, 259 | "eta" => 19 260 | }, 261 | "vehicle" => { 262 | "make" => "Bugatti", 263 | "model" => "Veyron", 264 | "license_plate" => "I<3Uber", 265 | "picture_url" => "https://d1w2poirtb3as9.cloudfront.net/car.jpeg", 266 | }, 267 | "surge_multiplier" => 1.0, 268 | "request_id" => "b2205127-a334-4df4-b1ba-fc9f28f56c96" 269 | }, 270 | status_code: 200) 271 | end 272 | 273 | it 'should show the request for a ride' do 274 | request = client.trip_details('deadbeef') 275 | expect(request.status).to eql 'accepted' 276 | expect(request.surge_multiplier).to eql 1.0 277 | expect(request.eta).to eql 4 278 | expect(request.request_id).to eql 'b2205127-a334-4df4-b1ba-fc9f28f56c96' 279 | 280 | expect(request.driver.phone_number).to eql '(555)555-5555' 281 | expect(request.driver.rating).to eql 5 282 | expect(request.driver.picture_url).to eql 'https://d1w2poirtb3as9.cloudfront.net/img.jpeg' 283 | expect(request.driver.name).to eql 'Bob' 284 | 285 | expect(request.location.latitude).to eql 37.776033 286 | expect(request.location.longitude).to eql -122.418143 287 | expect(request.location.bearing).to eql 33 288 | 289 | expect(request.pickup.latitude).to eql 0.0 290 | expect(request.pickup.longitude).to eql 0.5 291 | expect(request.pickup.eta).to eql 5 292 | 293 | expect(request.destination.latitude).to eql 0.0 294 | expect(request.destination.longitude).to eql 0.6 295 | expect(request.destination.eta).to eql 19 296 | 297 | expect(request.vehicle.make).to eql 'Bugatti' 298 | expect(request.vehicle.model).to eql 'Veyron' 299 | expect(request.vehicle.license_plate).to eql 'I<3Uber' 300 | expect(request.vehicle.picture_url).to eql 'https://d1w2poirtb3as9.cloudfront.net/car.jpeg' 301 | end 302 | end 303 | 304 | describe '#trip_map' do 305 | before do 306 | stub_uber_request(:get, "v1/requests/deadbeef/map", 307 | # From: https://developer.uber.com/v1/endpoints/#request-map 308 | { 309 | "request_id" => "b5512127-a134-4bf4-b1ba-fe9f48f56d9d", 310 | "href" => "https://trip.uber.com/abc123" 311 | }) 312 | end 313 | 314 | it 'should show the map for the ride' do 315 | map = client.trip_map('deadbeef') 316 | expect(map.request_id).to eql "b5512127-a134-4bf4-b1ba-fe9f48f56d9d" 317 | expect(map.href).to eql "https://trip.uber.com/abc123" 318 | end 319 | end 320 | 321 | describe '#trip_update' do 322 | let!(:sandbox_client) { setup_client(sandbox: true) } 323 | 324 | before do 325 | stub_uber_request(:put, "v1/sandbox/requests/deadbeef", 326 | # From: https://developer.uber.com/v1/sandbox/ 327 | nil, 328 | body: {status: 'accepted'}.to_json, 329 | status_code: 204, 330 | sandbox: true) 331 | end 332 | 333 | it 'should update the state of the request in the sandbox' do 334 | request = sandbox_client.trip_update('deadbeef', 'accepted') 335 | expect(request.class).to eql Uber::Request 336 | end 337 | end 338 | 339 | describe '#trip_cancel' do 340 | let!(:sandbox_client) { setup_client(sandbox: true) } 341 | 342 | before do 343 | stub_uber_request(:delete, "v1/requests/deadbeef", 344 | # From: https://developer.uber.com/docs/v1-requests-cancel 345 | nil, 346 | body: {}, 347 | status_code: 204, 348 | sandbox: true) 349 | end 350 | 351 | it 'should cancel the request in the sandbox' do 352 | request = sandbox_client.trip_cancel('deadbeef') 353 | expect(request.class).to eql Uber::Request 354 | end 355 | end 356 | 357 | describe '#trip_receipt' do 358 | before do 359 | stub_uber_request(:get, "v1.2/requests/b5512127-a134-4bf4-b1ba-fe9f48f56d9d/receipt", 360 | # From: https://developer.uber.com/docs/riders/references/api/v1.2/requests-request_id-receipt-get 361 | { 362 | "request_id" => "b5512127-a134-4bf4-b1ba-fe9f48f56d9d", 363 | "subtotal" => "$12.78", 364 | "total_charged" => "$5.92", 365 | "total_owed" => nil, 366 | "total_fare" => "$5.92", 367 | "currency_code" => "USD", 368 | "duration" => "00:11:35", 369 | "distance" => "1.49", 370 | "distance_label" => "miles" 371 | }, 372 | status_code: 200) 373 | end 374 | 375 | it 'should retrieve the ride receipt' do 376 | receipt = client.trip_receipt('b5512127-a134-4bf4-b1ba-fe9f48f56d9d') 377 | ride_receipt = client.ride_receipt('b5512127-a134-4bf4-b1ba-fe9f48f56d9d') 378 | expect(receipt.class).to eql Uber::Receipt 379 | expect(ride_receipt.class).to eql Uber::Receipt 380 | expect(receipt.subtotal).to eql "$12.78" 381 | expect(receipt.total_charged).to eql "$5.92" 382 | expect(receipt.total_owed).to be_nil 383 | expect(receipt.total_fare).to eql "$5.92" 384 | expect(receipt.currency_code).to eql "USD" 385 | expect(receipt.duration).to eql "00:11:35" 386 | expect(receipt.distance).to eql 1.49 387 | expect(receipt.distance_label).to eql "miles" 388 | 389 | end 390 | end 391 | 392 | describe 'client' do 393 | let!(:client) { setup_client } 394 | let!(:debug_client) { setup_client(debug: true) } 395 | 396 | it 'should not have logger middleware when debug option is not passed' do 397 | client.send(:connection).builder.handlers.should_not include Faraday::Response::Logger 398 | end 399 | 400 | it 'should have logger middleware when debug option is passed' do 401 | debug_client.send(:connection).builder.handlers.should include Faraday::Response::Logger 402 | end 403 | 404 | it 'should include Uber::Response::ParseJson middleware in both clients' do 405 | client.send(:connection).builder.handlers.should include Uber::Response::ParseJson 406 | debug_client.send(:connection).builder.handlers.should include Uber::Response::ParseJson 407 | end 408 | end 409 | end 410 | -------------------------------------------------------------------------------- /spec/lib/api/time_estimates_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | require 'uber' 3 | 4 | describe Uber::API::TimeEstimates do 5 | let!(:client) { setup_client } 6 | 7 | before do 8 | stub_uber_request(:get, 'v1/estimates/time?start_latitude=0.6&start_longitude=0.6', 9 | # From: https://developer.uber.com/v1/endpoints/#time-estimates 10 | { 11 | "times" => [ 12 | { 13 | "product_id" => "5f41547d-805d-4207-a297-51c571cf2a8c", 14 | "display_name" => "UberBLACK", 15 | "estimate" => 410 16 | }, 17 | { 18 | "product_id" => "694558c9-b34b-4836-855d-821d68a4b944", 19 | "display_name" => "UberSUV", 20 | "estimate" => 535 21 | }, 22 | { 23 | "product_id" => "65af3521-a04f-4f80-8ce2-6d88fb6648bc", 24 | "display_name" => "uberTAXI", 25 | "estimate" => 294 26 | }, 27 | { 28 | "product_id" => "17b011d3-65be-421d-adf6-a5480a366453", 29 | "display_name" => "uberX", 30 | "estimate" => 288 31 | } 32 | ] 33 | } 34 | ) 35 | end 36 | 37 | it "should return time estimates for various products" do 38 | estimates = client.time_estimations(start_latitude: 0.6, start_longitude: 0.6) 39 | expect(estimates.size).to eql 4 40 | 41 | expect(estimates[0].product_id).to eql "5f41547d-805d-4207-a297-51c571cf2a8c" 42 | expect(estimates[0].display_name).to eql "UberBLACK" 43 | expect(estimates[0].estimate).to eql 410 44 | 45 | expect(estimates[1].product_id).to eql "694558c9-b34b-4836-855d-821d68a4b944" 46 | expect(estimates[1].display_name).to eql "UberSUV" 47 | expect(estimates[1].estimate).to eql 535 48 | 49 | expect(estimates[2].product_id).to eql "65af3521-a04f-4f80-8ce2-6d88fb6648bc" 50 | expect(estimates[2].display_name).to eql "uberTAXI" 51 | expect(estimates[2].estimate).to eql 294 52 | 53 | expect(estimates[3].product_id).to eql "17b011d3-65be-421d-adf6-a5480a366453" 54 | expect(estimates[3].display_name).to eql "uberX" 55 | expect(estimates[3].estimate).to eql 288 56 | end 57 | end 58 | -------------------------------------------------------------------------------- /spec/lib/rate_limit_spec.rb: -------------------------------------------------------------------------------- 1 | require "spec_helper" 2 | require "uber" 3 | 4 | describe Uber::RateLimit do 5 | let!(:now) { Time.at(1449638388) } 6 | let(:rate_limit) { 7 | Uber::RateLimit.new({ 8 | 'x-rate-limit-limit' => 500, 9 | 'x-rate-limit-remaining' => 499, 10 | 'x-rate-limit-reset' => now.to_i 11 | }) 12 | } 13 | 14 | it 'should return rate limit values' do 15 | expect(rate_limit.limit).to eq 500 16 | expect(rate_limit.remaining).to eq 499 17 | end 18 | 19 | it 'should provide reset time' do 20 | allow(Time).to receive(:now) { now - 100 } 21 | expect(rate_limit.reset_at).to eq now 22 | expect(rate_limit.reset_in).to eq 100 23 | end 24 | end 25 | 26 | 27 | -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | require 'rspec' 2 | require 'webmock/rspec' 3 | 4 | Dir[File.join(File.dirname(__FILE__), "./support/**/*.rb")].each do |f| 5 | require f 6 | end 7 | 8 | RSpec.configure do |c| 9 | c.include ClientHelpers 10 | 11 | c.before :each do 12 | WebMock.disable_net_connect!(allow_localhost: true) 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /spec/support/client_helpers.rb: -------------------------------------------------------------------------------- 1 | require 'uber' 2 | 3 | module ClientHelpers 4 | def setup_client(opts = {}) 5 | Uber::Client.new do |c| 6 | c.bearer_token = 'UBER_BEARER_TOKEN' 7 | c.sandbox = opts[:sandbox] 8 | c.debug = opts[:debug] 9 | end 10 | end 11 | 12 | def stub_uber_request(method, api_endpoint, response_hash, opts = {}) 13 | with_opts = {headers: {'Authorization' => 'Bearer UBER_BEARER_TOKEN'}} 14 | with_opts[:body] = opts[:body] unless opts[:body].nil? 15 | status_code = opts[:status_code] || 200 16 | 17 | host = opts[:sandbox] ? Uber::Client::SANDBOX_ENDPOINT : Uber::Client::ENDPOINT 18 | 19 | response = response_hash.nil? ? "" : response_hash.to_json 20 | 21 | stub_request(method, "#{host}/#{api_endpoint}"). 22 | with(with_opts). 23 | to_return(status: status_code, body: response) 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /uber-ruby.gemspec: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | lib = File.expand_path('../lib', __FILE__) 3 | $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) 4 | require 'uber/version' 5 | 6 | Gem::Specification.new do |spec| 7 | spec.name = "uber-ruby" 8 | spec.version = Uber::Version 9 | spec.authors = ["Dingding Ye"] 10 | spec.email = ["yedingding@gmail.com"] 11 | spec.summary = %q{The Uber Ruby Gem.} 12 | spec.description = %q{A Ruby interface to the Uber API.} 13 | spec.homepage = "https://github.com/sishen/uber-ruby" 14 | spec.license = "MIT" 15 | 16 | spec.files = %w(LICENSE.txt README.md Rakefile uber-ruby.gemspec) 17 | spec.files += Dir.glob('lib/**/*.rb') 18 | spec.files += Dir.glob('test/**/*') 19 | spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) } 20 | spec.test_files = Dir.glob('test/**/*') 21 | spec.require_paths = ["lib"] 22 | spec.required_rubygems_version = '>= 1.3.5' 23 | 24 | spec.add_development_dependency "bundler", "~> 1.5" 25 | spec.add_development_dependency "rake", "~> 0" 26 | spec.add_development_dependency "webmock", "~> 1.21.0" 27 | spec.add_development_dependency "rspec", "~> 3.3.0" 28 | 29 | spec.add_dependency 'faraday', '~> 0.9.0' 30 | spec.add_dependency 'json' 31 | end 32 | --------------------------------------------------------------------------------