smartcar 2.5.0 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -2,5 +2,5 @@
2
2
 
3
3
  module Smartcar
4
4
  # Gem current version number
5
- VERSION = '2.5.0'
5
+ VERSION = '3.0.0'
6
6
  end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Custom SmartcarError class to represent errors from Smartcar APIs.
4
+ class SmartcarError < StandardError
5
+ attr_reader :code, :status_code, :request_id, :type, :description, :doc_url, :resolution, :detail
6
+
7
+ def initialize(status, body, headers)
8
+ @status_code = status
9
+ if body.is_a?(String)
10
+ super(body)
11
+ @request_id = headers['sc-request-id']
12
+ return
13
+ end
14
+ body = coerce_attributes(body)
15
+
16
+ super("#{body[:type]}:#{body[:code]} - #{body[:description]}")
17
+ @request_id = body[:requestId] || headers['sc-request-id']
18
+ set_attributes(body)
19
+ end
20
+
21
+ private
22
+
23
+ def coerce_attributes(body)
24
+ body[:type] = body.delete(:error) if body[:error]
25
+ unless body[:description]
26
+ body[:description] = if body[:error_description]
27
+ body.delete(:error_description)
28
+ elsif body[:message]
29
+ body.delete(:message)
30
+ else
31
+ 'Unknown error'
32
+ end
33
+ end
34
+
35
+ body
36
+ end
37
+
38
+ def set_attributes(body)
39
+ body.each do |attribute, value|
40
+ instance_variable_set("@#{attribute}", value)
41
+ end
42
+ @doc_url = body[:docURL]
43
+ @type = @error if @error
44
+
45
+ return unless @resolution
46
+
47
+ @resolution = @resolution.is_a?(String) ? OpenStruct.new({ type: @resolution }) : OpenStruct.new(@resolution)
48
+ end
49
+ end
data/ruby-sdk.gemspec CHANGED
@@ -27,10 +27,13 @@ Gem::Specification.new do |spec|
27
27
 
28
28
  spec.add_development_dependency 'bundler', '~> 2.0'
29
29
  spec.add_development_dependency 'byebug', '~> 11.0'
30
+ spec.add_development_dependency 'codecov', '~> 0.5.2'
30
31
  spec.add_development_dependency 'rake', '~> 12.3', '>= 12.3.3'
32
+ spec.add_development_dependency 'readapt', '~> 1.3'
31
33
  spec.add_development_dependency 'redcarpet', '~> 3.5.0'
32
34
  spec.add_development_dependency 'rspec', '~> 3.0'
33
35
  spec.add_development_dependency 'rubocop', '~> 1.12'
34
36
  spec.add_development_dependency 'selenium-webdriver', '~> 3.142'
37
+ spec.add_development_dependency 'webmock', '~> 3.13'
35
38
  spec.add_dependency 'oauth2', '~> 1.4'
36
39
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: smartcar
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.5.0
4
+ version: 3.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ashwin Subramanian
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-06-08 00:00:00.000000000 Z
11
+ date: 2021-07-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -38,6 +38,20 @@ dependencies:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
40
  version: '11.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: codecov
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: 0.5.2
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: 0.5.2
41
55
  - !ruby/object:Gem::Dependency
42
56
  name: rake
43
57
  requirement: !ruby/object:Gem::Requirement
@@ -58,6 +72,20 @@ dependencies:
58
72
  - - ">="
59
73
  - !ruby/object:Gem::Version
60
74
  version: 12.3.3
75
+ - !ruby/object:Gem::Dependency
76
+ name: readapt
77
+ requirement: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - "~>"
80
+ - !ruby/object:Gem::Version
81
+ version: '1.3'
82
+ type: :development
83
+ prerelease: false
84
+ version_requirements: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - "~>"
87
+ - !ruby/object:Gem::Version
88
+ version: '1.3'
61
89
  - !ruby/object:Gem::Dependency
62
90
  name: redcarpet
63
91
  requirement: !ruby/object:Gem::Requirement
@@ -114,6 +142,20 @@ dependencies:
114
142
  - - "~>"
115
143
  - !ruby/object:Gem::Version
116
144
  version: '3.142'
