spot-gps 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
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