smartcar 2.1.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.
@@ -1,4 +1,6 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Smartcar
2
4
  # Gem current version number
3
- VERSION = "2.1.0"
5
+ VERSION = '3.0.0'
4
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
@@ -1,33 +1,39 @@
1
- lib = File.expand_path("lib", __dir__)
1
+ # frozen_string_literal: true
2
+
3
+ lib = File.expand_path('lib', __dir__)
2
4
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
- require "smartcar/version"
5
+ require 'smartcar/version'
4
6
 
5
7
  Gem::Specification.new do |spec|
6
- spec.name = "smartcar"
8
+ spec.name = 'smartcar'
7
9
  spec.version = Smartcar::VERSION
8
- spec.required_ruby_version = ">= 2.5.0"
9
- spec.authors = ["Ashwin Subramanian"]
10
- spec.email = ["ashwin.subramanian@smartcar.com"]
10
+ spec.required_ruby_version = '>= 2.5.0'
11
+ spec.authors = ['Ashwin Subramanian']
12
+ spec.email = ['ashwin.subramanian@smartcar.com']
11
13
  spec.homepage = 'https://rubygems.org/gems/smartcar'
12
- spec.summary = %q{Ruby Gem to access smartcar APIs (https://smartcar.com/docs/)}
13
- spec.description = %q{This is a ruby gem to access the smartcar APIs. It includes the API classes and the OAuth system.}
14
- spec.license = "MIT"
15
- spec.metadata = {
16
- "source_code_uri" => "https://github.com/smartcar/ruby-sdk",
17
- "documentation_uri" => "https://www.rubydoc.info/gems/smartcar",
14
+ spec.summary = 'Ruby Gem to access smartcar APIs (https://smartcar.com/docs/)'
15
+ spec.description = 'This is a ruby gem to access the smartcar APIs. It includes the API classes and the OAuth system.'
16
+ spec.license = 'MIT'
17
+ spec.metadata = {
18
+ 'source_code_uri' => 'https://github.com/smartcar/ruby-sdk',
19
+ 'documentation_uri' => 'https://www.rubydoc.info/gems/smartcar'
18
20
  }
19
- spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
21
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
20
22
  `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
21
23
  end
22
- spec.bindir = "exe"
24
+ spec.bindir = 'exe'
23
25
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
24
- spec.require_paths = ["lib"]
26
+ spec.require_paths = ['lib']
25
27
 
26
- spec.add_development_dependency "bundler", "~> 2.0"
28
+ spec.add_development_dependency 'bundler', '~> 2.0'
29
+ spec.add_development_dependency 'byebug', '~> 11.0'
30
+ spec.add_development_dependency 'codecov', '~> 0.5.2'
27
31
  spec.add_development_dependency 'rake', '~> 12.3', '>= 12.3.3'
28
- spec.add_development_dependency "rspec", "~> 3.0"
29
- spec.add_development_dependency "byebug", "~> 11.0"
30
- spec.add_development_dependency "redcarpet", "~> 3.5.0"
31
- spec.add_development_dependency "selenium-webdriver", "~> 3.142"
32
- spec.add_dependency "oauth2", "~> 1.4"
32
+ spec.add_development_dependency 'readapt', '~> 1.3'
33
+ spec.add_development_dependency 'redcarpet', '~> 3.5.0'
34
+ spec.add_development_dependency 'rspec', '~> 3.0'
35
+ spec.add_development_dependency 'rubocop', '~> 1.12'
36
+ spec.add_development_dependency 'selenium-webdriver', '~> 3.142'
37
+ spec.add_development_dependency 'webmock', '~> 3.13'
38
+ spec.add_dependency 'oauth2', '~> 1.4'
33
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.1.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: 2020-12-29 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
@@ -24,6 +24,34 @@ dependencies:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
26
  version: '2.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: byebug
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '11.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
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
27
55
  - !ruby/object:Gem::Dependency
28
56
  name: rake
29
57
  requirement: !ruby/object:Gem::Requirement
@@ -45,47 +73,61 @@ dependencies:
45
73
  - !ruby/object:Gem::Version
46
74
  version: 12.3.3
47
75
  - !ruby/object:Gem::Dependency
48
- name: rspec
76
+ name: readapt
49
77
  requirement: !ruby/object:Gem::Requirement
50
78
  requirements:
51
79
  - - "~>"
52
80
  - !ruby/object:Gem::Version
53
- version: '3.0'
81
+ version: '1.3'
54
82
  type: :development
55
83
  prerelease: false
56
84
  version_requirements: !ruby/object:Gem::Requirement
57
85
  requirements:
58
86
  - - "~>"
59
87
  - !ruby/object:Gem::Version
60
- version: '3.0'
88
+ version: '1.3'
61
89
  - !ruby/object:Gem::Dependency
62
- name: byebug
90
+ name: redcarpet
63
91
  requirement: !ruby/object:Gem::Requirement
64
92
  requirements:
65
93
  - - "~>"
66
94
  - !ruby/object:Gem::Version
67
- version: '11.0'
95
+ version: 3.5.0
68
96
  type: :development
69
97
  prerelease: false
70
98
  version_requirements: !ruby/object:Gem::Requirement
71
99
  requirements:
72
100
  - - "~>"
73
101
  - !ruby/object:Gem::Version
74
- version: '11.0'
102
+ version: 3.5.0
75
103
  - !ruby/object:Gem::Dependency
76
- name: redcarpet
104
+ name: rspec
77
105
  requirement: !ruby/object:Gem::Requirement
78
106
  requirements:
79
107
  - - "~>"
80
108
  - !ruby/object:Gem::Version
81
- version: 3.5.0
109
+ version: '3.0'
82
110
  type: :development
83
111
  prerelease: false
84
112
  version_requirements: !ruby/object:Gem::Requirement
85
113
  requirements:
86
114
  - - "~>"
87
115
  - !ruby/object:Gem::Version
88
- version: 3.5.0
116
+ version: '3.0'
117
+ - !ruby/object:Gem::Dependency
118
+ name: rubocop
119
+ requirement: !ruby/object:Gem::Requirement
120
+ requirements:
121
+ - - "~>"
122
+ - !ruby/object:Gem::Version
123
+ version: '1.12'
124
+ type: :development
125
+ prerelease: false
126
+ version_requirements: !ruby/object:Gem::Requirement
127
+ requirements:
128
+ - - "~>"
129
+ - !ruby/object:Gem::Version
130
+ version: '1.12'
89
131
  - !ruby/object:Gem::Dependency
90
132
  name: selenium-webdriver
91
133
  requirement: !ruby/object:Gem::Requirement
@@ -100,6 +142,20 @@ dependencies:
100
142
  - - "~>"
101
143
  - !ruby/object:Gem::Version
102
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'
103
159
  - !ruby/object:Gem::Dependency
104
160
  name: oauth2
105
161
  requirement: !ruby/object:Gem::Requirement
@@ -124,6 +180,7 @@ extra_rdoc_files: []
124
180
  files:
125
181
  - ".gitignore"
126
182
  - ".rspec"
183
+ - ".rubocop.yml"
127
184
  - ".travis.yml"
128
185
  - ".yardopts"
129
186
  - CODE_OF_CONDUCT.md
@@ -134,24 +191,14 @@ files:
134
191
  - Rakefile
135
192
  - bin/console
136
193
  - bin/setup
194
+ - lib/open_struct_extensions.rb
137
195
  - lib/smartcar.rb
196
+ - lib/smartcar/auth_client.rb
138
197
  - lib/smartcar/base.rb
139
- - lib/smartcar/battery.rb
140
- - lib/smartcar/battery_capacity.rb
141
- - lib/smartcar/charge.rb
142
- - lib/smartcar/engine_oil.rb
143
- - lib/smartcar/fuel.rb
144
- - lib/smartcar/location.rb
145
- - lib/smartcar/oauth.rb
146
- - lib/smartcar/odometer.rb
147
- - lib/smartcar/permissions.rb
148
- - lib/smartcar/tire_pressure.rb
149
- - lib/smartcar/user.rb
150
198
  - lib/smartcar/utils.rb
151
199
  - lib/smartcar/vehicle.rb
152
- - lib/smartcar/vehicle_attributes.rb
153
200
  - lib/smartcar/version.rb
154
- - lib/smartcar/vin.rb
201
+ - lib/smartcar_error.rb
155
202
  - ruby-sdk.gemspec
156
203
  homepage: https://rubygems.org/gems/smartcar
157
204
  licenses:
@@ -1,13 +0,0 @@
1
- module Smartcar
2
- # class to represent Battery info
3
- #@attr [Number] percentRemaining Decimal value representing the remaining charge percent.
4
- #@attr [Number] range Remaining range of the vehicle.
5
- class Battery < Base
6
- # Path Proc for hitting battery end point
7
- PATH = Proc.new{|id| "/vehicles/#{id}/battery"}
8
- attr_reader :percentRemaining, :range
9
-
10
- # just to have Ruby-esque method names
11
- alias_method :percentage_remaining, :percentRemaining
12
- end
13
- end
@@ -1,9 +0,0 @@
1
- module Smartcar
2
- # class to represent Battery Capacity info
3
- #@attr [Number] capacity Decimal value representing the battery's total capacity in kWh.
4
- class BatteryCapacity < Base
5
- # Path Proc for hitting battery capacity end point
6
- PATH = Proc.new{|id| "/vehicles/#{id}/battery/capacity"}
7
- attr_reader :capacity
8
- end
9
- end
@@ -1,13 +0,0 @@
1
- module Smartcar
2
- # class to represent Charge info
3
- #@attr [Boolean] isPluggedIn Specifies if the vehicle is plugged in.
4
- #@attr [String] state Charging state of the vehicle.
5
- class Charge < Base
6
- # Path Proc for hitting charge end point
7
- PATH = Proc.new{|id| "/vehicles/#{id}/charge"}
8
- attr_reader :isPluggedIn, :state
9
-
10
- # just to have Ruby-esque method names
11
- alias_method :is_plugged_in?, :isPluggedIn
12
- end
13
- end
@@ -1,12 +0,0 @@
1
- module Smartcar
2
- # class to represent Engine oil info
3
- #@attr [Number] lifeRemaining Remaining life of the engine oil
4
- class EngineOil < Base
5
- # Path Proc for hitting engine oil end point
6
- PATH = Proc.new{|id| "/vehicles/#{id}/engine/oil"}
7
- attr_reader :lifeRemaining
8
-
9
- # just to have Ruby-esque method names
10
- alias_method :life_remaining, :lifeRemaining
11
- end
12
- end
data/lib/smartcar/fuel.rb DELETED
@@ -1,15 +0,0 @@
1
- module Smartcar
2
- # class to represent Fuel info
3
- #@attr [Number] amountRemaining Amount of fuel remaining.
4
- #@attr [Number] percentageRemaining Decimal value representing the remaining fuel percent.
5
- #@attr [Number] range Remaining range of the vehicle.
6
- class Fuel < Base
7
- # Path Proc for hitting fuel end point
8
- PATH = Proc.new{|id| "/vehicles/#{id}/fuel"}
9
- attr_reader :amountRemaining, :percentRemaining, :range
10
-
11
- # just to have Ruby-esque method names
12
- alias_method :amount_remaining, :amountRemaining
13
- alias_method :percent_remaining, :percentRemaining
14
- end
15
- end
@@ -1,10 +0,0 @@
1
- module Smartcar
2
- # class to represent Location info
3
- #@attr [Number] latitude Latitude of last recorded location.
4
- #@attr [Number] longitude Longitude of last recorded location.
5
- class Location < Base
6
- # Path Proc for hitting location end point
7
- PATH = Proc.new{|id| "/vehicles/#{id}/location"}
8
- attr_reader :latitude, :longitude
9
- end
10
- end
@@ -1,119 +0,0 @@
1
- module Smartcar
2
- # Oauth class to take care of the Oauth 2.0 with Smartcar APIs
3
- #
4
- class Oauth < Base
5
- extend Utils
6
- # By default users are not shown the permission dialog if they have already
7
- # approved the set of scopes for this application. The application can elect
8
- # to always display the permissions dialog to the user by setting
9
- # approval_prompt to `force`.
10
- #
11
- # @param options [Hash]
12
- # @option options[:client_id] [String] - Client ID, if not passed fallsback to ENV['CLIENT_ID']
13
- # @option options[:client_secret] [String] - Client Secret, if not passed fallsback to ENV['CLIENT_SECRET']
14
- # @option options[:redirect_uri] [String] - Redirect URI, if not passed fallsback to ENV['REDIRECT_URI']
15
- # @option options[:scope] [Array of Strings] - array of scopes that specify what the user can access
16
- # EXAMPLE : ['read_odometer', 'read_vehicle_info', 'required:read_location']
17
- # For further details refer to https://smartcar.com/docs/guides/scope/
18
- # @option options[:test_mode] [Boolean] - Setting this to 'true' runs it in test mode.
19
- #
20
- # @return [Smartcar::Oauth] Returns a Smartcar::Oauth Object that has other methods
21
- def initialize(options)
22
- @redirect_uri = options[:redirect_uri] || get_config('REDIRECT_URI')
23
- @client_id = options[:client_id] || get_config('CLIENT_ID')
24
- @client_secret = options[:client_secret] || get_config('CLIENT_SECRET')
25
- @scope = options[:scope]
26
- @test_mode = !!options[:test_mode]
27
- end
28
-
29
- # Generate the OAuth authorization URL.
30
- # @param options [Hash]
31
- # @option options[:state] [String] - OAuth state parameter passed to the
32
- # redirect uri. This parameter may be used for identifying the user who
33
- # initiated the request.
34
- # @option options[:force_prompt] [Boolean] - Setting `force_prompt` to
35
- # `true` will show the permissions approval screen on every authentication
36
- # attempt, even if the user has previously consented to the exact scope of
37
- # permissions.
38
- # @option options[:make] [String] - `make' is an optional parameter that allows
39
- # users to bypass the car brand selection screen.
40
- # For a complete list of supported makes, please see our
41
- # [API Reference](https://smartcar.com/docs/api#authorization) documentation.
42
- # @option options[:single_select] [Boolean, Hash] - An optional value that sets the
43
- # behavior of the grant dialog displayed to the user. If set to `true`,
44
- # `single_select` limits the user to selecting only one vehicle. If `single_select`
45
- # is an hash with the property `vin`, Smartcar will only authorize the vehicle
46
- # with the specified VIN. See the
47
- # [Single Select guide](https://smartcar.com/docs/guides/single-select/)
48
- # for more information.
49
- # @option options[:flags] [Array of Strings] - an optional array of early access features to enable.
50
- #
51
- # @return [String] Authorization URL string
52
- def authorization_url(options = {})
53
- options[:scope] = @scope
54
- auth_parameters = {
55
- redirect_uri: @redirect_uri,
56
- approval_prompt: options[:force_prompt] ? FORCE : AUTO,
57
- mode: @test_mode ? TEST : LIVE,
58
- response_type: CODE,
59
- }
60
-
61
- auth_parameters[:flags] = options[:flags].join(' ') unless options[:flags].nil?
62
- auth_parameters[:scope] = @scope.join(' ') unless @scope.nil?
63
-
64
- %I(state make).each do |parameter|
65
- auth_parameters[parameter] = options[parameter] unless options[parameter].nil?
66
- end
67
-
68
- if(options[:single_select].is_a?(Hash))
69
- auth_parameters[:single_select_vin] = options[:single_select][:vin]
70
- auth_parameters[:single_select] = true
71
- else
72
- auth_parameters[:single_select] = !!options[:single_select]
73
- end
74
- client.auth_code.authorize_url(auth_parameters)
75
- end
76
-
77
- # Generates the tokens hash using the code returned in oauth process.
78
- # @param auth_code [String] This is the code that is returned after user
79
- # visits and authorizes on the authorization URL.
80
- #
81
- # @return [Hash] Hash of token, refresh token, expiry info and token type
82
- def get_token(auth_code)
83
- client.auth_code
84
- .get_token(
85
- auth_code,
86
- redirect_uri: @redirect_uri
87
- ).to_hash
88
- end
89
-
90
- # Refreshing the access token
91
- # @param refresh_token [String] refresh_token received during token exchange
92
- #
93
- # @return [Hash] Hash of token, refresh token, expiry info and token type
94
- def exchange_refresh_token(refresh_token)
95
- token_object = OAuth2::AccessToken.from_hash(client, {refresh_token: refresh_token})
96
- token_object = token_object.refresh!
97
- token_object.to_hash
98
- end
99
-
100
- # Checks if token is expired using Oauth2 classes
101
- # @param expires_at [Number] expires_at as time since epoch
102
- #
103
- # @return [Boolean]
104
- def expired?(expires_at)
105
- OAuth2::AccessToken.from_hash(client, {expires_at: expires_at}).expired?
106
- end
107
-
108
- private
109
- # gets the Oauth Client object
110
- #
111
- # @return [OAuth2::Client] A Oauth Client object.
112
- def client
113
- @client ||= OAuth2::Client.new( @client_id,
114
- @client_secret,
115
- :site => OAUTH_PATH
116
- )
117
- end
118
- end
119
- end