sunspot 2.0.0.pre.120925 → 2.0.0.pre.130115

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.
@@ -70,8 +70,6 @@ module Sunspot
70
70
  #
71
71
  # field_name<Symbol>:: the field to use for grouping
72
72
  def group(*field_names, &block)
73
- options = Sunspot::Util.extract_options_from(field_names)
74
-
75
73
  field_names.each do |field_name|
76
74
  field = @setup.field(field_name)
77
75
  group = @query.add_group(Sunspot::Query::FieldGroup.new(field))
@@ -5,8 +5,6 @@ module Sunspot
5
5
  # handler.
6
6
  #
7
7
  class Fulltext
8
- attr_reader :exclude_fields #:nodoc:
9
-
10
8
  # accept function in boost
11
9
  include Functional
12
10
 
data/lib/sunspot/field.rb CHANGED
@@ -12,6 +12,7 @@ module Sunspot
12
12
  @name, @type = name.to_sym, type
13
13
  @stored = !!options.delete(:stored)
14
14
  @more_like_this = !!options.delete(:more_like_this)
15
+ @multiple ||= false
15
16
  set_indexed_name(options)
16
17
  raise ArgumentError, "Field of type #{type} cannot be used for more_like_this" unless type.accepts_more_like_this? or !@more_like_this
17
18
  end
@@ -34,7 +35,7 @@ module Sunspot
34
35
  #
35
36
  def to_indexed(value)
36
37
  if value.is_a? Array
37
- if @multiple
38
+ if multiple?
38
39
  value.map { |val| to_indexed(val) }
39
40
  else
40
41
  raise ArgumentError, "#{name} is not a multiple-value field, so it cannot index values #{value.inspect}"
@@ -106,7 +107,7 @@ module Sunspot
106
107
  if options[:as]
107
108
  options.delete(:as).to_s
108
109
  else
109
- "#{@type.indexed_name(@name).to_s}#{'m' if @multiple }#{'s' if @stored}#{'v' if more_like_this?}"
110
+ "#{@type.indexed_name(@name).to_s}#{'m' if multiple? }#{'s' if @stored}#{'v' if more_like_this?}"
110
111
  end
111
112
  end
112
113
 
@@ -10,6 +10,9 @@ module Sunspot
10
10
  else
11
11
  @scope.add_positive_restriction(TypeField.instance, Restriction::AnyOf, types)
12
12
  end
13
+
14
+ @pagination = nil
15
+ @parameter_adjustment = nil
13
16
  end
14
17
 
15
18
  def solr_parameter_adjustment=(block)
@@ -15,6 +15,12 @@ module Sunspot
15
15
  @boost_queries = []
16
16
  @boost_functions = []
17
17
  @highlights = []
18
+
19
+ @minimum_match = nil
20
+ @phrase_fields = nil
21
+ @phrase_slop = nil
22
+ @query_phrase_slop = nil
23
+ @tie = nil
18
24
  end
19
25
 
20
26
  #
@@ -31,7 +31,7 @@ module Sunspot
31
31
  # to include a tag in the local params.
32
32
  #
33
33
  def tagged?
34
- !!@tag
34
+ defined?(@tag) && !!@tag
35
35
  end
36
36
  end
37
37
  end
@@ -5,6 +5,11 @@ module Sunspot
5
5
  #
6
6
  class FunctionQuery
7
7
  include RSolr::Char
8
+
9
+ def ^(y)
10
+ @boost_amount = y
11
+ self
12
+ end
8
13
  end
9
14
 
10
15
  #
@@ -16,7 +21,7 @@ module Sunspot
16
21
  end
17
22
 
18
23
  def to_s
19
- Type.to_literal(@constant)
24
+ Type.to_literal(@constant) << (@boost_amount ? "^#{@boost_amount}" : "")
20
25
  end
21
26
  end
22
27
 
@@ -29,7 +34,7 @@ module Sunspot
29
34
  end
30
35
 
31
36
  def to_s
32
- "#{escape(@field.indexed_name)}"
37
+ "#{escape(@field.indexed_name)}" << (@boost_amount ? "^#{@boost_amount}" : "")
33
38
  end
34
39
  end
35
40
 
@@ -45,7 +50,7 @@ module Sunspot
45
50
 
46
51
  def to_s
47
52
  params = @function_args.map { |arg| arg.to_s }.join(",")
48
- "#{@function_name}(#{params})"
53
+ "#{@function_name}(#{params})" << (@boost_amount ? "^#{@boost_amount}" : "")
49
54
  end
50
55
  end
51
56
  end
@@ -1,6 +1,6 @@
1
1
  begin
2
2
  require 'geohash'
3
- rescue LoadError => e
3
+ rescue LoadError
4
4
  require 'pr_geohash'
5
5
  end
6
6
 
@@ -1,15 +1,49 @@
1
1
  module Sunspot
2
2
  module Query
3
+
3
4
  class RangeFacet < AbstractFieldFacet
5
+ def initialize(field, options)
6
+ if exclude_filters = options[:exclude]
7
+ @exclude_tag = Util.Array(exclude_filters).map do |filter|
8
+ filter.tag
9
+ end.join(',')
10
+ end
11
+ super
12
+ end
13
+
4
14
  def to_params
5
15
  params = super
6
- params[:"facet.range"] = [@field.indexed_name]
16
+ params[:"facet.range"] = [field_name_with_local_params]
7
17
  params[qualified_param('range.start')] = @field.to_indexed(@options[:range].first)
8
18
  params[qualified_param('range.end')] = @field.to_indexed(@options[:range].last)
9
19
  params[qualified_param('range.gap')] = "#{@options[:range_interval] || 10}"
10
20
  params[qualified_param('range.include')] = @options[:include].to_s if @options[:include]
11
21
  params
12
22
  end
23
+
24
+ private
25
+
26
+ def local_params
27
+ @local_params ||=
28
+ begin
29
+ local_params = {}
30
+ local_params[:ex] = @exclude_tag if @exclude_tag
31
+ local_params[:key] = @options[:name] if @options[:name]
32
+ local_params
33
+ end
34
+ end
35
+
36
+ def field_name_with_local_params
37
+ if local_params.empty?
38
+ @field.indexed_name
39
+ else
40
+ pairs = local_params.map do |key, value|
41
+ "#{key}=#{value}"
42
+ end
43
+ "{!#{pairs.join(' ')}}#{@field.indexed_name}"
44
+ end
45
+ end
13
46
  end
47
+
14
48
  end
15
49
  end
@@ -76,8 +76,18 @@ module Sunspot
76
76
  # (usually) randomly.
77
77
  #
78
78
  class RandomSort < Abstract
79
+ def initialize(options_or_direction=nil)
80
+ if options_or_direction.is_a?(Hash)
81
+ @seed, @direction = options_or_direction[:seed], options_or_direction[:direction]
82
+ else
83
+ @direction = options_or_direction
84
+ end
85
+
86
+ @direction = (@direction || :asc).to_sym
87
+ end
88
+
79
89
  def to_param
80
- "random_#{rand(1<<16)} #{direction_for_solr}"
90
+ "random_#{@seed || rand(1<<6)} #{direction_for_solr}"
81
91
  end
82
92
  end
83
93
 
@@ -1,8 +1,7 @@
1
1
  module Sunspot
2
2
  module Search
3
3
 
4
- class PaginatedCollection
5
- instance_methods.each { |m| undef_method m unless m =~ /^__|instance_eval|object_id/ }
4
+ class PaginatedCollection < Array
6
5
 
7
6
  attr_reader :current_page, :per_page
8
7
  attr_accessor :total_count
@@ -11,10 +10,10 @@ module Sunspot
11
10
  alias :limit_value :per_page
12
11
 
13
12
  def initialize(collection, page, per_page, total)
14
- @collection = collection
15
13
  @current_page = page
16
14
  @per_page = per_page
17
15
  @total_count = total
16
+ replace collection
18
17
  end
19
18
 
20
19
  def total_pages
@@ -45,12 +44,7 @@ module Sunspot
45
44
  def offset
46
45
  (current_page - 1) * per_page
47
46
  end
48
-
49
- private
50
-
51
- def method_missing(method, *args, &block)
52
- @collection.send(method, *args, &block)
53
- end
47
+ alias :offset_value :offset
54
48
 
