my_john_deere_api 0.0.1 → 0.0.2

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e2ae704f57aab2fa5c33972e626c85de1f4c870094f5b4e3807025da0bea6325
4
- data.tar.gz: 46a6f1d705a307c09829ae49b8df13cc8bdd49f7c5b650c8ea9d2d13b918ca6d
3
+ metadata.gz: 0a4a505a402a82195b10345e48301897a6af477a4ba60711c33caee9d77ba764
4
+ data.tar.gz: 4f3f21b7b110b76be7bcc99195b380a3d05154443cbab36732e1f32a0dc830b2
5
5
  SHA512:
6
- metadata.gz: abbd9e17e1ed5c709595de082e120381985aff0f78dfcd836474ad0f0de3fc1481a330484cec14962625bd658f5e89235f2ad5de40546fc247393898121e1e5a
7
- data.tar.gz: 4cf59f13b1cedf18648871e9e5cc623d0c43f939e0e1a440f006c2e32949bf67f6754090ecf38bfd6d9c4c1e29801f633e7b9e57cf458e6cf4cc5d55ade3a114
6
+ metadata.gz: 19b70538ef4d795113246f269c97f6efe22cd2ccb79903d5433ee8aad79fc5823eb383e047bac8409f37f73a01658519a2fa3ceb10740416945833db8e9f6388
7
+ data.tar.gz: f0bbf336465ab99361e74e5102abd2dc6ebb2b74116988e5c9b8319aa28a2bf104a02c5209d2759904624ddd340aa9db019f819d93d20a63f2a5d82ae1b6450d
data/Rakefile CHANGED
@@ -2,6 +2,7 @@ require 'rake/testtask'
2
2
 
3
3
  Rake::TestTask.new do |t|
4
4
  t.libs << 'test'
5
+ t.pattern = 'test/**/test*.rb'
5
6
  end
6
7
 
7
8
  desc "Run tests"
@@ -1,5 +1,8 @@
1
+ require 'oauth'
2
+ require 'uri'
1
3
  require 'json'
2
4
 
3
5
  module MyJohnDeereApi
4
6
  autoload :VERSION, 'my_john_deere_api/version'
7
+ autoload :Authorize, 'my_john_deere_api/authorize'
5
8
  end
@@ -0,0 +1,80 @@
1
+ class MyJohnDeereApi::Authorize
2
+ attr_reader :api_key, :api_secret, :request_token, :request_secret
3
+ attr_accessor :base_url
4
+
5
+ DEFAULTS = {
6
+ base_url: 'https://api.soa-proxy.deere.com',
7
+ }
8
+
9
+ def initialize(api_key, api_secret, options={})
10
+ @api_key = api_key
11
+ @api_secret = api_secret
12
+ @base_url = options[:base_url] || ENV['MY_JOHN_DEERE_URL'] || DEFAULTS[:base_url]
13
+ end
14
+
15
+ def authorize_url
16
+ return @authorize_url if defined?(@authorize_url)
17
+
18
+ requester = app_consumer.get_request_token
19
+
20
+ @request_token = requester.token
21
+ @request_secret = requester.secret
22
+
23
+ @authorize_url = requester.authorize_url
24
+ end
25
+
26
+ def app_consumer
27
+ @app_consumer ||= consumer(base_url)
28
+ end
29
+
30
+ def user_consumer
31
+ @user_consumer ||= consumer("#{base_url}/platform")
32
+ end
33
+
34
+ def consumer(site)
35
+ OAuth::Consumer.new(
36
+ api_key,
37
+ api_secret,
38
+ site: site,
39
+ header: header,
40
+ http_method: :get,
41
+ request_token_url: links[:request_token],
42
+ access_token_url: links[:access_token],
43
+ authorize_url: links[:authorize_request_token]
44
+ )
45
+ end
46
+
47
+ def links
48
+ return @links if defined?(@links)
49
+
50
+ catalog = OAuth::Consumer.new(api_key, api_secret)
51
+ .request(
52
+ :get,
53
+ "#{base_url}/platform/",
54
+ nil,
55
+ {},
56
+ header
57
+ ).body
58
+
59
+ @links = {}
60
+
61
+ JSON.parse(catalog)['links'].each do |link|
62
+ uri = URI.parse(link['uri'])
63
+ uri.query = nil
64
+
65
+ @links[keyify(link['rel'])] = uri.to_s
66
+ end
67
+
68
+ @links
69
+ end
70
+
71
+ private
72
+
73
+ def header
74
+ {accept: 'application/vnd.deere.axiom.v3+json'}
75
+ end
76
+
77
+ def keyify key_name
78
+ key_name.gsub(/^oauth/, '').gsub(/([a-z])([A-Z])/, '\1_\2').downcase.to_sym
79
+ end
80
+ end
@@ -1,3 +1,3 @@
1
1
  module MyJohnDeereApi
