spot-gps 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 +4 -4
- data/.gitignore +1 -0
- data/.travis.yml +14 -0
- data/CHANGELOG.md +12 -0
- data/README.md +12 -9
- data/lib/spot-gps/api_response.rb +43 -0
- data/lib/spot-gps/api_service.rb +21 -13
- data/lib/spot-gps/{api.rb → client.rb} +4 -2
- data/lib/spot-gps/configuration.rb +0 -13
- data/lib/spot-gps/list_response.rb +20 -0
- data/lib/spot-gps/resources/message.rb +46 -0
- data/lib/spot-gps/services/messages.rb +14 -5
- data/lib/spot-gps/version.rb +1 -1
- data/lib/spot.rb +5 -3
- data/spec/api_response_spec.rb +43 -0
- data/spec/api_service_spec.rb +54 -0
- data/spec/api_spec.rb +28 -0
- data/spec/fixtures/latest.json +36 -0
- data/spec/fixtures/message.json +54 -0
- data/spec/fixtures/no_messages.json +11 -0
- data/spec/resources/message_spec.rb +52 -0
- data/spec/services/messages_spec.rb +172 -0
- data/spec/spec_helper.rb +18 -0
- data/spot-gps.gemspec +3 -7
- metadata +42 -70
- data/lib/spot-gps/null_logger.rb +0 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 13e4a0abb43ad3882974975b75c91103d6d0be42
|
4
|
+
data.tar.gz: 164e08de3895f9d0f2dc8b666e6ba769f34941be
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: be02344cbfec73c32678b5d16b1829179ee9be435acdf5aa5957e1616152298fd69260f14783089b1b967f6b397af0ef2c528273854fba5d5068e421f049c7ac
|
7
|
+
data.tar.gz: 5c0207c3806fb992c1e7ba0a046442539c906674c886d704d829b4dd2196fa8e82b9b89ea06310dfd378d37ba1065be92ea2f9101a9cc92cf860493903578a0c
|
data/.gitignore
CHANGED
data/.travis.yml
ADDED
data/CHANGELOG.md
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
## v0.0.2, 10 July 2016
|
2
|
+
|
3
|
+
- Wrap responses in SPOT::Resources::Message objects, making them easier to work
|
4
|
+
with (allows date/time parsing, etc.).
|
5
|
+
- Drop support for all Ruby versions prior to 2.3 (would be easy to
|
6
|
+
re-introduce, but I imagine anyone using this gem is building a new app).
|
7
|
+
- Rename Spot::API to Spot::Client
|
8
|
+
- Remove logger configuation, and move to Faraday
|
9
|
+
|
10
|
+
## v0.0.1, 10 July 2016
|
11
|
+
|
12
|
+
- Initial release
|
data/README.md
CHANGED
@@ -1,6 +1,9 @@
|
|
1
1
|
# SPOT GPS
|
2
2
|
|
3
|
-
|
3
|
+
An API client library for SPOT's [API](http://faq.findmespot.com/index.php?action=showEntry&data=69).
|
4
|
+
|
5
|
+
[](http://badge.fury.io/rb/spot-gps)
|
6
|
+
[](https://travis-ci.org/greysteil/spot-gps)
|
4
7
|
|
5
8
|
## Installation
|
6
9
|
|
@@ -16,7 +19,6 @@ There are 3 configuration options:
|
|
16
19
|
|
17
20
|
```ruby
|
18
21
|
SPOT.configure do |config|
|
19
|
-
config.logger = Logger.new(STDOUT)
|
20
22
|
config.open_timeout = 30
|
21
23
|
config.read_timeout = 80
|
22
24
|
end
|
@@ -24,10 +26,10 @@ end
|
|
24
26
|
|
25
27
|
## Usage
|
26
28
|
|
27
|
-
|
29
|
+
API calls are made using an instance of the `API` class:
|
28
30
|
|
29
31
|
```ruby
|
30
|
-
api = SPOT::
|
32
|
+
api = SPOT::Client.new(feed_id: 'FEED_GIID', feed_password: 'OPTIONAL_PASSWORD')
|
31
33
|
```
|
32
34
|
|
33
35
|
### Resources
|
@@ -39,8 +41,8 @@ Currently, the SPOT API only supports a single `messages` resource.
|
|
39
41
|
Messages are communications sent from a SPOT device.
|
40
42
|
|
41
43
|
```ruby
|
42
|
-
api.
|
43
|
-
api.
|
44
|
+
api.messages.all # => Returns a (paginated) list of all messages for a feed
|
45
|
+
api.messages.latest # => Returns the most recent message for a feed
|
44
46
|
```
|
45
47
|
|
46
48
|
### Pagination
|
@@ -50,7 +52,7 @@ the first page of 50 records are fetched. To fetch subsequent pages (each of 50
|
|
50
52
|
records), specify a `page`.
|
51
53
|
|
52
54
|
```ruby
|
53
|
-
api.
|
55
|
+
api.messages.all(page: 2)
|
54
56
|
```
|
55
57
|
|
56
58
|
### Filtering
|
@@ -58,12 +60,13 @@ api.message.all(page: 2)
|
|
58
60
|
The SPOT API supports filtering by date.
|
59
61
|
|
60
62
|
```ruby
|
61
|
-
api.
|
63
|
+
api.messages.all(start_at: '2014-06-01T00:00:00', end_at: '2015-06-01T00:00:00')
|
62
64
|
```
|
63
65
|
|
64
66
|
### Error Handling
|
65
67
|
|
66
|
-
TODO: Currently the gem will just raise
|
68
|
+
TODO: Currently the gem will just raise Faraday errors if anything goes wrong
|
69
|
+
with a request.
|
67
70
|
|
68
71
|
## Contributing
|
69
72
|
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module SPOT
|
2
|
+
class ApiResponse
|
3
|
+
extend Forwardable
|
4
|
+
|
5
|
+
def_delegator :@response, :headers
|
6
|
+
def_delegator :@response, :status
|
7
|
+
def_delegator :@response, :status_code
|
8
|
+
|
9
|
+
def initialize(response)
|
10
|
+
@response = response
|
11
|
+
end
|
12
|
+
|
13
|
+
# Return the body of the API response
|
14
|
+
def body
|
15
|
+
json? ? handle_json : handle_raw
|
16
|
+
end
|
17
|
+
|
18
|
+
# Returns true if the response is JSON
|
19
|
+
def json?
|
20
|
+
content_type = @response.headers[:content_type] || ''
|
21
|
+
content_type.include?('application/json')
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def raw_body
|
27
|
+
@response.body
|
28
|
+
end
|
29
|
+
|
30
|
+
def handle_json
|
31
|
+
@json_body ||= JSON.parse(@response.body)
|
32
|
+
end
|
33
|
+
|
34
|
+
def handle_raw
|
35
|
+
non_json_msg = "Received non-JSON response:\n\n" \
|
36
|
+
"status: #{@response.status}\n" \
|
37
|
+
"headers: #{@response.headers}\n" \
|
38
|
+
"body: #{@response.body}"
|
39
|
+
|
40
|
+
raise non_json_msg
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
data/lib/spot-gps/api_service.rb
CHANGED
@@ -6,32 +6,40 @@ module SPOT
|
|
6
6
|
def initialize(feed_id:, feed_password: nil)
|
7
7
|
@feed_id = feed_id
|
8
8
|
@feed_password = feed_password
|
9
|
+
|
10
|
+
connection_options = {
|
11
|
+
request: {
|
12
|
+
timeout: SPOT.read_timeout,
|
13
|
+
open_timeout: SPOT.open_timeout
|
14
|
+
}
|
15
|
+
}
|
16
|
+
|
17
|
+
@connection = Faraday.new(base_uri, connection_options)
|
9
18
|
end
|
10
19
|
|
11
20
|
# Make a GET request to the SPOT API
|
12
21
|
def get(path:, params: {})
|
22
|
+
params ||= {}
|
13
23
|
params = params.merge(feedPassword: feed_password) if feed_password
|
14
24
|
|
15
|
-
|
16
|
-
uri.query = URI.encode_www_form(params) if params.any?
|
17
|
-
|
18
|
-
request_options = {
|
19
|
-
url: uri.to_s,
|
20
|
-
method: :get,
|
21
|
-
headers: headers,
|
22
|
-
open_timeout: SPOT.open_timeout,
|
23
|
-
timeout: SPOT.read_timeout
|
24
|
-
}
|
25
|
-
|
26
|
-
response = RestClient::Request.execute(request_options)
|
25
|
+
response = make_request(:get, path, params)
|
27
26
|
|
28
|
-
|
27
|
+
SPOT::ApiResponse.new(response)
|
29
28
|
end
|
30
29
|
|
31
30
|
private
|
32
31
|
|
33
32
|
attr_reader :feed_id, :feed_password
|
34
33
|
|
34
|
+
def make_request(method, path, params = {})
|
35
|
+
@connection.send(method.to_sym) do |request|
|
36
|
+
request.url path
|
37
|
+
request.body = @request_body
|
38
|
+
request.params = params
|
39
|
+
request.headers = headers
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
35
43
|
def base_uri
|
36
44
|
URI.join(SPOT.endpoint, feed_id + '/')
|
37
45
|
end
|
@@ -1,8 +1,10 @@
|
|
1
1
|
module SPOT
|
2
|
-
class
|
2
|
+
class Client
|
3
3
|
attr_reader :feed_id, :feed_password
|
4
4
|
|
5
|
-
def initialize(feed_id
|
5
|
+
def initialize(feed_id: nil, feed_password: nil)
|
6
|
+
raise ArgumentError, "feed_id is required" unless feed_id
|
7
|
+
|
6
8
|
@api_service = ApiService.new(feed_id: feed_id, feed_password: feed_password)
|
7
9
|
end
|
8
10
|
|
@@ -13,19 +13,6 @@ module SPOT
|
|
13
13
|
def reset
|
14
14
|
self.open_timeout = 30
|
15
15
|
self.read_timeout = 80
|
16
|
-
RestClient.log = nil
|
17
|
-
end
|
18
|
-
|
19
|
-
def logger=(log)
|
20
|
-
if log.respond_to?(:<<)
|
21
|
-
RestClient.log = log
|
22
|
-
else
|
23
|
-
raise "#{log.class} doesn't seem to behave like a logger!"
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
def logger
|
28
|
-
RestClient.log ||= NullLogger.new
|
29
16
|
end
|
30
17
|
|
31
18
|
def endpoint
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module SPOT
|
2
|
+
class ListResponse
|
3
|
+
attr_reader :records
|
4
|
+
|
5
|
+
def initialize(response:, resource_class:, unenveloped_body:)
|
6
|
+
@response = response
|
7
|
+
@resource_class = resource_class
|
8
|
+
@unenveloped_body = unenveloped_body
|
9
|
+
|
10
|
+
# SPOT returns a Hash, rather than an array of hashes, if there is only
|
11
|
+
# a single record.
|
12
|
+
@unenveloped_body = [@unenveloped_body] if @unenveloped_body.is_a?(Hash)
|
13
|
+
@unenveloped_body = [] if @unenveloped_body.nil?
|
14
|
+
|
15
|
+
@records = @unenveloped_body.map do |item|
|
16
|
+
@resource_class.new(item)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module SPOT
|
2
|
+
module Resources
|
3
|
+
class Message
|
4
|
+
attr_reader :id
|
5
|
+
attr_reader :created_at
|
6
|
+
attr_reader :type
|
7
|
+
attr_reader :latitude
|
8
|
+
attr_reader :longitude
|
9
|
+
attr_reader :battery_state
|
10
|
+
attr_reader :hidden
|
11
|
+
attr_reader :show_custom_message
|
12
|
+
attr_reader :content
|
13
|
+
attr_reader :messenger_id
|
14
|
+
attr_reader :messenger_name
|
15
|
+
attr_reader :messenger_model
|
16
|
+
|
17
|
+
def initialize(object, response = nil)
|
18
|
+
@object = object
|
19
|
+
|
20
|
+
@id = object.fetch('id')
|
21
|
+
@created_at = Time.at(object.fetch('unixTime'))
|
22
|
+
@type = object.fetch('messageType')
|
23
|
+
@latitude = object.fetch('latitude')
|
24
|
+
@longitude = object.fetch('longitude')
|
25
|
+
@battery_state = object.fetch('batteryState')
|
26
|
+
|
27
|
+
@hidden = object['hidden'] == 1
|
28
|
+
@show_custom_message = object['showCustomMsg'] == "Y"
|
29
|
+
@content = object['messageContent']
|
30
|
+
@messenger_id = object['messengerId']
|
31
|
+
@messenger_name = object['messengerName']
|
32
|
+
@messenger_model = object['modelId']
|
33
|
+
|
34
|
+
@response = response
|
35
|
+
end
|
36
|
+
|
37
|
+
def response
|
38
|
+
@response
|
39
|
+
end
|
40
|
+
|
41
|
+
def to_h
|
42
|
+
@object
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -7,17 +7,27 @@ module SPOT
|
|
7
7
|
query_params[:startDate] = spot_formatted_time(start_at) if start_at
|
8
8
|
query_params[:endDate] = spot_formatted_time(end_at) if end_at
|
9
9
|
|
10
|
-
get(path: "message.json", params: query_params)
|
10
|
+
response = get(path: "message.json", params: query_params)
|
11
|
+
|
12
|
+
SPOT::ListResponse.new(
|
13
|
+
response: response,
|
14
|
+
resource_class: SPOT::Resources::Message,
|
15
|
+
unenveloped_body: unenvelope_body(response.body)
|
16
|
+
)
|
11
17
|
end
|
12
18
|
|
13
19
|
def latest
|
14
|
-
get(path: "latest.json")
|
20
|
+
response = get(path: "latest.json")
|
21
|
+
Resources::Message.new(unenvelope_body(response.body), response)
|
15
22
|
end
|
16
23
|
|
17
24
|
private
|
18
25
|
|
26
|
+
def unenvelope_body(body)
|
27
|
+
body.dig("response", "feedMessageResponse", "messages", "message")
|
28
|
+
end
|
29
|
+
|
19
30
|
def spot_formatted_time(time)
|
20
|
-
return nil unless time
|
21
31
|
time = Time.parse(time) if time.is_a?(String)
|
22
32
|
time = time.to_time if time.is_a?(Date) || time.is_a?(DateTime)
|
23
33
|
|
@@ -25,9 +35,8 @@ module SPOT
|
|
25
35
|
end
|
26
36
|
|
27
37
|
def start(page)
|
28
|
-
return nil unless page
|
29
38
|
raise ArgumentError, "page must be an integer" unless page.is_a?(Integer)
|
30
|
-
raise ArgumentError, "page must be
|
39
|
+
raise ArgumentError, "page must be positive" unless page > 0
|
31
40
|
|
32
41
|
# SPOT start param is zero-indexed
|
33
42
|
(page - 1) * 50
|
data/lib/spot-gps/version.rb
CHANGED
data/lib/spot.rb
CHANGED
@@ -1,11 +1,13 @@
|
|
1
1
|
require 'json'
|
2
|
-
require '
|
2
|
+
require 'faraday'
|
3
3
|
|
4
4
|
require 'spot-gps/version'
|
5
5
|
require 'spot-gps/configuration'
|
6
|
-
require 'spot-gps/
|
7
|
-
require 'spot-gps/
|
6
|
+
require 'spot-gps/client'
|
7
|
+
require 'spot-gps/api_response'
|
8
8
|
require 'spot-gps/api_service'
|
9
|
+
require 'spot-gps/list_response'
|
10
|
+
require 'spot-gps/resources/message'
|
9
11
|
require 'spot-gps/services/base'
|
10
12
|
require 'spot-gps/services/messages'
|
11
13
|
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe SPOT::ApiResponse do
|
4
|
+
subject(:response) { described_class.new(raw_response) }
|
5
|
+
|
6
|
+
let(:raw_response) do
|
7
|
+
stub_url = SPOT.endpoint + 'EXAMPLE_ID/message.json'
|
8
|
+
stub_request(:get, /#{Regexp.escape(stub_url)}.*/).to_return(
|
9
|
+
body: load_fixture('message.json'),
|
10
|
+
headers: { 'Content-Type' => 'application/json' }
|
11
|
+
)
|
12
|
+
|
13
|
+
SPOT::ApiService.new(feed_id: 'EXAMPLE_ID').
|
14
|
+
send(:make_request, :get, stub_url)
|
15
|
+
end
|
16
|
+
|
17
|
+
its(:status) { is_expected.to eq(200) }
|
18
|
+
|
19
|
+
describe "#body" do
|
20
|
+
context "when the response is JSON" do
|
21
|
+
it 'returns the body parsed into a hash' do
|
22
|
+
expect(response.body).to be_a(Hash)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
context "when the response isn't JSON" do
|
27
|
+
let(:raw_response) do
|
28
|
+
stub_url = SPOT.endpoint + 'EXAMPLE_ID/message.json'
|
29
|
+
stub_request(:get, /#{Regexp.escape(stub_url)}.*/).to_return(
|
30
|
+
body: 'Bad body',
|
31
|
+
headers: { 'Content-Type' => 'application/xml' }
|
32
|
+
)
|
33
|
+
|
34
|
+
SPOT::ApiService.new(feed_id: 'EXAMPLE_ID').
|
35
|
+
send(:make_request, :get, stub_url)
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'raises an error' do
|
39
|
+
expect { response.body }.to raise_error(RuntimeError)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe SPOT::ApiService do
|
4
|
+
subject(:service) do
|
5
|
+
described_class.new(feed_id: 'EXAMPLE_ID', feed_password: password)
|
6
|
+
end
|
7
|
+
let(:password) { nil }
|
8
|
+
|
9
|
+
before do
|
10
|
+
allow(SPOT).to receive(:endpoint).and_return('https://example.com/')
|
11
|
+
stub_request(:get, /https:\/\/example\.com/).
|
12
|
+
to_return(body: '{}', status: 200)
|
13
|
+
end
|
14
|
+
|
15
|
+
describe 'making a get request without any parameters' do
|
16
|
+
it 'is expected to make a GET request to the correct URL' do
|
17
|
+
service.get(path: 'messages.json')
|
18
|
+
expect(WebMock).
|
19
|
+
to have_requested(:get, 'https://example.com/EXAMPLE_ID/messages.json').
|
20
|
+
with(query: {})
|
21
|
+
end
|
22
|
+
|
23
|
+
context 'with a password' do
|
24
|
+
let(:password) { 'password' }
|
25
|
+
|
26
|
+
it 'is expected to include the password in the querystring' do
|
27
|
+
service.get(path: 'messages.json')
|
28
|
+
expect(WebMock).
|
29
|
+
to have_requested(:get, 'https://example.com/EXAMPLE_ID/messages.json').
|
30
|
+
with(query: { feedPassword: 'password' })
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
describe 'making a get request with parameters' do
|
36
|
+
it 'is expected to make a GET request to the correct URL' do
|
37
|
+
service.get(path: 'messages.json', params: { example: 'param' })
|
38
|
+
expect(WebMock).
|
39
|
+
to have_requested(:get, 'https://example.com/EXAMPLE_ID/messages.json').
|
40
|
+
with(query: { example: 'param' })
|
41
|
+
end
|
42
|
+
|
43
|
+
context 'with a password' do
|
44
|
+
let(:password) { 'password' }
|
45
|
+
|
46
|
+
it 'is expected to include the password in the querystring' do
|
47
|
+
service.get(path: 'messages.json', params: { example: 'param' })
|
48
|
+
expect(WebMock).
|
49
|
+
to have_requested(:get, 'https://example.com/EXAMPLE_ID/messages.json').
|
50
|
+
with(query: { feedPassword: 'password', example: 'param' })
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
data/spec/api_spec.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe SPOT::Client do
|
4
|
+
subject(:api) { described_class.new(options) }
|
5
|
+
let(:options) { { feed_id: feed_id, feed_password: password } }
|
6
|
+
let(:feed_id) { "EXAMPLE_ID" }
|
7
|
+
let(:password) { nil }
|
8
|
+
|
9
|
+
describe ".new" do
|
10
|
+
subject { -> { described_class.new(options) } }
|
11
|
+
|
12
|
+
context 'when initialised without a feed ID' do
|
13
|
+
let(:feed_id) { nil }
|
14
|
+
it { is_expected.to raise_error('feed_id is required') }
|
15
|
+
end
|
16
|
+
|
17
|
+
context 'when initialised without a password' do
|
18
|
+
let(:password) { nil }
|
19
|
+
it { is_expected.to_not raise_error }
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
describe "#messages" do
|
24
|
+
subject { api.messages }
|
25
|
+
|
26
|
+
it { is_expected.to be_an_instance_of(SPOT::Services::Messages) }
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
{
|
2
|
+
"response": {
|
3
|
+
"feedMessageResponse": {
|
4
|
+
"count": 1,
|
5
|
+
"feed": {
|
6
|
+
"id": "FEED_ID",
|
7
|
+
"name": "Testing",
|
8
|
+
"description": "Testing",
|
9
|
+
"status": "ACTIVE",
|
10
|
+
"usage": 0,
|
11
|
+
"daysRange": 7,
|
12
|
+
"detailedMessageShown": true
|
13
|
+
},
|
14
|
+
"totalCount": 1,
|
15
|
+
"activityCount": 0,
|
16
|
+
"messages": {
|
17
|
+
"message": {
|
18
|
+
"@clientUnixTime": "0",
|
19
|
+
"id": 585079373,
|
20
|
+
"messengerId": "0-1234567",
|
21
|
+
"messengerName": "My SPOT",
|
22
|
+
"unixTime": 1468164566,
|
23
|
+
"messageType": "OK",
|
24
|
+
"latitude": 61.54875,
|
25
|
+
"longitude": -3.0697,
|
26
|
+
"modelId": "SPOT3",
|
27
|
+
"showCustomMsg": "Y",
|
28
|
+
"dateTime": "2016-07-10T15:29:26+0000",
|
29
|
+
"batteryState": "GOOD",
|
30
|
+
"hidden": 0,
|
31
|
+
"messageContent": "This is the default SPOT Check In/OK message. Please update."
|
32
|
+
}
|
33
|
+
}
|
34
|
+
}
|
35
|
+
}
|
36
|
+
}
|
@@ -0,0 +1,54 @@
|
|
1
|
+
{
|
2
|
+
"response": {
|
3
|
+
"feedMessageResponse": {
|
4
|
+
"count": 2,
|
5
|
+
"feed": {
|
6
|
+
"id": "1HXUWlonx0AInTM7LAnBoAFEBQ9GWLJ5e",
|
7
|
+
"name": "Testing",
|
8
|
+
"description": "Testing",
|
9
|
+
"status": "ACTIVE",
|
10
|
+
"usage": 0,
|
11
|
+
"daysRange": 7,
|
12
|
+
"detailedMessageShown": true
|
13
|
+
},
|
14
|
+
"totalCount": 2,
|
15
|
+
"activityCount": 0,
|
16
|
+
"messages": {
|
17
|
+
"message": [
|
18
|
+
{
|
19
|
+
"@clientUnixTime": "0",
|
20
|
+
"id": 585079373,
|
21
|
+
"messengerId": "0-2855693",
|
22
|
+
"messengerName": "Grey's SPOT",
|
23
|
+
"unixTime": 1468164566,
|
24
|
+
"messageType": "OK",
|
25
|
+
"latitude": 51.54875,
|
26
|
+
"longitude": -0.0697,
|
27
|
+
"modelId": "SPOT3",
|
28
|
+
"showCustomMsg": "Y",
|
29
|
+
"dateTime": "2016-07-10T15:29:26+0000",
|
30
|
+
"batteryState": "GOOD",
|
31
|
+
"hidden": 0,
|
32
|
+
"messageContent": "This is the default SPOT Check In/OK message. Please update."
|
33
|
+
},
|
34
|
+
{
|
35
|
+
"@clientUnixTime": "0",
|
36
|
+
"id": 584982167,
|
37
|
+
"messengerId": "0-2855693",
|
38
|
+
"messengerName": "Grey's SPOT",
|
39
|
+
"unixTime": 1468149143,
|
40
|
+
"messageType": "OK",
|
41
|
+
"latitude": 51.5489,
|
42
|
+
"longitude": -0.06988,
|
43
|
+
"modelId": "SPOT3",
|
44
|
+
"showCustomMsg": "Y",
|
45
|
+
"dateTime": "2016-07-10T11:12:23+0000",
|
46
|
+
"batteryState": "GOOD",
|
47
|
+
"hidden": 0,
|
48
|
+
"messageContent": "This is the default SPOT Check In/OK message. Please update."
|
49
|
+
}
|
50
|
+
]
|
51
|
+
}
|
52
|
+
}
|
53
|
+
}
|
54
|
+
}
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe SPOT::Resources::Message do
|
4
|
+
describe 'initialising' do
|
5
|
+
let(:data) do
|
6
|
+
{
|
7
|
+
'@clientUnixTime' => '0',
|
8
|
+
'id' => 585079373,
|
9
|
+
'messengerId' => '0-1234567',
|
10
|
+
'messengerName' => 'My SPOT',
|
11
|
+
'unixTime' => 1468164566,
|
12
|
+
'messageType' => 'OK',
|
13
|
+
'latitude' => 61.54875,
|
14
|
+
'longitude' => -3.0697,
|
15
|
+
'modelId' => 'SPOT3',
|
16
|
+
'showCustomMsg' => 'Y',
|
17
|
+
'dateTime' => '2016-07-10T15:29:26+0000',
|
18
|
+
'batteryState' => 'GOOD',
|
19
|
+
'hidden' => 0,
|
20
|
+
'messageContent' => 'Example SPOT message.'
|
21
|
+
}
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'can be initialized from an unenveloped response' do
|
25
|
+
resource = described_class.new(data)
|
26
|
+
|
27
|
+
expect(resource.id).to eq(585079373)
|
28
|
+
expect(resource.created_at).to eq(Time.at(1468164566))
|
29
|
+
expect(resource.type).to eq('OK')
|
30
|
+
expect(resource.latitude).to eq(61.54875)
|
31
|
+
expect(resource.longitude).to eq(-3.0697)
|
32
|
+
expect(resource.battery_state).to eq('GOOD')
|
33
|
+
expect(resource.hidden).to eq(false)
|
34
|
+
expect(resource.show_custom_message).to eq(true)
|
35
|
+
expect(resource.content).to eq('Example SPOT message.')
|
36
|
+
expect(resource.messenger_id).to eq('0-1234567')
|
37
|
+
expect(resource.messenger_name).to eq('My SPOT')
|
38
|
+
expect(resource.messenger_model).to eq('SPOT3')
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'can handle new attributes without erroring' do
|
42
|
+
data['foo'] = 'bar'
|
43
|
+
expect { described_class.new(data) }.to_not raise_error
|
44
|
+
end
|
45
|
+
|
46
|
+
describe '#to_h' do
|
47
|
+
it 'returns a hash representing the resource' do
|
48
|
+
expect(described_class.new(data).to_h).to eq(data)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,172 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe SPOT::Services::Messages do
|
4
|
+
let(:messages) { SPOT::Client.new(feed_id: 'EXAMPLE_ID').messages }
|
5
|
+
|
6
|
+
describe "#all" do
|
7
|
+
subject(:all) { messages.all(args) }
|
8
|
+
|
9
|
+
before do
|
10
|
+
stub_url = SPOT.endpoint + 'EXAMPLE_ID/message.json'
|
11
|
+
stub_request(:get, /#{Regexp.escape(stub_url)}.*/).to_return(
|
12
|
+
body: load_fixture('message.json'),
|
13
|
+
headers: { 'Content-Type' => 'application/json' }
|
14
|
+
)
|
15
|
+
end
|
16
|
+
|
17
|
+
|
18
|
+
context "without any arguments" do
|
19
|
+
let(:args) { {} }
|
20
|
+
|
21
|
+
it "makes a request without any querystring params" do
|
22
|
+
expect_any_instance_of(SPOT::ApiService).
|
23
|
+
to receive(:get).
|
24
|
+
with(path: 'message.json', params: {}).
|
25
|
+
and_call_original
|
26
|
+
|
27
|
+
messages.all
|
28
|
+
end
|
29
|
+
|
30
|
+
it { is_expected.to be_a(SPOT::ListResponse) }
|
31
|
+
its("records.first") { is_expected.to be_a(SPOT::Resources::Message) }
|
32
|
+
|
33
|
+
context "when there are no displayable messages" do
|
34
|
+
before do
|
35
|
+
stub_url = SPOT.endpoint + 'EXAMPLE_ID/message.json'
|
36
|
+
stub_request(:get, /#{Regexp.escape(stub_url)}.*/).to_return(
|
37
|
+
body: load_fixture('no_messages.json'),
|
38
|
+
headers: { 'Content-Type' => 'application/json' }
|
39
|
+
)
|
40
|
+
end
|
41
|
+
|
42
|
+
it { is_expected.to be_a(SPOT::ListResponse) }
|
43
|
+
its(:records) { is_expected.to eq([]) }
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
context "with a page parameter" do
|
48
|
+
context "that is invalid" do
|
49
|
+
let(:args) { { page: "invalid" } }
|
50
|
+
specify { expect { all }.to raise_error(ArgumentError) }
|
51
|
+
end
|
52
|
+
|
53
|
+
context "that is zero" do
|
54
|
+
let(:args) { { page: 0 } }
|
55
|
+
specify { expect { all }.to raise_error(ArgumentError) }
|
56
|
+
end
|
57
|
+
|
58
|
+
context "that is greater than zero" do
|
59
|
+
let(:args) { { page: 1 } }
|
60
|
+
|
61
|
+
it "makes a request with a start param" do
|
62
|
+
expect_any_instance_of(SPOT::ApiService).
|
63
|
+
to receive(:get).
|
64
|
+
with(path: 'message.json', params: { start: 0 }).
|
65
|
+
and_call_original
|
66
|
+
|
67
|
+
all
|
68
|
+
end
|
69
|
+
|
70
|
+
context "and greater than 1" do
|
71
|
+
let(:args) { { page: 2 } }
|
72
|
+
|
73
|
+
it "increases the start param by multiples of 50" do
|
74
|
+
expect_any_instance_of(SPOT::ApiService).
|
75
|
+
to receive(:get).
|
76
|
+
with(path: 'message.json', params: { start: 50 }).
|
77
|
+
and_call_original
|
78
|
+
|
79
|
+
all
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
context "with a start_at or end_at parameter" do
|
86
|
+
context "that is invalid" do
|
87
|
+
let(:args) { { start_at: "invalid" } }
|
88
|
+
specify { expect { all }.to raise_error(ArgumentError) }
|
89
|
+
end
|
90
|
+
|
91
|
+
context "that is a valid string" do
|
92
|
+
let(:args) { { start_at: "2016-01-01", end_at: "2016-02-01" } }
|
93
|
+
|
94
|
+
it "makes a request with a startDate param" do
|
95
|
+
expect_any_instance_of(SPOT::ApiService).
|
96
|
+
to receive(:get).
|
97
|
+
with(path: 'message.json',
|
98
|
+
params: { startDate: '2016-01-01T00:00:00-0000',
|
99
|
+
endDate: '2016-02-01T00:00:00-0000' }).
|
100
|
+
and_call_original
|
101
|
+
|
102
|
+
all
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
context "that is a Date" do
|
107
|
+
let(:args) { { start_at: Date.parse('2016-01-01') } }
|
108
|
+
|
109
|
+
it "makes a request with a startDate param" do
|
110
|
+
expect_any_instance_of(SPOT::ApiService).
|
111
|
+
to receive(:get).
|
112
|
+
with(path: 'message.json',
|
113
|
+
params: { startDate: '2016-01-01T00:00:00-0000' }).
|
114
|
+
and_call_original
|
115
|
+
|
116
|
+
all
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
context "that is a DateTime" do
|
121
|
+
let(:args) { { start_at: DateTime.parse('2016-01-01') } }
|
122
|
+
|
123
|
+
it "makes a request with a startDate param" do
|
124
|
+
expect_any_instance_of(SPOT::ApiService).
|
125
|
+
to receive(:get).
|
126
|
+
with(path: 'message.json',
|
127
|
+
params: { startDate: '2016-01-01T00:00:00-0000' }).
|
128
|
+
and_call_original
|
129
|
+
|
130
|
+
all
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
context "that is a Time" do
|
135
|
+
let(:args) { { start_at: Time.parse('2016-01-01') } }
|
136
|
+
|
137
|
+
it "makes a request with a startDate param" do
|
138
|
+
expect_any_instance_of(SPOT::ApiService).
|
139
|
+
to receive(:get).
|
140
|
+
with(path: 'message.json',
|
141
|
+
params: { startDate: '2016-01-01T00:00:00-0000' }).
|
142
|
+
and_call_original
|
143
|
+
|
144
|
+
all
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
describe "#latest" do
|
151
|
+
before do
|
152
|
+
stub_url = SPOT.endpoint + 'EXAMPLE_ID/latest.json'
|
153
|
+
stub_request(:get, stub_url).to_return(
|
154
|
+
body: load_fixture('latest.json'),
|
155
|
+
headers: { 'Content-Type' => 'application/json' }
|
156
|
+
)
|
157
|
+
end
|
158
|
+
|
159
|
+
it "makes a request for the `latest.json` path, without params" do
|
160
|
+
expect_any_instance_of(SPOT::ApiService).
|
161
|
+
to receive(:get).
|
162
|
+
with(path: 'latest.json').
|
163
|
+
and_call_original
|
164
|
+
|
165
|
+
messages.latest
|
166
|
+
end
|
167
|
+
|
168
|
+
it 'wraps the response in a resource' do
|
169
|
+
expect(messages.latest).to be_a(SPOT::Resources::Message)
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'spot'
|
2
|
+
require 'rspec/its'
|
3
|
+
require 'webmock/rspec'
|
4
|
+
|
5
|
+
WebMock.disable_net_connect!
|
6
|
+
|
7
|
+
RSpec.configure do |config|
|
8
|
+
config.mock_with(:rspec) { |mocks| mocks.verify_partial_doubles = true }
|
9
|
+
config.raise_errors_for_deprecations!
|
10
|
+
end
|
11
|
+
|
12
|
+
def fixture_path(filename)
|
13
|
+
File.join(File.dirname(__FILE__), "fixtures", filename)
|
14
|
+
end
|
15
|
+
|
16
|
+
def load_fixture(filename)
|
17
|
+
File.read(fixture_path(filename))
|
18
|
+
end
|
data/spot-gps.gemspec
CHANGED
@@ -18,13 +18,9 @@ Gem::Specification.new do |spec|
|
|
18
18
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
19
|
spec.require_paths = ['lib']
|
20
20
|
|
21
|
-
spec.add_development_dependency 'bundler', '~> 1.7'
|
22
|
-
spec.add_development_dependency 'rake', '~> 10.0'
|
23
21
|
spec.add_development_dependency 'webmock', '~> 1.22'
|
24
|
-
spec.add_development_dependency '
|
25
|
-
spec.add_development_dependency 'rspec'
|
26
|
-
spec.add_development_dependency 'rspec-its', '~> 1.2'
|
27
|
-
spec.add_development_dependency 'sinatra', '~> 1.4'
|
22
|
+
spec.add_development_dependency 'rspec', '~> 3.5'
|
23
|
+
spec.add_development_dependency 'rspec-its'
|
28
24
|
|
29
|
-
spec.add_dependency '
|
25
|
+
spec.add_dependency 'faraday', ['>= 0.8.9', '< 0.10']
|
30
26
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: spot-gps
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Grey Baker
|
@@ -10,34 +10,6 @@ bindir: bin
|
|
10
10
|
cert_chain: []
|
11
11
|
date: 2016-07-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
-
- !ruby/object:Gem::Dependency
|
14
|
-
name: bundler
|
15
|
-
requirement: !ruby/object:Gem::Requirement
|
16
|
-
requirements:
|
17
|
-
- - "~>"
|
18
|
-
- !ruby/object:Gem::Version
|
19
|
-
version: '1.7'
|
20
|
-
type: :development
|
21
|
-
prerelease: false
|
22
|
-
version_requirements: !ruby/object:Gem::Requirement
|
23
|
-
requirements:
|
24
|
-
- - "~>"
|
25
|
-
- !ruby/object:Gem::Version
|
26
|
-
version: '1.7'
|
27
|
-
- !ruby/object:Gem::Dependency
|
28
|
-
name: rake
|
29
|
-
requirement: !ruby/object:Gem::Requirement
|
30
|
-
requirements:
|
31
|
-
- - "~>"
|
32
|
-
- !ruby/object:Gem::Version
|
33
|
-
version: '10.0'
|
34
|
-
type: :development
|
35
|
-
prerelease: false
|
36
|
-
version_requirements: !ruby/object:Gem::Requirement
|
37
|
-
requirements:
|
38
|
-
- - "~>"
|
39
|
-
- !ruby/object:Gem::Version
|
40
|
-
version: '10.0'
|
41
13
|
- !ruby/object:Gem::Dependency
|
42
14
|
name: webmock
|
43
15
|
requirement: !ruby/object:Gem::Requirement
|
@@ -52,76 +24,54 @@ dependencies:
|
|
52
24
|
- - "~>"
|
53
25
|
- !ruby/object:Gem::Version
|
54
26
|
version: '1.22'
|
55
|
-
- !ruby/object:Gem::Dependency
|
56
|
-
name: rubocop
|
57
|
-
requirement: !ruby/object:Gem::Requirement
|
58
|
-
requirements:
|
59
|
-
- - "~>"
|
60
|
-
- !ruby/object:Gem::Version
|
61
|
-
version: 0.37.0
|
62
|
-
type: :development
|
63
|
-
prerelease: false
|
64
|
-
version_requirements: !ruby/object:Gem::Requirement
|
65
|
-
requirements:
|
66
|
-
- - "~>"
|
67
|
-
- !ruby/object:Gem::Version
|
68
|
-
version: 0.37.0
|
69
27
|
- !ruby/object:Gem::Dependency
|
70
28
|
name: rspec
|
71
29
|
requirement: !ruby/object:Gem::Requirement
|
72
30
|
requirements:
|
73
31
|
- - "~>"
|
74
32
|
- !ruby/object:Gem::Version
|
75
|
-
version: '3.
|
33
|
+
version: '3.5'
|
76
34
|
type: :development
|
77
35
|
prerelease: false
|
78
36
|
version_requirements: !ruby/object:Gem::Requirement
|
79
37
|
requirements:
|
80
38
|
- - "~>"
|
81
39
|
- !ruby/object:Gem::Version
|
82
|
-
version: '3.
|
40
|
+
version: '3.5'
|
83
41
|
- !ruby/object:Gem::Dependency
|
84
42
|
name: rspec-its
|
85
43
|
requirement: !ruby/object:Gem::Requirement
|
86
44
|
requirements:
|
87
|
-
- - "
|
45
|
+
- - ">="
|
88
46
|
- !ruby/object:Gem::Version
|
89
|
-
version: '
|
47
|
+
version: '0'
|
90
48
|
type: :development
|
91
49
|
prerelease: false
|
92
50
|
version_requirements: !ruby/object:Gem::Requirement
|
93
51
|
requirements:
|
94
|
-
- - "
|
52
|
+
- - ">="
|
95
53
|
- !ruby/object:Gem::Version
|
96
|
-
version: '
|
54
|
+
version: '0'
|
97
55
|
- !ruby/object:Gem::Dependency
|
98
|
-
name:
|
56
|
+
name: faraday
|
99
57
|
requirement: !ruby/object:Gem::Requirement
|
100
58
|
requirements:
|
101
|
-
- - "
|
102
|
-
- !ruby/object:Gem::Version
|
103
|
-
version: '1.4'
|
104
|
-
type: :development
|
105
|
-
prerelease: false
|
106
|
-
version_requirements: !ruby/object:Gem::Requirement
|
107
|
-
requirements:
|
108
|
-
- - "~>"
|
59
|
+
- - ">="
|
109
60
|
- !ruby/object:Gem::Version
|
110
|
-
version:
|
111
|
-
-
|
112
|
-
name: rest-client
|
113
|
-
requirement: !ruby/object:Gem::Requirement
|
114
|
-
requirements:
|
115
|
-
- - "~>"
|
61
|
+
version: 0.8.9
|
62
|
+
- - "<"
|
116
63
|
- !ruby/object:Gem::Version
|
117
|
-
version:
|
64
|
+
version: '0.10'
|
118
65
|
type: :runtime
|
119
66
|
prerelease: false
|
120
67
|
version_requirements: !ruby/object:Gem::Requirement
|
121
68
|
requirements:
|
122
|
-
- - "
|
69
|
+
- - ">="
|
70
|
+
- !ruby/object:Gem::Version
|
71
|
+
version: 0.8.9
|
72
|
+
- - "<"
|
123
73
|
- !ruby/object:Gem::Version
|
124
|
-
version:
|
74
|
+
version: '0.10'
|
125
75
|
description: A wrapper for the SPOT API
|
126
76
|
email:
|
127
77
|
- greysteil@gmail.com
|
@@ -130,16 +80,29 @@ extensions: []
|
|
130
80
|
extra_rdoc_files: []
|
131
81
|
files:
|
132
82
|
- ".gitignore"
|
83
|
+
- ".travis.yml"
|
84
|
+
- CHANGELOG.md
|
133
85
|
- Gemfile
|
134
86
|
- README.md
|
135
|
-
- lib/spot-gps/
|
87
|
+
- lib/spot-gps/api_response.rb
|
136
88
|
- lib/spot-gps/api_service.rb
|
89
|
+
- lib/spot-gps/client.rb
|
137
90
|
- lib/spot-gps/configuration.rb
|
138
|
-
- lib/spot-gps/
|
91
|
+
- lib/spot-gps/list_response.rb
|
92
|
+
- lib/spot-gps/resources/message.rb
|
139
93
|
- lib/spot-gps/services/base.rb
|
140
94
|
- lib/spot-gps/services/messages.rb
|
141
95
|
- lib/spot-gps/version.rb
|
142
96
|
- lib/spot.rb
|
97
|
+
- spec/api_response_spec.rb
|
98
|
+
- spec/api_service_spec.rb
|
99
|
+
- spec/api_spec.rb
|
100
|
+
- spec/fixtures/latest.json
|
101
|
+
- spec/fixtures/message.json
|
102
|
+
- spec/fixtures/no_messages.json
|
103
|
+
- spec/resources/message_spec.rb
|
104
|
+
- spec/services/messages_spec.rb
|
105
|
+
- spec/spec_helper.rb
|
143
106
|
- spot-gps.gemspec
|
144
107
|
homepage: http://github.com/greysteil/spot-gps
|
145
108
|
licenses:
|
@@ -165,4 +128,13 @@ rubygems_version: 2.5.1
|
|
165
128
|
signing_key:
|
166
129
|
specification_version: 4
|
167
130
|
summary: A wrapper for the SPOT API
|
168
|
-
test_files:
|
131
|
+
test_files:
|
132
|
+
- spec/api_response_spec.rb
|
133
|
+
- spec/api_service_spec.rb
|
134
|
+
- spec/api_spec.rb
|
135
|
+
- spec/fixtures/latest.json
|
136
|
+
- spec/fixtures/message.json
|
137
|
+
- spec/fixtures/no_messages.json
|
138
|
+
- spec/resources/message_spec.rb
|
139
|
+
- spec/services/messages_spec.rb
|
140
|
+
- spec/spec_helper.rb
|