55
49
  end
56
50
  end
data/lib/sunspot/setup.rb CHANGED
@@ -14,6 +14,7 @@ module Sunspot
14
14
  @stored_field_factories_cache = Hash.new { |h, k| h[k] = [] }
15
15
  @more_like_this_field_factories_cache = Hash.new { |h, k| h[k] = [] }
16
16
  @dsl = DSL::Fields.new(self)
17
+ @document_boost_extractor = nil
17
18
  add_field_factory(:class, Type::ClassType.instance)
18
19
  end
19
20
 
data/lib/sunspot/type.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  require 'singleton'
2
2
  begin
3
3
  require 'geohash'
4
- rescue LoadError => e
4
+ rescue LoadError
5
5
  require 'pr_geohash'
6
6
  end
7
7
 
data/lib/sunspot/util.rb CHANGED
@@ -202,7 +202,7 @@ module Sunspot
202
202
  class <<self
203
203
  def instance_eval_with_context(receiver, &block)
204
204
  calling_context = eval('self', block.binding)
205
- if parent_calling_context = calling_context.instance_eval{@__calling_context__}
205
+ if parent_calling_context = calling_context.instance_eval{@__calling_context__ if defined?(@__calling_context__)}
206
206
  calling_context = parent_calling_context
207
207
  end
208
208
  new(receiver, calling_context).instance_eval(&block)
@@ -1,3 +1,3 @@
1
1
  module Sunspot
2
- VERSION = '2.0.0.pre.120925'
2
+ VERSION = '2.0.0.pre.130115'
3
3
  end
@@ -287,6 +287,17 @@ shared_examples_for "facetable query" do
287
287
  connection.should have_last_search_with(:"f.average_rating_ft.facet.range.gap" => "1")
288
288
  end
289
289
 
290
+ it 'tags and excludes a scope filter in a range facet' do
291
+ search do |query|
292
+ blog_filter = query.with(:blog_id, 1)
293
+ query.facet(:average_rating, :range => @range, :exclude => blog_filter)
294
+ end
295
+ filter_tag = get_filter_tag('blog_id_i:1')
296
+ connection.should have_last_search_with(
297
+ :"facet.range" => %W({!ex=#{filter_tag}}average_rating_ft)
298
+ )
299
+ end
300
+
290
301
  it 'sets the include if one is specified' do
291
302
  search do |query|
292
303
  query.facet :average_rating, :range => @range, :include => :edge
@@ -10,6 +10,15 @@ describe 'function query' do
10
10
  connection.should have_last_search_including(:bf, 'average_rating_ft')
11
11
  end
12
12
 
13
+ it "should send query to solr with boost function and boost amount" do
14
+ session.search Post do
15
+ keywords('pizza') do
16
+ boost(function { :average_rating }^5)
17
+ end
18
+ end
19
+ connection.should have_last_search_including(:bf, 'average_rating_ft^5')
20
+ end
21
+
13
22
  it "should handle boost function with constant float" do
14
23
  session.search Post do
15
24
  keywords('pizza') do
@@ -19,6 +28,15 @@ describe 'function query' do
19
28
  connection.should have_last_search_including(:bf, '10.5')
20
29
  end
21
30
 
31
+ it "should handle boost function with constant float and boost amount" do
32
+ session.search Post do
33
+ keywords('pizza') do
34
+ boost(function { 10.5 }^5)
35
+ end
36
+ end
37
+ connection.should have_last_search_including(:bf, '10.5^5')
38
+ end
39
+
22
40
  it "should handle boost function with time literal" do
23
41
  session.search Post do
24
42
  keywords('pizza') do
@@ -45,6 +63,15 @@ describe 'function query' do
45
63
  end
46
64
  connection.should have_last_search_including(:bf, 'sub(average_rating_ft,10)')
47
65
  end
66
+
67
+ it "should handle boost amounts on function query block" do
68
+ session.search Post do
69
+ keywords('pizza') do
70
+ boost(function { sub(:average_rating, 10)^5 })
71
+ end
72
+ end
73
+ connection.should have_last_search_including(:bf, 'sub(average_rating_ft,10)^5')
74
+ end
48
75
 
49
76
  it "should handle nested functions in a function query block" do
50
77
  session.search Post do
@@ -68,6 +68,27 @@ shared_examples_for 'sortable query' do
68
68
  connection.searches.last[:sort].should =~ /^random_\d+ asc$/
69
69
  end
70
70
 
71
+ it 'orders by random with declared direction' do
72
+ search do
73
+ order_by :random, :desc
74
+ end
75
+ connection.searches.last[:sort].should =~ /^random_\d+ desc$/
76
+ end
77
+
78
+ it 'orders by random with provided seed value' do
79
+ search do
80
+ order_by :random, :seed => 9001
81
+ end
82
+ connection.searches.last[:sort].should =~ /^random_9001 asc$/
83
+ end
84
+
85
+ it 'orders by random with provided seed value and direction' do
86
+ search do
87
+ order_by :random, :seed => 12345, :direction => :desc
88
+ end
89
+ connection.searches.last[:sort].should =~ /^random_12345 desc$/
90
+ end
91
+
71
92
  it 'orders by score' do
72
93
  search do
73
94
  order_by :score, :desc
@@ -5,6 +5,18 @@ describe "PaginatedCollection" do
5
5
 
6
6
  it { subject.should be_an(Array) }
7
7
 
8
+ describe "#send" do
9
+ it 'should allow send' do
10
+ expect { subject.send(:current_page) }.not_to raise_error(NoMethodError)
11
+ end
12
+ end
13
+
14
+ describe "#respond_to?" do
15
+ it 'should return true for current_page' do
16
+ subject.respond_to?(:current_page).should be_true
17
+ end
18
+ end
19
+
8
20
  context "behaves like a WillPaginate::Collection" do
9
21
  it { subject.total_entries.should eql(20) }
10
22
  it { subject.total_pages.should eql(2) }
@@ -372,9 +372,12 @@ describe 'scoped_search' do
372
372
  end
373
373
 
374
374
  describe 'ordering by random' do
375
- it 'should order randomly (run this test again if it fails)' do
375
+ before do
376
376
  Sunspot.remove_all
377
377
  Sunspot.index!(Array.new(100) { Post.new })
378
+ end
379
+
380
+ it 'should order randomly (run this test again if it fails)' do
378
381
  result_sets = Array.new(2) do
379
382
  Sunspot.search(Post) { order_by_random }.results.map do |result|
380
383
  result.id
@@ -382,5 +385,38 @@ describe 'scoped_search' do
382
385
  end
383
386
  result_sets[0].should_not == result_sets[1]
384
387
  end
388
+
389
+ # This could fail if the random set returned just happens to be the same as the last random set (the nature of randomness)
390
+ it 'should order randomly using the order_by function and passing a direction' do
391
+ result_sets = Array.new(2) do
392
+ Sunspot.search(Post) { order_by(:random, :desc) }.results.map do |result|
393
+ result.id
394
+ end
395
+ end
396
+ result_sets[0].should_not == result_sets[1]
397
+ end
398
+
399
+ context 'when providing a custom seed value' do
400
+ before do
401
+ @first_results = Sunspot.search(Post) do
402
+ order_by(:random, :seed => 12345)
403
+ end.results.map { |result| result.id }
404
+ end
405
+
406
+ # This could fail if the random set returned just happens to be the same as the last random set (the nature of randomness)
407
+ it 'should return different results when passing a different seed value' do
408
+ next_results = Sunspot.search(Post) do
409
+ order_by(:random, :seed => 54321)
410
+ end.results.map { |result| result.id }
411
+ next_results.should_not == @first_results
412
+ end
413
+
414
+ it 'should return the same results when passing the same seed value' do
415
+ next_results = Sunspot.search(Post) do
416
+ order_by(:random, :seed => 12345)
417
+ end.results.map { |result| result.id }
418
+ next_results.should == @first_results
419
+ end
420
+ end
385
421
  end
386
422
  end
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: 2.0.0.pre.120925
4
+ version: 2.0.0.pre.130115
5
5
  prerelease: 6
6
6
  platform: ruby
7
7
  authors:
@@ -27,52 +27,72 @@ authors:
27
27
  autorequire:
28
28
  bindir: bin
29
29
  cert_chain: []
30
- date: 2012-09-25 00:00:00.000000000 Z
30
+ date: 2013-01-15 00:00:00.000000000 Z
31
31
  dependencies:
32
32
  - !ruby/object:Gem::Dependency
33
33
  name: rsolr
34
- requirement: &70302521090680 !ruby/object:Gem::Requirement
35
- none: false
34
+ prerelease: false
35
+ requirement: !ruby/object:Gem::Requirement
36
36
  requirements:
37
37
  - - ~>
38
38
  - !ruby/object:Gem::Version
39
39
  version: 1.0.7
40
+ none: false
40
41
  type: :runtime
41
- prerelease: false
42
- version_requirements: *70302521090680
42
+ version_requirements: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - ~>
45
+ - !ruby/object:Gem::Version
46
+ version: 1.0.7
47
+ none: false
43
48
  - !ruby/object:Gem::Dependency
44
49
  name: pr_geohash
45
- requirement: &70302521089300 !ruby/object:Gem::Requirement
46
- none: false
50
+ prerelease: false
51
+ requirement: !ruby/object:Gem::Requirement
47
52
  requirements:
48
53
  - - ~>
49
54
  - !ruby/object:Gem::Version
50
55
  version: '1.0'
56
+ none: false
51
57
  type: :runtime
52
- prerelease: false
53
- version_requirements: *70302521089300
58
+ version_requirements: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - ~>
61
+ - !ruby/object:Gem::Version
62
+ version: '1.0'
63
+ none: false
54
64
  - !ruby/object:Gem::Dependency
55
65
  name: rspec
56
- requirement: &70302521088380 !ruby/object:Gem::Requirement
57
- none: false
66
+ prerelease: false
67
+ requirement: !ruby/object:Gem::Requirement
58
68
  requirements:
59
69
  - - ~>
60
70
  - !ruby/object:Gem::Version
61
71
  version: 2.6.0
72
+ none: false
62
73
  type: :development
63
- prerelease: false
64
- version_requirements: *70302521088380
74
+ version_requirements: !ruby/object:Gem::Requirement
75
+ requirements:
76
+ - - ~>
77
+ - !ruby/object:Gem::Version
78
+ version: 2.6.0
79
+ none: false
65
80
  - !ruby/object:Gem::Dependency
66
81
  name: hanna
67
- requirement: &70302521086620 !ruby/object:Gem::Requirement
68
- none: false
82
+ prerelease: false
83
+ requirement: !ruby/object:Gem::Requirement
69
84
  requirements:
70
85
  - - ! '>='
71
86
  - !ruby/object:Gem::Version
72
87
  version: '0'
88
+ none: false
73
89
  type: :development
74
- prerelease: false
75
- version_requirements: *70302521086620
90
+ version_requirements: !ruby/object:Gem::Requirement
91
+ requirements:
92
+ - - ! '>='
93
+ - !ruby/object:Gem::Version
94
+ version: '0'
95
+ none: false
76
96
  description: ! " Sunspot is a library providing a powerful, all-ruby API for the
77
97
  Solr search engine. Sunspot manages the configuration of persistent\n Ruby classes
78
98
  for search and indexing and exposes Solr's most powerful features through a collection
@@ -276,20 +296,20 @@ rdoc_options:
276
296
  require_paths:
277
297
  - lib
278
298
  required_ruby_version: !ruby/object:Gem::Requirement
279
- none: false
280
299
  requirements:
281
300
  - - ! '>='
282
301
  - !ruby/object:Gem::Version
283
302
  version: '0'
284
- required_rubygems_version: !ruby/object:Gem::Requirement
285
303
  none: false
304
+ required_rubygems_version: !ruby/object:Gem::Requirement
286
305
  requirements:
287
306
  - - ! '>'
288
307
  - !ruby/object:Gem::Version
289
308
  version: 1.3.1
309
+ none: false
290
310
  requirements: []
291
311
  rubyforge_project: sunspot
292
- rubygems_version: 1.8.15
312
+ rubygems_version: 1.8.24
293
313
  signing_key:
294
314
  specification_version: 3
295
315
  summary: Library for expressive, powerful interaction with the Solr search engine