sunspot_rbg 1.3.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 (222) hide show
  1. data/.gitignore +12 -0
  2. data/Gemfile +4 -0
  3. data/History.txt +222 -0
  4. data/LICENSE +18 -0
  5. data/Rakefile +17 -0
  6. data/TODO +13 -0
  7. data/VERSION.yml +4 -0
  8. data/bin/sunspot-installer +19 -0
  9. data/bin/sunspot-solr +74 -0
  10. data/installer/config/schema.yml +95 -0
  11. data/lib/light_config.rb +40 -0
  12. data/lib/sunspot/adapters.rb +265 -0
  13. data/lib/sunspot/composite_setup.rb +202 -0
  14. data/lib/sunspot/configuration.rb +46 -0
  15. data/lib/sunspot/data_extractor.rb +50 -0
  16. data/lib/sunspot/dsl/adjustable.rb +47 -0
  17. data/lib/sunspot/dsl/field_query.rb +279 -0
  18. data/lib/sunspot/dsl/fields.rb +103 -0
  19. data/lib/sunspot/dsl/fulltext.rb +243 -0
  20. data/lib/sunspot/dsl/function.rb +14 -0
  21. data/lib/sunspot/dsl/functional.rb +44 -0
  22. data/lib/sunspot/dsl/more_like_this_query.rb +56 -0
  23. data/lib/sunspot/dsl/paginatable.rb +28 -0
  24. data/lib/sunspot/dsl/query_facet.rb +36 -0
  25. data/lib/sunspot/dsl/restriction.rb +25 -0
  26. data/lib/sunspot/dsl/restriction_with_near.rb +121 -0
  27. data/lib/sunspot/dsl/scope.rb +217 -0
  28. data/lib/sunspot/dsl/search.rb +30 -0
  29. data/lib/sunspot/dsl/standard_query.rb +121 -0
  30. data/lib/sunspot/dsl.rb +5 -0
  31. data/lib/sunspot/field.rb +193 -0
  32. data/lib/sunspot/field_factory.rb +129 -0
  33. data/lib/sunspot/indexer.rb +131 -0
  34. data/lib/sunspot/installer/library_installer.rb +45 -0
  35. data/lib/sunspot/installer/schema_builder.rb +219 -0
  36. data/lib/sunspot/installer/solrconfig_updater.rb +76 -0
  37. data/lib/sunspot/installer/task_helper.rb +18 -0
  38. data/lib/sunspot/installer.rb +31 -0
  39. data/lib/sunspot/query/abstract_field_facet.rb +52 -0
  40. data/lib/sunspot/query/boost_query.rb +24 -0
  41. data/lib/sunspot/query/common_query.rb +85 -0
  42. data/lib/sunspot/query/composite_fulltext.rb +36 -0
  43. data/lib/sunspot/query/connective.rb +206 -0
  44. data/lib/sunspot/query/date_field_facet.rb +14 -0
  45. data/lib/sunspot/query/dismax.rb +128 -0
  46. data/lib/sunspot/query/field_facet.rb +41 -0
  47. data/lib/sunspot/query/filter.rb +38 -0
  48. data/lib/sunspot/query/function_query.rb +52 -0
  49. data/lib/sunspot/query/geo.rb +53 -0
  50. data/lib/sunspot/query/highlighting.rb +55 -0
  51. data/lib/sunspot/query/more_like_this.rb +61 -0
  52. data/lib/sunspot/query/more_like_this_query.rb +12 -0
  53. data/lib/sunspot/query/pagination.rb +38 -0
  54. data/lib/sunspot/query/query_facet.rb +16 -0
  55. data/lib/sunspot/query/restriction.rb +262 -0
  56. data/lib/sunspot/query/scope.rb +9 -0
  57. data/lib/sunspot/query/sort.rb +95 -0
  58. data/lib/sunspot/query/sort_composite.rb +33 -0
  59. data/lib/sunspot/query/standard_query.rb +16 -0
  60. data/lib/sunspot/query/text_field_boost.rb +17 -0
  61. data/lib/sunspot/query.rb +11 -0
  62. data/lib/sunspot/schema.rb +151 -0
  63. data/lib/sunspot/search/abstract_search.rb +293 -0
  64. data/lib/sunspot/search/date_facet.rb +35 -0
  65. data/lib/sunspot/search/facet_row.rb +27 -0
  66. data/lib/sunspot/search/field_facet.rb +88 -0
  67. data/lib/sunspot/search/highlight.rb +38 -0
  68. data/lib/sunspot/search/hit.rb +136 -0
  69. data/lib/sunspot/search/more_like_this_search.rb +31 -0
  70. data/lib/sunspot/search/paginated_collection.rb +55 -0
  71. data/lib/sunspot/search/query_facet.rb +67 -0
  72. data/lib/sunspot/search/standard_search.rb +21 -0
  73. data/lib/sunspot/search.rb +9 -0
  74. data/lib/sunspot/server.rb +152 -0
  75. data/lib/sunspot/session.rb +260 -0
  76. data/lib/sunspot/session_proxy/abstract_session_proxy.rb +29 -0
  77. data/lib/sunspot/session_proxy/class_sharding_session_proxy.rb +66 -0
  78. data/lib/sunspot/session_proxy/id_sharding_session_proxy.rb +89 -0
  79. data/lib/sunspot/session_proxy/master_slave_session_proxy.rb +43 -0
  80. data/lib/sunspot/session_proxy/sharding_session_proxy.rb +222 -0
  81. data/lib/sunspot/session_proxy/silent_fail_session_proxy.rb +42 -0
  82. data/lib/sunspot/session_proxy/thread_local_session_proxy.rb +37 -0
  83. data/lib/sunspot/session_proxy.rb +87 -0
  84. data/lib/sunspot/setup.rb +350 -0
  85. data/lib/sunspot/text_field_setup.rb +29 -0
  86. data/lib/sunspot/type.rb +372 -0
  87. data/lib/sunspot/util.rb +243 -0
  88. data/lib/sunspot/version.rb +3 -0
  89. data/lib/sunspot.rb +569 -0
  90. data/lib/sunspot_rbg.rb +7 -0
  91. data/log/.gitignore +1 -0
  92. data/pkg/.gitignore +1 -0
  93. data/script/console +10 -0
  94. data/solr/README.txt +42 -0
  95. data/solr/etc/jetty.xml +218 -0
  96. data/solr/etc/webdefault.xml +379 -0
  97. data/solr/lib/jetty-6.1.3.jar +0 -0
  98. data/solr/lib/jetty-util-6.1.3.jar +0 -0
  99. data/solr/lib/jsp-2.1/ant-1.6.5.jar +0 -0
  100. data/solr/lib/jsp-2.1/core-3.1.1.jar +0 -0
  101. data/solr/lib/jsp-2.1/jsp-2.1.jar +0 -0
  102. data/solr/lib/jsp-2.1/jsp-api-2.1.jar +0 -0
  103. data/solr/lib/servlet-api-2.5-6.1.3.jar +0 -0
  104. data/solr/logs/.gitignore +1 -0
  105. data/solr/solr/.gitignore +1 -0
  106. data/solr/solr/README.txt +54 -0
  107. data/solr/solr/conf/admin-extra.html +31 -0
  108. data/solr/solr/conf/elevate.xml +36 -0
  109. data/solr/solr/conf/mapping-ISOLatin1Accent.txt +246 -0
  110. data/solr/solr/conf/protwords.txt +21 -0
  111. data/solr/solr/conf/schema.xml +238 -0
  112. data/solr/solr/conf/scripts.conf +24 -0
  113. data/solr/solr/conf/solrconfig.xml +934 -0
  114. data/solr/solr/conf/spellings.txt +2 -0
  115. data/solr/solr/conf/stopwords.txt +58 -0
  116. data/solr/solr/conf/synonyms.txt +31 -0
  117. data/solr/solr/conf/xslt/example.xsl +132 -0
  118. data/solr/solr/conf/xslt/example_atom.xsl +67 -0
  119. data/solr/solr/conf/xslt/example_rss.xsl +66 -0
  120. data/solr/solr/conf/xslt/luke.xsl +337 -0
  121. data/solr/start.jar +0 -0
  122. data/solr/webapps/solr.war +0 -0
  123. data/solr-1.3/etc/jetty.xml +212 -0
  124. data/solr-1.3/etc/webdefault.xml +379 -0
  125. data/solr-1.3/lib/jetty-6.1.3.jar +0 -0
  126. data/solr-1.3/lib/jetty-util-6.1.3.jar +0 -0
  127. data/solr-1.3/lib/jsp-2.1/ant-1.6.5.jar +0 -0
  128. data/solr-1.3/lib/jsp-2.1/core-3.1.1.jar +0 -0
  129. data/solr-1.3/lib/jsp-2.1/jsp-2.1.jar +0 -0
  130. data/solr-1.3/lib/jsp-2.1/jsp-api-2.1.jar +0 -0
  131. data/solr-1.3/lib/servlet-api-2.5-6.1.3.jar +0 -0
  132. data/solr-1.3/solr/conf/elevate.xml +36 -0
  133. data/solr-1.3/solr/conf/protwords.txt +21 -0
  134. data/solr-1.3/solr/conf/schema.xml +64 -0
  135. data/solr-1.3/solr/conf/solrconfig.xml +725 -0
  136. data/solr-1.3/solr/conf/stopwords.txt +57 -0
  137. data/solr-1.3/solr/conf/synonyms.txt +31 -0
  138. data/solr-1.3/solr/lib/geoapi-nogenerics-2.1-M2.jar +0 -0
  139. data/solr-1.3/solr/lib/gt2-referencing-2.3.1.jar +0 -0
  140. data/solr-1.3/solr/lib/jsr108-0.01.jar +0 -0
  141. data/solr-1.3/solr/lib/locallucene.jar +0 -0
  142. data/solr-1.3/solr/lib/localsolr.jar +0 -0
  143. data/solr-1.3/start.jar +0 -0
  144. data/solr-1.3/webapps/solr.war +0 -0
  145. data/spec/api/adapters_spec.rb +33 -0
  146. data/spec/api/binding_spec.rb +50 -0
  147. data/spec/api/indexer/attributes_spec.rb +149 -0
  148. data/spec/api/indexer/batch_spec.rb +46 -0
  149. data/spec/api/indexer/dynamic_fields_spec.rb +42 -0
  150. data/spec/api/indexer/fixed_fields_spec.rb +57 -0
  151. data/spec/api/indexer/fulltext_spec.rb +43 -0
  152. data/spec/api/indexer/removal_spec.rb +53 -0
  153. data/spec/api/indexer/spec_helper.rb +1 -0
  154. data/spec/api/indexer_spec.rb +14 -0
  155. data/spec/api/query/advanced_manipulation_examples.rb +35 -0
  156. data/spec/api/query/connectives_examples.rb +189 -0
  157. data/spec/api/query/dsl_spec.rb +18 -0
  158. data/spec/api/query/dynamic_fields_examples.rb +165 -0
  159. data/spec/api/query/faceting_examples.rb +397 -0
  160. data/spec/api/query/fulltext_examples.rb +313 -0
  161. data/spec/api/query/function_spec.rb +70 -0
  162. data/spec/api/query/geo_examples.rb +68 -0
  163. data/spec/api/query/highlighting_examples.rb +223 -0
  164. data/spec/api/query/more_like_this_spec.rb +140 -0
  165. data/spec/api/query/ordering_pagination_examples.rb +95 -0
  166. data/spec/api/query/scope_examples.rb +275 -0
  167. data/spec/api/query/spec_helper.rb +1 -0
  168. data/spec/api/query/standard_spec.rb +28 -0
  169. data/spec/api/query/text_field_scoping_examples.rb +30 -0
  170. data/spec/api/query/types_spec.rb +20 -0
  171. data/spec/api/search/dynamic_fields_spec.rb +33 -0
  172. data/spec/api/search/faceting_spec.rb +360 -0
  173. data/spec/api/search/highlighting_spec.rb +69 -0
  174. data/spec/api/search/hits_spec.rb +120 -0
  175. data/spec/api/search/paginated_collection_spec.rb +26 -0
  176. data/spec/api/search/results_spec.rb +66 -0
  177. data/spec/api/search/search_spec.rb +23 -0
  178. data/spec/api/search/spec_helper.rb +1 -0
  179. data/spec/api/server_spec.rb +91 -0
  180. data/spec/api/session_proxy/class_sharding_session_proxy_spec.rb +85 -0
  181. data/spec/api/session_proxy/id_sharding_session_proxy_spec.rb +30 -0
  182. data/spec/api/session_proxy/master_slave_session_proxy_spec.rb +41 -0
  183. data/spec/api/session_proxy/sharding_session_proxy_spec.rb +77 -0
  184. data/spec/api/session_proxy/silent_fail_session_proxy_spec.rb +24 -0
  185. data/spec/api/session_proxy/spec_helper.rb +9 -0
  186. data/spec/api/session_proxy/thread_local_session_proxy_spec.rb +50 -0
  187. data/spec/api/session_spec.rb +220 -0
  188. data/spec/api/spec_helper.rb +3 -0
  189. data/spec/api/sunspot_spec.rb +18 -0
  190. data/spec/ext.rb +11 -0
  191. data/spec/helpers/indexer_helper.rb +29 -0
  192. data/spec/helpers/query_helper.rb +38 -0
  193. data/spec/helpers/search_helper.rb +80 -0
  194. data/spec/integration/dynamic_fields_spec.rb +55 -0
  195. data/spec/integration/faceting_spec.rb +238 -0
  196. data/spec/integration/highlighting_spec.rb +22 -0
  197. data/spec/integration/indexing_spec.rb +33 -0
  198. data/spec/integration/keyword_search_spec.rb +317 -0
  199. data/spec/integration/local_search_spec.rb +64 -0
  200. data/spec/integration/more_like_this_spec.rb +43 -0
  201. data/spec/integration/scoped_search_spec.rb +354 -0
  202. data/spec/integration/spec_helper.rb +7 -0
  203. data/spec/integration/stored_fields_spec.rb +10 -0
  204. data/spec/integration/test_pagination.rb +32 -0
  205. data/spec/mocks/adapters.rb +32 -0
  206. data/spec/mocks/blog.rb +3 -0
  207. data/spec/mocks/comment.rb +21 -0
  208. data/spec/mocks/connection.rb +126 -0
  209. data/spec/mocks/mock_adapter.rb +30 -0
  210. data/spec/mocks/mock_class_sharding_session_proxy.rb +24 -0
  211. data/spec/mocks/mock_record.rb +52 -0
  212. data/spec/mocks/mock_sharding_session_proxy.rb +15 -0
  213. data/spec/mocks/photo.rb +11 -0
  214. data/spec/mocks/post.rb +85 -0
  215. data/spec/mocks/super_class.rb +2 -0
  216. data/spec/mocks/user.rb +13 -0
  217. data/spec/spec_helper.rb +30 -0
  218. data/sunspot.gemspec +40 -0
  219. data/tasks/rdoc.rake +27 -0
  220. data/tasks/schema.rake +19 -0
  221. data/tasks/todo.rake +4 -0
  222. metadata +457 -0
@@ -0,0 +1,265 @@
1
+ module Sunspot
2
+ #
3
+ # Sunspot works by saving references to the primary key (or natural ID) of
4
+ # each indexed object, and then retrieving the objects from persistent storage
5
+ # when their IDs are referenced in search results. In order for Sunspot to
6
+ # know what an object's primary key is, and how to retrieve objects from
7
+ # persistent storage given a primary key, an adapter must be registered for
8
+ # that object's class or one of its superclasses (for instance, an adapter
9
+ # registered for ActiveRecord::Base would be used for all ActiveRecord
10
+ # models).
11
+ #
12
+ # To provide Sunspot with this ability, adapters must have two roles:
13
+ #
14
+ # Data accessor::
15
+ # A subclass of Sunspot::Adapters::DataAccessor, this object is instantiated
16
+ # with a particular class and must respond to the #load() method, which
17
+ # returns an object from persistent storage given that object's primary key.
18
+ # It can also optionally implement the #load_all() method, which returns
19
+ # a collection of objects given a collection of primary keys, if that can be
20
+ # done more efficiently than calling #load() on each key.
21
+ # Instance adapter::
22
+ # A subclass of Sunspot::Adapters::InstanceAdapter, this object is
23
+ # instantiated with a particular instance. Its only job is to tell Sunspot
24
+ # what the object's primary key is, by implementing the #id() method.
25
+ #
26
+ # Adapters are registered by registering their two components, telling Sunspot
27
+ # that they are available for one or more classes, and all of their
28
+ # subclasses. See Sunspot::Adapters::DataAccessor.register and
29
+ # Sunspot::Adapters::InstanceAdapter.register for the details.
30
+ #
31
+ # See spec/mocks/mock_adapter.rb for an example of how adapter classes should
32
+ # be implemented.
33
+ #
34
+ module Adapters
35
+ # Subclasses of the InstanceAdapter class should implement the #id method,
36
+ # which returns the primary key of the instance stored in the @instance
37
+ # variable. The primary key must be unique within the scope of the
38
+ # instance's class.
39
+ #
40
+ # ==== Example:
41
+ #
42
+ # class FileAdapter < Sunspot::Adapters::InstanceAdapter
43
+ # def id
44
+ # File.expand_path(@instance.path)
45
+ # end
46
+ # end
47
+ #
48
+ # # then in your initializer
49
+ # Sunspot::Adapters::InstanceAdapter.register(MyAdapter, File)
50
+ #
51
+ class InstanceAdapter
52
+ def initialize(instance) #:nodoc:
53
+ @instance = instance
54
+ end
55
+
56
+ #
57
+ # The universally-unique ID for this instance that will be stored in solr
58
+ #
59
+ # ==== Returns
60
+ #
61
+ # String:: ID for use in Solr
62
+ #
63
+ def index_id #:nodoc:
64
+ InstanceAdapter.index_id_for(@instance.class.name, id)
65
+ end
66
+
67
+ class <<self
68
+ # Instantiate an InstanceAdapter for the given object, searching for
69
+ # registered adapters for the object's class.
70
+ #
71
+ # ==== Parameters
72
+ #
73
+ # instance<Object>:: The instance to adapt
74
+ #
75
+ # ==== Returns
76
+ #
77
+ # InstanceAdapter::
78
+ # An instance of an InstanceAdapter implementation that
79
+ # wraps the given instance
80
+ #
81
+ def adapt(instance) #:nodoc:
82
+ self.for(instance.class).new(instance)
83
+ end
84
+
85
+ # Register an instance adapter for a set of classes. When searching for
86
+ # an adapter for a given instance, Sunspot starts with the instance's
87
+ # class, and then searches for registered adapters up the class's
88
+ # ancestor chain.
89
+ #
90
+ # ==== Parameters
91
+ #
92
+ # instance_adapter<Class>:: The instance adapter class to register
93
+ # classes...<Class>::
94
+ # One or more classes that this instance adapter adapts
95
+ #
96
+ def register(instance_adapter, *classes)
97
+ classes.each do |clazz|
98
+ instance_adapters[clazz.name.to_sym] = instance_adapter
99
+ end
100
+ end
101
+
102
+ # Find the best InstanceAdapter implementation that adapts the given
103
+ # class. Starting with the class and then moving up the ancestor chain,
104
+ # looks for registered InstanceAdapter implementations.
105
+ #
106
+ # ==== Parameters
107
+ #
108
+ # clazz<Class>:: The class to find an InstanceAdapter for
109
+ #
110
+ # ==== Returns
111
+ #
112
+ # Class:: Subclass of InstanceAdapter, or nil if none found
113
+ #
114
+ # ==== Raises
115
+ #
116
+ # Sunspot::NoAdapterError:: If no adapter is registered for this class
117
+ #
118
+ def for(clazz) #:nodoc:
119
+ original_class_name = clazz.name
120
+ clazz.ancestors.each do |ancestor_class|
121
+ next if ancestor_class.name.nil? || ancestor_class.name.empty?
122
+ class_name = ancestor_class.name.to_sym
123
+ return instance_adapters[class_name] if instance_adapters[class_name]
124
+ end
125
+
126
+ raise(Sunspot::NoAdapterError,
127
+ "No adapter is configured for #{original_class_name} or its superclasses. See the documentation for Sunspot::Adapters")
128
+ end
129
+
130
+ def index_id_for(class_name, id) #:nodoc:
131
+ "#{class_name} #{id}"
132
+ end
133
+
134
+ protected
135
+
136
+ # Lazy-initialize the hash of registered instance adapters
137
+ #
138
+ # ==== Returns
139
+ #
140
+ # Hash:: Hash containing class names keyed to instance adapter classes
141
+ #
142
+ def instance_adapters #:nodoc:
143
+ @instance_adapters ||= {}
144
+ end
145
+ end
146
+ end
147
+
148
+ # Subclasses of the DataAccessor class take care of retreiving instances of
149
+ # the adapted class from (usually persistent) storage. Subclasses must
150
+ # implement the #load method, which takes an id (the value returned by
151
+ # InstanceAdapter#id, as a string), and returns the instance referenced by
152
+ # that ID. Optionally, it can also override the #load_all method, which
153
+ # takes an array of IDs and returns an array of instances in the order
154
+ # given. #load_all need only be implemented if it can be done more
155
+ # efficiently than simply iterating over the IDs and calling #load on each
156
+ # individually.
157
+ #
158
+ # ==== Example
159
+ #
160
+ # class FileAccessor < Sunspot::Adapters::InstanceAdapter
161
+ # def load(id)
162
+ # @clazz.open(id)
163
+ # end
164
+ # end
165
+ #
166
+ # Sunspot::Adapters::DataAccessor.register(FileAccessor, File)
167
+ #
168
+ class DataAccessor
169
+ def initialize(clazz) #:nodoc:
170
+ @clazz = clazz
171
+ end
172
+
173
+ # Subclasses can override this class to provide more efficient bulk
174
+ # loading of instances. Instances must be returned in the same order
175
+ # that the IDs were given.
176
+ #
177
+ # ==== Parameters
178
+ #
179
+ # ids<Array>:: collection of IDs
180
+ #
181
+ # ==== Returns
182
+ #
183
+ # Array:: collection of instances, in order of IDs given
184
+ #
185
+ def load_all(ids)
186
+ ids.map { |id| self.load(id) }
187
+ end
188
+
189
+ class <<self
190
+ # Create a DataAccessor for the given class, searching registered
191
+ # adapters for the best match. See InstanceAdapter#adapt for discussion
192
+ # of inheritence.
193
+ #
194
+ # ==== Parameters
195
+ #
196
+ # clazz<Class>:: Class to create DataAccessor for
197
+ #
198
+ # ==== Returns
199
+ #
200
+ # DataAccessor::
201
+ # DataAccessor implementation which provides access to given class
202
+ #
203
+ def create(clazz) #:nodoc:
204
+ self.for(clazz).new(clazz)
205
+ end
206
+
207
+ # Register data accessor for a set of classes. When searching for
208
+ # an accessor for a given class, Sunspot starts with the class,
209
+ # and then searches for registered adapters up the class's ancestor
210
+ # chain.
211
+ #
212
+ # ==== Parameters
213
+ #
214
+ # data_accessor<Class>:: The data accessor class to register
215
+ # classes...<Class>::
216
+ # One or more classes that this data accessor providess access to
217
+ #
218
+ def register(data_accessor, *classes)
219
+ classes.each do |clazz|
220
+ data_accessors[clazz.name.to_sym] = data_accessor
221
+ end
222
+ end
223
+
224
+ # Find the best DataAccessor implementation that adapts the given class.
225
+ # Starting with the class and then moving up the ancestor chain, looks
226
+ # for registered DataAccessor implementations.
227
+ #
228
+ # ==== Parameters
229
+ #
230
+ # clazz<Class>:: The class to find a DataAccessor for
231
+ #
232
+ # ==== Returns
233
+ #
234
+ # Class:: Implementation of DataAccessor
235
+ #
236
+ # ==== Raises
237
+ #
238
+ # Sunspot::NoAdapterError:: If no data accessor exists for the given class
239
+ #
240
+ def for(clazz) #:nodoc:
241
+ original_class_name = clazz.name
242
+ clazz.ancestors.each do |ancestor_class|
243
+ next if ancestor_class.name.nil? || ancestor_class.name.empty?
244
+ class_name = ancestor_class.name.to_sym
245
+ return data_accessors[class_name] if data_accessors[class_name]
246
+ end
247
+ raise(Sunspot::NoAdapterError,
248
+ "No data accessor is configured for #{original_class_name} or its superclasses. See the documentation for Sunspot::Adapters")
249
+ end
250
+
251
+ protected
252
+
253
+ # Lazy-initialize the hash of registered data accessors
254
+ #
255
+ # ==== Returns
256
+ #
257
+ # Hash:: Hash containing class names keyed to data accessor classes
258
+ #
259
+ def data_accessors #:nodoc:
260
+ @adapters ||= {}
261
+ end
262
+ end
263
+ end
264
+ end
265
+ end
@@ -0,0 +1,202 @@
1
+ module Sunspot
2
+ #
3
+ # The CompositeSetup class encapsulates a collection of setups, and responds
4
+ # to a subset of the methods that Setup responds to (in particular, the
5
+ # methods required to build queries).
6
+ #
7
+ class CompositeSetup #:nodoc:
8
+ class << self
9
+ alias_method :for, :new
10
+ end
11
+
12
+ def initialize(types)
13
+ @types = types
14
+ end
15
+
16
+ #
17
+ # Collection of Setup objects for the enclosed types
18
+ #
19
+ # ==== Returns
20
+ #
21
+ # Array:: Collection of Setup objects
22
+ #
23
+ def setups
24
+ @setups ||= @types.map { |type| Setup.for(type) }
25
+ end
26
+
27
+ #
28
+ # Return the names of the encapsulated types
29
+ #
30
+ # ==== Returns
31
+ #
32
+ # Array:: Collection of class names
33
+ #
34
+ def type_names
35
+ @type_names ||= @types.map { |clazz| clazz.name }
36
+ end
37
+
38
+ #
39
+ # Get a text field object by its public name. A field will be returned if
40
+ # it is configured for any of the enclosed types.
41
+ #
42
+ # ==== Returns
43
+ #
44
+ # Sunspot::FulltextField:: Text field with the given public name
45
+ #
46
+ # ==== Raises
47
+ #
48
+ # UnrecognizedFieldError::
49
+ # If no field with that name is configured for any of the enclosed types.
50
+ #
51
+ def text_fields(field_name)
52
+ if text_fields = text_fields_hash[field_name.to_sym]
53
+ text_fields.to_a
54
+ else
55
+ raise(
56
+ UnrecognizedFieldError,
57
+ "No text field configured for #{@types * ', '} with name '#{field_name}'"
58
+ )
59
+ end
60
+ end
61
+
62
+ #
63
+ # Get a Sunspot::AttributeField instance corresponding to the given field name
64
+ #
65
+ # ==== Parameters
66
+ #
67
+ # field_name<Symbol>:: The public field name for which to find a field
68
+ #
69
+ # ==== Returns
70
+ #
71
+ # Sunspot::AttributeField The field object corresponding to the given name
72
+ #
73
+ # ==== Raises
74
+ #
75
+ # ArgumentError::
76
+ # If the given field name is not configured for the types being queried
77
+ #
78
+ def field(field_name) #:nodoc:
79
+ fields_hash[field_name.to_sym] || raise(
80
+ UnrecognizedFieldError,
81
+ "No field configured for #{@types * ', '} with name '#{field_name}'"
82
+ )
83
+ end
84
+
85
+ #
86
+ # Get a dynamic field factory for the given base name.
87
+ #
88
+ # ==== Returns
89
+ #
90
+ # DynamicFieldFactory:: Factory for dynamic fields with the given base name
91
+ #
92
+ # ==== Raises
93
+ #
94
+ # UnrecognizedFieldError::
95
+ # If the given base name is not configured as a dynamic field for the types being queried
96
+ #
97
+ def dynamic_field_factory(field_name)
98
+ dynamic_field_factories_hash[field_name.to_sym] || raise(
99
+ UnrecognizedFieldError,
100
+ "No dynamic field configured for #{@types * ', '} with name #{field_name.inspect}"
101
+ )
102
+ end
103
+
104
+ #
105
+ # Collection of all text fields configured for any of the enclosed types.
106
+ #
107
+ # === Returns
108
+ #
109
+ # Array:: Text fields configured for the enclosed types
110
+ #
111
+ def all_text_fields
112
+ @text_fields ||= text_fields_hash.values.map { |set| set.to_a }.flatten
113
+ end
114
+
115
+ def all_more_like_this_fields
116
+ @more_like_this_fields ||= more_like_this_fields_hash.values.map { |set| set.to_a }.flatten
117
+ end
118
+
119
+ private
120
+
121
+ #
122
+ # Return a hash of field names to text field objects, containing all fields
123
+ # that are configured for any of the types enclosed.
124
+ #
125
+ # ==== Returns
126
+ #
127
+ # Hash:: Hash of field names to text field objects.
128
+ #
129
+ def text_fields_hash
130
+ @text_fields_hash ||=
131
+ setups.inject({}) do |hash, setup|
132
+ setup.all_text_fields.each do |text_field|
133
+ (hash[text_field.name] ||= Set.new) << text_field
134
+ end
135
+ hash
136
+ end
137
+ end
138
+
139
+ def more_like_this_fields_hash
140
+ @more_like_this_fields_hash ||=
141
+ setups.inject({}) do |hash, setup|
142
+ setup.all_more_like_this_fields.each do |more_like_this_field|
143
+ (hash[more_like_this_field.name] ||= Set.new) << more_like_this_field
144
+ end
145
+ hash
146
+ end
147
+ end
148
+
149
+ #
150
+ # Return a hash of field names to field objects, containing all fields
151
+ # that are common to all of the classes enclosed. In order for fields
152
+ # to be common, they must be of the same type and have the same
153
+ # value for allow_multiple? and stored?. This method is memoized.
154
+ #
155
+ # ==== Returns
156
+ #
157
+ # Hash:: field names keyed to field objects
158
+ #
159
+ def fields_hash
160
+ @fields_hash ||=
161
+ begin
162
+ field_sets_hash = Hash.new { |h, k| h[k] = Set.new }
163
+ @types.each do |type|
164
+ Setup.for(type).fields.each do |field|
165
+ field_sets_hash[field.name.to_sym] << field
166
+ end
167
+ end
168
+ fields_hash = {}
169
+ field_sets_hash.each_pair do |field_name, set|
170
+ if set.length == 1
171
+ fields_hash[field_name] = set.to_a.first
172
+ end
173
+ end
174
+ fields_hash
175
+ end
176
+ end
177
+
178
+ #
179
+ # Return a hash of dynamic field base names to dynamic field factories for
180
+ # those base names. Criteria for the inclusion are the same as for
181
+ # #fields_hash()
182
+ #
183
+ def dynamic_field_factories_hash
184
+ @dynamic_field_factories_hash ||=
185
+ begin
186
+ dynamic_field_factories_hash = @types.inject({}) do |hash, type|
187
+ Setup.for(type).dynamic_field_factories.each do |field_factory|
188
+ (hash[field_factory.name.to_sym] ||= {})[type.name] = field_factory
189
+ end
190
+ hash
191
+ end
192
+ dynamic_field_factories_hash.each_pair do |field_name, field_configurations_hash|
193
+ if @types.any? { |type| field_configurations_hash[type.name].nil? }
194
+ dynamic_field_factories_hash.delete(field_name)
195
+ else
196
+ dynamic_field_factories_hash[field_name] = field_configurations_hash.values.first
197
+ end
198
+ end
199
+ end
200
+ end
201
+ end
202
+ end
@@ -0,0 +1,46 @@
1
+ module Sunspot
2
+ # The Sunspot::Configuration module provides a factory method for Sunspot
3
+ # configuration objects. Available properties are:
4
+ #
5
+ # Sunspot.config.solr.url::
6
+ # The URL at which to connect to Solr
7
+ # (default: 'http://localhost:8983/solr')
8
+ # Sunspot.config.pagination.default_per_page::
9
+ # Solr always paginates its results. This sets Sunspot's default result
10
+ # count per page if it is not explicitly specified in the query.
11
+ #
12
+ module Configuration
13
+ class <<self
14
+ # Factory method to build configuration instances.
15
+ #
16
+ # ==== Returns
17
+ #
18
+ # LightConfig::Configuration:: new configuration instance with defaults
19
+ #
20
+ def build #:nodoc:
21
+ LightConfig.build do
22
+ solr do
23
+ url 'http://127.0.0.1:8983/solr'
24
+ end
25
+ master_solr do
26
+ url nil
27
+ end
28
+ pagination do
29
+ default_per_page 30
30
+ end
31
+ end
32
+ end
33
+
34
+ # Location for the default solr configuration files,
35
+ # required for bootstrapping a new solr installation
36
+ #
37
+ # ==== Returns
38
+ #
39
+ # String:: Directory with default solr config files
40
+ #
41
+ def solr_default_configuration_location
42
+ File.join( File.dirname(__FILE__), '../../solr/solr/conf' )
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,50 @@
1
+ module Sunspot
2
+ #
3
+ # DataExtractors present an internal API for the indexer to use to extract
4
+ # field values from models for indexing. They must implement the #value_for
5
+ # method, which takes an object and returns the value extracted from it.
6
+ #
7
+ module DataExtractor #:nodoc: all
8
+ #
9
+ # AttributeExtractors extract data by simply calling a method on the block.
10
+ #
11
+ class AttributeExtractor
12
+ def initialize(attribute_name)
13
+ @attribute_name = attribute_name
14
+ end
15
+
16
+ def value_for(object)
17
+ object.send(@attribute_name)
18
+ end
19
+ end
20
+
21
+ #
22
+ # BlockExtractors extract data by evaluating a block in the context of the
23
+ # object instance, or if the block takes an argument, by passing the object
24
+ # as the argument to the block. Either way, the return value of the block is
25
+ # the value returned by the extractor.
26
+ #
27
+ class BlockExtractor
28
+ def initialize(&block)
29
+ @block = block
30
+ end
31
+
32
+ def value_for(object)
33
+ Util.instance_eval_or_call(object, &@block)
34
+ end
35
+ end
36
+
37
+ #
38
+ # Constant data extractors simply return the same value for every object.
39
+ #
40
+ class Constant
41
+ def initialize(value)
42
+ @value = value
43
+ end
44
+
45
+ def value_for(object)
46
+ @value
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,47 @@
1
+ module Sunspot
2
+ module DSL #:nodoc:
3
+ module Adjustable #:nodoc
4
+ # <strong>Expert:</strong> Adjust or reset the parameters passed to Solr.
5
+ # The adjustment will take place just before sending the params to solr,
6
+ # after Sunspot builds the Solr params based on the methods called in the
7
+ # DSL.
8
+ #
9
+ # Under normal circumstances, using this method should not be necessary;
10
+ # if you find that it is, please consider submitting a feature request.
11
+ # Using this method requires knowledge of Sunspot's internal Solr schema
12
+ # and Solr query representations, which are not part of Sunspot's public
13
+ # API; they could change at any time. <strong>This method is unsupported
14
+ # and your mileage may vary.</strong>
15
+ #
16
+ # ==== Examples
17
+ #
18
+ # Sunspot.search(Post) do
19
+ # adjust_solr_params do |params|
20
+ # params[:q] += ' AND something_s:more'
21
+ # end
22
+ # end
23
+ #
24
+ # Sunspot.more_like_this(my_post) do
25
+ # adjust_solr_params do |params|
26
+ # params["mlt.match.include"] = true
27
+ # end
28
+ # end
29
+ #
30
+ def adjust_solr_params( &block )
31
+ @query.solr_parameter_adjustment = block
32
+ end
33
+
34
+ #
35
+ # <strong>Expert:</strong> Use a custom request handler for this search.
36
+ # The general use case for this would be a request handler configuration
37
+ # you've defined in solrconfig that has different search components,
38
+ # defaults, etc. Using this to point at an entirely different type of
39
+ # request handler that Sunspot doesn't support probably won't get you very
40
+ # far.
41
+ #
42
+ def request_handler(request_handler)
43
+ @search.request_handler = request_handler
44
+ end
45
+ end
46
+ end
47
+ end