marvelite 0.0.9 → 0.1.0

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: 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