thinking-sphinx 3.0.5 → 3.0.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (70) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +3 -0
  3. data/HISTORY +25 -0
  4. data/README.textile +2 -2
  5. data/lib/thinking_sphinx.rb +5 -0
  6. data/lib/thinking_sphinx/active_record/callbacks/update_callbacks.rb +1 -1
  7. data/lib/thinking_sphinx/active_record/database_adapters/mysql_adapter.rb +1 -1
  8. data/lib/thinking_sphinx/active_record/database_adapters/postgresql_adapter.rb +1 -1
  9. data/lib/thinking_sphinx/active_record/property_sql_presenter.rb +10 -2
  10. data/lib/thinking_sphinx/active_record/sql_builder/clause_builder.rb +6 -7
  11. data/lib/thinking_sphinx/active_record/sql_builder/query.rb +8 -4
  12. data/lib/thinking_sphinx/active_record/sql_builder/statement.rb +7 -4
  13. data/lib/thinking_sphinx/active_record/sql_source.rb +1 -1
  14. data/lib/thinking_sphinx/configuration.rb +8 -3
  15. data/lib/thinking_sphinx/connection.rb +2 -0
  16. data/lib/thinking_sphinx/deletion.rb +1 -1
  17. data/lib/thinking_sphinx/deltas.rb +1 -1
  18. data/lib/thinking_sphinx/deltas/delete_job.rb +1 -1
  19. data/lib/thinking_sphinx/errors.rb +8 -0
  20. data/lib/thinking_sphinx/excerpter.rb +2 -2
  21. data/lib/thinking_sphinx/facet.rb +2 -2
  22. data/lib/thinking_sphinx/facet_search.rb +2 -1
  23. data/lib/thinking_sphinx/float_formatter.rb +33 -0
  24. data/lib/thinking_sphinx/index_set.rb +2 -4
  25. data/lib/thinking_sphinx/masks/group_enumerators_mask.rb +4 -3
  26. data/lib/thinking_sphinx/masks/scopes_mask.rb +5 -0
  27. data/lib/thinking_sphinx/masks/weight_enumerator_mask.rb +1 -1
  28. data/lib/thinking_sphinx/middlewares/active_record_translator.rb +6 -1
  29. data/lib/thinking_sphinx/middlewares/geographer.rb +10 -4
  30. data/lib/thinking_sphinx/middlewares/sphinxql.rb +14 -11
  31. data/lib/thinking_sphinx/middlewares/utf8.rb +2 -3
  32. data/lib/thinking_sphinx/panes/weight_pane.rb +1 -1
  33. data/lib/thinking_sphinx/rake_interface.rb +9 -7
  34. data/lib/thinking_sphinx/real_time/interpreter.rb +18 -0
  35. data/lib/thinking_sphinx/real_time/property.rb +4 -2
  36. data/lib/thinking_sphinx/search.rb +11 -10
  37. data/lib/thinking_sphinx/sphinxql.rb +17 -0
  38. data/lib/thinking_sphinx/tasks.rb +5 -1
  39. data/lib/thinking_sphinx/utf8.rb +16 -0
  40. data/spec/acceptance/attribute_access_spec.rb +4 -2
  41. data/spec/acceptance/searching_within_a_model_spec.rb +6 -0
  42. data/spec/acceptance/sorting_search_results_spec.rb +7 -0
  43. data/spec/acceptance/support/sphinx_controller.rb +5 -0
  44. data/spec/internal/app/indices/city_index.rb +1 -0
  45. data/spec/internal/app/indices/product_index.rb +1 -1
  46. data/spec/internal/tmp/.gitkeep +0 -0
  47. data/spec/thinking_sphinx/active_record/base_spec.rb +10 -0
  48. data/spec/thinking_sphinx/active_record/callbacks/update_callbacks_spec.rb +3 -2
  49. data/spec/thinking_sphinx/active_record/database_adapters/mysql_adapter_spec.rb +1 -1
  50. data/spec/thinking_sphinx/active_record/database_adapters/postgresql_adapter_spec.rb +2 -2
  51. data/spec/thinking_sphinx/active_record/field_spec.rb +13 -0
  52. data/spec/thinking_sphinx/active_record/property_sql_presenter_spec.rb +13 -0
  53. data/spec/thinking_sphinx/active_record/sql_builder_spec.rb +62 -2
  54. data/spec/thinking_sphinx/configuration_spec.rb +1 -1
  55. data/spec/thinking_sphinx/deletion_spec.rb +4 -2
  56. data/spec/thinking_sphinx/deltas/default_delta_spec.rb +2 -1
  57. data/spec/thinking_sphinx/deltas_spec.rb +17 -6
  58. data/spec/thinking_sphinx/errors_spec.rb +7 -0
  59. data/spec/thinking_sphinx/facet_search_spec.rb +6 -6
  60. data/spec/thinking_sphinx/masks/scopes_mask_spec.rb +64 -0
  61. data/spec/thinking_sphinx/middlewares/active_record_translator_spec.rb +17 -1
  62. data/spec/thinking_sphinx/middlewares/geographer_spec.rb +11 -0
  63. data/spec/thinking_sphinx/middlewares/sphinxql_spec.rb +11 -0
  64. data/spec/thinking_sphinx/panes/weight_pane_spec.rb +1 -1
  65. data/spec/thinking_sphinx/rake_interface_spec.rb +6 -0
  66. data/spec/thinking_sphinx/real_time/field_spec.rb +13 -0
  67. data/spec/thinking_sphinx/real_time/interpreter_spec.rb +40 -0
  68. data/thinking-sphinx.gemspec +3 -2
  69. metadata +12 -8
  70. data/spec/internal/.gitignore +0 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 66940af3da082d3b4d69667b40b1b6495f226dd1
