eshopworks-rboss 0.1.8 → 0.1.9

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.
data/TODO.txt CHANGED
@@ -1,4 +1,3 @@
1
1
  == FEATURES/PROBLEMS:
2
2
 
3
- * Search all
4
3
  * Integrate with Tagging service
@@ -12,27 +12,39 @@ Given "a valid API key" do
12
12
  @api = Boss::Api.new("put-your-api-key-here")
13
13
  end
14
14
 
15
- When /I do a '(.+)' search for '(.+)'/ do |search, term|
15
+ When /^I do the following search$/ do |table|
16
+ # Do integer conversions
17
+ table.send :map_headers!, 'limit' => :limit, 'count' => :count
18
+ table.map_column!(:limit) { |x| x.nil? ? nil : x.to_i }
19
+ table.map_column!(:count) { |x| x.nil? ? nil : x.to_i }
16
20
 
17
- case search
21
+ search_options = table.hashes.first
22
+
23
+ type = search_options.delete('type')
24
+ term = search_options.delete('term')
25
+
26
+ case type
18
27
  when 'web'
19
- @results = @api.search_web(term)
28
+ @results = @api.search_web(term, search_options)
20
29
  when 'news'
21
- @results = @api.search_news(term)
30
+ @results = @api.search_news(term, search_options)
22
31
  when 'images'
23
- @results = @api.search_images(term)
32
+ @results = @api.search_images(term, search_options)
24
33
  when 'spell'
25
- @results = @api.search_spelling(term)
34
+ @results = @api.search_spelling(term, search_options)
26
35
  else
27
- raise Exception.new "invalid search: #{search}"
36
+ raise Exception.new "invalid search: #{type}"
28
37
  end
29
-
30
38
  end
31
39
 
32
40
  Then /I will receive search results/ do
33
41
  @results.results.nil?.should == false
34
42
  end
35
43
 
44
+ Then /^I will receive "([^\"]*)" search results$/ do |number_of_results|
45
+ @results.results.size.should == number_of_results.to_i
46
+ end
47
+
36
48
  Then /I will be able to see the total hits/ do
37
49
  @results.totalhits.to_i.should > 0
38
50
  end
@@ -3,16 +3,23 @@ Feature: Web Search
3
3
  As a API user
4
4
  I want to query yahoo boss
5
5
 
6
- Scenario: Search web
6
+ Scenario Outline: Search
7
7
  Given a valid API key
8
- When I do a 'web' search for 'monkeys'
9
- Then I will receive search results
8
+ When I do the following search
9
+ | type | term | count | limit |
10
+ | <type> | <term> | <count> | <limit> |
11
+ Then I will receive "<result_count>" search results
10
12
  And I will be able to see the total hits
11
13
 
12
- More Examples:
13
- | type | term |
14
- | web | monkey |
15
- | images | monkey |
16
- | news | monkey |
17
- | spell | girafe |
14
+ Examples: search types
15
+ | type | term | count | limit | result_count |
16
+ | web | monkey | | 5 | 5 |
17
+ | web | monkey | 1 | 3 | 3 |
18
+ | web | monkey | 5 | 6 | 10 |
19
+ | web | monkey | 50 | 100 | 100 |
20
+ | images | monkey | 1 | 10 | 10 |
21
+ | news | monkey | 1 | 1 | 1 |
22
+ | spell | girafe | 1 | 1 | 1 |
23
+
24
+
18
25
 
@@ -8,11 +8,13 @@ module Boss
8
8
 
9
9
  class Api
10
10
 
11
+ MAX_COUNT = 50
11
12
  attr_accessor :endpoint
12
13
 
13
14
  def initialize(app_id)
14
15
  @app_id = app_id
15
- @endpoint = 'http://boss.yahooapis.com/ysearch/'
16
+ @basepoint = 'http://boss.yahooapis.com'
17
+ @endpoint = "#{@basepoint}/ysearch/"
16
18
  end
17
19
 
18
20
  def search(term, *conditions, &block)
@@ -35,28 +37,59 @@ module Boss
35
37
  search_boss(term, SearchService::SPELLING, *conditions, &block)
36
38
  end
37
39
 
