smartcar 2.5.0 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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