4
- data.tar.gz: 52af0d5ae485c7caec6fab3206b28c34764ab1a5
3
+ metadata.gz: 7e8abde6121afcf9bad7eb33647ed1083d0f8bea
4
+ data.tar.gz: 2a372d2529cb95c232a5fc2d500aa9a5798eebd8
5
5
  SHA512:
6
- metadata.gz: eb3099e4ef3987b78b20003ba8c7ebaa13846fae26cdb6c384f47962d584dd144e511d8dcaa81f9900a9d18d3020edc489a1fde377a1816ec0337ba6b3da0ce8
7
- data.tar.gz: b43d0cb3be98bd7d738f4b8bf18492832e496a7c441368fb250ef8ecbfb4d13a5ebb66c6a14ce57b74d44cbcc6131b96f2a1581342852b7d576ccb6ffd75743c
6
+ metadata.gz: 2c22cc575eb577957271f00a0b04034871051634ddf7324132587be852ea35b995ad3e4f220dca5765d93766f69864c6d1df1a8379520fd9bc3637c239f04e28
7
+ data.tar.gz: c253ba339cf5dfc7903d6b98ebf63e77726194ab481d79ec009d3830f072598d6a65fee1efbc07dfa4ed6f6e561cef424883cbf834dbb76d0bf12dd5322f6214
data/.gitignore CHANGED
@@ -6,4 +6,7 @@ Gemfile.lock
6
6
  pkg/*
7
7
  spec/internal/config/test.sphinx.conf
8
8
  spec/internal/db/sphinx
9
+ !spec/internal/tmp/.gitkeep
10
+ spec/internal/tmp/*
11
+ !spec/internal/tmp/.gitkeep
9
12
  _site
data/HISTORY CHANGED
@@ -1,3 +1,28 @@
1
+ 2013-10-20: 3.0.6
2
+ * [FEATURE] Raise an error if no indices match the search criteria (Bryan Ricker).
3
+ * [FEATURE] skip_time_zone setting is now available per environment via config/thinking_sphinx.yml to avoid the sql_query_pre time zone command.
4
+ * [CHANGE] Updating Riddle dependency to be >= 1.5.9.
5
+ * [FEATURE] Added new search options in Sphinx 2.1.x.
6
+ * [FEATURE] Added ability to disable UTF-8 forced encoding, now that Sphinx 2.1.2 returns UTF-8 strings by default. This will be disabled by default in Thinking Sphinx 3.1.0.
7
+ * [FEATURE] Added ability to switch between Sphinx special variables and the equivalent functions. Sphinx 2.1.x requires the latter, and that behaviour will become the default in Sphinx 3.1.0.
8
+ * [FIX] Cast every column to a timestamp for timestamp attributes with multiple columns.
9
+ * [CHANGE] Separated directory preparation from data generation for real-time index (re)generation tasks.
10
+ * [CHANGE] Have tests index UTF-8 characters where appropriate (Pedro Cunha).
11
+ * [FIX] Don't use Sphinx ordering if SQL order option is supplied to a search.
12
+ * [CHANGE] Always use DISTINCT in group concatenation.
13
+ * [CHANGE] Sphinx connection failures now have their own class, ThinkingSphinx::ConnectionError, instead of the standard Mysql2::Error.
14
+ * [FIX] Custom middleware and mask options now function correctly with model-scoped searches.
15
+ * [FEATURE] Adding search_for_ids on scoped search calls.
16
+ * [CHANGE] Don't clobber custom :select options for facet searches (Timo Virkkala).
17
+ * [CHANGE] Automatically load Riddle's Sphinx 2.0.5 compatability changes.
18
+ * [FIX] Suspended deltas now no longer update core indices as well.
19
+ * [CHANGE] Realtime fields and attributes now accept symbols as well as column objects, and fields can be sortable (with a _sort prefix for the matching attribute).
20
+ * [FEATURE] MySQL users can enable a minimal GROUP BY statement, to speed up queries: set_property :minimal_group_by? => true.
21
+ * [CHANGE] Insist on the log directory existing, to ensure correct behaviour for symlinked paths. (Michael Pearson).
22
+ * [FIX] Use alphabetical ordering for index paths consistently (@grin).
23
+ * [FIX] Convert very small floats to fixed format for geo-searches.
24
+ * [CHANGE] Rake's silent mode is respected for indexing (@endoscient).
25
+
1
26
  2013-08-26: 3.0.5
2
27
  * [CHANGE] Updating Riddle dependency to be >= 1.5.8.
3
28
  * [FEATURE] Allow scoping of real-time index models.
@@ -7,7 +7,7 @@ h2. Installation
7
7
  It's a gem, so install it like you would any other gem. You will also need to specify the Mysql2 gem as well (this is not an inbuilt dependency because JRuby, when supported, will need something different):
8
8
 
9
9
  <pre><code>gem 'mysql2', '0.3.13'
10
- gem 'thinking-sphinx', '3.0.5'</code></pre>
10
+ gem 'thinking-sphinx', '3.0.6'</code></pre>
11
11
 
12
12
  The mysql2 gem is required for connecting to Sphinx, so please include it even when you're using PostgreSQL for your database.
13
13
 
@@ -216,7 +216,7 @@ May or may not be added:
216
216
 
217
217
  h3. Sphinx Versions
218
218
 
219
- TS 3 is built for Sphinx 2.x only. You cannot use 1.10-beta, 0.9.9 or anything earlier than that. 2.0.5 or newer is recommended.
219
+ TS 3 is built for Sphinx 2.0.5 or newer. You cannot use 1.10-beta, 0.9.9 or anything earlier than that.
220
220
 
221
221
  h3. Rails Versions
222
222
 
@@ -6,10 +6,12 @@ else
6
6
  end
7
7
 
8
8
  require 'riddle'
9
+ require 'riddle/2.1.0'
9
10
  require 'middleware'
10
11
  require 'active_record'
11
12
  require 'innertube'
12
13
  require 'active_support/core_ext/module/delegation'
14
+ require 'active_support/core_ext/module/attribute_accessors'
13
15
 
14
16
  module ThinkingSphinx
15
17
  def self.count(query = '', options = {})
@@ -49,6 +51,7 @@ require 'thinking_sphinx/errors'
49
51
  require 'thinking_sphinx/excerpter'
50
52
  require 'thinking_sphinx/facet'
51
53
  require 'thinking_sphinx/facet_search'
54
+ require 'thinking_sphinx/float_formatter'
52
55
  require 'thinking_sphinx/frameworks'
53
56
  require 'thinking_sphinx/index'
54
57
  require 'thinking_sphinx/index_set'
@@ -58,8 +61,10 @@ require 'thinking_sphinx/panes'
58
61
  require 'thinking_sphinx/rake_interface'
59
62
  require 'thinking_sphinx/scopes'
60
63
  require 'thinking_sphinx/search'
64
+ require 'thinking_sphinx/sphinxql'
61
65
  require 'thinking_sphinx/subscribers/populator_subscriber'
62
66
  require 'thinking_sphinx/test'
67
+ require 'thinking_sphinx/utf8'
63
68
  # Extended
64
69
  require 'thinking_sphinx/active_record'
65
70
  require 'thinking_sphinx/deltas'
@@ -45,7 +45,7 @@ class ThinkingSphinx::ActiveRecord::Callbacks::UpdateCallbacks <
45
45
  ThinkingSphinx::Connection.take do |connection|
46
46
  connection.execute(sphinxql)
47
47
  end
48
- rescue Mysql2::Error => error
48
+ rescue ThinkingSphinx::ConnectionError => error
49
49
  # This isn't vital, so don't raise the error.
50
50
  end
51
51
 
@@ -22,7 +22,7 @@ class ThinkingSphinx::ActiveRecord::DatabaseAdapters::MySQLAdapter <
22
22
  end
23
23
 
24
24
  def group_concatenate(clause, separator = ' ')
25
- "GROUP_CONCAT(#{clause} SEPARATOR '#{separator}')"
25
+ "GROUP_CONCAT(DISTINCT #{clause} SEPARATOR '#{separator}')"
26
26
  end
27
27
 
28
28
  def time_zone_query_pre
@@ -28,7 +28,7 @@ class ThinkingSphinx::ActiveRecord::DatabaseAdapters::PostgreSQLAdapter <
28
28
  end
29
29
 
30
30
  def group_concatenate(clause, separator = ' ')
31
- "array_to_string(array_agg(#{clause}), '#{separator}')"
31
+ "array_to_string(array_agg(DISTINCT #{clause}), '#{separator}')"
32
32
  end
33
33
 
34
34
  def time_zone_query_pre
@@ -19,6 +19,8 @@ class ThinkingSphinx::ActiveRecord::PropertySQLPresenter
19
19
 
20
20
  private
21
21
 
22
+ delegate :multi?, :to => :property
23
+
22
24
  def aggregate?
23
25
  property.columns.any? { |column|
24
26
  associations.aggregate_for?(column.__stack)
@@ -26,12 +28,18 @@ class ThinkingSphinx::ActiveRecord::PropertySQLPresenter
26
28
  end
27
29
 
28
30
  def aggregate_separator
29
- (property.multi?) ? ',' : ' '
31
+ multi? ? ',' : ' '
32
+ end
33
+
34
+ def cast_to_timestamp(clause)
35
+ clause.split(', ').collect { |part|
36
+ adapter.cast_to_timestamp part
37
+ }.join(', ')
30
38
  end
31
39
 
32
40
  def casted_column_with_table
33
41
  clause = columns_with_table
34
- clause = adapter.cast_to_timestamp(clause) if property.type == :timestamp
42
+ clause = cast_to_timestamp clause if property.type == :timestamp
35
43
  clause = concatenate clause
36
44
  if aggregate?
37
45
  clause = adapter.group_concatenate(clause, aggregate_separator)
@@ -2,27 +2,26 @@ module ThinkingSphinx
2
2
  module ActiveRecord
3
3
  class SQLBuilder::ClauseBuilder
4
4
  def initialize(first_element)
5
- @first_element = first_element
5
+ @clauses = [first_element]
6
6
  end
7
7
 
8
8
  def compose(*additions)
9
9
  additions.each &method(:add_clause)
10
+
10
11
  self
11
12
  end
12
13
 
13
14
  def add_clause(clause)
14
- self.clauses += Array(clause)
15
+ @clauses += Array(clause)
15
16
  end
16
17
 
17
18
  def separated(by = ', ')
18
19
  clauses.flatten.compact.join(by)
19
20
  end
20
21
 
21
- protected
22
- attr_accessor :clauses
23
- def clauses
24
- @clauses ||= [@first_element]
25
- end
22
+ private
23
+
24
+ attr_reader :clauses
26
25
  end
27
26
  end
28
27
  end
@@ -24,16 +24,20 @@ module ThinkingSphinx
24
24
  end
25
25
 
26
26
  def scope_by_delta_processor
27
- self.scope << delta_processor.reset_query if delta_processor && !source.delta?
27
+ return unless delta_processor && !source.delta?
28
+
29
+ self.scope << delta_processor.reset_query
28
30
  end
29
31
 
30
32
  def scope_by_session
31
- if max_len = source.options[:group_concat_max_len]
32
- self.scope << "SET SESSION group_concat_max_len = #{max_len}"
33
- end
33
+ return unless max_len = source.options[:group_concat_max_len]
34
+
35
+ self.scope << "SET SESSION group_concat_max_len = #{max_len}"
34
36
  end
35
37
 
36
38
  def scope_by_time_zone
39
+ return if config.settings['skip_time_zone']
40
+
37
41
  self.scope += time_zone_query_pre
38
42
  end
39
43
 
@@ -129,11 +129,14 @@ module ThinkingSphinx
129
129
  end
130
130
 
131
131
  def group_clause
132
- SQLBuilder::ClauseBuilder.new(quoted_primary_key).compose(
132
+ builder = SQLBuilder::ClauseBuilder.new(quoted_primary_key)
133
+
134
+ builder.compose(
133
135
  presenters_to_group(field_presenters),
134
- presenters_to_group(attribute_presenters),
135
- groupings
136
- ).separated
136
+ presenters_to_group(attribute_presenters)
137
+ ) unless source.options[:minimal_group_by?]
138
+
139
+ builder.compose(groupings).separated
137
140
  end
138
141
  end
139
142
  end
@@ -7,7 +7,7 @@ module ThinkingSphinx
7
7
  :groupings, :polymorphs
8
8
 
9
9
  OPTIONS = [:name, :offset, :delta_processor, :delta?, :disable_range?,
10
- :group_concat_max_len, :utf8?, :position]
10
+ :group_concat_max_len, :utf8?, :position, :minimal_group_by?]
11
11
 
12
12
  def initialize(model, options = {})
13
13
  @model = model
@@ -68,7 +68,7 @@ class ThinkingSphinx::Configuration < Riddle::Configuration
68
68
  return if @preloaded_indices
69
69
 
70
70
  index_paths.each do |path|
71
- Dir["#{path}/**/*.rb"].each do |file|
71
+ Dir["#{path}/**/*.rb"].sort.each do |file|
72
72
  ActiveSupport::Dependencies.require_or_load file
73
73
  end
74
74
  end
@@ -100,7 +100,7 @@ class ThinkingSphinx::Configuration < Riddle::Configuration
100
100
  def configure_searchd
101
101
  configure_searchd_log_files
102
102
 
103
- searchd.binlog_path = framework_root.join('tmp', 'binlog',environment).to_s
103
+ searchd.binlog_path = tmp_path.join('binlog', environment).to_s
104
104
  searchd.address = settings['address'].presence || Defaults::ADDRESS
105
105
  searchd.mysql41 = settings['mysql41'] || settings['port'] || Defaults::PORT
106
106
  searchd.workers = 'threads'
@@ -113,7 +113,7 @@ class ThinkingSphinx::Configuration < Riddle::Configuration
113
113
  end
114
114
 
115
115
  def log_root
116
- framework_root.join('log')
116
+ framework_root.join('log').realpath
117
117
  end
118
118
 
119
119
  def framework_root
@@ -147,6 +147,11 @@ class ThinkingSphinx::Configuration < Riddle::Configuration
147
147
  @offsets = {}
148
148
  end
149
149
 
150
+ def tmp_path
151
+ path = framework_root.join('tmp')
152
+ File.exists?(path) ? path.realpath : path
153
+ end
154
+
150
155
  def apply_sphinx_settings!
151
156
  [indexer, searchd].each do |object|
152
157
  settings.each do |key, value|
@@ -62,6 +62,8 @@ module ThinkingSphinx::Connection
62
62
  :port => port,
63
63
  :flags => Mysql2::Client::MULTI_STATEMENTS
64
64
  }.merge(options))
65
+ rescue Mysql2::Error => error
66
+ raise ThinkingSphinx::SphinxError.new_from_mysql error
65
67
  end
66
68
 
67
69
  def close
@@ -6,7 +6,7 @@ class ThinkingSphinx::Deletion
6
6
  'plain' => PlainDeletion,
7
7
  'rt' => RealtimeDeletion
8
8
  }[index.type].new(index, instance).perform
9
- rescue Mysql2::Error => error
9
+ rescue ThinkingSphinx::ConnectionError => error
10
10
  # This isn't vital, so don't raise the error.
11
11
  end
12
12
 
@@ -26,7 +26,7 @@ module ThinkingSphinx::Deltas
26
26
  resume!
27
27
 
28
28
  config.indices_for_references(reference).each do |index|
29
- index.delta_processor.index index
29
+ index.delta_processor.index index if index.delta?
30
30
  end
31
31
  end
32
32
 
@@ -9,7 +9,7 @@ class ThinkingSphinx::Deltas::DeleteJob
9
9
  @index_name, @document_id, :sphinx_deleted => true
