rsolr-ext 0.12.0 → 0.12.1

Sign up to get free protection for your applications and to get access to all the features.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.12.0
1
+ 0.12.1
@@ -38,4 +38,26 @@ module RSolr::Ext::Client
38
38
  self.request(path, params).to_mash
39
39
  end
40
40
 
41
+ # sends request to /admin/ping
42
+ def ping *args
43
+ path = args.first.is_a?(String) ? args.shift : '/admin/ping'
44
+ params = args.pop || {}
45
+ self.request(path, params).to_mash
46
+ end
47
+
48
+ # Ping the server and make sure it is alright
49
+ # solr.ping?
50
+ #
51
+ # It returns true if the server pings and the status is OK
52
+ # It returns false otherwise -- which probably cannot happen
53
+ # Or raises an exception if there is a failure to connect or
54
+ # the ping service is not activated in the solr server
55
+ #
56
+ # The default configuration point of the PingRequestHandler
57
+ # in the solr server of '/admin/ping' is assumed.
58
+ #
59
+ def ping?
60
+ ping['status'] == 'OK'
61
+ end
62
+
41
63
  end
@@ -9,7 +9,23 @@
9
9
  # number_10 = Book.find_by_id(10)
10
10
  #
11
11
  module RSolr::Ext::Model
12
-
12
+
13
+ # ripped from MongoMapper!
14
+ module Pluggable
15
+
16
+ def plugins
17
+ @plugins ||= []
18
+ end
19
+
20
+ def plugin(mod)
21
+ extend mod::ClassMethods if mod.const_defined?(:ClassMethods)
22
+ include mod::InstanceMethods if mod.const_defined?(:InstanceMethods)
23
+ mod.configure(self) if mod.respond_to?(:configure)
24
+ plugins << mod
25
+ end
26
+
27
+ end
28
+
13
29
  # Class level methods for altering object instances
14
30
  module Callbacks
15
31
 
@@ -37,11 +53,11 @@ module RSolr::Ext::Model
37
53
 
38
54
  #
39
55
  # Findable is a module that gets mixed into the SolrDocument *class* object.
40
- # These methods will be available through the class like: SolrDocument.find and SolrDocument.find_by_id
56
+ # These methods will be available through the class: SolrDocument.find
41
57
  #
42
58
  module Findable
43
59
 
44
- attr_accessor :connection, :default_params
60
+ attr_accessor :connection
45
61
 
46
62
  def connection
47
63
  @connection ||= RSolr::Ext.connect
@@ -49,41 +65,37 @@ module RSolr::Ext::Model
49
65
 
50
66
  # this method decorates the connection find method
51
67
  # and then creates new instance of the class that uses this module.
52
- def find(*args)
53
- decorate_response_docs connection.find(*args)
68
+ def find *args, &block
69
+ response = connection.find(*args)
70
+ response.docs.map {|doc|
71
+ d = self.new doc, response
72
+ yield d if block_given?
73
+ d
74
+ }
54
75
  end
55
76
 
56
- # this method decorates the connection find_by_id method
57
- # and then creates new instance of the class that uses this module.
58
- def find_by_id(id, solr_params={}, opts={})
59
- decorate_response_docs connection.find_by_id(id, solr_params, opts)
60
- end
61
-
62
- protected
63
-
64
- def decorate_response_docs response
65
- response['response']['docs'].map!{|d| self.new d }
66
- response
67
- end
68
-
69
77
  end
70
78
 
71
79
  # Called by Ruby Module API
72
80
  # extends this *class* object
73
81
  def self.included(base)
82
+ base.extend Pluggable
74
83
  base.extend Callbacks
75
84
  base.extend Findable
76
85
  base.send :include, RSolr::Ext::Doc
77
86
  end
78
87
 
88
+ attr_reader :solr_response
89
+
79
90
  # The original object passed in to the #new method
80
91
  attr :_source
81
92
 
82
93
  # Constructor **for the class that is getting this module included**
83
94
  # source_doc should be a hash or something similar
84
95
  # calls each of after_initialize blocks
85
- def initialize(source_doc={})
96
+ def initialize(source_doc={}, solr_response=nil)
86
97
  @_source = source_doc.to_mash
98
+ @solr_response = solr_response
87
99
  self.class.hooks.each do |h|
88
100
  instance_eval &h
89
101
  end
@@ -66,12 +66,14 @@ module RSolr::Ext::Request
66
66
  # passed back into build_query (recursive)
67
67
  def build_query(value, quote_string=false)
68
68
  case value
69
- when String,Symbol
69
+ when String,Symbol,Numeric
70
70
  quote_string ? quote(value.to_s) : value.to_s
71
71
  when Array
72
72
  value.collect do |v|
73
73
  build_query(v, quote_string)
74
74
  end.flatten
75
+ when Range
76
+ build_range(value)
75
77
  when Hash
76
78
  return value.collect do |(k,v)|
77
79
  if v.is_a?(Range)
@@ -105,4 +107,4 @@ module RSolr::Ext::Request
105
107
  extend QueryHelpers
106
108
  extend Params
107
109
 
108
- end
110
+ end
@@ -3,23 +3,23 @@
3
3
  # response.spelling.words
4
4
  #
5
5
  module RSolr::Ext::Response::Spelling
6
-
6
+
7
7
  def spelling
8
8
  @spelling ||= Base.new(self)
9
9
  end
10
-
10
+
11
11
  class Base
12
-
12
+
13
13
  attr :response
14
-
14
+
15
15
  def initialize(response)
16
16
  @response = response
17
17
  end
18
-
19
- # returns an array of spelling suggestion for specific query words,
18
+
19
+ # returns an array of spelling suggestion for specific query words,
20
20
  # as provided in the solr response. Only includes words with higher
21
21
  # frequency of occurrence than word in original query.
22
- # can't do a full query suggestion because we only get info for each word;
22
+ # can't do a full query suggestion because we only get info for each word;
23
23
  # combination of words may not have results.
24
24
  # Thanks to Naomi Dushay!
25
25
  def words
@@ -29,37 +29,64 @@ module RSolr::Ext::Response::Spelling
29
29
  if spellcheck && spellcheck[:suggestions]
30
30
  suggestions = spellcheck[:suggestions]
31
31
  unless suggestions.nil?
32
- # suggestions is an array:
32
+ # suggestions is an array:
33
33
  # (query term)
34
- # (hash of term info and term suggestion)
34
+ # (hash of term info and term suggestion)
35
35
  # ...
36
36
  # (query term)
37
- # (hash of term info and term suggestion)
37
+ # (hash of term info and term suggestion)
38
38
  # 'correctlySpelled'
39
39
  # true/false
40
40
  # collation
41
41
  # (suggestion for collation)
42
- i_stop = suggestions.index("correctlySpelled")
43
- # step through array in 2s to get info for each term
44
- 0.step(i_stop-1, 2) do |i|
45
- term = suggestions[i]
46
- term_info = suggestions[i+1]
47
- # term_info is a hash:
48
- # numFound =>
49
- # startOffset =>
50
- # endOffset =>
51
- # origFreq =>
52
- # suggestion => { frequency =>, word => }
53
- origFreq = term_info['origFreq']
54
- suggFreq = term_info['suggestion']['frequency']
55
- word_suggestions << term_info['suggestion']['word'] if suggFreq > origFreq
42
+ if suggestions.index("correctlySpelled") #if extended results
43
+ i_stop = suggestions.index("correctlySpelled")
44
+ elsif suggestions.index("collation")
45
+ i_stop = suggestions.index("collation")
46
+ else
47
+ i_stop = suggestions.length
56
48
  end
49
+ # step through array in 2s to get info for each term
50
+ 0.step(i_stop-1, 2) do |i|
51
+ term = suggestions[i]
52
+ term_info = suggestions[i+1]
53
+ # term_info is a hash:
54
+ # numFound =>
55
+ # startOffset =>
56
+ # endOffset =>
57
+ # origFreq =>
58
+ # suggestion => [{ frequency =>, word => }] # for extended results
59
+ # suggestion => ['word'] # for non-extended results
60
+ origFreq = term_info['origFreq']
61
+ if suggestions.index("correctlySpelled")
62
+ word_suggestions << term_info['suggestion'].map do |suggestion|
63
+ suggestion['word'] if suggestion['freq'] > origFreq
64
+ end
65
+ else
66
+ # only extended suggestions have frequency so we just return all suggestions
67
+ word_suggestions << term_info['suggestion']
68
+ end
69
+ end
57
70
  end
58
71
  end
59
- word_suggestions.uniq
72
+ word_suggestions.flatten.compact.uniq
60
73
  )
61
74
  end
62
-
75
+
76
+ def collation
77
+ # FIXME: DRY up with words
78
+ spellcheck = self.response[:spellcheck]
79
+ if spellcheck && spellcheck[:suggestions]
80
+ suggestions = spellcheck[:suggestions]
81
+ unless suggestions.nil?
82
+ if suggestions.index("collation")
83
+ suggestions[suggestions.index("collation") + 1]
84
+ end
85
+ end
86
+ end
87
+ end
88
+
63
89
  end
64
-
65
- end
90
+
91
+ end
92
+
@@ -13,10 +13,10 @@ module RSolr::Ext::Response
13
13
  super hash
14
14
  @original_hash = hash
15
15
  @request_path, @request_params = request_path, request_params
16
- extend Response# if self['response']
17
- extend Docs# if self['response'] and self['response']['docs']
18
- extend Facets# if self['facet_counts']
19
- extend Spelling# if self['spellcheck']
16
+ extend Response
17
+ extend Docs
18
+ extend Facets
19
+ extend Spelling
20
20
  end
21
21
 
22
22
  def header
data/lib/rsolr-ext.rb CHANGED
@@ -1,10 +1,6 @@
1
1
  # add this directory to the load path if it hasn't already been added
2
2
 
3
- lambda { |base|
4
- $: << base unless $:.include?(base) || $:.include?(File.expand_path(base))
5
- }.call(File.dirname(__FILE__))
6
-
7
- require 'mash' unless defined?(Mash)
3
+ require File.join(File.dirname(__FILE__), 'mash') unless defined?(Mash)
8
4
 
9
5
  unless Hash.respond_to?(:to_mash)
10
6
  class Hash
@@ -1,26 +1,26 @@
1
1
  require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
2
 
3
3
  describe RSolr::Ext do
4
-
4
+
5
5
  context RSolr::Client do
6
-
7
- let(:connection){RSolr.connect}
8
-
6
+
7
+ let(:client){RSolr.connect}
8
+
9
9
  it 'should now have a #find method' do
10
- connection.should respond_to(:find)
10
+ client.should respond_to(:find)
11
11
  end
12
-
12
+
13
13
  it 'should produce results from the #find method' do
14
- c = connection
14
+ c = client
15
15
  c.should_receive(:request).
16
16
  with('/select', {:rows=>10, :start=>20, :q=>"*:*"}).
17
17
  and_return({'response'=>{'docs' => []}, 'responseHeader' => {}})
18
18
  response = c.find :page=>3, :per_page=>10, :q=>'*:*'#, :page=>1, :per_page=>10
19
19
  response.should be_a(Mash)
20
20
  end
21
-
21
+
22
22
  it 'should call the #find method with a custom request handler' do
23
- c = connection
23
+ c = client
24
24
  expected_response = {'response'=>{'docs' => []}, 'responseHeader' => {}}
25
25
  # ok this is hacky... the raw method needs to go into a mixin dude
26
26
  def expected_response.raw
@@ -32,9 +32,9 @@ describe RSolr::Ext do
32
32
  response = c.find '/select', :q=>'*:*'
33
33
  response.raw[:path].should match(/\/select/)
34
34
  end
35
-
35
+
36
36
  it 'should be ok' do
37
- c = connection
37
+ c = client
38
38
  c.should_receive(:request).
39
39
  with('/select', :q=>'*:*').
40
40
  and_return({'response'=>{'docs' => []}, 'responseHeader' => {'status'=>0}})
@@ -42,9 +42,9 @@ describe RSolr::Ext do
42
42
  response.should respond_to(:ok?)
43
43
  response.ok?.should == true
44
44
  end
45
-
45
+
46
46
  it 'should call the #luke method' do
47
- c = connection
47
+ c = client
48
48
  c.should_receive(:request).
49
49
  with('/admin/luke', {"numTerms"=>0}).
50
50
  and_return({"fields"=>nil, "index"=>nil, "info" => nil})
@@ -54,9 +54,26 @@ describe RSolr::Ext do
54
54
  info.should have_key('index')
55
55
  info.should have_key('info')
56
56
  end
57
-
57
+
58
+ it 'should forwad #ping? calls to the connection' do
59
+ client.connection.should_receive(:request).
60
+ with('/admin/ping', :wt => :ruby ).
61
+ and_return( :params => { :wt => :ruby },
62
+ :status_code => 200,
63
+ :body => "{'responseHeader'=>{'status'=>0,'QTime'=>44,'params'=>{'echoParams'=>'all','echoParams'=>'all','q'=>'solrpingquery','qt'=>'standard','wt'=>'ruby'}},'status'=>'OK'}" )
64
+ client.ping?
65
+ end
66
+
67
+ it 'should raise an error if the ping service is not available' do
68
+ client.connection.should_receive(:request).
69
+ with('/admin/ping', :wt => :ruby ).
70
+ # the first part of the what the message would really be
71
+ and_raise( RSolr::RequestError.new("Solr Response: pingQuery_not_configured_consider_registering_PingRequestHandler_with_the_name_adminping_instead__") )
72
+ lambda { client.ping? }.should raise_error( RSolr::RequestError )
73
+ end
74
+
58
75
  end
59
-
76
+
60
77
  context 'requests' do
61
78
 
62
79
  it 'should create a valid request' do
@@ -77,26 +94,26 @@ describe RSolr::Ext do
77
94
  solr_params['facet.field'].should == ['cat', 'blah']
78
95
  solr_params[:facet].should == true
79
96
  end
80
-
97
+
81
98
  it 'should map fq using the phrase_filters mapping' do
82
99
  solr_params = RSolr::Ext::Request.map(
83
100
  :phrase_filters=>{:manu=>['Apple', 'ASG'], :color=>['red', 'blue']}
84
101
  )
85
-
102
+
86
103
  solr_params[:fq].size.should == 4
87
104
  solr_params[:fq].should include("color:\"red\"")
88
105
  solr_params[:fq].should include("color:\"blue\"")
89
106
  solr_params[:fq].should include("manu:\"Apple\"")
90
107
  solr_params[:fq].should include("manu:\"ASG\"")
91
-
108
+
92
109
  end
93
-
110
+
94
111
  it 'should map :filters and :phrase_filters while keeping an existing :fq' do
95
112
  solr_params = RSolr::Ext::Request.map(
96
113
  :fq => 'blah blah',
97
114
  :phrase_filters=>{:manu=>['Apple', 'ASG'], :color=>['red', 'blue']}
98
115
  )
99
-
116
+
100
117
  solr_params[:fq].size.should == 5
101
118
  solr_params[:fq].should include("blah blah")
102
119
  solr_params[:fq].should include("color:\"red\"")
@@ -104,22 +121,31 @@ describe RSolr::Ext do
104
121
  solr_params[:fq].should include("manu:\"Apple\"")
105
122
  solr_params[:fq].should include("manu:\"ASG\"")
106
123
  end
107
-
124
+
125
+ it 'should map arrays of ranges in :phrase_filters' do
126
+ solr_params = RSolr::Ext::Request.map(
127
+ :phrase_filters=>{:range=>[1940..2020]}
128
+ )
129
+
130
+ solr_params[:fq].size.should == 1
131
+ solr_params[:fq].should include("range:[1940 TO 2020]")
132
+ end
133
+
108
134
  end
109
-
135
+
110
136
  context 'response' do
111
-
137
+
112
138
  def create_response
113
139
  raw_response = eval(mock_query_response)
114
140
  RSolr::Ext::Response::Base.new(raw_response, '/select', raw_response['params'])
115
141
  end
116
-
142
+
117
143
  it 'should create a valid response' do
118
144
  r = create_response
119
145
  r.should respond_to(:header)
120
146
  r.ok?.should == true
121
147
  end
122
-
148
+
123
149
  it 'should have accurate pagination numbers' do
124
150
  r = create_response
125
151
  r.rows.should == 11
@@ -127,10 +153,10 @@ describe RSolr::Ext do
127
153
  r.start.should == 0
128
154
  r.docs.per_page.should == 11
129
155
  end
130
-
156
+
131
157
  it 'should create a valid response class' do
132
158
  r = create_response
133
-
159
+
134
160
  r.should respond_to(:response)
135
161
  r.ok?.should == true
136
162
  r.docs.size.should == 11
@@ -141,40 +167,40 @@ describe RSolr::Ext do
141
167
  r.should be_a(RSolr::Ext::Response::Docs)
142
168
  r.should be_a(RSolr::Ext::Response::Facets)
143
169
  end
144
-
170
+
145
171
  it 'should create a doc with rsolr-ext methods' do
146
172
  r = create_response
147
-
173
+
148
174
  doc = r.docs.first
149
175
  doc.has?(:cat, /^elec/).should == true
150
176
  doc.has?(:cat, 'elec').should_not == true
151
177
  doc.has?(:cat, 'electronics').should == true
152
-
178
+
153
179
  doc.get(:cat).should == 'electronics, hard drive'
154
180
  doc.get(:xyz).should == nil
155
181
  doc.get(:xyz, :default=>'def').should == 'def'
156
182
  end
157
-
183
+
158
184
  it 'should provide facet helpers' do
159
185
  r = create_response
160
186
  r.facets.size.should == 2
161
-
187
+
162
188
  field_names = r.facets.collect{|facet|facet.name}
163
189
  field_names.include?('cat').should == true
164
190
  field_names.include?('manu').should == true
165
-
191
+
166
192
  first_facet = r.facets.first
167
193
  first_facet.name.should == 'cat'
168
-
194
+
169
195
  first_facet.items.size.should == 10
170
-
196
+
171
197
  expected = "electronics - 14, memory - 3, card - 2, connector - 2, drive - 2, graphics - 2, hard - 2, monitor - 2, search - 2, software - 2"
172
198
  received = first_facet.items.collect do |item|
173
199
  item.value + ' - ' + item.hits.to_s
174
200
  end.join(', ')
175
-
201
+
176
202
  expected.should == received
177
-
203
+
178
204
  r.facets.each do |facet|
179
205
  facet.respond_to?(:name).should == true
180
206
  facet.items.each do |item|
@@ -182,35 +208,69 @@ describe RSolr::Ext do
182
208
  item.respond_to?(:hits).should == true
183
209
  end
184
210
  end
185
-
211
+
186
212
  end
187
-
213
+
188
214
  it 'should return the correct value when calling facet_by_field_name' do
189
215
  r = create_response
190
216
  facet = r.facet_by_field_name('cat')
191
217
  facet.name.should == 'cat'
192
218
  end
193
-
219
+
194
220
  it 'should provide the responseHeader params' do
195
221
  raw_response = eval(mock_query_response)
196
222
  raw_response['responseHeader']['params']['test'] = :test
197
223
  r = RSolr::Ext::Response::Base.new(raw_response, '/catalog', raw_response['params'])
198
224
  r.params['test'].should == :test
199
225
  end
200
-
226
+
201
227
  it 'should provide the solr-returned params and "rows" should be 11' do
202
228
  raw_response = eval(mock_query_response)
203
229
  r = RSolr::Ext::Response::Base.new(raw_response, '/catalog', {})
204
230
  r.params[:rows].to_s.should == '11'
205
231
  end
206
-
232
+
207
233
  it 'should provide the ruby request params if responseHeader["params"] does not exist' do
208
234
  raw_response = eval(mock_query_response)
209
235
  raw_response.delete 'responseHeader'
210
236
  r = RSolr::Ext::Response::Base.new(raw_response, '/catalog', :rows => 999)
211
237
  r.params[:rows].to_s.should == '999'
212
238
  end
213
-
239
+
240
+ it 'should provide spelling suggestions for regular spellcheck results' do
241
+ raw_response = eval(mock_response_with_spellcheck)
242
+ r = RSolr::Ext::Response::Base.new(raw_response, '/catalog', {})
243
+ r.spelling.words.should include("dell")
244
+ r.spelling.words.should include("ultrasharp")
245
+ end
246
+
247
+ it 'should provide spelling suggestions for extended spellcheck results' do
248
+ raw_response = eval(mock_response_with_spellcheck_extended)
249
+ r = RSolr::Ext::Response::Base.new(raw_response, '/catalog', {})
250
+ r.spelling.words.should include("dell")
251
+ r.spelling.words.should include("ultrasharp")
252
+ end
253
+
254
+ it 'should provide no spelling suggestions when extended results and suggestion frequency is the same as original query frequency' do
255
+ raw_response = eval(mock_response_with_spellcheck_same_frequency)
256
+ r = RSolr::Ext::Response::Base.new(raw_response, '/catalog', {})
257
+ r.spelling.words.should == []
258
+ end
259
+
260
+ it 'should provide spelling suggestions for a regular spellcheck results with a collation' do
261
+ raw_response = eval(mock_response_with_spellcheck_collation)
262
+ r = RSolr::Ext::Response::Base.new(raw_response, '/catalog', {})
263
+ r.spelling.words.should include("dell")
264
+ r.spelling.words.should include("ultrasharp")
265
+ end
266
+
267
+ it 'should provide spelling suggestion collation' do
268
+ raw_response = eval(mock_response_with_spellcheck_collation)
269
+ r = RSolr::Ext::Response::Base.new(raw_response, '/catalog', {})
270
+ r.spelling.collation.should == 'dell ultrasharp'
271
+ end
272
+
214
273
  end
215
-
216
- end
274
+
275
+ end
276
+
data/spec/spec_helper.rb CHANGED
@@ -5,9 +5,28 @@ require 'spec'
5
5
  require 'spec/autorun'
6
6
 
7
7
  Spec::Runner.configure do |config|
8
-
8
+
9
9
  def mock_query_response
10
10
  %({'responseHeader'=>{'status'=>0,'QTime'=>5,'params'=>{'facet.limit'=>'10','wt'=>'ruby','rows'=>'11','facet'=>'true','facet.field'=>['manu','cat'],'echoParams'=>'EXPLICIT','q'=>'*:*','facet.sort'=>'true'}},'response'=>{'numFound'=>26,'start'=>0,'docs'=>[{'id'=>'SP2514N','inStock'=>true,'manu'=>'Samsung Electronics Co. Ltd.','name'=>'Samsung SpinPoint P120 SP2514N - hard drive - 250 GB - ATA-133','popularity'=>6,'price'=>92.0,'sku'=>'SP2514N','timestamp'=>'2009-03-20T14:42:49.795Z','cat'=>['electronics','hard drive'],'spell'=>['Samsung SpinPoint P120 SP2514N - hard drive - 250 GB - ATA-133'],'features'=>['7200RPM, 8MB cache, IDE Ultra ATA-133','NoiseGuard, SilentSeek technology, Fluid Dynamic Bearing (FDB) motor']},{'id'=>'6H500F0','inStock'=>true,'manu'=>'Maxtor Corp.','name'=>'Maxtor DiamondMax 11 - hard drive - 500 GB - SATA-300','popularity'=>6,'price'=>350.0,'sku'=>'6H500F0','timestamp'=>'2009-03-20T14:42:49.877Z','cat'=>['electronics','hard drive'],'spell'=>['Maxtor DiamondMax 11 - hard drive - 500 GB - SATA-300'],'features'=>['SATA 3.0Gb/s, NCQ','8.5ms seek','16MB cache']},{'id'=>'F8V7067-APL-KIT','inStock'=>false,'manu'=>'Belkin','name'=>'Belkin Mobile Power Cord for iPod w/ Dock','popularity'=>1,'price'=>19.95,'sku'=>'F8V7067-APL-KIT','timestamp'=>'2009-03-20T14:42:49.937Z','weight'=>4.0,'cat'=>['electronics','connector'],'spell'=>['Belkin Mobile Power Cord for iPod w/ Dock'],'features'=>['car power adapter, white']},{'id'=>'IW-02','inStock'=>false,'manu'=>'Belkin','name'=>'iPod & iPod Mini USB 2.0 Cable','popularity'=>1,'price'=>11.5,'sku'=>'IW-02','timestamp'=>'2009-03-20T14:42:49.944Z','weight'=>2.0,'cat'=>['electronics','connector'],'spell'=>['iPod & iPod Mini USB 2.0 Cable'],'features'=>['car power adapter for iPod, white']},{'id'=>'MA147LL/A','inStock'=>true,'includes'=>'earbud headphones, USB cable','manu'=>'Apple Computer Inc.','name'=>'Apple 60 GB iPod with Video Playback Black','popularity'=>10,'price'=>399.0,'sku'=>'MA147LL/A','timestamp'=>'2009-03-20T14:42:49.962Z','weight'=>5.5,'cat'=>['electronics','music'],'spell'=>['Apple 60 GB iPod with Video Playback Black'],'features'=>['iTunes, Podcasts, Audiobooks','Stores up to 15,000 songs, 25,000 photos, or 150 hours of video','2.5-inch, 320x240 color TFT LCD display with LED backlight','Up to 20 hours of battery life','Plays AAC, MP3, WAV, AIFF, Audible, Apple Lossless, H.264 video','Notes, Calendar, Phone book, Hold button, Date display, Photo wallet, Built-in games, JPEG photo playback, Upgradeable firmware, USB 2.0 compatibility, Playback speed control, Rechargeable capability, Battery level indication']},{'id'=>'TWINX2048-3200PRO','inStock'=>true,'manu'=>'Corsair Microsystems Inc.','name'=>'CORSAIR XMS 2GB (2 x 1GB) 184-Pin DDR SDRAM Unbuffered DDR 400 (PC 3200) Dual Channel Kit System Memory - Retail','popularity'=>5,'price'=>185.0,'sku'=>'TWINX2048-3200PRO','timestamp'=>'2009-03-20T14:42:49.99Z','cat'=>['electronics','memory'],'spell'=>['CORSAIR XMS 2GB (2 x 1GB) 184-Pin DDR SDRAM Unbuffered DDR 400 (PC 3200) Dual Channel Kit System Memory - Retail'],'features'=>['CAS latency 2, 2-3-3-6 timing, 2.75v, unbuffered, heat-spreader']},{'id'=>'VS1GB400C3','inStock'=>true,'manu'=>'Corsair Microsystems Inc.','name'=>'CORSAIR ValueSelect 1GB 184-Pin DDR SDRAM Unbuffered DDR 400 (PC 3200) System Memory - Retail','popularity'=>7,'price'=>74.99,'sku'=>'VS1GB400C3','timestamp'=>'2009-03-20T14:42:50Z','cat'=>['electronics','memory'],'spell'=>['CORSAIR ValueSelect 1GB 184-Pin DDR SDRAM Unbuffered DDR 400 (PC 3200) System Memory - Retail']},{'id'=>'VDBDB1A16','inStock'=>true,'manu'=>'A-DATA Technology Inc.','name'=>'A-DATA V-Series 1GB 184-Pin DDR SDRAM Unbuffered DDR 400 (PC 3200) System Memory - OEM','popularity'=>5,'sku'=>'VDBDB1A16','timestamp'=>'2009-03-20T14:42:50.004Z','cat'=>['electronics','memory'],'spell'=>['A-DATA V-Series 1GB 184-Pin DDR SDRAM Unbuffered DDR 400 (PC 3200) System Memory - OEM'],'features'=>['CAS latency 3, 2.7v']},{'id'=>'3007WFP','inStock'=>true,'includes'=>'USB cable','manu'=>'Dell, Inc.','name'=>'Dell Widescreen UltraSharp 3007WFP','popularity'=>6,'price'=>2199.0,'sku'=>'3007WFP','timestamp'=>'2009-03-20T14:42:50.017Z','weight'=>401.6,'cat'=>['electronics','monitor'],'spell'=>['Dell Widescreen UltraSharp 3007WFP'],'features'=>['30" TFT active matrix LCD, 2560 x 1600, .25mm dot pitch, 700:1 contrast']},{'id'=>'VA902B','inStock'=>true,'manu'=>'ViewSonic Corp.','name'=>'ViewSonic VA902B - flat panel display - TFT - 19"','popularity'=>6,'price'=>279.95,'sku'=>'VA902B','timestamp'=>'2009-03-20T14:42:50.034Z','weight'=>190.4,'cat'=>['electronics','monitor'],'spell'=>['ViewSonic VA902B - flat panel display - TFT - 19"'],'features'=>['19" TFT active matrix LCD, 8ms response time, 1280 x 1024 native resolution']},{'id'=>'0579B002','inStock'=>true,'manu'=>'Canon Inc.','name'=>'Canon PIXMA MP500 All-In-One Photo Printer','popularity'=>6,'price'=>179.99,'sku'=>'0579B002','timestamp'=>'2009-03-20T14:42:50.062Z','weight'=>352.0,'cat'=>['electronics','multifunction printer','printer','scanner','copier'],'spell'=>['Canon PIXMA MP500 All-In-One Photo Printer'],'features'=>['Multifunction ink-jet color photo printer','Flatbed scanner, optical scan resolution of 1,200 x 2,400 dpi','2.5" color LCD preview screen','Duplex Copying','Printing speed up to 29ppm black, 19ppm color','Hi-Speed USB','memory card: CompactFlash, Micro Drive, SmartMedia, Memory Stick, Memory Stick Pro, SD Card, and MultiMediaCard']}]},'facet_counts'=>{'facet_queries'=>{},'facet_fields'=>{'manu'=>['inc',8,'apach',2,'belkin',2,'canon',2,'comput',2,'corp',2,'corsair',2,'foundat',2,'microsystem',2,'softwar',2],'cat'=>['electronics',14,'memory',3,'card',2,'connector',2,'drive',2,'graphics',2,'hard',2,'monitor',2,'search',2,'software',2]},'facet_dates'=>{}}})
11
11
  end
12
-
13
- end
12
+
13
+ # These spellcheck responses are all Solr 1.4 responses
14
+ def mock_response_with_spellcheck
15
+ %|{'responseHeader'=>{'status'=>0,'QTime'=>9,'params'=>{'spellcheck'=>'true','spellcheck.collate'=>'true','wt'=>'ruby','q'=>'hell ultrashar'}},'response'=>{'numFound'=>0,'start'=>0,'docs'=>[]},'spellcheck'=>{'suggestions'=>['hell',{'numFound'=>1,'startOffset'=>0,'endOffset'=>4,'suggestion'=>['dell']},'ultrashar',{'numFound'=>1,'startOffset'=>5,'endOffset'=>14,'suggestion'=>['ultrasharp']},'collation','dell ultrasharp']}}|
16
+ end
17
+
18
+ def mock_response_with_spellcheck_extended
19
+ %|{'responseHeader'=>{'status'=>0,'QTime'=>8,'params'=>{'spellcheck'=>'true','spellcheck.collate'=>'true','wt'=>'ruby','spellcheck.extendedResults'=>'true','q'=>'hell ultrashar'}},'response'=>{'numFound'=>0,'start'=>0,'docs'=>[]},'spellcheck'=>{'suggestions'=>['hell',{'numFound'=>1,'startOffset'=>0,'endOffset'=>4,'origFreq'=>0,'suggestion'=>[{'word'=>'dell','freq'=>1}]},'ultrashar',{'numFound'=>1,'startOffset'=>5,'endOffset'=>14,'origFreq'=>0,'suggestion'=>[{'word'=>'ultrasharp','freq'=>1}]},'correctlySpelled',false,'collation','dell ultrasharp']}}|
20
+ end
21
+
22
+ def mock_response_with_spellcheck_same_frequency
23
+ %|{'responseHeader'=>{'status'=>0,'QTime'=>8,'params'=>{'spellcheck'=>'true','spellcheck.collate'=>'true','wt'=>'ruby','spellcheck.extendedResults'=>'true','q'=>'hell ultrashar'}},'response'=>{'numFound'=>0,'start'=>0,'docs'=>[]},'spellcheck'=>{'suggestions'=>['hell',{'numFound'=>1,'startOffset'=>0,'endOffset'=>4,'origFreq'=>1,'suggestion'=>[{'word'=>'dell','freq'=>1}]},'ultrashard',{'numFound'=>1,'startOffset'=>5,'endOffset'=>14,'origFreq'=>1,'suggestion'=>[{'word'=>'ultrasharp','freq'=>1}]},'correctlySpelled',false,'collation','dell ultrasharp']}}|
24
+ end
25
+
26
+ # it can be the case that extended results are off and collation is on
27
+ def mock_response_with_spellcheck_collation
28
+ %|{'responseHeader'=>{'status'=>0,'QTime'=>3,'params'=>{'spellspellcheck.build'=>'true','spellcheck'=>'true','q'=>'hell','spellcheck.q'=>'hell ultrashar','wt'=>'ruby','spellcheck.collate'=>'true'}},'response'=>{'numFound'=>0,'start'=>0,'docs'=>[]},'spellcheck'=>{'suggestions'=>['hell',{'numFound'=>1,'startOffset'=>0,'endOffset'=>4,'suggestion'=>['dell']},'ultrashar',{'numFound'=>1,'startOffset'=>5,'endOffset'=>14,'suggestion'=>['ultrasharp']},'collation','dell ultrasharp']}}|
29
+ end
30
+
31
+ end
32
+
metadata CHANGED
@@ -1,7 +1,12 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rsolr-ext
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.12.0
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 12
8
+ - 1
9
+ version: 0.12.1
5
10
  platform: ruby
6
11
  authors:
7
12
  - Matt Mitchell
@@ -9,29 +14,37 @@ autorequire:
9
14
  bindir: bin
10
15
  cert_chain: []
11
16
 
12
- date: 2010-02-09 00:00:00 -05:00
17
+ date: 2010-08-04 00:00:00 -04:00
13
18
  default_executable:
14
19
  dependencies:
15
20
  - !ruby/object:Gem::Dependency
16
21
  name: rspec
17
- type: :development
18
- version_requirement:
19
- version_requirements: !ruby/object:Gem::Requirement
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
20
24
  requirements:
21
25
  - - ">="
22
26
  - !ruby/object:Gem::Version
27
+ segments:
28
+ - 1
29
+ - 2
30
+ - 9
23
31
  version: 1.2.9
24
- version:
32
+ type: :development
33
+ version_requirements: *id001
25
34
  - !ruby/object:Gem::Dependency
26
35
  name: rsolr
27
- type: :runtime
28
- version_requirement:
29
- version_requirements: !ruby/object:Gem::Requirement
36
+ prerelease: false
37
+ requirement: &id002 !ruby/object:Gem::Requirement
30
38
  requirements:
31
39
  - - ">="
32
40
  - !ruby/object:Gem::Version
41
+ segments:
42
+ - 0
43
+ - 12
44
+ - 1
33
45
  version: 0.12.1
34
- version:
46
+ type: :runtime
47
+ version_requirements: *id002
35
48
  description: A query/response extension lib for RSolr
36
49
  email: goodieboy@gmail.com
37
50
  executables: []
@@ -68,18 +81,20 @@ required_ruby_version: !ruby/object:Gem::Requirement
68
81
  requirements:
69
82
  - - ">="
70
83
  - !ruby/object:Gem::Version
84
+ segments:
85
+ - 0
71
86
  version: "0"
72
- version:
73
87
  required_rubygems_version: !ruby/object:Gem::Requirement
74
88
  requirements:
75
89
  - - ">="
76
90
  - !ruby/object:Gem::Version
91
+ segments:
92
+ - 0
77
93
  version: "0"
78
- version:
79
94
  requirements: []
80
95
 
81
96
  rubyforge_project:
82
- rubygems_version: 1.3.5
97
+ rubygems_version: 1.3.6
83
98
  signing_key:
84
99
  specification_version: 3
85
100
  summary: A query/response extension lib for RSolr