145
+ - !ruby/object:Gem::Dependency
146
+ name: webmock
147
+ requirement: !ruby/object:Gem::Requirement
148
+ requirements:
149
+ - - "~>"
150
+ - !ruby/object:Gem::Version
151
+ version: '3.13'
152
+ type: :development
153
+ prerelease: false
154
+ version_requirements: !ruby/object:Gem::Requirement
155
+ requirements:
156
+ - - "~>"
157
+ - !ruby/object:Gem::Version
158
+ version: '3.13'
117
159
  - !ruby/object:Gem::Dependency
118
160
  name: oauth2
119
161
  requirement: !ruby/object:Gem::Requirement
@@ -149,27 +191,14 @@ files:
149
191
  - Rakefile
150
192
  - bin/console
151
193
  - bin/setup
194
+ - lib/open_struct_extensions.rb
152
195
  - lib/smartcar.rb
196
+ - lib/smartcar/auth_client.rb
153
197
  - lib/smartcar/base.rb
154
- - lib/smartcar/battery.rb
155
- - lib/smartcar/battery_capacity.rb
156
- - lib/smartcar/charge.rb
157
- - lib/smartcar/engine_oil.rb
158
- - lib/smartcar/fuel.rb
159
- - lib/smartcar/location.rb
160
- - lib/smartcar/oauth.rb
161
- - lib/smartcar/odometer.rb
162
- - lib/smartcar/permissions.rb
163
- - lib/smartcar/tire_pressure.rb
164
- - lib/smartcar/user.rb
165
198
  - lib/smartcar/utils.rb
166
199
  - lib/smartcar/vehicle.rb
167
- - lib/smartcar/vehicle_attributes.rb
168
- - lib/smartcar/vehicle_utils/actions.rb
169
- - lib/smartcar/vehicle_utils/batch.rb
170
- - lib/smartcar/vehicle_utils/data.rb
171
200
  - lib/smartcar/version.rb
172
- - lib/smartcar/vin.rb
201
+ - lib/smartcar_error.rb
173
202
  - ruby-sdk.gemspec
174
203
  homepage: https://rubygems.org/gems/smartcar
175
204
  licenses:
@@ -1,15 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Smartcar
4
- # class to represent Battery info
5
- # @attr [Number] percentRemaining Decimal value representing the remaining charge percent.
6
- # @attr [Number] range Remaining range of the vehicle.
7
- class Battery < Base
8
- # Path Proc for hitting battery end point
9
- PATH = proc { |id| "/vehicles/#{id}/battery" }
10
- attr_reader :percentRemaining, :range
11
-
12
- # just to have Ruby-esque method names
13
- alias percentage_remaining percentRemaining
14
- end
15
- end
@@ -1,11 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Smartcar
4
- # class to represent Battery Capacity info
5
- # @attr [Number] capacity Decimal value representing the battery's total capacity in kWh.
6
- class BatteryCapacity < Base
7
- # Path Proc for hitting battery capacity end point
8
- PATH = proc { |id| "/vehicles/#{id}/battery/capacity" }
9
- attr_reader :capacity
10
- end
11
- end
@@ -1,15 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Smartcar
4
- # class to represent Charge info
5
- # @attr [Boolean] isPluggedIn Specifies if the vehicle is plugged in.
6
- # @attr [String] state Charging state of the vehicle.
7
- class Charge < Base
8
- # Path Proc for hitting charge end point
9
- PATH = proc { |id| "/vehicles/#{id}/charge" }
10
- attr_reader :isPluggedIn, :state
11
-
12
- # just to have Ruby-esque method names
13
- alias is_plugged_in? isPluggedIn
14
- end
15
- end
@@ -1,14 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Smartcar
4
- # class to represent Engine oil info
5
- # @attr [Number] lifeRemaining Remaining life of the engine oil
6
- class EngineOil < Base
7
- # Path Proc for hitting engine oil end point
8
- PATH = proc { |id| "/vehicles/#{id}/engine/oil" }
9
- attr_reader :lifeRemaining
10
-
11
- # just to have Ruby-esque method names
12
- alias life_remaining lifeRemaining
13
- end
14
- end
data/lib/smartcar/fuel.rb DELETED
@@ -1,17 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Smartcar
4
- # class to represent Fuel info
5
- # @attr [Number] amountRemaining Amount of fuel remaining.
6
- # @attr [Number] percentageRemaining Decimal value representing the remaining fuel percent.
7
- # @attr [Number] range Remaining range of the vehicle.
8
- class Fuel < Base
9
- # Path Proc for hitting fuel end point
10
- PATH = proc { |id| "/vehicles/#{id}/fuel" }
11
- attr_reader :amountRemaining, :percentRemaining, :range
12
-
13
- # just to have Ruby-esque method names
14
- alias amount_remaining amountRemaining
15
- alias percent_remaining percentRemaining
16
- end
17
- end
@@ -1,12 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Smartcar
4
- # class to represent Location info
5
- # @attr [Number] latitude Latitude of last recorded location.
6
- # @attr [Number] longitude Longitude of last recorded location.
7
- class Location < Base
8
- # Path Proc for hitting location end point
9
- PATH = proc { |id| "/vehicles/#{id}/location" }
10
- attr_reader :latitude, :longitude
11
- end
12
- end
@@ -1,127 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Smartcar
4
- # Oauth class to take care of the Oauth 2.0 with Smartcar APIs
5
- #
6
- class Oauth < Base
7
- extend Smartcar::Utils
8
-
9
- attr_reader :redirect_uri, :client_id, :client_secret, :scope, :mode
10
-
11
- # By default users are not shown the permission dialog if they have already
12
- # approved the set of scopes for this application. The application can elect
13
- # to always display the permissions dialog to the user by setting
14
- # approval_prompt to `force`.
15
- #
16
- # @param options [Hash]
17
- # @option options[:client_id] [String] - Client ID, if not passed fallsback to ENV['CLIENT_ID']
18
- # @option options[:client_secret] [String] - Client Secret, if not passed fallsback to ENV['CLIENT_SECRET']
19
- # @option options[:redirect_uri] [String] - Redirect URI, if not passed fallsback to ENV['REDIRECT_URI']
20
- # @option options[:scope] [Array of Strings] - array of scopes that specify what the user can access
21
- # EXAMPLE : ['read_odometer', 'read_vehicle_info', 'required:read_location']
22
- # For further details refer to https://smartcar.com/docs/guides/scope/
23
- # @option options[:test_mode] [Boolean] - Setting this to 'true' runs it in test mode.
24
- #
25
- # @return [Smartcar::Oauth] Returns a Smartcar::Oauth Object that has other methods
26
- def initialize(options)
27
- options[:redirect_uri] ||= get_config('REDIRECT_URI')
28
- options[:client_id] ||= get_config('CLIENT_ID')
29
- options[:client_secret] ||= get_config('CLIENT_SECRET')
30
- options[:mode] = options[:test_mode].nil? || !options[:test_mode] ? LIVE : TEST
31
- super
32
- end
33
-
34
- # Generate the OAuth authorization URL.
35
- # @param options [Hash]
36
- # @option options[:state] [String] - OAuth state parameter passed to the
37
- # redirect uri. This parameter may be used for identifying the user who
38
- # initiated the request.
39
- # @option options[:force_prompt] [Boolean] - Setting `force_prompt` to
40
- # `true` will show the permissions approval screen on every authentication
41
- # attempt, even if the user has previously consented to the exact scope of
42
- # permissions.
43
- # @option options[:make] [String] - `make' is an optional parameter that allows
44
- # users to bypass the car brand selection screen.
45
- # For a complete list of supported makes, please see our
46
- # [API Reference](https://smartcar.com/docs/api#authorization) documentation.
47
- # @option options[:single_select] [Boolean, Hash] - An optional value that sets the
48
- # behavior of the grant dialog displayed to the user. If set to `true`,
49
- # `single_select` limits the user to selecting only one vehicle. If `single_select`
50
- # is an hash with the property `vin`, Smartcar will only authorize the vehicle
51
- # with the specified VIN. See the
52
- # [Single Select guide](https://smartcar.com/docs/guides/single-select/)
53
- # for more information.
54
- # @option options[:flags] [Array of Strings] - an optional array of early access features to enable.
55
- #
56
- # @return [String] Authorization URL string
57
- def authorization_url(options = {})
58
- initialize_auth_parameters(options)
59
- add_single_select_options(options[:single_select])
60
- client.auth_code.authorize_url(@auth_parameters)
61
- end
62
-
63
- # Generates the tokens hash using the code returned in oauth process.
64
- # @param auth_code [String] This is the code that is returned after user
65
- # visits and authorizes on the authorization URL.
66
- #
67
- # @return [Hash] Hash of token, refresh token, expiry info and token type
68
- def get_token(auth_code)
69
- client.auth_code
70
- .get_token(
71
- auth_code,
72
- redirect_uri: redirect_uri
73
- ).to_hash
74
- end
75
-
76
- # Refreshing the access token
77
- # @param refresh_token [String] refresh_token received during token exchange
78
- #
79
- # @return [Hash] Hash of token, refresh token, expiry info and token type
80
- def exchange_refresh_token(refresh_token)
81
- token_object = OAuth2::AccessToken.from_hash(client, { refresh_token: refresh_token })
82
- token_object = token_object.refresh!
83
- token_object.to_hash
84
- end
85
-
86
- # Checks if token is expired using Oauth2 classes
87
- # @param expires_at [Number] expires_at as time since epoch
88
- #
89
- # @return [Boolean]
90
- def expired?(expires_at)
91
- OAuth2::AccessToken.from_hash(client, { expires_at: expires_at }).expired?
92
- end
93
-
94
- private
95
-
96
- def initialize_auth_parameters(options)
97
- @auth_parameters = {
98
- response_type: CODE,
99
- redirect_uri: redirect_uri,
100
- mode: mode,
101
- state: options[:state],
102
- make: options[:make],
103
- approval_prompt: options[:force_prompt] ? FORCE : AUTO,
104
- flags: options[:flags]&.join(' '),
105
- scope: scope&.join(' ')
106
- }
107
- end
108
-
109
- def add_single_select_options(single_select)
110
- if single_select.is_a?(Hash)
111
- @auth_parameters[:single_select_vin] = single_select[:vin]
112
- @auth_parameters[:single_select] = true
113
- else
114
- @auth_parameters[:single_select] = !single_select.nil?
115
- end
116
- end
117
-
118
- # gets the Oauth Client object
119
- #
120
- # @return [OAuth2::Client] A Oauth Client object.
121
- def client
122
- @client ||= OAuth2::Client.new(client_id,
123
- client_secret,
124
- site: OAUTH_PATH)
125
- end
126
- end
127
- end
@@ -1,11 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Smartcar
4
- # class to represent Odometer
5
- # @attr [Number] distanceLast recorded odometer reading.
6
- class Odometer < Base
7
- # Path Proc for hitting odometer end point
8
- PATH = proc { |id| "/vehicles/#{id}/odometer" }
9
- attr_reader :distance
10
- end
11
- end
@@ -1,11 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Smartcar
4
- # class to represent permissions response
5
- # @attr [Array] permissions Array of permissions granted on the vehicle.
6
- class Permissions < Base
7
- # Path Proc for hitting permissions end point
8
- PATH = proc { |id| "/vehicles/#{id}/permissions" }
9
- attr_reader :permissions
10
- end
11
- end
@@ -1,20 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Smartcar
4
- # class to represent Tire Pressure response
5
- # @attr [Number] back_left Last recorded tire pressure of the back left tire.
6
- # @attr [Number] back_right Last recorded tire pressure of the back right tire.
7
- # @attr [Number] front_left Last recorded tire pressure of the front left tire.
8
- # @attr [Number] front_right Last recorded tire pressure of the front right tire.
9
- class TirePressure < Base
10
- # Path Proc for hitting tire pressure end point
11
- PATH = proc { |id| "/vehicles/#{id}/tires/pressure" }
12
- attr_reader :backLeft, :backRight, :frontLeft, :frontRight
13
-
14
- # just to have Ruby-esque method names
15
- alias back_left backLeft
16
- alias back_right backRight
17
- alias front_left frontLeft
18
- alias front_right frontRight
19
- end
20
- end