luchadeer 0.1.0 → 0.2.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: 77d28c953c62036e898630d204bd3e630ecc90e5
4
- data.tar.gz: 675625e43a2d925c7e1697d37ff5563a91536eb0
3
+ metadata.gz: bfbc3969949f80b2c6fe14722317f9b88cbdb31e
4
+ data.tar.gz: f1ad8f45243b83a111039bbf6dc5263f6342edb2
5
5
  SHA512:
6
- metadata.gz: 53d5e8f133ffabf11316572708618b7a937c374647b30d09ed0fd6ea142f8a99b8a2862cb4f9d8b1e27707f4f731c9ae8ad10a80ad7c76b86b72c4d28814990d
7
- data.tar.gz: dc98a568a7fb9af7c92ddcac6b99e7744f0ceae2f9c34466484c4e5d91762f893a6c1d6632a728c044ac4bc978dab654d92bc4b881d9262945d07166a918031a
6
+ metadata.gz: 769594975368dc99024b093ae1027068e8d659c43833f6d4b8e47b702959e9dcd696bbd6a483251a3b13dae49b7fbf6367f5a1934f4cc50aa145b419ca381b63
7
+ data.tar.gz: 8124aef0e0a7062d4d5ee373ab196d1a34f64381fb9cf748d228acbd432be0a816802987a08249c14cf7ebc475119131c14f6aea4020ff3ddcf288f84471edbf
data/README.md CHANGED
@@ -4,7 +4,7 @@
4
4
  [![Coverage Status](https://coveralls.io/repos/paulfri/luchadeer/badge.png?branch=master)][coverage]
5
5
  [![Code Climate](https://codeclimate.com/github/paulfri/luchadeer.png)][grade]
6
6
 
7
- [build]: (https://travis-ci.org/paulfri/luchadeer)
7
+ [build]: https://travis-ci.org/paulfri/luchadeer
8
8
  [coverage]: https://coveralls.io/r/paulfri/luchadeer?branch=master
9
9
  [grade]: https://codeclimate.com/github/paulfri/luchadeer
10
10
 
@@ -18,16 +18,13 @@ The bombingest Giant Bomb API client library for Ruby.
18
18
  5. Thread-ready (thready?): no global or class state. Use convenience methods to use a default client per-thread, or use an alternate syntax for full control.
19
19
 
20
20
  ## Configuration
21
- Get your API key [here](http://www.giantbomb.com/api).
21
+ Get your API key [here](http://www.giantbomb.com/api). If you have a premium account, your API key should give you access to subscriber-only video resources, as well as links to HD-quality videos.
22
22
 
23
23
  ```ruby
24
24
  Luchadeer.configure(api_key: 'my_api_key') # default client for this thread
25
25
  Luchadeer::Client.new(api_key: 'my_api_key')
26
- ```
27
-
28
- You can also pass a block to either method, and it will yield the client object to configure to your liking.
29
26
 
30
- ```ruby
27
+ # You can also pass a block to either method, and it will yield the client object to configure to your liking.
31
28
  Luchadeer.configure do |client|
32
29
  client.api_key = 'my_api_key'
33
30
  end
@@ -47,12 +44,29 @@ end
47
44
  ## Usage
48
45
 
49
46
  ```ruby
47
+ # Resources
50
48
  Luchadeer::Game.find(21373) # or...
51
49
  my_client.game(21373) # => #<Luchadeer::Game name="Shin Megami Tensei: Persona 4" ...>
50
+
51
+ # Search: mix and match whatever syntax you like
52
+ Luchadeer::Search.new(page: 1, limit: 50, query: 'valkyria').fetch
53
+
54
+ search = Luchadeer::Search.new
55
+ search.page(1).limit(50).sort('name', :desc)
56
+ search.resources([Luchadeer::Game, Luchadeer::Character])
57
+ search.query('valkyria')
58
+ search.fetch
59
+
60
+ Luchadeer::Search.new { |s|
61
+ s.query = 'valkyria'
62
+ s.page = 1
63
+ s.limit = 50
64
+ }.fetch
52
65
  ```
53
66
 
54
67
  ## TODO
55
- 1. Add filtering to search.
68
+ 1. Add custom filtering to search (i.e., the 'filter' request parameter).
56
69
  2. Add per-resource searching class methods on each resource object.
57
70
  3. Refactor the test suite with shared example groups.
58
71
  4. Make the caching layer more flexible - more options besides in-memory store. Add a null store, too.
72
+ 5. Add remaining missing resources: accessory, chat, game_rating, genre, platform, promo, rating_board, region, release, review, theme, types, user_review, video_type. None of these show up in search. Refactoring is probably necessary.
@@ -12,10 +12,7 @@ module Luchadeer
12
12
  GIANT_BOMB = 'http://www.giantbomb.com/api'
13
13
 
14
14
  def initialize(opts = {})
15
- opts.each do |key, value|
16
- send(:"#{key}=", value)
17
- end
18
-
15
+ @api_key = opts[:api_key] if opts[:api_key]
19
16
  yield self if block_given?
20
17
  end
21
18
 
@@ -10,8 +10,6 @@ require 'luchadeer/video'
10
10
 
11
11
  module Luchadeer
12
12
  class Search
13
- attr_accessor :query
14
-
15
13
  RESOURCE_TYPES = {
16
14
  'character' => Luchadeer::Character,
17
15
  'company' => Luchadeer::Company,
@@ -24,8 +22,12 @@ module Luchadeer
24
22
  'video' => Luchadeer::Video
25
23
  }
26
24
 
27
- def initialize(query)
28
- @query = query
25
+ def initialize(opts = {})
26
+ opts.each do |key, value|
27
+ send(:"#{key}=", value)
28
+ end
29
+
30
+ yield self if block_given?
29
31
  end
30
32
 
31
33
  def fetch
@@ -35,10 +37,49 @@ module Luchadeer
35
37
  end.compact
36
38
  end
37
39
 
40
+ QUERY_PARAMS = [:query, :limit, :page, :fields, :resources, :sort]
41
+ attr_writer *QUERY_PARAMS
42
+
43
+ QUERY_PARAMS.each do |method|
44
+ define_method("#{method}") do |param = nil|
45
+ ivar = "@#{method.to_s}"
46
+ return instance_variable_get(ivar) unless param
47
+ instance_variable_set(ivar, param)
48
+ self
49
+ end
50
+ end
51
+
52
+ def resources(resources = nil)
53
+ return @resources unless resources
54
+ append_resources(resources)
55
+ self
56
+ end
57
+
58
+ def sort(attribute = nil, dir = :asc)
59
+ return @sort unless attribute
60
+ @sort = "#{attribute}:#{dir}"
61
+ self
62
+ end
63
+
38
64
  private
39
65
 
40
66
  def search_params
41
- { query: @query }
67
+ { query: @query, limit: @limit, resources: @resources, page: @page,
68
+ sort: @sort }.delete_if { |_, v| v.nil? }
69
+ end
70
+
71
+ def append_resources(resources)
72
+ @resources ||= ''
73
+ resources = (RESOURCE_TYPES.invert[resources] || '') if resources.is_a? Class
74
+
75
+ rx = resources.is_a?(Array) ? resources : resources.split(',')
76
+ rx.each do |r|
77
+ r = (RESOURCE_TYPES.invert[r] || '') if r.is_a? Class
78
+ RESOURCE_TYPES[r] or raise(ArgumentError, 'Invalid resource type supplied')
79
+ @resources << ",#{r}"
80
+ end
81
+
82
+ @resources.sub!(/\A,+/, '')
42
83
  end
43
84
 
44
85
  end
@@ -1,3 +1,3 @@
1
1
  module Luchadeer
2
- VERSION = '0.1.0'
2
+ VERSION = '0.2.0'
3
3
  end
@@ -2,26 +2,161 @@ require 'spec_helper'
2
2
 
3
3
  describe Luchadeer::Search do
4
4
  let(:query) { 'Chie Satonaka' }
5
+ let(:limit) { 10 }
6
+ let(:page) { 1 }
7
+ let(:sort) { 'name' }
8
+ let(:search) { described_class.new }
5
9
  let(:search_path) { %r(#{Luchadeer::Client::GIANT_BOMB}/search) }
10
+ let(:empty_body) { { body: '{ "results": [] }' } }
6
11
 
7
12
  describe '#initialize' do
8
- it 'instantiates with a search query' do
9
- expect(described_class.new(query).query).to eq query
13
+ it 'instantiates with no arguments' do
14
+ expect(described_class.new).to be_instance_of described_class
15
+ end
16
+
17
+ it 'instantiates with an options hash' do
18
+ expect(described_class.new(query: query).query).to eq query
19
+ end
20
+
21
+ it 'yields self if block given' do
22
+ expect { |b| described_class.new(&b) }.to yield_control
23
+ end
24
+ end
25
+
26
+ describe '#query' do
27
+ it 'sets the query' do
28
+ expect(search.query(query).query).to eq query
29
+ end
30
+
31
+ it 'returns the search instance' do
32
+ expect(search.query(query)).to eq search
33
+ end
34
+ end
35
+
36
+ describe '#limit' do
37
+ it 'sets the limit' do
38
+ expect(search.limit(limit).limit).to eq limit
39
+ end
40
+
41
+ it 'returns the search instance' do
42
+ expect(search.limit(limit)).to eq search
43
+ end
44
+ end
45
+
46
+ describe '#page' do
47
+ it 'sets the page' do
48
+ expect(search.page(page).page).to eq page
49
+ end
50
+
51
+ it 'returns the search instance' do
52
+ expect(search.page(page)).to eq search
53
+ end
54
+ end
55
+
56
+ describe '#sort' do
57
+ it 'sets the sort to the given parameter and defaults to ascending' do
58
+ expect(search.sort(sort).sort).to eq "#{sort}:asc"
59
+ end
60
+
61
+ it 'allows changing the sort direction' do
62
+ expect(search.sort(sort, :desc).sort).to eq "#{sort}:desc"
63
+ end
64
+
65
+ it 'allows changing the sort with a string' do
66
+ expect(search.sort(sort, 'desc').sort).to eq "#{sort}:desc"
67
+ end
68
+
69
+ it 'returns the search instance' do
70
+ expect(search.sort(sort)).to eq search
71
+ end
72
+ end
73
+
74
+ describe '#resources' do
75
+ context 'when called with a valid string' do
76
+ it 'sets resources to the given string' do
77
+ expect(search.resources('person,location').resources).to eq 'person,location'
78
+ end
79
+ end
80
+
81
+ context 'when called with an invalid string' do
82
+ it 'raises ArgumentError' do
83
+ expect { search.resources('naoto,yosuke,kanji').resources }.to raise_error ArgumentError
84
+ end
85
+ end
86
+
87
+ context 'when called with class' do
88
+ it 'maps the class to a string' do
89
+ expect(search.resources(Luchadeer::Person).resources).to eq 'person'
90
+ end
91
+ end
92
+
93
+ context 'when called with array' do
94
+ context 'of valid' do
95
+ context 'strings' do
96
+ it 'sets resources to comma-delimited string of given strings' do
97
+ expect(search.resources(['person', 'location']).resources).to eq 'person,location'
98
+ end
99
+ end
100
+
101
+ context 'classes' do
102
+ it 'maps the classes to strings' do
103
+ expect(search.resources([Luchadeer::Person, Luchadeer::Location]).resources).to eq 'person,location'
104
+ end
105
+ end
106
+ end
107
+
108
+ context 'of invalid' do
109
+ context 'strings' do
110
+ it 'raises ArgumentError' do
111
+ expect { search.resources ['person', 'naoto'] }.to raise_error ArgumentError
112
+ end
113
+ end
114
+
115
+ context 'classes' do
116
+ it 'raises ArgumentError' do
117
+ expect { search.resources [String, BasicObject, Luchadeer::Search] }.to raise_error ArgumentError
118
+ end
119
+ end
120
+ end
10
121
  end
11
122
  end
12
123
 
13
124
  describe '#fetch' do
125
+ let(:search) { described_class.new(query: query).fetch }
126
+
14
127
  before :each do
15
128
  Luchadeer.client = Luchadeer::Client.new
16
129
  end
17
130
 
18
131
  it 'queries the Giant Bomb search API' do
19
- stub = stub_request(:get, search_path).to_return(body: '{ "results": [] }')
132
+ stub = stub_request(:get, search_path).to_return(empty_body)
20
133
 
21
- described_class.new(query).fetch
134
+ search
22
135
  expect(stub).to have_been_requested
23
136
  end
24
137
 
138
+ describe 'request parameters' do
139
+ it 'includes supplied parameters' do
140
+ params = { query: query, limit: 10, page: 1, resources: 'video', sort: 'name:asc' }
141
+
142
+ stub = stub_request(:get, "http://www.giantbomb.com/api/search")
143
+ .with(query: { api_key: nil, format: 'json' }.merge(params))
144
+ .to_return(empty_body)
145
+
146
+ described_class.new(params).fetch
147
+ expect(stub).to have_been_requested
148
+ end
149
+
150
+ it 'omits nil parameters' do
151
+ stub = stub_request(:get, "http://www.giantbomb.com/api/search")
152
+ .with(query: { api_key: nil, format: 'json', query: query })
153
+ .to_return(empty_body)
154
+
155
+ described_class.new(query: query, limit: nil, page: nil).fetch
156
+ expect(stub).to have_been_requested
157
+ end
158
+ end
159
+
25
160
  describe 'generates the proper class based on the result type' do
26
161
  subject do
27
162
  stub_request(:get, search_path).to_return(body:
@@ -36,7 +171,7 @@ describe Luchadeer::Search do
36
171
  {"resource_type": "person"},
37
172
  {"resource_type": "video"}
38
173
  ] }')
39
- described_class.new(query).fetch
174
+ search
40
175
  end
41
176
 
42
177
  its([0]) { should be_instance_of Luchadeer::Character }
@@ -50,18 +185,18 @@ describe Luchadeer::Search do
50
185
  its([8]) { should be_instance_of Luchadeer::Video }
51
186
  end
52
187
 
53
- context 'when there are no results' do
54
- it 'returns an empty array' do
188
+ context 'when the resource type isn\'t mapped' do
189
+ it 'skips modeling the resource' do
55
190
  stub_request(:get, search_path).to_return(body:
56
191
  '{ "results": [{ "resource_type": "banana"}] }')
57
- expect(described_class.new(query).fetch).to eq []
192
+ expect(search).to be_empty
58
193
  end
59
194
  end
60
195
 
61
- context 'when the resource type isn\'t mapped' do
62
- it 'skips modeling the resource' do
63
- stub_request(:get, search_path).to_return(body: '{ "results": [] }')
64
- expect(described_class.new(query).fetch).to eq []
196
+ context 'when there are no results' do
197
+ it 'returns an empty array' do
198
+ stub_request(:get, search_path).to_return(empty_body)
199
+ expect(search).to be_empty
65
200
  end
66
201
  end
67
202
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: luchadeer
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Paul Friedman
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-02-09 00:00:00.000000000 Z
11
+ date: 2014-02-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday
@@ -184,7 +184,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
184
184
  version: '0'
185
185
  requirements: []
186
186
  rubyforge_project:
187
- rubygems_version: 2.2.1
187
+ rubygems_version: 2.2.0
188
188
  signing_key:
189
189
  specification_version: 4
190
190
  summary: The bombingest Giant Bomb API client library for Ruby.