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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 4cefc691cf3adc7c13929ac4ad0aad2e03657b7e
4
- data.tar.gz: 930728e3875f407014521e9f60bdbf3c9305076f
3
+ metadata.gz: 13e4a0abb43ad3882974975b75c91103d6d0be42
4
+ data.tar.gz: 164e08de3895f9d0f2dc8b666e6ba769f34941be
5
5
  SHA512:
6
- metadata.gz: ee497615830b2294640d2752a7d8ca11100ba4f4b0e3fe1eb4d8002610343807fefb3841b3ac799253e28a250aeb5918aa8967149133eed8580714be79336172
7
- data.tar.gz: 8f01ed30a2fa1e5c73cd911d36ec558266043396b9f0f21ab1021de1364f444af0b41665a53e0997564b480e16c96ba50a978b9d54240e11bb75c6d6b84314a1
6
+ metadata.gz: be02344cbfec73c32678b5d16b1829179ee9be435acdf5aa5957e1616152298fd69260f14783089b1b967f6b397af0ef2c528273854fba5d5068e421f049c7ac
7
+ data.tar.gz: 5c0207c3806fb992c1e7ba0a046442539c906674c886d704d829b4dd2196fa8e82b9b89ea06310dfd378d37ba1065be92ea2f9101a9cc92cf860493903578a0c
data/.gitignore CHANGED
@@ -1,2 +1,3 @@
1
1
  .bundle
2
2
  Gemfile.lock
3
+ *.gem
data/.travis.yml ADDED
@@ -0,0 +1,14 @@
1
+ language: ruby
2
+
3
+ matrix:
4
+ allow_failures:
5
+ - rvm: jruby
6
+ - rvm: rbx-2
7
+
8
+ rvm:
9
+ - '2.3.1'
10
+ - jruby
11
+ - rbx-2
12
+
13
+ script:
14
+ - bundle exec rspec spec
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
- A thin wrapper for SPOT's [API](http://www.findmespot.com/en/index.php?cid=1700).
3
+ An API client library for SPOT's [API](http://faq.findmespot.com/index.php?action=showEntry&data=69).
4
+
5
+ [![Gem Version](https://badge.fury.io/rb/spot-gps.svg)](http://badge.fury.io/rb/spot-gps)
6
+ [![Build Status](https://travis-ci.org/greysteil/spot-gps.svg?branch=master)](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
- You can make API calls by using an instance of the `API` class:
29
+ API calls are made using an instance of the `API` class:
28
30
 
29
31
  ```ruby
30
- api = SPOT::API.new(feed_id: 'FEED_GIID', feed_password: 'OPTIONAL_PASSWORD')
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.applicant.all # => Returns a (paginated) list of all messages for a feed
43
- api.applicant.latest # => Returns the most recent message for a feed
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.message.all(page: 2)
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.message.all(start_at: '2014-06-01T00:00:00', end_at: '2015-06-01T00:00:00')
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 RestClient errors.
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
@@ -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
- uri = URI.join(base_uri, path)
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
- JSON.parse(response.body.to_s)
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 API
2
+ class Client
3
3
  attr_reader :feed_id, :feed_password
4
4
 
5
- def initialize(feed_id:, feed_password: nil)
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 non-negative" if page < 0
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
@@ -1,3 +1,3 @@
1
1
  module SPOT
2
- VERSION = '0.0.1'.freeze
2
+ VERSION = '0.0.2'.freeze
3
3
  end
data/lib/spot.rb CHANGED
@@ -1,11 +1,13 @@
1
1
  require 'json'
2
- require 'rest-client'
2
+ require 'faraday'
3
3
 
4
4
  require 'spot-gps/version'
5
5
  require 'spot-gps/configuration'
6
- require 'spot-gps/null_logger'
7
- require 'spot-gps/api'
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,11 @@
1
+ {
2
+ "response": {
3
+ "errors": {
4
+ "error": {
5
+ "code": "E-0195",
6
+ "text": "No Messages to display",
7
+ "description": "No displayable messages found found for feed: 1HXUWlonx0AInTM7LAnBoAFEBQ9GWLJ5e"
8
+ }
9
+ }
10
+ }
11
+ }
@@ -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
@@ -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 'rubocop', '~> 0.37.0'
25
- spec.add_development_dependency 'rspec', '~> 3.1'
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 'rest-client', '~> 1.8.0'
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.1
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.1'
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.1'
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: '1.2'
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: '1.2'
54
+ version: '0'
97
55
  - !ruby/object:Gem::Dependency
98
- name: sinatra
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: '1.4'
111
- - !ruby/object:Gem::Dependency
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: 1.8.0
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: 1.8.0
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/api.rb
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/null_logger.rb
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
@@ -1,6 +0,0 @@
1
- module SPOT
2
- class NullLogger
3
- def <<(*args)
4
- end
5
- end
6
- end