2
- VERSION = '0.0.1'
3
- end
2
+ VERSION='0.0.2'
3
+ end
@@ -0,0 +1,132 @@
1
+ require 'uri'
2
+ require 'cgi'
3
+ require 'support/helper'
4
+
5
+ URL_ENV = 'MY_JOHN_DEERE_URL'
6
+ TOKEN_PATTERN = /^[0-9a-z\-]+$/
7
+ SECRET_PATTERN = /^[0-9A-Za-z\-+=\/]+$/
8
+ API_KEY = ENV['API_KEY']
9
+ API_SECRET = ENV['API_SECRET']
10
+
11
+ def contains_parameters?(uri)
12
+ !URI.parse(uri).query.nil?
13
+ end
14
+
15
+ def create_authorize
16
+ JD::Authorize.new(API_KEY, API_SECRET, base_url: 'https://sandboxapi.deere.com')
17
+ end
18
+
19
+ def fancy_url
20
+ 'https://example.com/turtles'
21
+ end
22
+
23
+ class AuthorizeTest < MiniTest::Test
24
+ describe 'initialization' do
25
+ it "accepts an API key and secret" do
26
+ authorize = JD::Authorize.new('key', 'secret')
27
+
28
+ assert_equal 'key', authorize.api_key
29
+ assert_equal 'secret', authorize.api_secret
30
+ end
31
+
32
+ it "can set the base_url" do
33
+ authorize = JD::Authorize.new('key', 'secret', base_url: fancy_url)
34
+ assert_equal fancy_url, authorize.base_url
35
+ end
36
+
37
+ it 'prefers passed-in base_url over ENV variable' do
38
+ ENV[URL_ENV] = 'https://example.com/disposable'
39
+
40
+ authorize = JD::Authorize.new('key', 'secret', base_url: fancy_url)
41
+ assert_equal fancy_url, authorize.base_url
42
+
43
+ ENV.delete(URL_ENV)
44
+ end
45
+ end
46
+
47
+ describe '#authorize_url' do
48
+ it 'retrieves a request url' do
49
+ authorize = create_authorize
50
+
51
+ url = VCR.use_cassette('get_request_token') { authorize.authorize_url }
52
+
53
+ assert_includes url, "#{authorize.links[:authorize_request_token]}?oauth_token="
54
+
55
+ query = URI.parse(url).query
56
+ params = CGI::parse(query)
57
+
58
+ assert_match(TOKEN_PATTERN, params['oauth_token'].first)
59
+ end
60
+
61
+ it 'sets the request token/secret' do
62
+ authorize = create_authorize
63
+
64
+ VCR.use_cassette('get_request_token') { authorize.authorize_url }
65
+
66
+ assert_match TOKEN_PATTERN, authorize.request_token
67
+ assert_match SECRET_PATTERN, authorize.request_secret
68
+ end
69
+ end
70
+
71
+ describe '#links' do
72
+ it "returns a list of catalog urls" do
73
+ authorize = create_authorize
74
+
75
+ links = VCR.use_cassette("catalog"){ authorize.links }
76
+
77
+ assert_kind_of Hash, links
78
+
79
+ [:request_token, :authorize_request_token, :access_token].each do |link|
80
+ assert links.has_key?(link)
81
+ refute contains_parameters?(links[link])
82
+ end
83
+ end
84
+ end
85
+
86
+ describe '#base_url' do
87
+ it 'defaults to production deere url' do
88
+ authorize = JD::Authorize.new('key', 'secret')
89
+ assert_equal 'https://api.soa-proxy.deere.com', authorize.base_url
90
+ end
91
+
92
+ it 'can be set via accessor' do
93
+ authorize = create_authorize
94
+ authorize.base_url = fancy_url
95
+
96
+ assert_equal fancy_url, authorize.base_url
97
+ end
98
+
99
+ it 'can be set via environment variable' do
100
+ ENV[URL_ENV] = fancy_url
101
+
102
+ authorize = JD::Authorize.new('key', 'secret')
103
+ assert_equal fancy_url, authorize.base_url
104
+
105
+ ENV.delete(URL_ENV)
106
+ end
107
+ end
108
+
109
+ describe '#app_consumer' do
110
+ it 'creates a working oAuth consumer for non-user-specific requests' do
111
+ auth = create_authorize
112
+ app_consumer = VCR.use_cassette('app_consumer') { auth.app_consumer }
113
+
114
+ assert_kind_of OAuth::Consumer, app_consumer
115
+ assert_equal API_KEY, app_consumer.key
116
+ assert_equal API_SECRET, app_consumer.secret
117
+ assert_equal auth.base_url, app_consumer.site
118
+ end
119
+ end
120
+
121
+ describe '#user_consumer' do
122
+ it 'creates a working oAuth consumer for user-specific requests' do
123
+ auth = create_authorize
124
+ user_consumer = VCR.use_cassette('app_consumer') { auth.user_consumer }
125
+
126
+ assert_kind_of OAuth::Consumer, user_consumer
127
+ assert_equal API_KEY, user_consumer.key
128
+ assert_equal API_SECRET, user_consumer.secret
129
+ assert_equal "#{auth.base_url}/platform", user_consumer.site
130
+ end
131
+ end
132
+ end
@@ -0,0 +1,9 @@
1
+ require 'support/helper'
2
+
3
+ class VersionTest < MiniTest::Test
4
+ describe 'VERSION' do
5
+ it 'conforms to the semantic version format' do
6
+ assert_match(/^\d+\.\d+\.\d+$/, MyJohnDeereApi::VERSION)
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,14 @@
1
+ require 'rubygems'
2
+ require 'vcr'
3
+ require 'webmock'
4
+ require 'dotenv/load'
5
+ require 'minitest/autorun'
6
+ require 'my_john_deere_api'
7
+
8
+ # shortcut for long module name
9
+ JD = MyJohnDeereApi
10
+
11
+ VCR.configure do |config|
12
+ config.cassette_library_dir = 'test/support/vcr'
13
+ config.hook_into :webmock
14
+ end
@@ -0,0 +1,46 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: get
5
+ uri: https://sandboxapi.deere.com/platform/
6
+ body:
7
+ encoding: US-ASCII
8
+ string: ''
9
+ headers:
10
+ Accept:
11
+ - application/vnd.deere.axiom.v3+json
12
+ Accept-Encoding:
13
+ - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
14
+ User-Agent:
15
+ - OAuth gem v0.5.4
16
+ Authorization:
17
+ - OAuth oauth_consumer_key="johndeere-wgmADngYCRmfpEbVgSyc709wnyRux5J7PAv8SE7B",
18
+ oauth_nonce="hLAsNSIk6Q2d3ULD6bT6rVf10km1qN5edh9HvNUgSc", oauth_signature="wjrjTVSXWY3uanxn69Y251jDFn8%3D",
19
+ oauth_signature_method="HMAC-SHA1", oauth_timestamp="1578174980", oauth_version="1.0"
20
+ response:
21
+ status:
22
+ code: 200
23
+ message: OK
24
+ headers:
25
+ Date:
26
+ - Sat, 04 Jan 2020 21:56:21 GMT
27
+ Content-Type:
28
+ - application/vnd.deere.axiom.v3+json;charset=UTF-8
29
+ X-Deere-Handling-Server:
30
+ - ip-10-214-44-80
31
+ X-Frame-Options:
32
+ - SAMEORIGIN
33
+ X-Deere-Elapsed-Ms:
34
+ - '16'
35
+ Cache-Control:
36
+ - no-store
37
+ Content-Language:
38
+ - en-US
39
+ Transfer-Encoding:
40
+ - chunked
41
+ body:
42
+ encoding: ASCII-8BIT
43
+ string: '{"@type":"ApiCatalog","links":[{"@type":"Link","rel":"oauthRequestToken","uri":"https://sandboxapi.deere.com/platform/oauth/request_token"},{"@type":"Link","rel":"oauthAuthorizeRequestToken","uri":"https://my.deere.com/consentToUseOfData?oauth_token={token}"},{"@type":"Link","rel":"oauthAccessToken","uri":"https://sandboxapi.deere.com/platform/oauth/access_token"},{"@type":"Link","rel":"agencies","uri":"https://sandboxapi.deere.com/platform/agencies"}]}'
44
+ http_version:
45
+ recorded_at: Sat, 04 Jan 2020 21:56:21 GMT
46
+ recorded_with: VCR 5.0.0
@@ -0,0 +1,46 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: get
5
+ uri: https://sandboxapi.deere.com/platform/
6
+ body:
7
+ encoding: US-ASCII
8
+ string: ''
9
+ headers:
10
+ Accept:
11
+ - application/vnd.deere.axiom.v3+json
12
+ Accept-Encoding:
13
+ - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
14
+ User-Agent:
15
+ - OAuth gem v0.5.4
16
+ Authorization:
17
+ - OAuth oauth_consumer_key="johndeere-wgmADngYCRmfpEbVgSyc709wnyRux5J7PAv8SE7B",
18
+ oauth_nonce="3O7ELJDsWLUeJWwOv38z2KBoobVksbYRYDspg7fpMyc", oauth_signature="TL0zdGeZxLQ%2BYKgQDqnZQ%2BBZsJA%3D",
19
+ oauth_signature_method="HMAC-SHA1", oauth_timestamp="1578166502", oauth_version="1.0"
20
+ response:
21
+ status:
22
+ code: 200
23
+ message: OK
24
+ headers:
25
+ Date:
26
+ - Sat, 04 Jan 2020 19:35:04 GMT
27
+ Content-Type:
28
+ - application/vnd.deere.axiom.v3+json;charset=UTF-8
29
+ X-Deere-Handling-Server:
30
+ - ip-10-214-44-145
31
+ X-Frame-Options:
32
+ - SAMEORIGIN
33
+ X-Deere-Elapsed-Ms:
34
+ - '11'
35
+ Cache-Control:
36
+ - no-store
37
+ Content-Language:
38
+ - en-US
39
+ Transfer-Encoding:
40
+ - chunked
41
+ body:
42
+ encoding: ASCII-8BIT
43
+ string: '{"@type":"ApiCatalog","links":[{"@type":"Link","rel":"oauthRequestToken","uri":"https://sandboxapi.deere.com/platform/oauth/request_token"},{"@type":"Link","rel":"oauthAuthorizeRequestToken","uri":"https://my.deere.com/consentToUseOfData?oauth_token={token}"},{"@type":"Link","rel":"oauthAccessToken","uri":"https://sandboxapi.deere.com/platform/oauth/access_token"},{"@type":"Link","rel":"agencies","uri":"https://sandboxapi.deere.com/platform/agencies"}]}'
44
+ http_version:
45
+ recorded_at: Sat, 04 Jan 2020 19:35:04 GMT
46
+ recorded_with: VCR 5.0.0
@@ -0,0 +1,83 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: get
5
+ uri: https://sandboxapi.deere.com/platform/
6
+ body:
7
+ encoding: US-ASCII
8
+ string: ''
9
+ headers:
10
+ Accept:
11
+ - application/vnd.deere.axiom.v3+json
12
+ Accept-Encoding:
13
+ - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
14
+ User-Agent:
15
+ - OAuth gem v0.5.4
16
+ Authorization:
17
+ - OAuth oauth_consumer_key="johndeere-wgmADngYCRmfpEbVgSyc709wnyRux5J7PAv8SE7B",
18
+ oauth_nonce="bA9m9jeEEXtDVO6t3evCoJcxWV6ask0dqv90ULA", oauth_signature="URbHoE5qi3YLnZlA5FiS6mloDPE%3D",
19
+ oauth_signature_method="HMAC-SHA1", oauth_timestamp="1578170525", oauth_version="1.0"
20
+ response:
21
+ status:
22
+ code: 200
23
+ message: OK
24
+ headers:
25
+ Date:
26
+ - Sat, 04 Jan 2020 20:42:06 GMT
27
+ Content-Type:
28
+ - application/vnd.deere.axiom.v3+json;charset=UTF-8
29
+ X-Deere-Handling-Server:
30
+ - ip-10-214-45-13
31
+ X-Frame-Options:
32
+ - SAMEORIGIN
33
+ X-Deere-Elapsed-Ms:
34
+ - '14'
35
+ Cache-Control:
36
+ - no-store
37
+ Content-Language:
38
+ - en-US
39
+ Transfer-Encoding:
40
+ - chunked
41
+ body:
42
+ encoding: ASCII-8BIT
43
+ string: '{"@type":"ApiCatalog","links":[{"@type":"Link","rel":"oauthRequestToken","uri":"https://sandboxapi.deere.com/platform/oauth/request_token"},{"@type":"Link","rel":"oauthAuthorizeRequestToken","uri":"https://my.deere.com/consentToUseOfData?oauth_token={token}"},{"@type":"Link","rel":"oauthAccessToken","uri":"https://sandboxapi.deere.com/platform/oauth/access_token"},{"@type":"Link","rel":"agencies","uri":"https://sandboxapi.deere.com/platform/agencies"}]}'
44
+ http_version:
45
+ recorded_at: Sat, 04 Jan 2020 20:42:07 GMT
46
+ - request:
47
+ method: get
48
+ uri: https://sandboxapi.deere.com/platform/oauth/request_token
49
+ body:
50
+ encoding: US-ASCII
51
+ string: ''
52
+ headers:
53
+ Accept-Encoding:
54
+ - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
55
+ Accept:
56
+ - "*/*"
57
+ User-Agent:
58
+ - OAuth gem v0.5.4
59
+ Authorization:
60
+ - OAuth oauth_callback="oob", oauth_consumer_key="johndeere-wgmADngYCRmfpEbVgSyc709wnyRux5J7PAv8SE7B",
61
+ oauth_nonce="D1Wa1SttrwCzWrFAAoEDUUyRmzVRkd6ka8rpAmWw8", oauth_signature="HciHAu%2Bojp4olApwEKk14WrhMt0%3D",
62
+ oauth_signature_method="HMAC-SHA1", oauth_timestamp="1578170527", oauth_version="1.0"
63
+ response:
64
+ status:
65
+ code: 200
66
+ message: OK
67
+ headers:
68
+ Date:
69
+ - Sat, 04 Jan 2020 20:42:07 GMT
70
+ Content-Type:
71
+ - text/plain;charset=UTF-8
72
+ X-Deere-Handling-Server:
73
+ - ip-10-214-45-13
74
+ Vary:
75
+ - Accept-Encoding
76
+ Transfer-Encoding:
77
+ - chunked
78
+ body:
79
+ encoding: ASCII-8BIT
80
+ string: oauth_token=27f8a03d-cda3-4b80-a42d-8f10065448e5&oauth_token_secret=mAsr2Tfy4YGUOrZG1%2BhIMefCIqom1yCQ90mXsQm7TOEjh%2B3HpRKgif8DrCdhNcKB31lpZqKbxX%2FKSD3xseT1BsFeFRlJPADHGd78B1mWtJI%3D&oauth_callback_confirmed=true
81
+ http_version:
82
+ recorded_at: Sat, 04 Jan 2020 20:42:08 GMT
83
+ recorded_with: VCR 5.0.0
@@ -1,10 +1,13 @@
1
- require 'minitest/autorun'
2
- require 'my_john_deere_api'
1
+ require 'support/helper'
3
2
 
4
3
  class MyJohnDeereApiTest < MiniTest::Test
5
- describe 'VERSION' do
6
- it 'conforms to the semantic version format' do
7
- assert_match /^\d+\.\d+\.\d+$/, MyJohnDeereApi::VERSION
4
+ describe 'loading dependencies' do
5
+ it 'loads VERSION' do
6
+ assert JD::VERSION
7
+ end
8
+
9
+ it 'loads Authorize' do
10
+ assert JD::Authorize
8
11
  end
9
12
  end
10
13
  end
metadata CHANGED
@@ -1,15 +1,85 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: my_john_deere_api
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jaime. Bellmyer
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-01-04 00:00:00.000000000 Z
12
- dependencies: []
11
+ date: 2020-01-06 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: vcr
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '5.0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '5.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: dotenv
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: 2.7.5
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 2.7.5
41
+ - !ruby/object:Gem::Dependency
42
+ name: webmock
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: 3.7.6
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: 3.7.6
55
+ - !ruby/object:Gem::Dependency
56
+ name: oauth
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: 0.5.4
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: 0.5.4
69
+ - !ruby/object:Gem::Dependency
70
+ name: json
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: 2.1.0
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: 2.1.0
13
83
  description: |
14
84
  == My John Deere API
15
85
 
@@ -26,7 +96,14 @@ files:
26
96
  - README.md
27
97
  - Rakefile
28
98
  - lib/my_john_deere_api.rb
99
+ - lib/my_john_deere_api/authorize.rb
29
100
  - lib/my_john_deere_api/version.rb
101
+ - test/lib/test_authorize.rb
102
+ - test/lib/test_version.rb
103
+ - test/support/helper.rb
104
+ - test/support/vcr/app_consumer.yml
105
+ - test/support/vcr/catalog.yml
106
+ - test/support/vcr/get_request_token.yml
30
107
  - test/test_my_john_deere_api.rb
31
108
  homepage: https://github.com/Intellifarm/my_john_deere_api
32
109
  licenses: