marvelite 0.0.9 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 16d19808169b8963aa3ebea4bd9cfdb47c752c5b
4
- data.tar.gz: 5d16ff33769cd4f3febb31ef18d27b424acc2b2e
3
+ metadata.gz: 1a25275235911ff6c298db40d9a53cbdba48da58
4
+ data.tar.gz: 704f6f949a889ed333d996af13223fcda8a96b06
5
5
  SHA512:
6
- metadata.gz: 4d53422e7d9b2a5c9587fe6c47c47bab17588d7b198817dc6ac63673b9d121e2485ca28042166f1d094e6d1c9c242a65e4144870340c7c17ed67c0f879c65505
7
- data.tar.gz: 3f1d488133bf1dc17d83a78afa8d94498809df61e07c370980d4668308a90e3527a85e66730f97d6a9ff1cafbf2f2b7451f5cd1a5d6a5d778768f52925949a37
6
+ metadata.gz: 9057f0a8b511dced1d1865cca70270c80c86ac8befdad542e2592b8c5b37b0be845e318b7c43a5fbcf61f3a3e85a15e72baadff99905e991ec920ab470bc78f5
7
+ data.tar.gz: 265c411137e5af68cd206be287ba5c50bbf2874dec5a4703a2a6463f0259bc64021be5ea8e93e0bd8ba4c9771a9b308b1464b74ad1094f3ec68aff456cd137c9
@@ -1,5 +1,10 @@
1
1
  ## Changelog
2
2
 
3
+ ### 0.1.0
4
+ * Adds Travis CI support.
5
+ * Support for Etags and Gzip compression. Infinite thanks to [Jon Allured](https://github.com/jonallured) for this contribution.
6
+ * Refactorings and cleanups, courtesy of [Jon Allured](https://github.com/jonallured)
7
+
3
8
  ### 0.0.9
4
9
  * Adds the following endpoints (contributed by: [Patrick Hereford (@phereford)](https://github.com/phereford)):
5
10
  * retrieve creators by connecting to the API's `/creators` endpoint
data/README.md CHANGED
@@ -1,4 +1,7 @@
1
- # Marvelite
1
+ # Marvelite [![Build Status][travis-badge]][travis]
2
+
3
+ [travis-badge]: https://travis-ci.org/antillas21/marvelite.png
4
+ [travis]: http://travis-ci.org/antillas21/marvelite
2
5
 
3
6
  Simple Ruby wrapper to communicate with the Marvel Comics API.
4
7
 
@@ -21,18 +24,16 @@ Or install it yourself as:
21
24
  * [Usage](#usage)
22
25
  * [Responses](#responses)
23
26
 
24
-
25
27
  ## Usage
26
28
 
27
- Please register first in the [Marvel Comics Developer Portal](http://developer.marvel.com/) to get your API credentials (a public key and a private key, you'll need them both to configure and instantiate a client).
29
+ Please register first in the [Marvel Comics Developer
30
+ Portal](http://developer.marvel.com/) to get your API credentials (a public key
31
+ and a private key, you'll need them both to configure and instantiate a client).
28
32
 
29
33
  ### Instantiate a client
30
34
 
31
35
  ```ruby
32
- client = Marvelite::API::Client.new(
33
- :public_key => 'abcd1234',
34
- :private_key => '5678efgh'
35
- )
36
+ client = Marvelite::API::Client.new( :public_key => 'abcd1234', :private_key => '5678efgh')
36
37
 
37
38
  # fetch a list of characters
38
39
  client.characters
@@ -104,12 +105,16 @@ client.story_comics(2210)
104
105
  client.story_comics(2210, :format => 'graphic novel', :orderBy => 'title', :limit => 10)
105
106
  ```
106
107
 
107
- See the list of [available methods](https://github.com/antillas21/marvelite/wiki/Documentation) in the wiki.
108
-
108
+ See the list of [available
109
+ methods](https://github.com/antillas21/marvelite/wiki/Documentation) in the
110
+ wiki.
109
111
 
110
112
  ## Responses
111
113
 
112
- All requests to the API, return a `Marvelite::API::Response` object if successful or a `Marvelite::API::ErrorResponse` if API response returns an error. These objects are nothing more than the raw API response enhanced with Hashie methods.
114
+ Most requests to the API, return a `Marvelite::API::Response` object if
115
+ successful or a `Marvelite::API::ErrorResponse` if API response returns an
116
+ error. These objects are nothing more than the raw API response enhanced with
117
+ Hashie methods.
113
118
 
114
119
  This way you gain several adavantages to manipulate the response, like:
115
120
 
@@ -123,11 +128,22 @@ response.data
123
128
  response.data[:results]
124
129
  ```
125
130
 
131
+ ## Etags and Gzip support
132
+
133
+ Support for Etags is built into every endpoint:
126
134
 
135
+ ```ruby
136
+ first_response = client.series
137
+ first_response.status # => 200
127
138
 
128
- ## Todo
139
+ second_response = client.series headers: { 'If-None-Match' => first_response.etag }
140
+ second_response.status # => 304
141
+ ```
129
142
 
130
- * Add more endpoints
143
+ ```ruby
144
+ gzipped_response = client.series(:headers => {'Accept-Encoding' => 'gzip'})
145
+ #=> Faster response hash from Marvel's API series endpoint. :)
146
+ ```
131
147
 
132
148
 
133
149
  ## Contributing
@@ -1,4 +1,3 @@
1
- require 'active_model'
2
1
  require 'digest/md5'
3
2
  require 'httparty'
4
3
  require 'hashie'
@@ -1,23 +1,29 @@
1
1
  module Marvelite
2
2
  module API
3
3
  class Client
4
- include ActiveModel::Model
5
4
  include HTTParty
6
5
  base_uri 'http://gateway.marvel.com'
7
6
 
8
7
  attr_accessor :public_key, :private_key, :router, :api_version
9
8
 
10
- validates_presence_of :public_key
11
- validates_presence_of :private_key
9
+ class InvalidClientError < StandardError; end
12
10
 
13
11
  def initialize(attrs)
14
- super
12
+ check_for_errors(attrs)
13
+ @public_key = attrs.fetch(:public_key)
14
+ @private_key = attrs.fetch(:private_key)
15
15
  @api_version = attrs.fetch(:api_version) { 'v1' }
16
16
  @router = attrs.fetch(:router) { Marvelite.router(:api_version => @api_version) }
17
17
  build_methods
18
18
  end
19
19
 
20
20
  private
21
+ def check_for_errors(attrs)
22
+ [:public_key, :private_key].each do |key|
23
+ raise InvalidClientError, "You need to provide a :#{key} param." unless attrs[key]
24
+ end
25
+ end
26
+
21
27
  def params(additional_params = {})
22
28
  base_hash = { :apikey => public_key, :ts => ts, :hash => request_hash }
23
29
  additional_params.merge(base_hash)
@@ -34,9 +40,11 @@ module Marvelite
34
40
  end
35
41
 
36
42
  def build_response_object(response)
37
- case response["code"]
43
+ case response.code
38
44
  when 200
39
45
  Response.new(response)
46
+ when 304
47
+ NotModifiedResponse.new(response)
40
48
  else
41
49
  ErrorResponse.new(response)
42
50
  end
@@ -49,6 +57,11 @@ module Marvelite
49
57
  response
50
58
  end
51
59
 
60
+ def pull_headers(options)
61
+ headers = options.delete(:headers) || {}
62
+ [options, headers]
63
+ end
64
+
52
65
  def process_arguments(*args)
53
66
  temp_id, temp_options = *args
54
67
  if temp_id && temp_id.is_a?(Hash)
@@ -60,18 +73,24 @@ module Marvelite
60
73
  else
61
74
  options = {}
62
75
  end
63
- { id: id, options: options}
76
+ params, headers = pull_headers(options)
77
+ [{ id: id, options: params}, headers]
64
78
  end
65
79
 
66
- def fetch_response(route, params_hash = {})
80
+ def fetch_response(route, params_hash = {}, headers = {})
67
81
  id = params_hash[:id]
68
82
  options = params_hash[:options]
83
+ path = find_path(route, id)
84
+
85
+ self.class.get(path, query: params(options), headers: headers)
86
+ end
69
87
 
88
+ def find_path(route, id)
70
89
  if id.nil?
71
- self.class.get(router.send("#{route}_path".to_sym), :query => params(options))
90
+ router.send("#{route}_path".to_sym)
72
91
  else
73
92
  id = fetch_resource_id(route, id) if id.is_a?(String)
74
- self.class.get(router.send("#{route}_path".to_sym, {:id => id}), :query => params(options))
93
+ router.send("#{route}_path".to_sym, {:id => id})
75
94
  end
76
95
  end
77
96
 
@@ -86,8 +105,8 @@ module Marvelite
86
105
  @router.routes.each do |_, hash|
87
106
  name = hash[:name]
88
107
  self.class.send(:define_method, name) do |*args|
89
- params = process_arguments(*args)
90
- response = fetch_response(name, params)
108
+ params, headers = process_arguments(*args)
109
+ response = fetch_response(name, params, headers)
91
110
  build_response_object(response)
92
111
  end
93
112
  end
@@ -95,4 +114,4 @@ module Marvelite
95
114
 
96
115
  end
97
116
  end
98
- end
117
+ end
@@ -7,11 +7,17 @@ module Marvelite
7
7
  include Hashie::Extensions::IndifferentAccess
8
8
  end
9
9
 
10
- class ErrorResponse < Hash
11
- include Hashie::Extensions::MergeInitializer
12
- include Hashie::Extensions::KeyConversion
13
- include Hashie::Extensions::MethodAccess
14
- include Hashie::Extensions::IndifferentAccess
10
+ class ErrorResponse < Response; end
11
+
12
+ class NotModifiedResponse < Response
13
+ def initialize(response)
14
+ super({
15
+ status: 'Not Modified',
16
+ code: 304,
17
+ data: {},
18
+ etag: response.headers['etag']
19
+ })
20
+ end
15
21
  end
16
22
  end
17
- end
23
+ end
@@ -1,3 +1,3 @@
1
1
  module Marvelite
2
- VERSION = "0.0.9"
2
+ VERSION = '0.1.0'
3
3
  end
@@ -3,13 +3,15 @@ require 'spec_helper'
3
3
  describe Marvelite::API::Client do
4
4
  describe 'initialization' do
5
5
  it 'requires a :public_key to be set' do
6
- client = Marvelite::API::Client.new(:private_key => '12345')
7
- expect(client).to_not be_valid
6
+ expect{ Marvelite::API::Client.new(:private_key => '12345') }.to raise_error(
7
+ Marvelite::API::Client::InvalidClientError, "You need to provide a :public_key param."
8
+ )
8
9
  end
9
10
 
10
11
  it 'requires a :private_key to be set' do
11
- client = Marvelite::API::Client.new(:public_key => '1234')
12
- expect(client).to_not be_valid
12
+ expect{ Marvelite::API::Client.new(:public_key => '1234') }.to raise_error(
13
+ Marvelite::API::Client::InvalidClientError, "You need to provide a :private_key param."
14
+ )
13
15
  end
14
16
 
15
17
  context 'valid' do
@@ -17,7 +19,9 @@ describe Marvelite::API::Client do
17
19
 
18
20
  describe '#api_version' do
19
21
  it 'receives an :api_version optional param' do
20
- client = Marvelite::API::Client.new(:public_key => '1234', :private_key => 'abcd', :api_version => 'v1')
22
+ client = Marvelite::API::Client.new(
23
+ :public_key => '1234', :private_key => 'abcd', :api_version => 'v1'
24
+ )
21
25
  expect(client.api_version).to eq('v1')
22
26
  end
23
27
 
@@ -27,7 +31,7 @@ describe Marvelite::API::Client do
27
31
  end
28
32
 
29
33
  it 'is an instance of Marvelite::Client' do
30
- expect(client).to be_valid
34
+ expect{ client }.to_not raise_error
31
35
  expect(client).to be_a(Marvelite::API::Client)
32
36
  end
33
37
 
@@ -38,6 +42,26 @@ describe Marvelite::API::Client do
38
42
  end
39
43
  end
40
44
 
45
+ describe 'etags' do
46
+ let(:client) { marvelite_test_client }
47
+ let(:etag) { '64aceb407b735957130fce343bf4933ed21a7cfc' }
48
+
49
+ before do
50
+ stub_304('series?apikey=123456&ts=1&hash=d4f1bab013916a533ef31e3ad5fb0887', etag)
51
+ end
52
+
53
+ it 'returns a NotModifiedResponse' do
54
+ headers = { 'If-None-Match' => "\"#{etag}\"" }
55
+ response = client.series(headers: headers)
56
+
57
+ expect(response).to be_a Marvelite::API::NotModifiedResponse
58
+ expect(response.code).to eq(304)
59
+ expect(response.status).to eq("Not Modified")
60
+ expect(response.etag).to eq(etag)
61
+ expect(response.data).to eq({})
62
+ end
63
+ end
64
+
41
65
  context "private methods" do
42
66
  describe '#ts' do
43
67
  let(:client) { Marvelite::API::Client.new(:public_key => '1234', :private_key => 'abcd') }
@@ -57,8 +81,10 @@ describe Marvelite::API::Client do
57
81
 
58
82
  it 'passes required API params to all requests' do
59
83
  client.stub(:ts).and_return('1')
60
- expect(client.send(:params)).to eq({:apikey => client.public_key, :ts => '1', :hash => 'ffd275c5130566a2916217b101f26150'})
84
+ expect(client.send(:params)).to eq(
85
+ {:apikey => client.public_key, :ts => '1', :hash => 'ffd275c5130566a2916217b101f26150'}
86
+ )
61
87
  end
62
88
  end
63
89
  end
64
- end
90
+ end
@@ -34,4 +34,8 @@ RSpec.configure do |config|
34
34
  }.merge(options)
35
35
  FakeWeb.register_uri(:get, marvel_url(url), opts)
36
36
  end
37
- end
37
+
38
+ def stub_304(url, etag)
39
+ FakeWeb.register_uri(:get, marvel_url(url), status: 304, body: '', etag: etag)
40
+ end
41
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: marvelite
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.9
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Antonio Antillon
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-02-10 00:00:00.000000000 Z
11
+ date: 2014-05-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: httparty
@@ -38,20 +38,6 @@ dependencies:
38
38
  - - ~>
39
39
  - !ruby/object:Gem::Version
40
40
  version: 2.0.5
41
- - !ruby/object:Gem::Dependency
42
- name: activemodel
43
- requirement: !ruby/object:Gem::Requirement
44
- requirements:
45
- - - '>='
46
- - !ruby/object:Gem::Version
47
- version: '0'
48
- type: :runtime
49
- prerelease: false
50
- version_requirements: !ruby/object:Gem::Requirement
51
- requirements:
52
- - - '>='
53
- - !ruby/object:Gem::Version
54
- version: '0'
55
41
  - !ruby/object:Gem::Dependency
56
42
  name: bundler
57
43
  requirement: !ruby/object:Gem::Requirement
@@ -201,7 +187,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
201
187
  requirements:
202
188
  - - '>='
203
189
  - !ruby/object:Gem::Version
204
- version: '0'
190
+ version: 1.9.2
205
191
  required_rubygems_version: !ruby/object:Gem::Requirement
206
192
  requirements:
207
193
  - - '>='
@@ -209,7 +195,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
209
195
  version: '0'
210
196
  requirements: []
211
197
  rubyforge_project:
212
- rubygems_version: 2.0.6
198
+ rubygems_version: 2.1.11
213
199
  signing_key:
214
200
  specification_version: 4
215
201
  summary: Simple wrapper around the Marvel Comics API