sunspot_solr 2.0.0.pre.120720 → 2.0.0.pre.120924

Sign up to get free protection for your applications and to get access to all the features.
Files changed (293) hide show
  1. data/.gitignore +11 -0
  2. data/.travis.yml +35 -0
  3. data/README.md +863 -0
  4. data/Rakefile +37 -0
  5. data/ci/travis.sh +67 -0
  6. data/sunspot/.gitignore +13 -0
  7. data/sunspot/Gemfile +5 -0
  8. data/sunspot/History.txt +258 -0
  9. data/sunspot/LICENSE +18 -0
  10. data/sunspot/Rakefile +13 -0
  11. data/sunspot/TODO +13 -0
  12. data/sunspot/lib/light_config.rb +40 -0
  13. data/sunspot/lib/sunspot.rb +579 -0
  14. data/sunspot/lib/sunspot/adapters.rb +349 -0
  15. data/sunspot/lib/sunspot/batcher.rb +62 -0
  16. data/sunspot/lib/sunspot/class_set.rb +23 -0
  17. data/sunspot/lib/sunspot/composite_setup.rb +202 -0
  18. data/sunspot/lib/sunspot/configuration.rb +53 -0
  19. data/sunspot/lib/sunspot/data_extractor.rb +50 -0
  20. data/sunspot/lib/sunspot/dsl.rb +5 -0
  21. data/sunspot/lib/sunspot/dsl/adjustable.rb +47 -0
  22. data/sunspot/lib/sunspot/dsl/field_group.rb +57 -0
  23. data/sunspot/lib/sunspot/dsl/field_query.rb +345 -0
  24. data/sunspot/lib/sunspot/dsl/fields.rb +103 -0
  25. data/sunspot/lib/sunspot/dsl/fulltext.rb +243 -0
  26. data/sunspot/lib/sunspot/dsl/function.rb +27 -0
  27. data/sunspot/lib/sunspot/dsl/functional.rb +44 -0
  28. data/sunspot/lib/sunspot/dsl/more_like_this_query.rb +56 -0
  29. data/sunspot/lib/sunspot/dsl/paginatable.rb +32 -0
  30. data/sunspot/lib/sunspot/dsl/query_facet.rb +36 -0
  31. data/sunspot/lib/sunspot/dsl/restriction.rb +25 -0
  32. data/sunspot/lib/sunspot/dsl/restriction_with_near.rb +160 -0
  33. data/sunspot/lib/sunspot/dsl/scope.rb +214 -0
  34. data/sunspot/lib/sunspot/dsl/search.rb +30 -0
  35. data/sunspot/lib/sunspot/dsl/standard_query.rb +122 -0
  36. data/sunspot/lib/sunspot/field.rb +193 -0
  37. data/sunspot/lib/sunspot/field_factory.rb +129 -0
  38. data/sunspot/lib/sunspot/indexer.rb +136 -0
  39. data/sunspot/lib/sunspot/query.rb +11 -0
  40. data/sunspot/lib/sunspot/query/abstract_field_facet.rb +55 -0
  41. data/sunspot/lib/sunspot/query/bbox.rb +15 -0
  42. data/sunspot/lib/sunspot/query/boost_query.rb +24 -0
  43. data/sunspot/lib/sunspot/query/common_query.rb +96 -0
  44. data/sunspot/lib/sunspot/query/composite_fulltext.rb +36 -0
  45. data/sunspot/lib/sunspot/query/connective.rb +206 -0
  46. data/sunspot/lib/sunspot/query/date_field_facet.rb +14 -0
  47. data/sunspot/lib/sunspot/query/dismax.rb +132 -0
  48. data/sunspot/lib/sunspot/query/field_facet.rb +41 -0
  49. data/sunspot/lib/sunspot/query/field_group.rb +37 -0
  50. data/sunspot/lib/sunspot/query/filter.rb +38 -0
  51. data/sunspot/lib/sunspot/query/function_query.rb +52 -0
  52. data/sunspot/lib/sunspot/query/geo.rb +53 -0
  53. data/sunspot/lib/sunspot/query/geofilt.rb +16 -0
  54. data/sunspot/lib/sunspot/query/highlighting.rb +62 -0
  55. data/sunspot/lib/sunspot/query/more_like_this.rb +61 -0
  56. data/sunspot/lib/sunspot/query/more_like_this_query.rb +12 -0
  57. data/sunspot/lib/sunspot/query/pagination.rb +42 -0
  58. data/sunspot/lib/sunspot/query/query_facet.rb +53 -0
  59. data/sunspot/lib/sunspot/query/range_facet.rb +15 -0
  60. data/sunspot/lib/sunspot/query/restriction.rb +308 -0
  61. data/sunspot/lib/sunspot/query/scope.rb +9 -0
  62. data/sunspot/lib/sunspot/query/sort.rb +109 -0
  63. data/sunspot/lib/sunspot/query/sort_composite.rb +34 -0
  64. data/sunspot/lib/sunspot/query/standard_query.rb +16 -0
  65. data/sunspot/lib/sunspot/query/text_field_boost.rb +17 -0
  66. data/sunspot/lib/sunspot/schema.rb +151 -0
  67. data/sunspot/lib/sunspot/search.rb +9 -0
  68. data/sunspot/lib/sunspot/search/abstract_search.rb +286 -0
  69. data/sunspot/lib/sunspot/search/date_facet.rb +35 -0
  70. data/sunspot/lib/sunspot/search/facet_row.rb +27 -0
  71. data/sunspot/lib/sunspot/search/field_facet.rb +88 -0
  72. data/sunspot/lib/sunspot/search/field_group.rb +70 -0
  73. data/sunspot/lib/sunspot/search/group.rb +54 -0
  74. data/sunspot/lib/sunspot/search/highlight.rb +38 -0
  75. data/sunspot/lib/sunspot/search/hit.rb +150 -0
  76. data/sunspot/lib/sunspot/search/hit_enumerable.rb +68 -0
  77. data/sunspot/lib/sunspot/search/more_like_this_search.rb +31 -0
  78. data/sunspot/lib/sunspot/search/paginated_collection.rb +57 -0
  79. data/sunspot/lib/sunspot/search/query_facet.rb +67 -0
  80. data/sunspot/lib/sunspot/search/range_facet.rb +37 -0
  81. data/sunspot/lib/sunspot/search/standard_search.rb +21 -0
  82. data/sunspot/lib/sunspot/session.rb +262 -0
  83. data/sunspot/lib/sunspot/session_proxy.rb +95 -0
  84. data/sunspot/lib/sunspot/session_proxy/abstract_session_proxy.rb +29 -0
  85. data/sunspot/lib/sunspot/session_proxy/class_sharding_session_proxy.rb +66 -0
  86. data/sunspot/lib/sunspot/session_proxy/id_sharding_session_proxy.rb +89 -0
  87. data/sunspot/lib/sunspot/session_proxy/master_slave_session_proxy.rb +43 -0
  88. data/sunspot/lib/sunspot/session_proxy/retry_5xx_session_proxy.rb +67 -0
  89. data/sunspot/lib/sunspot/session_proxy/sharding_session_proxy.rb +222 -0
  90. data/sunspot/lib/sunspot/session_proxy/silent_fail_session_proxy.rb +42 -0
  91. data/sunspot/lib/sunspot/session_proxy/thread_local_session_proxy.rb +37 -0
  92. data/sunspot/lib/sunspot/setup.rb +350 -0
  93. data/sunspot/lib/sunspot/text_field_setup.rb +29 -0
  94. data/sunspot/lib/sunspot/type.rb +393 -0
  95. data/sunspot/lib/sunspot/util.rb +252 -0
  96. data/sunspot/lib/sunspot/version.rb +3 -0
  97. data/sunspot/script/console +10 -0
  98. data/sunspot/spec/api/adapters_spec.rb +68 -0
  99. data/sunspot/spec/api/batcher_spec.rb +112 -0
  100. data/sunspot/spec/api/binding_spec.rb +50 -0
  101. data/sunspot/spec/api/class_set_spec.rb +24 -0
  102. data/sunspot/spec/api/hit_enumerable_spec.rb +47 -0
  103. data/sunspot/spec/api/indexer/attributes_spec.rb +149 -0
  104. data/sunspot/spec/api/indexer/batch_spec.rb +72 -0
  105. data/sunspot/spec/api/indexer/dynamic_fields_spec.rb +42 -0
  106. data/sunspot/spec/api/indexer/fixed_fields_spec.rb +57 -0
  107. data/sunspot/spec/api/indexer/fulltext_spec.rb +43 -0
  108. data/sunspot/spec/api/indexer/removal_spec.rb +53 -0
  109. data/sunspot/spec/api/indexer/spec_helper.rb +1 -0
  110. data/sunspot/spec/api/indexer_spec.rb +14 -0
  111. data/sunspot/spec/api/query/advanced_manipulation_examples.rb +35 -0
  112. data/sunspot/spec/api/query/connectives_examples.rb +201 -0
  113. data/sunspot/spec/api/query/dsl_spec.rb +18 -0
  114. data/sunspot/spec/api/query/dynamic_fields_examples.rb +165 -0
  115. data/sunspot/spec/api/query/faceting_examples.rb +497 -0
  116. data/sunspot/spec/api/query/fulltext_examples.rb +313 -0
  117. data/sunspot/spec/api/query/function_spec.rb +79 -0
  118. data/sunspot/spec/api/query/geo_examples.rb +68 -0
  119. data/sunspot/spec/api/query/group_spec.rb +32 -0
  120. data/sunspot/spec/api/query/highlighting_examples.rb +245 -0
  121. data/sunspot/spec/api/query/more_like_this_spec.rb +140 -0
  122. data/sunspot/spec/api/query/ordering_pagination_examples.rb +116 -0
  123. data/sunspot/spec/api/query/scope_examples.rb +275 -0
  124. data/sunspot/spec/api/query/spatial_examples.rb +27 -0
  125. data/sunspot/spec/api/query/spec_helper.rb +1 -0
  126. data/sunspot/spec/api/query/standard_spec.rb +29 -0
  127. data/sunspot/spec/api/query/text_field_scoping_examples.rb +30 -0
  128. data/sunspot/spec/api/query/types_spec.rb +20 -0
  129. data/sunspot/spec/api/search/dynamic_fields_spec.rb +33 -0
  130. data/sunspot/spec/api/search/faceting_spec.rb +360 -0
  131. data/sunspot/spec/api/search/highlighting_spec.rb +69 -0
  132. data/sunspot/spec/api/search/hits_spec.rb +147 -0
  133. data/sunspot/spec/api/search/paginated_collection_spec.rb +36 -0
  134. data/sunspot/spec/api/search/results_spec.rb +72 -0
  135. data/sunspot/spec/api/search/search_spec.rb +23 -0
  136. data/sunspot/spec/api/search/spec_helper.rb +1 -0
  137. data/sunspot/spec/api/session_proxy/class_sharding_session_proxy_spec.rb +85 -0
  138. data/sunspot/spec/api/session_proxy/id_sharding_session_proxy_spec.rb +30 -0
  139. data/sunspot/spec/api/session_proxy/master_slave_session_proxy_spec.rb +41 -0
  140. data/sunspot/spec/api/session_proxy/retry_5xx_session_proxy_spec.rb +78 -0
  141. data/sunspot/spec/api/session_proxy/sharding_session_proxy_spec.rb +77 -0
  142. data/sunspot/spec/api/session_proxy/silent_fail_session_proxy_spec.rb +24 -0
  143. data/sunspot/spec/api/session_proxy/spec_helper.rb +9 -0
  144. data/sunspot/spec/api/session_proxy/thread_local_session_proxy_spec.rb +39 -0
  145. data/sunspot/spec/api/session_spec.rb +232 -0
  146. data/sunspot/spec/api/spec_helper.rb +3 -0
  147. data/sunspot/spec/api/sunspot_spec.rb +29 -0
  148. data/sunspot/spec/ext.rb +11 -0
  149. data/sunspot/spec/helpers/indexer_helper.rb +17 -0
  150. data/sunspot/spec/helpers/integration_helper.rb +8 -0
  151. data/sunspot/spec/helpers/mock_session_helper.rb +13 -0
  152. data/sunspot/spec/helpers/query_helper.rb +26 -0
  153. data/sunspot/spec/helpers/search_helper.rb +68 -0
  154. data/sunspot/spec/integration/dynamic_fields_spec.rb +57 -0
  155. data/sunspot/spec/integration/faceting_spec.rb +330 -0
  156. data/sunspot/spec/integration/field_grouping_spec.rb +100 -0
  157. data/sunspot/spec/integration/geospatial_spec.rb +96 -0
  158. data/sunspot/spec/integration/highlighting_spec.rb +44 -0
  159. data/sunspot/spec/integration/indexing_spec.rb +55 -0
  160. data/sunspot/spec/integration/keyword_search_spec.rb +317 -0
  161. data/sunspot/spec/integration/local_search_spec.rb +64 -0
  162. data/sunspot/spec/integration/more_like_this_spec.rb +43 -0
  163. data/sunspot/spec/integration/scoped_search_spec.rb +386 -0
  164. data/sunspot/spec/integration/stored_fields_spec.rb +12 -0
  165. data/sunspot/spec/integration/test_pagination.rb +43 -0
  166. data/sunspot/spec/integration/unicode_spec.rb +15 -0
  167. data/sunspot/spec/mocks/adapters.rb +33 -0
  168. data/sunspot/spec/mocks/blog.rb +3 -0
  169. data/sunspot/spec/mocks/comment.rb +21 -0
  170. data/sunspot/spec/mocks/connection.rb +126 -0
  171. data/sunspot/spec/mocks/mock_adapter.rb +30 -0
  172. data/sunspot/spec/mocks/mock_class_sharding_session_proxy.rb +24 -0
  173. data/sunspot/spec/mocks/mock_record.rb +52 -0
  174. data/sunspot/spec/mocks/mock_sharding_session_proxy.rb +15 -0
  175. data/sunspot/spec/mocks/photo.rb +11 -0
  176. data/sunspot/spec/mocks/post.rb +86 -0
  177. data/sunspot/spec/mocks/super_class.rb +2 -0
  178. data/sunspot/spec/mocks/user.rb +13 -0
  179. data/sunspot/spec/spec_helper.rb +40 -0
  180. data/sunspot/sunspot.gemspec +37 -0
  181. data/sunspot/tasks/rdoc.rake +27 -0
  182. data/sunspot/tasks/schema.rake +19 -0
  183. data/sunspot/tasks/todo.rake +4 -0
  184. data/sunspot_rails/.gitignore +7 -0
  185. data/sunspot_rails/.rspec +1 -0
  186. data/sunspot_rails/History.txt +74 -0
  187. data/sunspot_rails/LICENSE +18 -0
  188. data/sunspot_rails/MIT-LICENSE +20 -0
  189. data/sunspot_rails/README.rdoc +265 -0
  190. data/sunspot_rails/Rakefile +17 -0
  191. data/sunspot_rails/TODO +8 -0
  192. data/sunspot_rails/dev_tasks/rdoc.rake +24 -0
  193. data/sunspot_rails/dev_tasks/release.rake +4 -0
  194. data/sunspot_rails/dev_tasks/spec.rake +107 -0
  195. data/sunspot_rails/dev_tasks/todo.rake +4 -0
  196. data/sunspot_rails/gemfiles/rails-2.3.14 +12 -0
  197. data/sunspot_rails/gemfiles/rails-3.0.15 +12 -0
  198. data/sunspot_rails/gemfiles/rails-3.1.6 +12 -0
  199. data/sunspot_rails/gemfiles/rails-3.2.6 +12 -0
  200. data/sunspot_rails/generators/sunspot/sunspot_generator.rb +9 -0
  201. data/sunspot_rails/generators/sunspot/templates/sunspot.yml +20 -0
  202. data/sunspot_rails/install.rb +1 -0
  203. data/sunspot_rails/lib/generators/sunspot_rails.rb +9 -0
  204. data/sunspot_rails/lib/generators/sunspot_rails/install/install_generator.rb +13 -0
  205. data/sunspot_rails/lib/generators/sunspot_rails/install/templates/config/sunspot.yml +19 -0
  206. data/sunspot_rails/lib/sunspot/rails.rb +69 -0
  207. data/sunspot_rails/lib/sunspot/rails/adapters.rb +88 -0
  208. data/sunspot_rails/lib/sunspot/rails/configuration.rb +352 -0
  209. data/sunspot_rails/lib/sunspot/rails/init.rb +5 -0
  210. data/sunspot_rails/lib/sunspot/rails/log_subscriber.rb +45 -0
  211. data/sunspot_rails/lib/sunspot/rails/railtie.rb +41 -0
  212. data/sunspot_rails/lib/sunspot/rails/railties/controller_runtime.rb +36 -0
  213. data/sunspot_rails/lib/sunspot/rails/request_lifecycle.rb +36 -0
  214. data/sunspot_rails/lib/sunspot/rails/searchable.rb +495 -0
  215. data/sunspot_rails/lib/sunspot/rails/server.rb +106 -0
  216. data/sunspot_rails/lib/sunspot/rails/solr_instrumentation.rb +19 -0
  217. data/sunspot_rails/lib/sunspot/rails/solr_logging.rb +62 -0
  218. data/sunspot_rails/lib/sunspot/rails/spec_helper.rb +26 -0
  219. data/sunspot_rails/lib/sunspot/rails/stub_session_proxy.rb +146 -0
  220. data/sunspot_rails/lib/sunspot/rails/tasks.rb +94 -0
  221. data/sunspot_rails/lib/sunspot_rails.rb +12 -0
  222. data/sunspot_rails/spec/configuration_spec.rb +209 -0
  223. data/sunspot_rails/spec/model_lifecycle_spec.rb +63 -0
  224. data/sunspot_rails/spec/model_spec.rb +601 -0
  225. data/sunspot_rails/spec/rails_template/app/controllers/application_controller.rb +10 -0
  226. data/sunspot_rails/spec/rails_template/app/controllers/posts_controller.rb +6 -0
  227. data/sunspot_rails/spec/rails_template/app/models/author.rb +10 -0
  228. data/sunspot_rails/spec/rails_template/app/models/blog.rb +14 -0
  229. data/sunspot_rails/spec/rails_template/app/models/location.rb +3 -0
  230. data/sunspot_rails/spec/rails_template/app/models/photo_post.rb +2 -0
  231. data/sunspot_rails/spec/rails_template/app/models/post.rb +13 -0
  232. data/sunspot_rails/spec/rails_template/app/models/post_with_auto.rb +12 -0
  233. data/sunspot_rails/spec/rails_template/app/models/post_with_default_scope.rb +13 -0
  234. data/sunspot_rails/spec/rails_template/config/boot.rb +127 -0
  235. data/sunspot_rails/spec/rails_template/config/preinitializer.rb +22 -0
  236. data/sunspot_rails/spec/rails_template/config/routes.rb +9 -0
  237. data/sunspot_rails/spec/rails_template/config/sunspot.yml +24 -0
  238. data/sunspot_rails/spec/rails_template/db/schema.rb +27 -0
  239. data/sunspot_rails/spec/request_lifecycle_spec.rb +61 -0
  240. data/sunspot_rails/spec/schema.rb +27 -0
  241. data/sunspot_rails/spec/searchable_spec.rb +12 -0
  242. data/sunspot_rails/spec/server_spec.rb +33 -0
  243. data/sunspot_rails/spec/session_spec.rb +57 -0
  244. data/sunspot_rails/spec/shared_examples/indexed_after_save.rb +8 -0
  245. data/sunspot_rails/spec/shared_examples/not_indexed_after_save.rb +8 -0
  246. data/sunspot_rails/spec/spec_helper.rb +48 -0
  247. data/sunspot_rails/spec/stub_session_proxy_spec.rb +122 -0
  248. data/sunspot_rails/sunspot_rails.gemspec +43 -0
  249. data/{Gemfile → sunspot_solr/Gemfile} +0 -0
  250. data/{README.rdoc → sunspot_solr/README.rdoc} +0 -0
  251. data/{bin → sunspot_solr/bin}/sunspot-installer +0 -0
  252. data/{bin → sunspot_solr/bin}/sunspot-solr +0 -0
  253. data/{lib → sunspot_solr/lib}/sunspot/solr/installer.rb +0 -0
  254. data/{lib → sunspot_solr/lib}/sunspot/solr/installer/config_installer.rb +0 -0
  255. data/{lib → sunspot_solr/lib}/sunspot/solr/installer/task_helper.rb +0 -0
  256. data/{lib → sunspot_solr/lib}/sunspot/solr/java.rb +0 -0
  257. data/{lib → sunspot_solr/lib}/sunspot/solr/railtie.rb +0 -0
  258. data/{lib → sunspot_solr/lib}/sunspot/solr/server.rb +1 -2
  259. data/{lib → sunspot_solr/lib}/sunspot/solr/tasks.rb +0 -0
  260. data/{lib → sunspot_solr/lib}/sunspot_solr.rb +0 -0
  261. data/{solr → sunspot_solr/solr}/README.txt +0 -0
  262. data/{solr → sunspot_solr/solr}/etc/jetty.xml +0 -0
  263. data/{solr → sunspot_solr/solr}/etc/webdefault.xml +0 -0
  264. data/{solr → sunspot_solr/solr}/lib/jetty-6.1.26-patched-JETTY-1340.jar +0 -0
  265. data/{solr → sunspot_solr/solr}/lib/jetty-util-6.1.26-patched-JETTY-1340.jar +0 -0
  266. data/{solr → sunspot_solr/solr}/lib/jsp-2.1/ant-1.6.5.jar +0 -0
  267. data/{solr → sunspot_solr/solr}/lib/jsp-2.1/core-3.1.1.jar +0 -0
  268. data/{solr → sunspot_solr/solr}/lib/jsp-2.1/jsp-2.1.jar +0 -0
  269. data/{solr → sunspot_solr/solr}/lib/jsp-2.1/jsp-api-2.1.jar +0 -0
  270. data/{solr → sunspot_solr/solr}/lib/servlet-api-2.5-20081211.jar +0 -0
  271. data/{solr → sunspot_solr/solr}/solr/.gitignore +0 -0
  272. data/{solr → sunspot_solr/solr}/solr/README.txt +0 -0
  273. data/{solr → sunspot_solr/solr}/solr/conf/admin-extra.html +0 -0
  274. data/{solr → sunspot_solr/solr}/solr/conf/elevate.xml +0 -0
  275. data/{solr → sunspot_solr/solr}/solr/conf/mapping-ISOLatin1Accent.txt +0 -0
  276. data/{solr → sunspot_solr/solr}/solr/conf/protwords.txt +0 -0
  277. data/{solr → sunspot_solr/solr}/solr/conf/schema.xml +0 -0
  278. data/{solr → sunspot_solr/solr}/solr/conf/scripts.conf +0 -0
  279. data/{solr → sunspot_solr/solr}/solr/conf/solrconfig.xml +0 -0
  280. data/{solr → sunspot_solr/solr}/solr/conf/spellings.txt +0 -0
  281. data/{solr → sunspot_solr/solr}/solr/conf/stopwords.txt +0 -0
  282. data/{solr → sunspot_solr/solr}/solr/conf/synonyms.txt +0 -0
  283. data/{solr → sunspot_solr/solr}/solr/conf/xslt/example.xsl +0 -0
  284. data/{solr → sunspot_solr/solr}/solr/conf/xslt/example_atom.xsl +0 -0
  285. data/{solr → sunspot_solr/solr}/solr/conf/xslt/example_rss.xsl +0 -0
  286. data/{solr → sunspot_solr/solr}/solr/conf/xslt/luke.xsl +0 -0
  287. data/{solr → sunspot_solr/solr}/start.jar +0 -0
  288. data/{solr → sunspot_solr/solr}/webapps/solr.war +0 -0
  289. data/{spec → sunspot_solr/spec}/server_spec.rb +0 -0
  290. data/{spec → sunspot_solr/spec}/spec_helper.rb +0 -0
  291. data/{sunspot_solr.gemspec → sunspot_solr/sunspot_solr.gemspec} +0 -0
  292. data/tools/gem_tasks.rb +69 -0
  293. metadata +340 -110
@@ -0,0 +1,393 @@
1
+ require 'singleton'
2
+ begin
3
+ require 'geohash'
4
+ rescue LoadError => e
5
+ require 'pr_geohash'
6
+ end
7
+
8
+ module Sunspot
9
+ #
10
+ # This module contains singleton objects that represent the types that can be
11
+ # indexed and searched using Sunspot. Plugin developers should be able to
12
+ # add new constants to the Type module; as long as they implement the
13
+ # appropriate methods, Sunspot should be able to integrate them (note that
14
+ # this capability is untested at the moment). The required methods are:
15
+ #
16
+ # +indexed_name+::
17
+ # Convert a given field name into its form as stored in Solr. This
18
+ # generally means adding a suffix to match a Solr dynamicField definition.
19
+ # +to_indexed+::
20
+ # Convert a value of this type into the appropriate Solr string
21
+ # representation.
22
+ # +cast+::
23
+ # Convert a Solr string representation of a value into the appropriate
24
+ # Ruby type.
25
+ #
26
+ module Type
27
+ class <<self
28
+ def register(sunspot_type, *classes)
29
+ classes.each do |clazz|
30
+ ruby_type_map[clazz.name.to_sym] = sunspot_type.instance
31
+ end
32
+ end
33
+
34
+ def for_class(clazz)
35
+ if clazz
36
+ ruby_type_map[clazz.name.to_sym] || for_class(clazz.superclass)
37
+ end
38
+ end
39
+
40
+ def for(object)
41
+ for_class(object.class)
42
+ end
43
+
44
+ def to_indexed(object)
45
+ if type = self.for(object)
46
+ type.to_indexed(object)
47
+ else
48
+ object.to_s
49
+ end
50
+ end
51
+
52
+ def to_literal(object)
53
+ if type = self.for(object)
54
+ type.to_literal(object)
55
+ else
56
+ raise ArgumentError, "Can't use #{object.inspect} as Solr literal: #{object.class} has no registered Solr type"
57
+ end
58
+ end
59
+
60
+ private
61
+
62
+ def ruby_type_map
63
+ @ruby_type_map ||= {}
64
+ end
65
+ end
66
+
67
+ class AbstractType #:nodoc:
68
+ include Singleton
69
+
70
+ def accepts_dynamic?
71
+ true
72
+ end
73
+
74
+ def accepts_more_like_this?
75
+ false
76
+ end
77
+
78
+ def to_literal(object)
79
+ raise(
80
+ ArgumentError,
81
+ "#{self.class.name} cannot be used as a Solr literal"
82
+ )
83
+ end
84
+ end
85
+
86
+ #
87
+ # Text is a special type that stores data for fulltext search. Unlike other
88
+ # types, Text fields are tokenized and are made available to the keyword
89
+ # search phrase. Text fields cannot be faceted, ordered upon, or used in
90
+ # restrictions. Similarly, text fields are the only fields that are made
91
+ # available to keyword search.
92
+ #
93
+ class TextType < AbstractType
94
+ def indexed_name(name) #:nodoc:
95
+ "#{name}_text"
96
+ end
97
+
98
+ def to_indexed(value) #:nodoc:
99
+ value.to_s if value
100
+ end
101
+
102
+ def cast(text)
103
+ text
104
+ end
105
+
106
+ def accepts_dynamic?
107
+ false
108
+ end
109
+
110
+ def accepts_more_like_this?
111
+ true
112
+ end
113
+ end
114
+
115
+ #
116
+ # The String type represents string data.
117
+ #
118
+ class StringType < AbstractType
119
+ def indexed_name(name) #:nodoc:
120
+ "#{name}_s"
121
+ end
122
+
123
+ def to_indexed(value) #:nodoc:
124
+ value.to_s if value
125
+ end
126
+
127
+ def cast(string) #:nodoc:
128
+ string
129
+ end
130
+ end
131
+ register(StringType, String)
132
+
133
+ #
134
+ # The Integer type represents integers.
135
+ #
136
+ class IntegerType < AbstractType
137
+ def indexed_name(name) #:nodoc:
138
+ "#{name}_i"
139
+ end
140
+
141
+ def to_indexed(value) #:nodoc:
142
+ value.to_i.to_s if value
143
+ end
144
+
145
+ def to_literal(value)
146
+ to_indexed(value)
147
+ end
148
+
149
+ def cast(string) #:nodoc:
150
+ string.to_i
151
+ end
152
+ end
153
+ register(IntegerType, Integer)
154
+
155
+ #
156
+ # The Long type indexes Ruby Fixnum and Bignum numbers into Java Longs
157
+ #
158
+ class LongType < IntegerType
159
+ def indexed_name(name) #:nodoc:
160
+ "#{name}_l"
161
+ end
162
+ end
163
+
164
+ #
165
+ # The Float type represents floating-point numbers.
166
+ #
167
+ class FloatType < AbstractType
168
+ def indexed_name(name) #:nodoc:
169
+ "#{name}_f"
170
+ end
171
+
172
+ def to_indexed(value) #:nodoc:
173
+ value.to_f.to_s if value
174
+ end
175
+
176
+ def to_literal(value)
177
+ to_indexed(value)
178
+ end
179
+
180
+ def cast(string) #:nodoc:
181
+ string.to_f
182
+ end
183
+ end
184
+ register(FloatType, Float)
185
+
186
+ #
187
+ # The Double type indexes Ruby Floats (which are in fact doubles) into Java
188
+ # Double fields
189
+ #
190
+ class DoubleType < FloatType
191
+ def indexed_name(name)
192
+ "#{name}_e"
193
+ end
194
+ end
195
+
196
+ #
197
+ # The time type represents times. Note that times are always converted to
198
+ # UTC before indexing, and facets of Time fields always return times in UTC.
199
+ #
200
+ class TimeType < AbstractType
201
+ XMLSCHEMA = "%Y-%m-%dT%H:%M:%SZ"
202
+
203
+ def indexed_name(name) #:nodoc:
204
+ "#{name}_d"
205
+ end
206
+
207
+ def to_indexed(value) #:nodoc:
208
+ if value
209
+ value_to_utc_time(value).strftime(XMLSCHEMA)
210
+ end
211
+ end
212
+
213
+ def to_literal(value)
214
+ to_indexed(value)
215
+ end
216
+
217
+ def cast(string) #:nodoc:
218
+ begin
219
+ Time.xmlschema(string)
220
+ rescue ArgumentError
221
+ DateTime.strptime(string, XMLSCHEMA)
222
+ end
223
+ end
224
+
225
+ private
226
+
227
+ def value_to_utc_time(value)
228
+ if value.respond_to?(:utc)
229
+ value.utc
230
+ elsif value.respond_to?(:new_offset)
231
+ value.new_offset
232
+ else
233
+ begin
234
+ Time.parse(value.to_s).utc
235
+ rescue ArgumentError
236
+ DateTime.parse(value.to_s).new_offset
237
+ end
238
+ end
239
+ end
240
+ end
241
+ register TimeType, Time, DateTime
242
+
243
+ #
244
+ # The DateType encapsulates dates (without time information). Internally,
245
+ # Solr does not have a date-only type, so this type indexes data using
246
+ # Solr's DateField type (which is actually date/time), midnight UTC of the
247
+ # indexed date.
248
+ #
249
+ class DateType < TimeType
250
+ def to_indexed(value) #:nodoc:
251
+ if value
252
+ time =
253
+ if %w(year mon mday).all? { |method| value.respond_to?(method) }
254
+ Time.utc(value.year, value.mon, value.mday)
255
+ else
256
+ date = Date.parse(value.to_s)
257
+ Time.utc(date.year, date.mon, date.mday)
258
+ end
259
+ super(time)
260
+ end
261
+ end
262
+
263
+ def cast(string) #:nodoc:
264
+ time = super
265
+ Date.civil(time.year, time.mon, time.mday)
266
+ end
267
+ end
268
+ register DateType, Date
269
+
270
+ #
271
+ # Store integers in a TrieField, which makes range queries much faster.
272
+ #
273
+ class TrieIntegerType < IntegerType
274
+ def indexed_name(name)
275
+ "#{super}t"
276
+ end
277
+ end
278
+
279
+ #
280
+ # Store floats in a TrieField, which makes range queries much faster.
281
+ #
282
+ class TrieFloatType < FloatType
283
+ def indexed_name(name)
284
+ "#{super}t"
285
+ end
286
+ end
287
+
288
+ #
289
+ # Index times using a TrieField. Internally, trie times are indexed as
290
+ # Unix timestamps in a trie integer field, as TrieField does not support
291
+ # datetime types natively. This distinction should have no effect from the
292
+ # standpoint of the library's API.
293
+ #
294
+ class TrieTimeType < TimeType
295
+ def indexed_name(name)
296
+ "#{super}t"
297
+ end
298
+ end
299
+
300
+
301
+ #
302
+ # The boolean type represents true/false values. Note that +nil+ will not be
303
+ # indexed at all; only +false+ will be indexed with a false value.
304
+ #
305
+ class BooleanType < AbstractType
306
+ def indexed_name(name) #:nodoc:
307
+ "#{name}_b"
308
+ end
309
+
310
+ def to_indexed(value) #:nodoc:
311
+ unless value.nil?
312
+ value ? 'true' : 'false'
313
+ end
314
+ end
315
+
316
+ def cast(string) #:nodoc:
317
+ case string
318
+ when 'true'
319
+ true
320
+ when 'false'
321
+ false
322
+ when true, false
323
+ string
324
+ end
325
+ end
326
+ end
327
+ register BooleanType, TrueClass, FalseClass
328
+
329
+ #
330
+ # The Location type encodes geographical coordinates as a GeoHash.
331
+ # The data for this type must respond to the `lat` and `lng` methods; you
332
+ # can use Sunspot::Util::Coordinates as a wrapper if your source data does
333
+ # not follow this API.
334
+ #
335
+ # Location fields are most usefully searched using the
336
+ # Sunspot::DSL::RestrictionWithType#near method; see that method for more
337
+ # information on geographical search.
338
+ #
339
+ # ==== Example
340
+ #
341
+ # Sunspot.setup(Post) do
342
+ # location :coordinates do
343
+ # Sunspot::Util::Coordinates.new(coordinates[0], coordinates[1])
344
+ # end
345
+ # end
346
+ #
347
+ class LocationType < AbstractType
348
+ def indexed_name(name)
349
+ "#{name}_s"
350
+ end
351
+
352
+ def to_indexed(value)
353
+ GeoHash.encode(value.lat.to_f, value.lng.to_f, 12)
354
+ end
355
+ end
356
+
357
+ #
358
+ # The Latlon type encodes geographical coordinates in the native
359
+ # Solr LatLonType.
360
+ #
361
+ # The data for this type must respond to the `lat` and `lng` methods; you
362
+ # can use Sunspot::Util::Coordinates as a wrapper if your source data does
363
+ # not follow this API.
364
+ #
365
+ # Location fields can be used with the geospatial DSL. See the
366
+ # Geospatial section of the README for examples.
367
+ #
368
+ class LatlonType < AbstractType
369
+ def indexed_name(name)
370
+ "#{name}_ll"
371
+ end
372
+
373
+ def to_indexed(value)
374
+ "#{value.lat.to_f},#{value.lng.to_f}"
375
+ end
376
+ end
377
+
378
+ class ClassType < AbstractType
379
+ def indexed_name(name) #:nodoc:
380
+ 'class_name'
381
+ end
382
+
383
+ def to_indexed(value) #:nodoc:
384
+ value.name
385
+ end
386
+
387
+ def cast(string) #:nodoc:
388
+ Sunspot::Util.full_const_get(string)
389
+ end
390
+ end
391
+ register ClassType, Class
392
+ end
393
+ end
@@ -0,0 +1,252 @@
1
+ module Sunspot
2
+ #
3
+ # The Sunspot::Util module provides utility methods used elsewhere in the
4
+ # library.
5
+ #
6
+ module Util #:nodoc:
7
+ class <<self
8
+ #
9
+ # Get all of the superclasses for a given class, including the class
10
+ # itself.
11
+ #
12
+ # ==== Parameters
13
+ #
14
+ # clazz<Class>:: class for which to get superclasses
15
+ #
16
+ # ==== Returns
17
+ #
18
+ # Array:: Collection containing class and its superclasses
19
+ #
20
+ def superclasses_for(clazz)
21
+ superclasses = [clazz]
22
+ superclasses << (clazz = clazz.superclass) while clazz.superclass != Object
23
+ superclasses
24
+ end
25
+
26
+ #
27
+ # Convert a string to snake case
28
+ #
29
+ # ==== Parameters
30
+ #
31
+ # string<String>:: String to convert to snake case
32
+ #
33
+ # ==== Returns
34
+ #
35
+ # String:: String in snake case
36
+ #
37
+ def snake_case(string)
38
+ string.scan(/(^|[A-Z])([^A-Z]+)/).map! { |word| word.join.downcase }.join('_')
39
+ end
40
+
41
+ #
42
+ # Convert a string to camel case
43
+ #
44
+ # ==== Parameters
45
+ #
46
+ # string<String>:: String to convert to camel case
47
+ #
48
+ # ==== Returns
49
+ #
50
+ # String:: String in camel case
51
+ #
52
+ def camel_case(string)
53
+ string.split('_').map! { |word| word.capitalize }.join
54
+ end
55
+
56
+ #
57
+ # Get a constant from a fully qualified name
58
+ #
59
+ # ==== Parameters
60
+ #
61
+ # string<String>:: The fully qualified name of a constant
62
+ #
63
+ # ==== Returns
64
+ #
65
+ # Object:: Value of constant named
66
+ #
67
+ def full_const_get(string)
68
+ string.split('::').inject(Object) do |context, const_name|
69
+ context.const_defined?(const_name) ? context.const_get(const_name) : context.const_missing(const_name)
70
+ end
71
+ end
72
+
73
+ #
74
+ # Evaluate the given proc in the context of the given object if the
75
+ # block's arity is non-positive, or by passing the given object as an
76
+ # argument if it is negative.
77
+ #
78
+ # ==== Parameters
79
+ #
80
+ # object<Object>:: Object to pass to the proc
81
+ #
82
+ def instance_eval_or_call(object, &block)
83
+ if block.arity > 0
84
+ block.call(object)
85
+ else
86
+ ContextBoundDelegate.instance_eval_with_context(object, &block)
87
+ end
88
+ end
89
+
90
+ def extract_options_from(args)
91
+ if args.last.is_a?(Hash)
92
+ args.pop
93
+ else
94
+ {}
95
+ end
96
+ end
97
+
98
+ #
99
+ # Ruby's treatment of Strings as Enumerables is heavily annoying. As far
100
+ # as I know the behavior of Kernel.Array() is otherwise fine.
101
+ #
102
+ def Array(object)
103
+ case object
104
+ when String, Hash
105
+ [object]
106
+ else
107
+ super
108
+ end
109
+ end
110
+
111
+ #
112
+ # When generating boosts, Solr requires that the values be in standard
113
+ # (not scientific) notation. We would like to ensure a minimum number of
114
+ # significant digits (i.e., digits that are not prefix zeros) for small
115
+ # float values.
116
+ #
117
+ def format_float(f, digits)
118
+ if f < 1
119
+ sprintf('%.*f', digits - Math.log10(f), f)
120
+ else
121
+ f.to_s
122
+ end
123
+ end
124
+
125
+ #
126
+ # Perform a deep merge of hashes, returning the result as a new hash.
127
+ # See #deep_merge_into for rules used to merge the hashes
128
+ #
129
+ # ==== Parameters
130
+ #
131
+ # left<Hash>:: Hash to merge
132
+ # right<Hash>:: The other hash to merge
133
+ #
134
+ # ==== Returns
135
+ #
136
+ # Hash:: New hash containing the given hashes deep-merged.
137
+ #
138
+ def deep_merge(left, right)
139
+ deep_merge_into({}, left, right)
140
+ end
141
+
142
+ #
143
+ # Perform a deep merge of the right hash into the left hash
144
+ #
145
+ # ==== Parameters
146
+ #
147
+ # left:: Hash to receive merge
148
+ # right:: Hash to merge into left
149
+ #
150
+ # ==== Returns
151
+ #
152
+ # Hash:: left
153
+ #
154
+ def deep_merge!(left, right)
155
+ deep_merge_into(left, left, right)
156
+ end
157
+
158
+ private
159
+
160
+ #
161
+ # Deep merge two hashes into a third hash, using rules that produce nice
162
+ # merged parameter hashes. The rules are as follows, for a given key:
163
+ #
164
+ # * If only one hash has a value, or if both hashes have the same value,
165
+ # just use the value.
166
+ # * If either of the values is not a hash, create arrays out of both
167
+ # values and concatenate them.
168
+ # * Otherwise, deep merge the two values (which are both hashes)
169
+ #
170
+ # ==== Parameters
171
+ #
172
+ # destination<Hash>:: Hash into which to perform the merge
173
+ # left<Hash>:: One hash to merge
174
+ # right<Hash>:: The other hash to merge
175
+ #
176
+ # ==== Returns
177
+ #
178
+ # Hash:: destination
179
+ #
180
+ def deep_merge_into(destination, left, right)
181
+ left.each_pair do |name, left_value|
182
+ right_value = right[name] if right
183
+ destination[name] =
184
+ if right_value.nil? || left_value == right_value
185
+ left_value
186
+ elsif !left_value.respond_to?(:each_pair) || !right_value.respond_to?(:each_pair)
187
+ Array(left_value) + Array(right_value)
188
+ else
189
+ merged_value = {}
190
+ deep_merge_into(merged_value, left_value, right_value)
191
+ end
192
+ end
193
+ left_keys = Set.new(left.keys)
194
+ destination.merge!(right.reject { |k, v| left_keys.include?(k) })
195
+ destination
196
+ end
197
+ end
198
+
199
+ Coordinates = Struct.new(:lat, :lng)
200
+
201
+ class ContextBoundDelegate
202
+ class <<self
203
+ def instance_eval_with_context(receiver, &block)
204
+ calling_context = eval('self', block.binding)
205
+ if parent_calling_context = calling_context.instance_eval{@__calling_context__}
206
+ calling_context = parent_calling_context
207
+ end
208
+ new(receiver, calling_context).instance_eval(&block)
209
+ end
210
+ private :new
211
+ end
212
+
213
+ BASIC_METHODS = Set[:==, :equal?, :"!", :"!=", :instance_eval,
214
+ :object_id, :__send__, :__id__]
215
+
216
+ instance_methods.each do |method|
217
+ unless BASIC_METHODS.include?(method.to_sym)
218
+ undef_method(method)
219
+ end
220
+ end
221
+
222
+ def initialize(receiver, calling_context)
223
+ @__receiver__, @__calling_context__ = receiver, calling_context
224
+ end
225
+
226
+ def id
227
+ @__calling_context__.__send__(:id)
228
+ end
229
+
230
+ # Special case due to `Kernel#sub`'s existence
231
+ def sub(*args, &block)
232
+ __proxy_method__(:sub, *args, &block)
233
+ end
234
+
235
+ def method_missing(method, *args, &block)
236
+ __proxy_method__(method, *args, &block)
237
+ end
238
+
239
+ def __proxy_method__(method, *args, &block)
240
+ begin
241
+ @__receiver__.__send__(method.to_sym, *args, &block)
242
+ rescue ::NoMethodError => e
243
+ begin
244
+ @__calling_context__.__send__(method.to_sym, *args, &block)
245
+ rescue ::NoMethodError
246
+ raise(e)
247
+ end
248
+ end
249
+ end
250
+ end
251
+ end
252
+ end