sunspot 2.2.7 → 2.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (117) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +1 -0
  3. data/.rspec +2 -0
  4. data/Appraisals +7 -0
  5. data/Gemfile +0 -8
  6. data/lib/sunspot/adapters.rb +4 -1
  7. data/lib/sunspot/configuration.rb +1 -0
  8. data/lib/sunspot/data_extractor.rb +36 -6
  9. data/lib/sunspot/dsl/field_query.rb +11 -0
  10. data/lib/sunspot/dsl/field_stats.rb +7 -0
  11. data/lib/sunspot/dsl/fields.rb +16 -0
  12. data/lib/sunspot/dsl/group.rb +10 -0
  13. data/lib/sunspot/dsl/scope.rb +23 -18
  14. data/lib/sunspot/field.rb +11 -0
  15. data/lib/sunspot/field_factory.rb +6 -2
  16. data/lib/sunspot/query/abstract_json_field_facet.rb +70 -0
  17. data/lib/sunspot/query/bbox.rb +5 -1
  18. data/lib/sunspot/query/date_field_json_facet.rb +25 -0
  19. data/lib/sunspot/query/field_json_facet.rb +19 -0
  20. data/lib/sunspot/query/field_stats.rb +35 -2
  21. data/lib/sunspot/query/group.rb +4 -5
  22. data/lib/sunspot/query/join.rb +2 -4
  23. data/lib/sunspot/query/range_json_facet.rb +28 -0
  24. data/lib/sunspot/query/restriction.rb +19 -4
  25. data/lib/sunspot/query.rb +3 -3
  26. data/lib/sunspot/schema.rb +10 -2
  27. data/lib/sunspot/search/abstract_search.rb +14 -1
  28. data/lib/sunspot/search/field_json_facet.rb +33 -0
  29. data/lib/sunspot/search/hit.rb +6 -1
  30. data/lib/sunspot/search/hit_enumerable.rb +4 -1
  31. data/lib/sunspot/search/json_facet_row.rb +40 -0
  32. data/lib/sunspot/search/json_facet_stats.rb +23 -0
  33. data/lib/sunspot/search/standard_search.rb +2 -3
  34. data/lib/sunspot/search/stats_json_row.rb +82 -0
  35. data/lib/sunspot/search/stats_row.rb +3 -1
  36. data/lib/sunspot/search.rb +4 -3
  37. data/lib/sunspot/session.rb +13 -5
  38. data/lib/sunspot/setup.rb +31 -0
  39. data/lib/sunspot/util.rb +23 -0
  40. data/lib/sunspot/version.rb +1 -1
  41. data/spec/api/adapters_spec.rb +32 -19
  42. data/spec/api/batcher_spec.rb +15 -15
  43. data/spec/api/binding_spec.rb +3 -3
  44. data/spec/api/class_set_spec.rb +3 -3
  45. data/spec/api/data_extractor_spec.rb +39 -0
  46. data/spec/api/hit_enumerable_spec.rb +32 -9
  47. data/spec/api/indexer/attributes_spec.rb +31 -31
  48. data/spec/api/indexer/batch_spec.rb +8 -7
  49. data/spec/api/indexer/dynamic_fields_spec.rb +8 -8
  50. data/spec/api/indexer/fixed_fields_spec.rb +12 -12
  51. data/spec/api/indexer/fulltext_spec.rb +8 -8
  52. data/spec/api/indexer/removal_spec.rb +14 -14
  53. data/spec/api/indexer_spec.rb +2 -2
  54. data/spec/api/query/advanced_manipulation_examples.rb +3 -3
  55. data/spec/api/query/connectives_examples.rb +26 -14
  56. data/spec/api/query/dsl_spec.rb +17 -9
  57. data/spec/api/query/dynamic_fields_examples.rb +18 -18
  58. data/spec/api/query/faceting_examples.rb +62 -62
  59. data/spec/api/query/fulltext_examples.rb +63 -58
  60. data/spec/api/query/function_spec.rb +26 -26
  61. data/spec/api/query/geo_examples.rb +6 -6
  62. data/spec/api/query/group_spec.rb +6 -6
  63. data/spec/api/query/highlighting_examples.rb +26 -26
  64. data/spec/api/query/join_spec.rb +2 -2
  65. data/spec/api/query/more_like_this_spec.rb +29 -29
  66. data/spec/api/query/ordering_pagination_examples.rb +25 -25
  67. data/spec/api/query/scope_examples.rb +39 -39
  68. data/spec/api/query/spatial_examples.rb +3 -3
  69. data/spec/api/query/spellcheck_examples.rb +3 -3
  70. data/spec/api/query/standard_spec.rb +1 -1
  71. data/spec/api/query/stats_examples.rb +8 -8
  72. data/spec/api/query/text_field_scoping_examples.rb +5 -5
  73. data/spec/api/query/types_spec.rb +4 -4
  74. data/spec/api/search/cursor_paginated_collection_spec.rb +12 -12
  75. data/spec/api/search/dynamic_fields_spec.rb +4 -4
  76. data/spec/api/search/faceting_spec.rb +55 -52
  77. data/spec/api/search/highlighting_spec.rb +7 -7
  78. data/spec/api/search/hits_spec.rb +43 -29
  79. data/spec/api/search/paginated_collection_spec.rb +18 -18
  80. data/spec/api/search/results_spec.rb +13 -13
  81. data/spec/api/search/search_spec.rb +3 -3
  82. data/spec/api/search/stats_spec.rb +10 -10
  83. data/spec/api/session_proxy/class_sharding_session_proxy_spec.rb +19 -18
  84. data/spec/api/session_proxy/id_sharding_session_proxy_spec.rb +9 -9
  85. data/spec/api/session_proxy/master_slave_session_proxy_spec.rb +10 -6
  86. data/spec/api/session_proxy/retry_5xx_session_proxy_spec.rb +10 -10
  87. data/spec/api/session_proxy/sharding_session_proxy_spec.rb +14 -13
  88. data/spec/api/session_proxy/silent_fail_session_proxy_spec.rb +2 -2
  89. data/spec/api/session_proxy/spec_helper.rb +1 -1
  90. data/spec/api/session_proxy/thread_local_session_proxy_spec.rb +9 -5
  91. data/spec/api/session_spec.rb +42 -42
  92. data/spec/api/sunspot_spec.rb +7 -4
  93. data/spec/helpers/integration_helper.rb +1 -0
  94. data/spec/integration/atomic_updates_spec.rb +25 -11
  95. data/spec/integration/dynamic_fields_spec.rb +10 -10
  96. data/spec/integration/faceting_spec.rb +252 -39
  97. data/spec/integration/field_grouping_spec.rb +35 -16
  98. data/spec/integration/field_lists_spec.rb +57 -0
  99. data/spec/integration/geospatial_spec.rb +34 -8
  100. data/spec/integration/highlighting_spec.rb +5 -5
  101. data/spec/integration/indexing_spec.rb +5 -5
  102. data/spec/integration/join_spec.rb +45 -0
  103. data/spec/integration/keyword_search_spec.rb +47 -45
  104. data/spec/integration/local_search_spec.rb +4 -4
  105. data/spec/integration/more_like_this_spec.rb +7 -7
  106. data/spec/integration/scoped_search_spec.rb +108 -108
  107. data/spec/integration/spellcheck_spec.rb +52 -7
  108. data/spec/integration/stats_spec.rb +54 -13
  109. data/spec/integration/stored_fields_spec.rb +1 -1
  110. data/spec/integration/test_pagination.rb +4 -4
  111. data/spec/integration/unicode_spec.rb +1 -1
  112. data/spec/mocks/adapters.rb +33 -0
  113. data/spec/mocks/photo.rb +14 -4
  114. data/spec/mocks/post.rb +9 -1
  115. data/spec/spec_helper.rb +11 -10
  116. data/sunspot.gemspec +3 -1
  117. metadata +49 -6
@@ -16,7 +16,7 @@ module Sunspot
16
16
  # Retrieve all facet objects defined for this search, in order they were
17
17
  # defined. To retrieve an individual facet by name, use #facet()
18
18
  #
19
- attr_reader :facets, :groups, :stats
19
+ attr_reader :facets, :groups
20
20
  attr_reader :query #:nodoc:
21
21
  attr_accessor :request_handler
22
22
 
@@ -182,6 +182,10 @@ module Sunspot
182
182
  end
183
183
  end
184
184
 
185
+ def json_facet_stats(name, options = {})
186
+ JsonFacetStats.new(name, self, options)
187
+ end
188
+
185
189
  #
186
190
  # Deprecated in favor of optional second argument to #facet
187
191
  #
@@ -193,6 +197,10 @@ module Sunspot
193
197
  @solr_result['facet_counts']
194
198
  end
195
199
 
200
+ def json_facet_response #:nodoc:
201
+ @solr_result['facets']
202
+ end
203
+
196
204
  def stats_response #:nodoc:
197
205
  @solr_result['stats']['stats_fields']
198
206
  end
@@ -255,6 +263,11 @@ module Sunspot
255
263
  add_stats(field.name, FieldStats.new(field, self))
256
264
  end
257
265
 
266
+ def add_json_facet(field, options = {})
267
+ name = (options[:name] || field.name)
268
+ add_facet(name, FieldJsonFacet.new(field, self, options))
269
+ end
270
+
258
271
  def highlights_for(doc) #:nodoc:
259
272
  if @solr_result['highlighting']
260
273
  @solr_result['highlighting'][doc['id']]
@@ -0,0 +1,33 @@
1
+ module Sunspot
2
+ module Search
3
+ class FieldJsonFacet
4
+
5
+ attr_reader :name
6
+
7
+ def initialize(field, search, options)
8
+ @name, @search, @options = name, search, options
9
+ @field = field
10
+ end
11
+
12
+ def rows
13
+ @rows ||=
14
+ begin
15
+ json_facet_response = @search.json_facet_response[@field.name.to_s]
16
+ data = json_facet_response.nil? ? [] : json_facet_response['buckets']
17
+ rows = []
18
+ data.each do |d|
19
+ rows << JsonFacetRow.new(d, self)
20
+ end
21
+
22
+ if @options[:sort] == :count
23
+ rows.sort! { |lrow, rrow| rrow.count <=> lrow.count }
24
+ else
25
+ rows.sort! { |lrow, rrow| lrow.value <=> rrow.value }
26
+ end
27
+ rows
28
+ end
29
+
30
+ end
31
+ end
32
+ end
33
+ end
@@ -17,6 +17,10 @@ module Sunspot
17
17
  # Class name of object associated with this hit, as string.
18
18
  #
19
19
  attr_reader :class_name
20
+ #
21
+ # ID prefix used for compositeId shard router
22
+ #
23
+ attr_reader :id_prefix
20
24
  #
21
25
  # Keyword relevance score associated with this result. Nil if this hit
22
26
  # is not from a keyword search.
@@ -27,7 +31,8 @@ module Sunspot
27
31
  attr_writer :result #:nodoc:
28
32
 
29
33
  def initialize(raw_hit, highlights, search) #:nodoc:
30
- @class_name, @primary_key = *raw_hit['id'].match(/([^ ]+) (.+)/)[1..2]
34
+ @id_prefix, @class_name, @primary_key =
35
+ *raw_hit['id'].match(/((?:[^!]+!)+)*([^\s]+)\s(.+)/)[1..3]
31
36
  @score = raw_hit['score']
32
37
  @search = search
33
38
  @stored_values = raw_hit
@@ -11,6 +11,9 @@ module Sunspot
11
11
  end
12
12
  end
13
13
 
14
+ #
15
+ # Returns all of the hits that have a result
16
+ #
14
17
  def verified_hits
15
18
  hits.select { |h| h.result }
16
19
  end
@@ -31,7 +34,7 @@ module Sunspot
31
34
  hits_for_class = id_hit_hash[class_name]
32
35
  data_accessor.load_all(ids).each do |result|
33
36
  hit = hits_for_class.delete(Adapters::InstanceAdapter.adapt(result).id.to_s)
34
- hit.result = result
37
+ hit.result = result if hit
35
38
  end
36
39
  hits_for_class.values.each { |hit| hit.result = nil }
37
40
  end
@@ -0,0 +1,40 @@
1
+ module Sunspot
2
+ module Search
3
+ class JsonFacetRow
4
+ attr_reader :value, :count, :nested
5
+ attr_writer :instance #:nodoc:
6
+
7
+ def initialize(data, facet) #:nodoc:
8
+ @value = data['val']
9
+ @count = data['distinct'] || data['count']
10
+ @facet = facet
11
+ @nested_key = data.keys.select { |k| data[k].is_a?(Hash) }.first
12
+ @nested = recursive_nested_initialization(data) unless @nested_key.nil?
13
+ end
14
+
15
+ #
16
+ # Return the instance referenced by this facet row. Only valid for field
17
+ # facets whose fields are defined with the :references key.
18
+ #
19
+ def instance
20
+ if !defined?(@instance)
21
+ @facet.populate_instances
22
+ end
23
+ @instance
24
+ end
25
+
26
+ def inspect
27
+ "<Sunspot::Search::FacetRow:#{value.inspect} (#{count}) #{nested.nil? ? '' : " nested_count=#{nested.size}"}>"
28
+ end
29
+
30
+ private
31
+
32
+ def recursive_nested_initialization(data)
33
+ data[@nested_key]['buckets'].map do |d|
34
+ JsonFacetRow.new(d, @facet)
35
+ end
36
+ end
37
+
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,23 @@
1
+ module Sunspot
2
+ module Search
3
+ class JsonFacetStats
4
+ def initialize(field, search, options)
5
+ @field, @search, @options = field, search, options
6
+ end
7
+
8
+ def rows
9
+ @rows ||=
10
+ begin
11
+ json_facet_response = @search.json_facet_response[@field.to_s]
12
+ data = json_facet_response.nil? ? [] : json_facet_response['buckets']
13
+ rows = []
14
+ data.each do |d|
15
+ rows << StatsJsonRow.new(d, nil, d['val'])
16
+ end
17
+ rows
18
+ end
19
+
20
+ end
21
+ end
22
+ end
23
+ end
@@ -49,12 +49,11 @@ module Sunspot
49
49
  # the index. Otherwise return Solr's suggested collation.
50
50
  #
51
51
  # Solr's suggested collation is more liberal, replacing even terms that
52
- # are present in the index. This may not be useful if only one term is
53
- # misspelled and preventing useful results.
52
+ # are present in the index.
54
53
  #
55
54
  # Mix and match in your views for a blend of strict and liberal collations.
56
55
  def spellcheck_collation(*terms)
57
- if solr_spellcheck['suggestions'] && solr_spellcheck['suggestions'].length > 2
56
+ if solr_spellcheck['suggestions'] && solr_spellcheck['suggestions'].length > 0
58
57
  collation = terms.join(" ").dup if terms
59
58
 
60
59
  # If we are given a query string, tokenize it and strictly replace
@@ -0,0 +1,82 @@
1
+ module Sunspot
2
+ module Search
3
+ class StatsJsonRow
4
+ attr_reader :data, :value, :nested
5
+ attr_writer :instance #:nodoc:
6
+
7
+ def initialize(data, facet = nil, value = nil) #:nodoc:
8
+ @data, @facet, @value = data, facet, value
9
+ @facet_fields = []
10
+ @nested_key = data.keys.select { |k| data[k].is_a?(Hash) }.first
11
+ @nested = recursive_nested_initialization(data) unless @nested_key.nil?
12
+ end
13
+
14
+ def min
15
+ data['min']
16
+ end
17
+
18
+ def max
19
+ data['max']
20
+ end
21
+
22
+ def count
23
+ data['count']
24
+ end
25
+
26
+ def sum
27
+ data['sum']
28
+ end
29
+
30
+ def missing
31
+ data['missing']
32
+ end
33
+
34
+ def sum_of_squares
35
+ data['sumsq']
36
+ end
37
+ alias :sumsq :sum_of_squares
38
+
39
+ def mean
40
+ data['avg']
41
+ end
42
+ alias :avg :mean
43
+
44
+ def standard_deviation
45
+ data['stddev']
46
+ end
47
+
48
+ def facet name
49
+ facets.find { |facet| facet.field.name == name.to_sym }
50
+ end
51
+
52
+ def facets
53
+ @facets ||= @facet_fields.map do |field|
54
+ StatsFacet.new(field, data['facets'][field.indexed_name])
55
+ end
56
+ end
57
+
58
+ def instance
59
+ if !defined?(@instance)
60
+ @facet.populate_instances
61
+ end
62
+ @instance
63
+ end
64
+
65
+ def inspect
66
+ "<Sunspot::Search::StatsJsonRow:#{value.inspect} min=#{min} max=#{max}"\
67
+ " count=#{count} sum=#{sum} missing=#{missing} sum_of_squares=#{sum_of_squares}"\
68
+ " mean=#{mean} standard_deviation=#{standard_deviation}"\
69
+ " #{nested.nil? ? '' : "nested_count=#{nested.size}"}>"
70
+ end
71
+
72
+ private
73
+
74
+ def recursive_nested_initialization(data)
75
+ data[@nested_key]['buckets'].map do |d|
76
+ StatsJsonRow.new(d, @facet, d['val'])
77
+ end
78
+ end
79
+
80
+ end
81
+ end
82
+ end
@@ -59,7 +59,9 @@ module Sunspot
59
59
  end
60
60
 
61
61
  def inspect
62
- "<Sunspot::Search::StatsRow:#{value.inspect} min=#{min} max=#{max} count=#{count}>"
62
+ "<Sunspot::Search::StatsRow:#{value.inspect} min=#{min} max=#{max}"\
63
+ " count=#{self.count} sum=#{sum} missing=#{missing} sum_of_squares=#{sum_of_squares}"\
64
+ " mean=#{mean} standard_deviation=#{standard_deviation}>"
63
65
  end
64
66
  end
65
67
  end
@@ -1,6 +1,7 @@
1
- %w(abstract_search standard_search more_like_this_search query_facet field_facet
2
- date_facet range_facet facet_row hit highlight field_group group hit_enumerable
3
- stats_row field_stats stats_facet query_group).each do |file|
1
+ %w(abstract_search standard_search more_like_this_search query_facet
2
+ field_facet field_json_facet date_facet range_facet json_facet_stats
3
+ facet_row json_facet_row hit highlight field_group group hit_enumerable
4
+ stats_row stats_json_row field_stats stats_facet query_group).each do |file|
4
5
  require File.join(File.dirname(__FILE__), 'search', file)
5
6
  end
6
7
 
@@ -254,11 +254,13 @@ module Sunspot
254
254
  # RSolr::Connection::Base:: The connection for this session
255
255
  #
256
256
  def connection
257
- @connection ||=
258
- self.class.connection_class.connect(:url => config.solr.url,
259
- :read_timeout => config.solr.read_timeout,
260
- :open_timeout => config.solr.open_timeout,
261
- :proxy => config.solr.proxy)
257
+ @connection ||= self.class.connection_class.connect(
258
+ url: config.solr.url,
259
+ read_timeout: config.solr.read_timeout,
260
+ open_timeout: config.solr.open_timeout,
261
+ proxy: config.solr.proxy,
262
+ update_format: update_format_generator
263
+ )
262
264
  end
263
265
 
264
266
  def indexer
@@ -275,5 +277,11 @@ module Sunspot
275
277
  CompositeSetup.for(types)
276
278
  end
277
279
  end
280
+
281
+ def update_format_generator
282
+ if config.solr.update_format && RSolr.version.to_i > 1
283
+ config.solr.update_format.downcase.to_sym == :json ? RSolr::JSON::Generator : RSolr::Xml::Generator
284
+ end
285
+ end
278
286
  end
279
287
  end
data/lib/sunspot/setup.rb CHANGED
@@ -15,6 +15,7 @@ module Sunspot
15
15
  @more_like_this_field_factories_cache = Hash.new { |h, k| h[k] = [] }
16
16
  @dsl = DSL::Fields.new(self)
17
17
  @document_boost_extractor = nil
18
+ @id_prefix_extractor = nil
18
19
  add_field_factory(:class, Type::ClassType.instance)
19
20
  end
20
21
 
@@ -61,6 +62,7 @@ module Sunspot
61
62
  field_factory = FieldFactory::Static.new(name, Type::TextType.instance, options, &block)
62
63
  @text_field_factories[name] = field_factory
63
64
  @text_field_factories_cache[field_factory.name] = field_factory
65
+ @field_factories_cache[field_factory.name] = field_factory
64
66
  if stored
65
67
  @stored_field_factories_cache[field_factory.name] << field_factory
66
68
  end
@@ -81,6 +83,7 @@ module Sunspot
81
83
  field_factory = FieldFactory::Dynamic.new(name, type, options, &block)
82
84
  @dynamic_field_factories[field_factory.signature] = field_factory
83
85
  @dynamic_field_factories_cache[field_factory.name] = field_factory
86
+ @field_factories_cache[field_factory.name] = field_factory
84
87
  if stored
85
88
  @stored_field_factories_cache[field_factory.name] << field_factory
86
89
  end
@@ -107,6 +110,24 @@ module Sunspot
107
110
  end
108
111
  end
109
112
 
113
+ #
114
+ # Add id prefix for compositeId router
115
+ #
116
+ def add_id_prefix(attr_name, &block)
117
+ @id_prefix_extractor =
118
+ case attr_name
119
+ when Symbol
120
+ DataExtractor::AttributeExtractor.new(attr_name)
121
+ when String
122
+ DataExtractor::Constant.new(attr_name)
123
+ when nil
124
+ DataExtractor::BlockExtractor.new(&block) if block_given?
125
+ else
126
+ raise ArgumentError,
127
+ "The ID prefix has to be either a Symbol, a String or a Proc"
128
+ end
129
+ end
130
+
110
131
  #
111
132
  # Builder method for evaluating the setup DSL
112
133
  #
@@ -271,6 +292,16 @@ module Sunspot
271
292
  end
272
293
  end
273
294
 
295
+ def id_prefix_for(model)
296
+ if @id_prefix_extractor
297
+ value = @id_prefix_extractor.value_for(model)
298
+
299
+ if value.is_a?(String) and value.size > 0
300
+ value[-1] == "!" ? value : "#{value}!"
301
+ end
302
+ end
303
+ end
304
+
274
305
  protected
275
306
 
276
307
  #
data/lib/sunspot/util.rb CHANGED
@@ -188,6 +188,29 @@ module Sunspot
188
188
  RSolr.solr_escape(value).gsub(/([\s\.])/, '\\\\\1')
189
189
  end
190
190
 
191
+ def parse_json_facet(field_name, options, setup)
192
+ field = setup.field(field_name)
193
+ if options[:time_range]
194
+ unless field.type.is_a?(Sunspot::Type::TimeType)
195
+ raise(
196
+ ArgumentError,
197
+ ':time_range can only be specified for Date or Time fields'
198
+ )
199
+ end
200
+ Sunspot::Query::DateFieldJsonFacet.new(field, options, setup)
201
+ elsif options[:range]
202
+ unless [Sunspot::Type::TimeType, Sunspot::Type::FloatType, Sunspot::Type::IntegerType ].find{|type| field.type.is_a?(type)}
203
+ raise(
204
+ ArgumentError,
205
+ ':range can only be specified for date or numeric fields'
206
+ )
207
+ end
208
+ Sunspot::Query::RangeJsonFacet.new(field, options, setup)
209
+ else
210
+ Sunspot::Query::FieldJsonFacet.new(field, options, setup)
211
+ end
212
+ end
213
+
191
214
  private
192
215
 
193
216
  #
@@ -1,3 +1,3 @@
1
1
  module Sunspot
2
- VERSION = '2.2.7'
2
+ VERSION = '2.5.0'
3
3
  end
@@ -2,45 +2,58 @@ require File.expand_path('spec_helper', File.dirname(__FILE__))
2
2
 
3
3
  describe Sunspot::Adapters::InstanceAdapter do
4
4
  it "finds adapter by superclass" do
5
- Sunspot::Adapters::InstanceAdapter::for(Model).should be(AbstractModelInstanceAdapter)
5
+ expect(Sunspot::Adapters::InstanceAdapter::for(Model)).to be(AbstractModelInstanceAdapter)
6
6
  end
7
7
 
8
8
  it "finds adapter by mixin" do
9
- Sunspot::Adapters::InstanceAdapter::for(MixModel).should be(MixInModelInstanceAdapter)
9
+ expect(Sunspot::Adapters::InstanceAdapter::for(MixModel)).to be(MixInModelInstanceAdapter)
10
10
  end
11
11
 
12
12
  it 'throws NoAdapterError if anonymous module passed in' do
13
- lambda do
13
+ expect do
14
14
  Sunspot::Adapters::InstanceAdapter::for(Module.new)
15
- end.should raise_error(Sunspot::NoAdapterError)
15
+ end.to raise_error(Sunspot::NoAdapterError)
16
16
  end
17
17
 
18
18
  it "registers adapters found by ancestor lookup with the descendant class" do
19
- Sunspot::Adapters::InstanceAdapter::registered_adapter_for(UnseenModel).should be(nil)
19
+ expect(Sunspot::Adapters::InstanceAdapter::registered_adapter_for(UnseenModel)).to be(nil)
20
20
  Sunspot::Adapters::InstanceAdapter::for(UnseenModel)
21
- Sunspot::Adapters::InstanceAdapter::registered_adapter_for(UnseenModel).should be(AbstractModelInstanceAdapter)
21
+ expect(Sunspot::Adapters::InstanceAdapter::registered_adapter_for(UnseenModel)).to be(AbstractModelInstanceAdapter)
22
+ end
23
+
24
+ it "appends ID prefix when configured" do
25
+ expect(AbstractModelInstanceAdapter.new(ModelWithPrefixId.new).index_id).to eq "USERDATA!ModelWithPrefixId 1"
26
+ end
27
+
28
+ it "supports nested ID prefixes" do
29
+ expect(AbstractModelInstanceAdapter.
30
+ new(ModelWithNestedPrefixId.new).index_id).to eq "USER!USERDATA!ModelWithNestedPrefixId 1"
31
+ end
32
+
33
+ it "doesn't appends ID prefix when not configured" do
34
+ expect(AbstractModelInstanceAdapter.new(ModelWithoutPrefixId.new).index_id).to eq "ModelWithoutPrefixId 1"
22
35
  end
23
36
  end
24
37
 
25
38
  describe Sunspot::Adapters::DataAccessor do
26
39
  it "finds adapter by superclass" do
27
- Sunspot::Adapters::DataAccessor::for(Model).should be(AbstractModelDataAccessor)
40
+ expect(Sunspot::Adapters::DataAccessor::for(Model)).to be(AbstractModelDataAccessor)
28
41
  end
29
42
 
30
43
  it "finds adapter by mixin" do
31
- Sunspot::Adapters::DataAccessor::for(MixModel).should be(MixInModelDataAccessor)
44
+ expect(Sunspot::Adapters::DataAccessor::for(MixModel)).to be(MixInModelDataAccessor)
32
45
  end
33
46
 
34
47
  it 'throws NoAdapterError if anonymous module passed in' do
35
- lambda do
48
+ expect do
36
49
  Sunspot::Adapters::DataAccessor::for(Module.new)
37
- end.should raise_error(Sunspot::NoAdapterError)
50
+ end.to raise_error(Sunspot::NoAdapterError)
38
51
  end
39
52
 
40
53
  it "registers adapters found by ancestor lookup with the descendant class" do
41
- Sunspot::Adapters::DataAccessor::registered_accessor_for(UnseenModel).should be(nil)
54
+ expect(Sunspot::Adapters::DataAccessor::registered_accessor_for(UnseenModel)).to be(nil)
42
55
  Sunspot::Adapters::DataAccessor::for(UnseenModel)
43
- Sunspot::Adapters::DataAccessor::registered_accessor_for(UnseenModel).should be(AbstractModelDataAccessor)
56
+ expect(Sunspot::Adapters::DataAccessor::registered_accessor_for(UnseenModel)).to be(AbstractModelDataAccessor)
44
57
  end
45
58
  end
46
59
 
@@ -51,30 +64,30 @@ describe Sunspot::Adapters::Registry do
51
64
  let(:mixin_accessor){ Sunspot::Adapters::DataAccessor::for(MixModel) }
52
65
 
53
66
  it "registers and retrieves a data accessor for abstractclass" do
54
- registry.retrieve(AbstractModel).should be_a(abstractclass_accessor)
67
+ expect(registry.retrieve(AbstractModel)).to be_a(abstractclass_accessor)
55
68
  end
56
69
 
57
70
  it "registers and retrieves a data accessor for superclass" do
58
- registry.retrieve(Model).should be_a(superclass_accessor)
71
+ expect(registry.retrieve(Model)).to be_a(superclass_accessor)
59
72
  end
60
73
 
61
74
  it "registers and retrieves a data accessor for mixin" do
62
- registry.retrieve(MixModel).should be_a(mixin_accessor)
75
+ expect(registry.retrieve(MixModel)).to be_a(mixin_accessor)
63
76
  end
64
77
 
65
78
  it "injects inherited attributes" do
66
- AbstractModelDataAccessor.any_instance.stub(:inherited_attributes).and_return([:to_be_injected])
79
+ allow_any_instance_of(AbstractModelDataAccessor).to receive(:inherited_attributes).and_return([:to_be_injected])
67
80
  in_registry_data_accessor = registry.retrieve(AbstractModel)
68
81
  in_registry_data_accessor.to_be_injected = "value"
69
- registry.retrieve(Model).to_be_injected.should == "value"
82
+ expect(registry.retrieve(Model).to_be_injected).to eq("value")
70
83
  end
71
84
 
72
85
  it "not overrides inherited attributes" do
73
- AbstractModelDataAccessor.any_instance.stub(:inherited_attributes).and_return([:to_be_injected])
86
+ allow_any_instance_of(AbstractModelDataAccessor).to receive(:inherited_attributes).and_return([:to_be_injected])
74
87
  parent_data_accessor = registry.retrieve(AbstractModel)
75
88
  current_data_accessor = registry.retrieve(Model)
76
89
  parent_data_accessor.to_be_injected = "value"
77
90
  current_data_accessor.to_be_injected = "safe-value"
78
- registry.retrieve(Model).to_be_injected.should == "safe-value"
91
+ expect(registry.retrieve(Model).to_be_injected).to eq("safe-value")
79
92
  end
80
93
  end
@@ -2,12 +2,12 @@ require File.expand_path('spec_helper', File.dirname(__FILE__))
2
2
 
3
3
  describe Sunspot::Batcher do
4
4
  it "includes Enumerable" do
5
- described_class.should include Enumerable
5
+ expect(described_class).to include Enumerable
6
6
  end
7
7
 
8
8
  describe "#each" do
9
9
  let(:current) { [:foo, :bar] }
10
- before { subject.stub(:current).and_return current }
10
+ before { allow(subject).to receive(:current).and_return current }
11
11
 
12
12
  it "iterates over current" do
13
13
  yielded_values = []
@@ -16,25 +16,25 @@ describe Sunspot::Batcher do
16
16
  yielded_values << value
17
17
  end
18
18
 
19
- yielded_values.should eq current
19
+ expect(yielded_values).to eq current
20
20
  end
21
21
  end
22
22
 
23
23
  describe "adding to current batch" do
24
24
  it "#push pushes to current" do
25
25
  subject.push :foo
26
- subject.current.should include :foo
26
+ expect(subject.current).to include :foo
27
27
  end
28
28
 
29
29
  it "#<< pushes to current" do
30
30
  subject.push :foo
31
- subject.current.should include :foo
31
+ expect(subject.current).to include :foo
32
32
  end
33
33
 
34
34
  it "#concat concatinates on current batch" do
35
35
  subject << :foo
36
36
  subject.concat [:bar, :mix]
37
- should include :foo, :bar, :mix
37
+ is_expected.to include :foo, :bar, :mix
38
38
  end
39
39
  end
40
40
 
@@ -46,7 +46,7 @@ describe Sunspot::Batcher do
46
46
  end
47
47
 
48
48
  it "is empty by default" do
49
- subject.current.should be_empty
49
+ expect(subject.current).to be_empty
50
50
  end
51
51
  end
52
52
 
@@ -58,7 +58,7 @@ describe Sunspot::Batcher do
58
58
  end
59
59
 
60
60
  it "returns the same as last time" do
61
- subject.current.should eq subject.current
61
+ expect(subject.current).to eq subject.current
62
62
  end
63
63
  end
64
64
  end
@@ -71,7 +71,7 @@ describe Sunspot::Batcher do
71
71
  it "changes current" do
72
72
  subject << :foo
73
73
  subject.start_new
74
- should_not include :foo
74
+ is_expected.not_to include :foo
75
75
  end
76
76
  end
77
77
 
@@ -88,25 +88,25 @@ describe Sunspot::Batcher do
88
88
  it "changes current" do
89
89
  subject << :foo
90
90
  subject.end_current
91
- should_not include :foo
91
+ is_expected.not_to include :foo
92
92
  end
93
93
 
94
94
  it "returns current" do
95
95
  subject << :foo
96
- subject.end_current.should include :foo
96
+ expect(subject.end_current).to include :foo
97
97
  end
98
98
  end
99
99
  end
100
100
 
101
101
  describe "#batching?" do
102
102
  it "is false when depth is 0" do
103
- subject.should_receive(:depth).and_return 0
104
- should_not be_batching
103
+ expect(subject).to receive(:depth).and_return 0
104
+ is_expected.not_to be_batching
105
105
  end
106
106
 
107
107
  it "is true when depth is more than 0" do
108
- subject.should_receive(:depth).and_return 1
109
- should be_batching
108
+ expect(subject).to receive(:depth).and_return 1
109
+ is_expected.to be_batching
110
110
  end
111
111
  end
112
112
  end
@@ -6,7 +6,7 @@ describe "DSL bindings" do
6
6
  session.search(Post) do
7
7
  value = test_method
8
8
  end
9
- value.should == 'value'
9
+ expect(value).to eq('value')
10
10
  end
11
11
 
12
12
  it 'should give access to calling context\'s id method in search DSL' do
@@ -14,7 +14,7 @@ describe "DSL bindings" do
14
14
  session.search(Post) do
15
15
  value = id
16
16
  end
17
- value.should == 16
17
+ expect(value).to eq(16)
18
18
  end
19
19
 
20
20
  it 'should give access to calling context\'s methods in nested DSL block' do
@@ -24,7 +24,7 @@ describe "DSL bindings" do
24
24
  value = test_method
25
25
  end
26
26
  end
27
- value.should == 'value'
27
+ expect(value).to eq('value')
28
28
  end
29
29
 
30
30
  it 'should give access to calling context\'s methods in double-nested DSL block' do