DrMark-thinking-sphinx 1.1.15 → 1.2.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (63) hide show
  1. data/README.textile +22 -0
  2. data/VERSION.yml +4 -0
  3. data/lib/thinking_sphinx/active_record/scopes.rb +39 -0
  4. data/lib/thinking_sphinx/active_record.rb +27 -7
  5. data/lib/thinking_sphinx/adapters/postgresql_adapter.rb +9 -3
  6. data/lib/thinking_sphinx/association.rb +4 -1
  7. data/lib/thinking_sphinx/attribute.rb +91 -30
  8. data/lib/thinking_sphinx/configuration.rb +51 -12
  9. data/lib/thinking_sphinx/deltas/datetime_delta.rb +2 -2
  10. data/lib/thinking_sphinx/deltas/default_delta.rb +1 -1
  11. data/lib/thinking_sphinx/deltas/delayed_delta/delta_job.rb +1 -1
  12. data/lib/thinking_sphinx/deltas/delayed_delta.rb +3 -0
  13. data/lib/thinking_sphinx/deploy/capistrano.rb +25 -8
  14. data/lib/thinking_sphinx/excerpter.rb +22 -0
  15. data/lib/thinking_sphinx/facet.rb +1 -1
  16. data/lib/thinking_sphinx/facet_search.rb +134 -0
  17. data/lib/thinking_sphinx/index.rb +2 -1
  18. data/lib/thinking_sphinx/rails_additions.rb +14 -0
  19. data/lib/thinking_sphinx/search.rb +599 -658
  20. data/lib/thinking_sphinx/search_methods.rb +421 -0
  21. data/lib/thinking_sphinx/source/internal_properties.rb +1 -1
  22. data/lib/thinking_sphinx/source/sql.rb +17 -13
  23. data/lib/thinking_sphinx/source.rb +6 -6
  24. data/lib/thinking_sphinx/tasks.rb +42 -8
  25. data/lib/thinking_sphinx.rb +82 -54
  26. data/rails/init.rb +14 -0
  27. data/spec/{unit → lib}/thinking_sphinx/active_record/delta_spec.rb +5 -5
  28. data/spec/{unit → lib}/thinking_sphinx/active_record/has_many_association_spec.rb +0 -0
  29. data/spec/lib/thinking_sphinx/active_record/scopes_spec.rb +96 -0
  30. data/spec/{unit → lib}/thinking_sphinx/active_record_spec.rb +51 -31
  31. data/spec/{unit → lib}/thinking_sphinx/association_spec.rb +4 -5
  32. data/spec/lib/thinking_sphinx/attribute_spec.rb +465 -0
  33. data/spec/{unit → lib}/thinking_sphinx/configuration_spec.rb +161 -29
  34. data/spec/{unit → lib}/thinking_sphinx/core/string_spec.rb +0 -0
  35. data/spec/lib/thinking_sphinx/excerpter_spec.rb +49 -0
  36. data/spec/lib/thinking_sphinx/facet_search_spec.rb +176 -0
  37. data/spec/{unit → lib}/thinking_sphinx/facet_spec.rb +24 -0
  38. data/spec/{unit → lib}/thinking_sphinx/field_spec.rb +8 -8
  39. data/spec/{unit → lib}/thinking_sphinx/index/builder_spec.rb +6 -2
  40. data/spec/{unit → lib}/thinking_sphinx/index/faux_column_spec.rb +0 -0
  41. data/spec/lib/thinking_sphinx/index_spec.rb +45 -0
  42. data/spec/{unit → lib}/thinking_sphinx/rails_additions_spec.rb +25 -5
  43. data/spec/lib/thinking_sphinx/search_methods_spec.rb +152 -0
  44. data/spec/lib/thinking_sphinx/search_spec.rb +960 -0
  45. data/spec/{unit → lib}/thinking_sphinx/source_spec.rb +63 -2
  46. data/spec/{unit → lib}/thinking_sphinx_spec.rb +32 -4
  47. data/tasks/distribution.rb +36 -35
  48. data/vendor/riddle/lib/riddle/client/message.rb +4 -3
  49. data/vendor/riddle/lib/riddle/client.rb +3 -0
  50. data/vendor/riddle/lib/riddle/configuration/section.rb +8 -2
  51. data/vendor/riddle/lib/riddle/controller.rb +17 -7
  52. data/vendor/riddle/lib/riddle.rb +1 -1
  53. metadata +79 -83
  54. data/lib/thinking_sphinx/active_record/search.rb +0 -57
  55. data/lib/thinking_sphinx/collection.rb +0 -148
  56. data/lib/thinking_sphinx/facet_collection.rb +0 -59
  57. data/lib/thinking_sphinx/search/facets.rb +0 -98
  58. data/spec/unit/thinking_sphinx/active_record/search_spec.rb +0 -107
  59. data/spec/unit/thinking_sphinx/attribute_spec.rb +0 -232
  60. data/spec/unit/thinking_sphinx/collection_spec.rb +0 -14
  61. data/spec/unit/thinking_sphinx/facet_collection_spec.rb +0 -64
  62. data/spec/unit/thinking_sphinx/index_spec.rb +0 -139
  63. data/spec/unit/thinking_sphinx/search_spec.rb +0 -130
