sunspot 2.2.7 → 2.5.0

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.
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