10
10
  )
11
11
  end
12
- rescue Mysql2::Error => error
12
+ rescue ThinkingSphinx::ConnectionError => error
13
13
  # This isn't vital, so don't raise the error.
14
14
  end
15
15
  end
@@ -9,6 +9,8 @@ class ThinkingSphinx::SphinxError < StandardError
9
9
  replacement = ThinkingSphinx::SyntaxError.new(error.message)
10
10
  when /query error/
11
11
  replacement = ThinkingSphinx::QueryError.new(error.message)
12
+ when /Can't connect to MySQL server/
13
+ replacement = ThinkingSphinx::ConnectionError.new(error.message)
12
14
  else
13
15
  replacement = new(error.message)
14
16
  end
@@ -19,6 +21,9 @@ class ThinkingSphinx::SphinxError < StandardError
19
21
  end
20
22
  end
21
23
 
24
+ class ThinkingSphinx::ConnectionError < ThinkingSphinx::SphinxError
25
+ end
26
+
22
27
  class ThinkingSphinx::QueryError < ThinkingSphinx::SphinxError
23
28
  end
24
29
 
@@ -34,3 +39,6 @@ end
34
39
 
35
40
  class ThinkingSphinx::MixedScopesError < StandardError
36
41
  end
42
+
43
+ class ThinkingSphinx::NoIndicesError < StandardError
44
+ end
@@ -18,8 +18,8 @@ class ThinkingSphinx::Excerpter
18
18
  connection.query(statement_for(text)).first['snippet']
19
19
  end
20
20
 
21
- result.encode!("ISO-8859-1")
22
- result.force_encoding("UTF-8")
21
+ ThinkingSphinx::Configuration.instance.settings['utf8'] ? result :
22
+ ThinkingSphinx::UTF8.encode(result)
23
23
  end
24
24
 
25
25
  private
@@ -11,7 +11,7 @@ class ThinkingSphinx::Facet
11
11
 
12
12
  def results_from(raw)
13
13
  raw.inject({}) { |hash, row|
14
- hash[row[group_column]] = row['@count']
14
+ hash[row[group_column]] = row[ThinkingSphinx::SphinxQL.count]
15
15
  hash
16
16
  }
17
17
  end
@@ -19,7 +19,7 @@ class ThinkingSphinx::Facet
19
19
  private
20
20
 
21
21
  def group_column
22
- @properties.any?(&:multi?) ? '@groupby' : name
22
+ @properties.any?(&:multi?) ? ThinkingSphinx::SphinxQL.group_by : name
23
23
  end
24
24
 
25
25
  def use_field?
@@ -101,7 +101,8 @@ class ThinkingSphinx::FacetSearch
101
101
 
102
102
  def options_for(facet)
103
103
  options.merge(
104
- :select => '*, @groupby, @count',
104
+ :select => (options[:select] || '*') +
105
+ ", #{ThinkingSphinx::SphinxQL.group_by}, #{ThinkingSphinx::SphinxQL.count}",
105
106
  :group_by => facet.name,
106
107
  :indices => index_names_for(facet),
107
108
  :max_matches => limit,
@@ -0,0 +1,33 @@
1
+ class ThinkingSphinx::FloatFormatter
2
+ PATTERN = /(\d+)e\-(\d+)$/
3
+
4
+ def initialize(float)
5
+ @float = float
6
+ end
7
+
8
+ def fixed
9
+ return float.to_s unless exponent_present?
10
+
11
+ ("%0.#{decimal_places}f" % float).gsub(/0+$/, '')
12
+ end
13
+
14
+ private
15
+
16
+ attr_reader :float
17
+
18
+ def exponent_decimal_places
19
+ float.to_s[PATTERN, 1].length
20
+ end
21
+
22
+ def exponent_factor
23
+ float.to_s[PATTERN, 2].to_i
24
+ end
25
+
26
+ def exponent_present?
27
+ float.to_s['e']
28
+ end
29
+
30
+ def decimal_places
31
+ exponent_factor + exponent_decimal_places
32
+ end
33
+ end
@@ -1,6 +1,8 @@
1
1
  class ThinkingSphinx::IndexSet
2
2
  include Enumerable
3
3
 
4
+ delegate :each, :empty?, :to => :indices
5
+
4
6
  def initialize(classes, index_names, configuration = nil)
5
7
  @classes = classes || []
6
8
  @index_names = index_names
@@ -11,10 +13,6 @@ class ThinkingSphinx::IndexSet
11
13
  classes_and_ancestors - classes
12
14
  end
13
15
 
14
- def each(&block)
15
- indices.each { |index| yield index }
16
- end
17
-
18
16
  def to_a
19
17
  indices
20
18
  end