@@ -0,0 +1,22 @@
1
+ module ThinkingSphinx
2
+ class Excerpter
3
+ CoreMethods = %w( kind_of? object_id respond_to? should should_not stub! )
4
+ # Hide most methods, to allow them to be passed through to the instance.
5
+ instance_methods.select { |method|
6
+ method.to_s[/^__/].nil? && !CoreMethods.include?(method.to_s)
7
+ }.each { |method|
8
+ undef_method method
9
+ }
10
+
11
+ def initialize(search, instance)
12
+ @search = search
13
+ @instance = instance
14
+ end
15
+
16
+ def method_missing(method, *args, &block)
17
+ string = @instance.send(method, *args, &block).to_s
18
+
19
+ @search.excerpt_for(string, @instance.class)
20
+ end
21
+ end
22
+ end
@@ -92,7 +92,7 @@ module ThinkingSphinx
92
92
 
93
93
  def translate(object, attribute_value)
94
94
  column.__stack.each { |method|
95
- object = object.send(method)
95
+ return nil unless object = object.send(method)
96
96
  }
97
97
  if object.is_a?(Array)
98
98
  object.collect { |item| item.send(column.__name) }
@@ -0,0 +1,134 @@
1
+ module ThinkingSphinx
2
+ class FacetSearch < Hash
3
+ attr_accessor :args, :options
4
+
5
+ def initialize(*args)
6
+ @options = args.extract_options!
7
+ @args = args
8
+
9
+ set_default_options
10
+
11
+ populate
12
+ end
13
+
14
+ def for(hash = {})
15
+ for_options = {:with => {}}.merge(options)
16
+
17
+ hash.each do |key, value|
18
+ attrib = ThinkingSphinx::Facet.attribute_name_from_value(key, value)
19
+ for_options[:with][attrib] = underlying_value key, value
20
+ end
21
+
22
+ ThinkingSphinx.search *(args + [for_options])
23
+ end
24
+
25
+ def facet_names
26
+ @facet_names ||= begin
27
+ names = options[:all_facets] ?
28
+ facet_names_for_all_classes : facet_names_common_to_all_classes
29
+
30
+ names.delete "class_crc" unless options[:class_facet]
31
+ names
32
+ end
33
+ end
34
+
35
+ private
36
+
37
+ def set_default_options
38
+ options[:all_facets] ||= false
39
+ if options[:class_facet].nil?
40
+ options[:class_facet] = ((options[:classes] || []).length != 1)
41
+ end
42
+ end
43
+
44
+ def populate
45
+ facet_names.each do |name|
46
+ search_options = facet_search_options.merge(:group_by => name)
47
+ add_from_results name, ThinkingSphinx.search(
48
+ *(args + [search_options])
49
+ )
50
+ end
51
+ end
52
+
53
+ def facet_search_options
54
+ config = ThinkingSphinx::Configuration.instance
55
+ max = config.configuration.searchd.max_matches || 1000
56
+
57
+ options.merge(
58
+ :group_function => :attr,
59
+ :limit => max,
60
+ :max_matches => max,
61
+ :page => 1
62
+ )
63
+ end
64
+
65
+ def facet_classes
66
+ (
67
+ options[:classes] || ThinkingSphinx.indexed_models.collect { |model|
68
+ model.constantize
69
+ }
70
+ ).select { |klass| klass.sphinx_facets.any? }
71
+ end
72
+
73
+ def all_facets
74
+ facet_classes.collect { |klass|
75
+ klass.sphinx_facets
76
+ }.flatten.select { |facet|
77
+ options[:facets].blank? || Array(options[:facets]).include?(facet.name)
78
+ }
79
+ end
80
+
81
+ def facet_names_for_all_classes
82
+ all_facets.group_by { |facet|
83
+ facet.name
84
+ }.collect { |name, facets|
85
+ if facets.collect { |facet| facet.type }.uniq.length > 1
86
+ raise "Facet #{name} exists in more than one model with different types"
87
+ end
88
+ facets.first.attribute_name
89
+ }
90
+ end
91
+
92
+ def facet_names_common_to_all_classes
93
+ facet_names_for_all_classes.select { |name|
94
+ facet_classes.all? { |klass|
95
+ klass.sphinx_facets.detect { |facet|
96
+ facet.attribute_name == name
97
+ }
98
+ }
99
+ }
100
+ end
101
+
102
+ def add_from_results(facet, results)
103
+ name = ThinkingSphinx::Facet.name_for(facet)
104
+
105
+ self[name] ||= {}
106
+
107
+ return if results.empty?
108
+
109
+ facet = facet_from_object(results.first, facet) if facet.is_a?(String)
110
+
111
+ results.each_with_groupby_and_count { |result, group, count|
112
+ facet_value = facet.value(result, group)
113
+
114
+ self[name][facet_value] ||= 0
115
+ self[name][facet_value] += count
116
+ }
117
+ end
118
+
119
+ def underlying_value(key, value)
120
+ case value
121
+ when Array
122
+ value.collect { |item| underlying_value(key, item) }
123
+ when String
124
+ value.to_crc32
125
+ else
126
+ value
127
+ end
128
+ end
129
+
130
+ def facet_from_object(object, name)
131
+ object.sphinx_facets.detect { |facet| facet.attribute_name == name }
132
+ end
133
+ end
134
+ end
@@ -63,7 +63,8 @@ module ThinkingSphinx
63
63
  def options
64
64
  all_index_options = ThinkingSphinx::Configuration.instance.index_options.clone
65
65
  @options.keys.select { |key|
66
- ThinkingSphinx::Configuration::IndexOptions.include?(key.to_s)
66
+ ThinkingSphinx::Configuration::IndexOptions.include?(key.to_s) ||
67
+ ThinkingSphinx::Configuration::CustomOptions.include?(key.to_s)
67
68
  }.each { |key| all_index_options[key.to_sym] = @options[key] }
68
69
  all_index_options
69
70
  end
@@ -134,3 +134,17 @@ end
134
134
  Class.extend(
135
135
  ThinkingSphinx::ClassAttributeMethods
136
136
  ) unless Class.respond_to?(:cattr_reader)
137
+
138
+ module ThinkingSphinx
139
+ module MetaClass
140
+ def metaclass
141
+ class << self
142
+ self
143
+ end
144
+ end
145
+ end
146
+ end
147
+
148
+ unless Object.new.respond_to?(:metaclass)
149
+ Object.send(:include, ThinkingSphinx::MetaClass)
150
+ end