40
+ def next_page
41
+ make_request(@basepoint + @next_page_path) if @next_page_path
42
+ end
43
+
44
+ def previous_page
45
+ make_request(@basepoint + @previous_page_path) if @previous_page_path
46
+ end
47
+
38
48
  private
39
49
  def search_boss(terms, search_type=SearchService::WEB, config = {})
40
50
  config = config.empty? ? Config.new : Config.new(config)
41
51
  yield config if block_given?
42
-
52
+
43
53
  raise InvalidFormat, "'#{config.format}' is not a valid format. Valid formats are: #{FORMATS.join(',')}" unless FORMATS.include?(config.format) || config.format?
44
54
  raise InvalidConfig, "count must be > 0" unless config.count>0
45
55
  raise InvalidConfig, "App ID cannot be empty!" if @app_id.empty?
46
56
 
47
- request = URI.parse(build_request_url(terms, search_type, config))
57
+ config.count = MAX_COUNT if config.count > MAX_COUNT
58
+
59
+ # Remember search instructions for iterating over pages
60
+ @current_config = config.dup
61
+
62
+ if limit = config.delete_field(:limit)
63
+ # Do a first request to gather required information
64
+ results = make_request(build_request_url(terms, search_type, config) )
65
+ total_count = results.totalhits.to_i
66
+ limit = total_count if total_count < limit
67
+ number_of_requests = (limit.to_f / config.count).ceil - 1
68
+
69
+ number_of_requests.times { results += next_page }
70
+ results
71
+ else
72
+ results = make_request(build_request_url(terms, search_type, config))
73
+ end
74
+ end
75
+
76
+ def make_request(url)
77
+ request = URI.parse(url)
48
78
  response = Net::HTTP.get_response(request)
49
79
 
50
80
  case response.code
51
81
  when "200"
52
82
  data = response.body
53
-
54
- if config.format?
83
+
84
+ if @current_config.format?
55
85
  search_results = ResultFactory.build(data)
56
86
 
57
87
  # set requested page count size
58
88
  # Used in math to determine total pages and current page
59
- search_results.set_instance_variable('page_count', config.count) if search_results.kind_of?(Boss::ResultCollection)
89
+ search_results.set_instance_variable('page_count', @current_config.count) if search_results.kind_of?(Boss::ResultCollection)
90
+
91
+ @next_page_path = search_results.nextpage if search_results.respond_to?(:nextpage)
92
+ @previous_page_path = search_results.prevpage if search_results.respond_to?(:prevpage)
60
93
  else
61
94
  search_results = data
62
95
  end
@@ -94,4 +127,4 @@ module Boss
94
127
 
95
128
  end
96
129
 
97
- end
130
+ end
@@ -5,8 +5,10 @@ module Boss
5
5
  class Config < OpenStruct
6
6
 
7
7
  def initialize(hash={})
8
- #Setup defaults
9
- super({:count => 10, :lang => "en"}.merge(hash))
8
+ #Setup defaults
9
+ hash[:count] ||= hash[:limit] ||= 10
10
+
11
+ super({:lang => "en"}.merge(hash))
10
12
  end
11
13
 
12
14
  def to_url
@@ -25,6 +25,12 @@ module Boss
25
25
  @results[key]
26
26
  end
27
27
 
28
+ def +(other)
29
+ clone = self.clone
30
+ clone.instance_variable_set("@results", clone.results + other.results)
31
+ clone
32
+ end
33
+
28
34
  # Implements neccessary api for the will_paginate view helper
29
35
  # to work with result sets out of the box
30
36
  def size
@@ -2,7 +2,7 @@ module Boss #:nodoc:
2
2
  class VERSION #:nodoc:
3
3
  MAJOR = 0
4
4
  MINOR = 1
5
- TINY = 8
5
+ TINY = 9
6
6
 
7
7
  STRING = [MAJOR, MINOR, TINY].join('.')
8
8
  end
@@ -1,10 +1,12 @@
1
+ # -*- encoding: utf-8 -*-
2
+
1
3
  Gem::Specification.new do |s|
2
4
  s.name = %q{rboss}
3
- s.version = "0.1.8"
5
+ s.version = "0.1.9"
4
6
 
5
7
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
6
8
  s.authors = ["Joseph Wilk"]
7
- s.date = %q{2008-10-31}
9
+ s.date = %q{2009-06-04}
8
10
  s.description = %q{Api wrapping Yahoo Boss search}
9
11
  s.email = ["joe@eshopworks.co.uk"]
10
12
  s.extra_rdoc_files = ["History.txt", "License.txt", "Manifest.txt", "README.txt", "TODO.txt"]
@@ -14,28 +16,28 @@ Gem::Specification.new do |s|
14
16
  s.rdoc_options = ["--main", "README.txt"]
15
17
  s.require_paths = ["lib"]
16
18
  s.rubyforge_project = %q{rboss}
17
- s.rubygems_version = %q{1.2.0}
19
+ s.rubygems_version = %q{1.3.1}
18
20
  s.summary = %q{Api wrapping Yahoo Boss search}
19
21
 
20
22
  if s.respond_to? :specification_version then
21
23
  current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
22
24
  s.specification_version = 2
23
25
 
24
- if current_version >= 3 then
26
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
25
27
  s.add_runtime_dependency(%q<json_pure>, [">= 1.1.3"])
26
28
  s.add_runtime_dependency(%q<rspec>, [">= 1.1.4"])
27
29
  s.add_runtime_dependency(%q<diff-lcs>, [">= 1.1.2"])
28
- s.add_development_dependency(%q<hoe>, [">= 1.8.2"])
30
+ s.add_development_dependency(%q<hoe>, [">= 1.12.2"])
29
31
  else
30
32
  s.add_dependency(%q<json_pure>, [">= 1.1.3"])
31
33
  s.add_dependency(%q<rspec>, [">= 1.1.4"])
32
34
  s.add_dependency(%q<diff-lcs>, [">= 1.1.2"])
33
- s.add_dependency(%q<hoe>, [">= 1.8.2"])
35
+ s.add_dependency(%q<hoe>, [">= 1.12.2"])
34
36
  end
35
37
  else
36
38
  s.add_dependency(%q<json_pure>, [">= 1.1.3"])
37
39
  s.add_dependency(%q<rspec>, [">= 1.1.4"])
38
40
  s.add_dependency(%q<diff-lcs>, [">= 1.1.2"])
39
- s.add_dependency(%q<hoe>, [">= 1.8.2"])
41
+ s.add_dependency(%q<hoe>, [">= 1.12.2"])
40
42
  end
41
43
  end
@@ -15,80 +15,44 @@ describe Boss::Api do
15
15
  #TODO: Mock HTTPSuccess
16
16
  def mock_http_response(stubs={})
17
17
  # mock('Net::HTTPSuccess',{:head => Net::HTTPSuccess.new('1.2', '200', 'OK'), :body => '{"ysearchresponse":{}}' })
18
- mock('http_response', {:body => '{"ysearchresponse":{}}', :code => "200"}.merge(stubs))
18
+ mock('http_response', {:body => yahoo_json, :code => "200"}.merge(stubs))
19
19
  end
20
20
 
21
- def yahoo_json
22
- '{"ysearchresponse":{}}'
21
+ def mock_http_response_with_one_record(stubs={})
22
+ mock_http_response(:body => yahoo_json)
23
23
  end
24
24
 
25
- before(:each) do
26
- @api = Boss::Api.new( appid = 'test' )
27
- @api.endpoint = 'http://www.example.com/'
25
+ def mock_results(stubs={})
26
+ mock(:results, {:totalhits => 100 }.merge(stubs) )
28
27
  end
29
-
30
- describe "responding to spelling search" do
31
-
32
- it "should make a spelling request to yahoo service" do
33
- Net::HTTP.should_receive(:get_response).and_return{ mock_http_response }
34
-
35
- @api.search_spelling("girafes")
36
- end
37
-
38
- it "should build the spelling objects" do
39
- Net::HTTP.stub!(:get_response).and_return{ mock_http_response }
40
- Boss::ResultFactory.should_receive(:build).with(yahoo_json)
41
-
42
- @api.search_spelling("girafes")
43
- end
44
-
28
+
29
+ def yahoo_json(hash = {})
30
+ defaults = {:nextpage => "nextpage", :totalhits => "1000"}
31
+ %[{"ysearchresponse": #{defaults.merge(hash).to_json} }]
45
32
  end
46
33
 
47
- describe "responding to news search" do
48
- it "should make a news request to yahoo service" do
49
- Net::HTTP.should_receive(:get_response).and_return{ mock_http_response }
50
-
51
- @api.search_news("monkey")
52
- end
53
-
54
- it "should build the news objects" do
55
- Net::HTTP.stub!(:get_response).and_return{ mock_http_response }
56
- Boss::ResultFactory.should_receive(:build).with(yahoo_json)
57
-
58
- @api.search_news("monkey")
59
- end
34
+ before(:each) do
35
+ @api = Boss::Api.new( appid = 'test' )
36
+ @api.endpoint = 'http://www.example.com/'
60
37
  end
61
38
 
62
- describe "responding to image search" do
63
- it "should make a image request to yahoo service" do
64
- Net::HTTP.should_receive(:get_response).and_return{ mock_http_response }
39
+ %w(spelling new web image).each do |type|
40
+ describe "responding to #{type} search" do
65
41
 
66
- @api.search_images("hippo")
67
- end
68
-
69
- it "should build the image objects" do
70
- Net::HTTP.stub!(:get_response).and_return{ mock_http_response }
71
- Boss::ResultFactory.should_receive(:build).with(yahoo_json)
72
-
73
- @api.search_images("hippo")
74
- end
75
- end
42
+ it "should make a #{type} request to yahoo service" do
43
+ Net::HTTP.should_receive(:get_response).and_return{ mock_http_response }
76
44
 
77
- describe "responding to web search" do
78
-
79
- it "should make a web request to yahoo service" do
80
- Net::HTTP.should_receive(:get_response).and_return{ mock_http_response }
45
+ @api.search_web("monkey")
46
+ end
81
47
 
82
- @api.search_web("monkey")
83
- end
48
+ it "should build the #{type} objects" do
49
+ Net::HTTP.stub!(:get_response).and_return{ mock_http_response }
50
+ Boss::ResultFactory.should_receive(:build).with(yahoo_json).and_return(mock_results)
84
51
 
85
- it "should build the web objects" do
86
- Net::HTTP.stub!(:get_response).and_return{ mock_http_response }
87
- Boss::ResultFactory.should_receive(:build).with(yahoo_json)
52
+ @api.search_web("monkey")
53
+ end
88
54
 
89
- @api.search_web("monkey")
90
55
  end
91
-
92
56
  end
93
57
 
94
58
  describe "failed search" do
@@ -183,5 +147,64 @@ describe Boss::Api do
183
147
  end
184
148
 
185
149
  end
186
-
150
+
151
+ describe "#next_page" do
152
+ it "should request the next results when 'nextpage' is given" do
153
+ response_mock = mock_http_response(:body => yahoo_json(:nextpage => "nextpage"))
154
+
155
+ Net::HTTP.should_receive(:get_response).exactly(2).times.and_return{ response_mock }
156
+ @api.search_web("monkey?magic", :count => 1)
157
+ @api.next_page.should be_kind_of Boss::ResultCollection
158
+ end
159
+
160
+ it "should not request the next results when 'nextpage' is nil" do
161
+ response_mock = mock_http_response(:body => yahoo_json(:nextpage => nil))
162
+
163
+ Net::HTTP.should_receive(:get_response).exactly(1).times.and_return{ response_mock }
164
+ @api.search_web("monkey?magic", :count => 1)
165
+ @api.next_page.should be_nil
166
+ end
167
+ end
168
+
169
+ describe "#previous_page" do
170
+ it "should request the next results when 'nextpage' is given" do
171
+ response_mock = mock_http_response(:body => yahoo_json(:prevpage => "prevpage"))
172
+
173
+ Net::HTTP.should_receive(:get_response).exactly(2).times.and_return{ response_mock }
174
+ @api.search_web("monkey?magic", :count => 1)
175
+ @api.previous_page.should be_kind_of Boss::ResultCollection
176
+ end
177
+
178
+ it "should not request the next results when 'nextpage' is nil" do
179
+ response_mock = mock_http_response(:body => yahoo_json(:prevpage => nil))
180
+
181
+ Net::HTTP.should_receive(:get_response).exactly(1).times.and_return{ response_mock }
182
+ @api.search_web("monkey?magic", :count => 1)
183
+ @api.previous_page.should be_nil
184
+ end
185
+ end
186
+
187
+ describe "MAX_COUNT" do
188
+ it "should be 50" do
189
+ Boss::Api::MAX_COUNT.should eql 50
190
+ end
191
+ end
192
+
193
+ describe "#search" do
194
+
195
+ [ {:count => 2, :limit => 100, :number_of_requests => 50, :totalhits => "400"},
196
+ {:count => 50, :limit => 100, :number_of_requests => 2, :totalhits => "400"},
197
+ {:count => 3, :limit => 50, :number_of_requests => 17, :totalhits => "50"},
198
+ {:count => 3, :limit => 50, :number_of_requests => 14, :totalhits => "40"},
199
+ {:count => 100, :limit => 1, :number_of_requests => 1, :totalhits => "40"},
200
+ {:limit => 50, :count => nil, :number_of_requests => 1, :totalhits => "100"}
201
+ ].each do |prop|
202
+ it "should do #{prop[:number_of_requests]} number of requests when count is #{prop[:count]} and limit is #{prop[:limit]}" do
203
+ response_mock = mock_http_response(:body => yahoo_json(:nextpage => "nextpage", :totalhits => prop[:totalhits]))
204
+ Net::HTTP.should_receive(:get_response).exactly(prop[:number_of_requests]).times.and_return{ response_mock }
205
+ @api.search_web("monkey?magic", :count => prop[:count], :limit => prop[:limit])
206
+ end
207
+
208
+ end
209
+ end
187
210
  end
@@ -5,6 +5,7 @@ describe Boss::Config do
5
5
  it "should create with defaults" do
6
6
  config = Boss::Config.new
7
7
 
8
+ config.respond_to?(:limit).should be_true
8
9
  config.respond_to?(:count).should be_true
9
10
  config.respond_to?(:lang).should be_true
10
11
  end
@@ -21,6 +21,16 @@ describe Boss::ResultCollection do
21
21
 
22
22
  end
23
23
 
24
+ it "should allow merging two results collections" do
25
+ collection_one = Boss::ResultCollection.new
26
+ collection_one << 1
27
+ collection_two = Boss::ResultCollection.new
28
+ collection_two << 2
29
+
30
+ collection_one += collection_two
31
+ collection_one.size.should be 2
32
+ end
33
+
24
34
  end
25
35
 
26
36
  describe Boss::ResultCollection, 'implementing the will_paginate collection api' do
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: eshopworks-rboss
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.8
4
+ version: 0.1.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - Joseph Wilk
@@ -9,11 +9,12 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2008-10-31 00:00:00 -07:00
12
+ date: 2009-06-04 00:00:00 -07:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: json_pure
17
+ type: :runtime
17
18
  version_requirement:
18
19
  version_requirements: !ruby/object:Gem::Requirement
19
20
  requirements:
@@ -23,6 +24,7 @@ dependencies:
23
24
  version:
24
25
  - !ruby/object:Gem::Dependency
25
26
  name: rspec
27
+ type: :runtime
26
28
  version_requirement:
27
29
  version_requirements: !ruby/object:Gem::Requirement
28
30
  requirements:
@@ -32,6 +34,7 @@ dependencies:
32
34
  version:
33
35
  - !ruby/object:Gem::Dependency
34
36
  name: diff-lcs
37
+ type: :runtime
35
38
  version_requirement:
36
39
  version_requirements: !ruby/object:Gem::Requirement
37
40
  requirements:
@@ -41,12 +44,13 @@ dependencies:
41
44
  version:
42
45
  - !ruby/object:Gem::Dependency
43
46
  name: hoe
47
+ type: :development
44
48
  version_requirement:
45
49
  version_requirements: !ruby/object:Gem::Requirement
46
50
  requirements:
47
51
  - - ">="
48
52
  - !ruby/object:Gem::Version
49
- version: 1.8.2
53
+ version: 1.12.2
50
54
  version:
51
55
  description: Api wrapping Yahoo Boss search
52
56
  email: