sunspot 0.10.6 → 0.10.7

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/History.txt CHANGED
@@ -1,3 +1,10 @@
1
+ == 0.10.7 2009-11-16
2
+ * Ignore boost_fields that don't apply
3
+ * Ability to specify text_fields inside connectives
4
+ * Fix bug with newlines in strings incorrectly being considered multi-value
5
+ * Compatibility with RSolr 0.10.1
6
+ * Remove commented-out code entirely
7
+
1
8
  == 0.10.6 2009-11-05
2
9
  * Support more dismax parameters
3
10
  * Support multiple boost queries
data/README.rdoc CHANGED
@@ -125,7 +125,7 @@ me so I can rectify the situation!
125
125
 
126
126
  == Dependencies
127
127
 
128
- 1. RSolr 0.9.6
128
+ 1. RSolr 0.10.1
129
129
  2. Daemons 1.x
130
130
  4. Java 1.5+
131
131
 
@@ -184,6 +184,7 @@ Sunspot repository at `upstream`:
184
184
  * Peter Berkenbosch (peterberkenbosch@me.com)
185
185
  * Brian Atkinson
186
186
  * Tom Coleman (tom@thesnail.org)
187
+ * Matt Mitchell (goodieboy@gmail.com)
187
188
 
188
189
  == License
189
190
 
data/TODO CHANGED
@@ -1,4 +1,8 @@
1
1
  === 0.10.x ===
2
+ * Can retrieve facets from search via string
3
+ * Allow #latitude and #longitude as coordinate attributes
4
+ * Allow use of #text_fields from inside disjunction
5
+
2
6
  * Assumed inconsistency
3
7
  * Support all operations in batches. Make it smart.
4
8
  * Don't use more than one commits when one is equivalent
data/VERSION.yml CHANGED
@@ -1,4 +1,4 @@
1
1
  ---
2
2
  :minor: 10
3
- :patch: 6
3
+ :patch: 7
4
4
  :major: 0
data/lib/sunspot.rb CHANGED
@@ -161,7 +161,7 @@ module Sunspot
161
161
  #
162
162
  # ==== Example
163
163
  #
164
- # post1, post2 = Array(2) { Post.create }
164
+ # post1, post2 = new Array(2) { Post.create }
165
165
  # Sunspot.index(post1, post2)
166
166
  #
167
167
  # Note that indexed objects won't be reflected in search until a commit is
@@ -94,7 +94,7 @@ module Sunspot
94
94
  # One or more classes that this instance adapter adapts
95
95
  #
96
96
  def register(instance_adapter, *classes)
97
- for clazz in classes
97
+ classes.each do |clazz|
98
98
  instance_adapters[clazz.name.to_sym] = instance_adapter
99
99
  end
100
100
  end
@@ -216,7 +216,7 @@ module Sunspot
216
216
  # One or more classes that this data accessor providess access to
217
217
  #
218
218
  def register(data_accessor, *classes)
219
- for clazz in classes
219
+ classes.each do |clazz|
220
220
  data_accessors[clazz.name.to_sym] = data_accessor
221
221
  end
222
222
  end
@@ -29,9 +29,6 @@ module Sunspot
29
29
  #
30
30
  def build #:nodoc:
31
31
  LightConfig.build do
32
- http_client :net_http
33
- xml_builder :builder
34
-
35
32
  solr do
36
33
  url 'http://127.0.0.1:8983/solr'
37
34
  end
@@ -84,7 +84,7 @@ module Sunspot
84
84
  field_names.each do |field_name|
85
85
  field = @setup.field(field_name)
86
86
  search_facet = @search.add_field_facet(field, options)
87
- Array(options[:only]).each do |value|
87
+ Util.Array(options[:only]).each do |value|
88
88
  facet = Sunspot::Query::QueryFacet.new
89
89
  facet.add_restriction(field, Sunspot::Query::Restriction::EqualTo, value)
90
90
  @query.add_query_facet(facet)
@@ -110,7 +110,7 @@ module Sunspot
110
110
  Sunspot::Query::FieldFacet.new(field, options)
111
111
  end
112
112
  @query.add_field_facet(facet)
113
- Array(options[:extra]).each do |extra|
113
+ Util.Array(options[:extra]).each do |extra|
114
114
  extra_facet = Sunspot::Query::QueryFacet.new
115
115
  case extra
116
116
  when :any
@@ -34,7 +34,7 @@ module Sunspot
34
34
  #
35
35
  def text(*names, &block)
36
36
  options = names.pop if names.last.is_a?(Hash)
37
- for name in names
37
+ names.each do |name|
38
38
  @setup.add_text_field_factory(
39
39
  name,
40
40
  options || {},
@@ -179,8 +179,12 @@ module Sunspot
179
179
  #
180
180
  def boost_fields(boosts)
181
181
  boosts.each_pair do |field_name, boost|
182
- @setup.text_fields(field_name).each do |field|
183
- @query.add_fulltext_field(field, boost)
182
+ begin
183
+ @setup.text_fields(field_name).each do |field|
184
+ @query.add_fulltext_field(field, boost)
185
+ end
186
+ rescue Sunspot::UnrecognizedFieldError
187
+ # We'll let this one slide.
184
188
  end
185
189
  end
186
190
  end
@@ -55,7 +55,7 @@ module Sunspot
55
55
  if keywords && !(keywords.to_s =~ /^\s*$/)
56
56
  fulltext_query = @query.set_fulltext(keywords)
57
57
  if field_names = options.delete(:fields)
58
- Array(field_names).each do |field_name|
58
+ Util.Array(field_names).each do |field_name|
59
59
  @setup.text_fields(field_name).each do |field|
60
60
  fulltext_query.add_fulltext_field(field, field.default_boost)
61
61
  end
@@ -75,7 +75,7 @@ module Sunspot
75
75
  fulltext_query.add_highlight
76
76
  else
77
77
  highlight_fields = []
78
- Array(highlight_field_names).each do |field_name|
78
+ Util.Array(highlight_field_names).each do |field_name|
79
79
  highlight_fields.concat(@setup.text_fields(field_name))
80
80
  end
81
81
  fulltext_query.add_highlight(highlight_fields)
@@ -157,31 +157,6 @@ module Sunspot
157
157
  def near(coordinates, miles)
158
158
  @query.add_location_restriction(coordinates, miles)
159
159
  end
160
-
161
- #
162
- # Apply scope-type restrictions on fulltext fields. In certain situations,
163
- # it may be desirable to place logical restrictions on text fields.
164
- # Remember that text fields are tokenized; your mileage may very.
165
- #
166
- # The block works exactly like a normal scope, except that the field names
167
- # refer to text fields instead of attribute fields.
168
- #
169
- # === Example
170
- #
171
- # Sunspot.search(Post) do
172
- # text_fields do
173
- # with :body, nil
174
- # end
175
- # end
176
- #
177
- # This will return all documents that do not have a body.
178
- #
179
- def text_fields(&block)
180
- Sunspot::Util.instance_eval_or_call(
181
- Scope.new(@scope, TextFieldSetup.new(@setup)),
182
- &block
183
- )
184
- end
185
160
  end
186
161
  end
187
162
  end
@@ -117,7 +117,7 @@ module Sunspot
117
117
  end
118
118
  else
119
119
  instances = args
120
- for instance in instances.flatten
120
+ instances.flatten.each do |instance|
121
121
  @scope.add_negated_restriction(
122
122
  IdField.instance,
123
123
  Sunspot::Query::Restriction::EqualTo,
@@ -195,6 +195,31 @@ module Sunspot
195
195
  &block
196
196
  )
197
197
  end
198
+
199
+ #
200
+ # Apply scope-type restrictions on fulltext fields. In certain situations,
201
+ # it may be desirable to place logical restrictions on text fields.
202
+ # Remember that text fields are tokenized; your mileage may very.
203
+ #
204
+ # The block works exactly like a normal scope, except that the field names
205
+ # refer to text fields instead of attribute fields.
206
+ #
207
+ # === Example
208
+ #
209
+ # Sunspot.search(Post) do
210
+ # text_fields do
211
+ # with :body, nil
212
+ # end
213
+ # end
214
+ #
215
+ # This will return all documents that do not have a body.
216
+ #
217
+ def text_fields(&block)
218
+ Sunspot::Util.instance_eval_or_call(
219
+ Scope.new(@scope, TextFieldSetup.new(@setup)),
220
+ &block
221
+ )
222
+ end
198
223
  end
199
224
  end
200
225
  end
@@ -56,7 +56,7 @@ module Sunspot
56
56
  #
57
57
  def populate_document(document, model) #:nodoc:
58
58
  unless (value = @data_extractor.value_for(model)).nil?
59
- for scalar_value in Array(@field.to_indexed(value))
59
+ Util.Array(@field.to_indexed(value)).each do |scalar_value|
60
60
  document.add_field(
61
61
  @field.indexed_name.to_sym,
62
62
  scalar_value, @field.attributes
@@ -105,7 +105,7 @@ module Sunspot
105
105
  if values = @data_extractor.value_for(model)
106
106
  values.each_pair do |dynamic_name, value|
107
107
  field_instance = build(dynamic_name)
108
- for scalar_value in Array(field_instance.to_indexed(value))
108
+ Util.Array(field_instance.to_indexed(value)).each do |scalar_value|
109
109
  document.add_field(
110
110
  field_instance.indexed_name.to_sym,
111
111
  scalar_value
@@ -21,7 +21,7 @@ module Sunspot
21
21
  # model<Object>:: the model to index
22
22
  #
23
23
  def add(model)
24
- documents = Array(model).map { |m| prepare(m) }
24
+ documents = Util.Array(model).map { |m| prepare(m) }
25
25
  if @batch.nil?
26
26
  add_documents(documents)
27
27
  else
@@ -75,7 +75,7 @@ module Sunspot
75
75
  if boost = setup.document_boost_for(model)
76
76
  document.attrs[:boost] = boost
77
77
  end
78
- for field_factory in setup.all_field_factories
78
+ setup.all_field_factories.each do |field_factory|
79
79
  field_factory.populate_document(document, model)
80
80
  end
81
81
  document
@@ -105,7 +105,7 @@ module Sunspot
105
105
  #
106
106
  def negate
107
107
  negated = self.class.new(!negated?)
108
- for component in @components
108
+ @components.each do |component|
109
109
  negated.add_component(component)
110
110
  end
111
111
  negated
@@ -157,7 +157,7 @@ module Sunspot
157
157
  #
158
158
  def denormalize
159
159
  denormalized = self.class.inverse.new(!negated?)
160
- for component in @components
160
+ @components.each do |component|
161
161
  denormalized.add_component(component.negate)
162
162
  end
163
163
  denormalized
@@ -47,8 +47,8 @@ module Sunspot
47
47
  #
48
48
  def dynamic_fields
49
49
  fields = []
50
- for field_variants in variant_combinations
51
- for type in FIELD_TYPES
50
+ variant_combinations.each do |field_variants|
51
+ FIELD_TYPES.each do |type|
52
52
  fields << DynamicField.new(type, field_variants)
53
53
  end
54
54
  end
@@ -94,7 +94,7 @@ module Sunspot
94
94
  def remove(*objects)
95
95
  objects.flatten!
96
96
  @deletes += objects.length
97
- for object in objects
97
+ objects.each do |object|
98
98
  indexer.remove(object)
99
99
  end
100
100
  end
@@ -138,9 +138,7 @@ module Sunspot
138
138
  Indexer.remove_all(master_connection)
139
139
  else
140
140
  @deletes += classes.length
141
- for clazz in classes
142
- indexer.remove_all(clazz)
143
- end
141
+ classes.each { |clazz| indexer.remove_all(clazz) }
144
142
  end
145
143
  end
146
144
 
@@ -203,13 +201,8 @@ module Sunspot
203
201
  @connection ||=
204
202
  begin
205
203
  connection = self.class.connection_class.connect(
206
- :url => config.solr.url,
207
- :adapter => config.http_client
204
+ :url => config.solr.url
208
205
  )
209
- connection.message.adapter =
210
- RSolr::Message::Adapter.const_get(
211
- Util.camel_case(config.xml_builder.to_s)
212
- ).new
213
206
  connection
214
207
  end
215
208
  end
@@ -227,9 +220,8 @@ module Sunspot
227
220
  begin
228
221
  if config.master_solr.url && config.master_solr.url != config.solr.url
229
222
  master_connection = self.class.connection_class.new(
230
- RSolr::Adapter::HTTP.new(:url => config.master_solr.url)
223
+ RSolr::Connection::NetHttp.new(:url => config.master_solr.url)
231
224
  )
232
- master_connection.adapter.connector.adapter_name = config.http_client
233
225
  master_connection
234
226
  else
235
227
  connection
data/lib/sunspot/util.rb CHANGED
@@ -95,6 +95,18 @@ module Sunspot
95
95
  end
96
96
  end
97
97
 
98
+ #
99
+ # Ruby's treatment of Strings as Enumerables is heavily annoying. As far
100
+ # as I know the behavior of Kernel.Array() is otherwise fine.
101
+ #
102
+ def Array(object)
103
+ if object.is_a?(String)
104
+ [object]
105
+ else
106
+ super
107
+ end
108
+ end
109
+
98
110
  #
99
111
  # Perform a deep merge of hashes, returning the result as a new hash.
100
112
  # See #deep_merge_into for rules used to merge the hashes
@@ -21,6 +21,11 @@ describe 'indexing attribute fields', :type => :indexer do
21
21
  connection.should have_add_with(:category_ids_im => ['3', '14'])
22
22
  end
23
23
 
24
+ it 'should not index a single-value field with newlines as multiple' do
25
+ session.index(post(:title => "Multi\nLine"))
26
+ connection.adds.last.first.field_by_name(:title_ss).value.should == "Multi\nLine"
27
+ end
28
+
24
29
  it 'should correctly index a time field' do
25
30
  session.index(
26
31
  post(:published_at => Time.parse('1983-07-08 05:00:00 -0400'))
@@ -153,6 +153,20 @@ describe 'connective in scope', :type => :query do
153
153
  )
154
154
  end
155
155
 
156
+ it 'creates a disjunction with some text field components' do
157
+ session.search Post do
158
+ any_of do
159
+ text_fields do
160
+ with(:title).starting_with('test')
161
+ end
162
+ with(:blog_id, 1)
163
+ end
164
+ end
165
+ connection.should have_last_search_including(
166
+ :fq, '(title_text:test* OR blog_id_i:1)'
167
+ )
168
+ end
169
+
156
170
  it 'should ignore empty connectives' do
157
171
  session.search Post do
158
172
  any_of {}
@@ -151,6 +151,15 @@ describe 'fulltext query', :type => :query do
151
151
  connection.searches.last[:qf].split(' ').sort.should == %w(backwards_title_text body_texts title_text^1.5)
152
152
  end
153
153
 
154
+ it 'ignores boost fields that do not apply' do
155
+ session.search Post do
156
+ keywords 'great pizza' do
157
+ boost_fields :bogus => 1.2, :title => 1.5
158
+ end
159
+ end
160
+ connection.searches.last[:qf].split(' ').sort.should == %w(backwards_title_text body_texts title_text^1.5)
161
+ end
162
+
154
163
  it 'sets default boost with default fields' do
155
164
  session.search Photo do
156
165
  keywords 'great pizza'
@@ -75,23 +75,6 @@ describe 'Session' do
75
75
  Sunspot.commit
76
76
  connection.opts[:url].should == 'http://127.0.0.1:8981/solr'
77
77
  end
78
-
79
- it 'should use Net::HTTP adapter by default' do
80
- Sunspot.commit
81
- connection.adapter.should == :net_http
82
- end
83
-
84
- it 'should use Net::HTTP adapter when specified' do
85
- Sunspot.config.http_client = :curb
86
- Sunspot.commit
87
- connection.adapter.should == :curb
88
- end
89
-
90
- it 'should use LibXML builder when specified' do
91
- Sunspot.config.xml_builder = :libxml
92
- Sunspot.commit
93
- connection.message.adapter.should be_a(RSolr::Message::Adapter::Libxml)
94
- end
95
78
  end
96
79
 
97
80
  context 'custom session' do
@@ -0,0 +1,7 @@
1
+ describe 'indexing' do
2
+ it 'should index non-multivalued field with newlines' do
3
+ lambda do
4
+ Sunspot.index!(Post.new(:title => "A\nTitle"))
5
+ end.should_not raise_error(RSolr::RequestError)
6
+ end
7
+ end
data/spec/spec_helper.rb CHANGED
@@ -1,4 +1,12 @@
1
1
  using_gems = false
2
+
3
+ if rsolr_gem_version = ENV['RSOLR_GEM_VERSION']
4
+ STDERR.puts("Forcing RSolr gem version #{rsolr_gem_version}")
5
+ using_gems = true
6
+ require 'rubygems'
7
+ gem 'rsolr', rsolr_gem_version
8
+ end
9
+
2
10
  begin
3
11
  require 'spec'
4
12
  begin
data/tasks/gemspec.rake CHANGED
@@ -11,10 +11,10 @@ begin
11
11
  s.description = <<TEXT
12
12
  Sunspot is a library providing a powerful, all-ruby API for the Solr search engine. Sunspot manages the configuration of persistent Ruby classes for search and indexing and exposes Solr's most powerful features through a collection of DSLs. Complex search operations can be performed without hand-writing any boolean queries or building Solr parameters by hand.
13
13
  TEXT
14
- s.authors = ['Mat Brown', 'Peer Allan', 'Dmitriy Dzema', 'Benjamin Krause', 'Marcel de Graaf', 'Brandon Keepers', 'Peter Berkenbosch', 'Brian Atkinson', 'Tom Coleman']
14
+ s.authors = ['Mat Brown', 'Peer Allan', 'Dmitriy Dzema', 'Benjamin Krause', 'Marcel de Graaf', 'Brandon Keepers', 'Peter Berkenbosch', 'Brian Atkinson', 'Tom Coleman', 'Matt Mitchell']
15
15
  s.rubyforge_project = 'sunspot'
16
16
  s.files = FileList['[A-Z]*', '{bin,lib,spec,tasks,templates}/**/*', 'solr/{etc,lib,webapps}/**/*', 'solr/solr/{conf,lib}/*', 'solr/start.jar']
17
- s.add_dependency 'rsolr', '= 0.9.6'
17
+ s.add_dependency 'rsolr', '>= 0.9.6', '<= 0.10.1'
18
18
  s.add_dependency 'daemons', '~> 1.0'
19
19
  s.add_development_dependency 'rspec', '~> 1.1'
20
20
  s.add_development_dependency 'ruby-debug', '~> 0.10'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sunspot
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.10.6
4
+ version: 0.10.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mat Brown
@@ -13,11 +13,12 @@ authors:
13
13
  - Peter Berkenbosch
14
14
  - Brian Atkinson
15
15
  - Tom Coleman
16
+ - Matt Mitchell
16
17
  autorequire:
17
18
  bindir: bin
18
19
  cert_chain: []
19
20
 
20
- date: 2009-11-05 00:00:00 -05:00
21
+ date: 2009-11-16 00:00:00 -05:00
21
22
  default_executable:
22
23
  dependencies:
23
24
  - !ruby/object:Gem::Dependency
@@ -26,9 +27,12 @@ dependencies:
26
27
  version_requirement:
27
28
  version_requirements: !ruby/object:Gem::Requirement
28
29
  requirements:
29
- - - "="
30
+ - - ">="
30
31
  - !ruby/object:Gem::Version
31
32
  version: 0.9.6
33
+ - - <=
34
+ - !ruby/object:Gem::Version
35
+ version: 0.10.1
32
36
  version:
33
37
  - !ruby/object:Gem::Dependency
34
38
  name: daemons
@@ -198,6 +202,7 @@ files:
198
202
  - spec/integration/dynamic_fields_spec.rb
199
203
  - spec/integration/faceting_spec.rb
200
204
  - spec/integration/highlighting_spec.rb
205
+ - spec/integration/indexing_spec.rb
201
206
  - spec/integration/keyword_search_spec.rb
202
207
  - spec/integration/local_search_spec.rb
203
208
  - spec/integration/scoped_search_spec.rb
@@ -266,6 +271,7 @@ test_files:
266
271
  - spec/integration/scoped_search_spec.rb
267
272
  - spec/integration/highlighting_spec.rb
268
273
  - spec/integration/keyword_search_spec.rb
274
+ - spec/integration/indexing_spec.rb
269
275
  - spec/integration/dynamic_fields_spec.rb
270
276
  - spec/integration/stored_fields_spec.rb
271
277
  - spec/integration/test_pagination.rb