acts_as_solr 1.0.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 (163) hide show
  1. data/.gitignore +8 -0
  2. data/CHANGE_LOG +233 -0
  3. data/FORKED_CHANGES +3 -0
  4. data/LICENSE +19 -0
  5. data/README.markdown +94 -0
  6. data/README.rdoc +84 -0
  7. data/Rakefile +57 -0
  8. data/TESTING_THE_PLUGIN +25 -0
  9. data/VERSION +1 -0
  10. data/acts_as_solr.gemspec +237 -0
  11. data/config/solr.yml +15 -0
  12. data/config/solr_environment.rb +22 -0
  13. data/init.rb +21 -0
  14. data/install.rb +11 -0
  15. data/lib/acts_as_solr.rb +61 -0
  16. data/lib/acts_methods.rb +284 -0
  17. data/lib/class_methods.rb +239 -0
  18. data/lib/common_methods.rb +89 -0
  19. data/lib/deprecation.rb +61 -0
  20. data/lib/instance_methods.rb +181 -0
  21. data/lib/lazy_document.rb +18 -0
  22. data/lib/parser_methods.rb +230 -0
  23. data/lib/search_results.rb +69 -0
  24. data/lib/solr/connection.rb +191 -0
  25. data/lib/solr/document.rb +78 -0
  26. data/lib/solr/exception.rb +13 -0
  27. data/lib/solr/field.rb +39 -0
  28. data/lib/solr/importer/array_mapper.rb +26 -0
  29. data/lib/solr/importer/delimited_file_source.rb +38 -0
  30. data/lib/solr/importer/hpricot_mapper.rb +27 -0
  31. data/lib/solr/importer/mapper.rb +51 -0
  32. data/lib/solr/importer/solr_source.rb +43 -0
  33. data/lib/solr/importer/xpath_mapper.rb +35 -0
  34. data/lib/solr/importer.rb +19 -0
  35. data/lib/solr/indexer.rb +52 -0
  36. data/lib/solr/request/add_document.rb +63 -0
  37. data/lib/solr/request/base.rb +36 -0
  38. data/lib/solr/request/commit.rb +31 -0
  39. data/lib/solr/request/delete.rb +50 -0
  40. data/lib/solr/request/dismax.rb +46 -0
  41. data/lib/solr/request/index_info.rb +22 -0
  42. data/lib/solr/request/modify_document.rb +51 -0
  43. data/lib/solr/request/optimize.rb +21 -0
  44. data/lib/solr/request/ping.rb +36 -0
  45. data/lib/solr/request/select.rb +56 -0
  46. data/lib/solr/request/spellcheck.rb +30 -0
  47. data/lib/solr/request/standard.rb +402 -0
  48. data/lib/solr/request/update.rb +23 -0
  49. data/lib/solr/request.rb +26 -0
  50. data/lib/solr/response/add_document.rb +17 -0
  51. data/lib/solr/response/base.rb +42 -0
  52. data/lib/solr/response/commit.rb +17 -0
  53. data/lib/solr/response/delete.rb +13 -0
  54. data/lib/solr/response/dismax.rb +8 -0
  55. data/lib/solr/response/index_info.rb +26 -0
  56. data/lib/solr/response/modify_document.rb +17 -0
  57. data/lib/solr/response/optimize.rb +14 -0
  58. data/lib/solr/response/ping.rb +28 -0
  59. data/lib/solr/response/ruby.rb +42 -0
  60. data/lib/solr/response/select.rb +17 -0
  61. data/lib/solr/response/spellcheck.rb +20 -0
  62. data/lib/solr/response/standard.rb +64 -0
  63. data/lib/solr/response/xml.rb +42 -0
  64. data/lib/solr/response.rb +27 -0
  65. data/lib/solr/solrtasks.rb +27 -0
  66. data/lib/solr/util.rb +32 -0
  67. data/lib/solr/xml.rb +44 -0
  68. data/lib/solr.rb +21 -0
  69. data/lib/solr_fixtures.rb +13 -0
  70. data/lib/tasks/database.rake +18 -0
  71. data/lib/tasks/solr.rake +137 -0
  72. data/lib/tasks/test.rake +7 -0
  73. data/lib/will_paginate_support.rb +12 -0
  74. data/solr/CHANGES.txt +1207 -0
  75. data/solr/LICENSE.txt +712 -0
  76. data/solr/NOTICE.txt +90 -0
  77. data/solr/etc/jetty.xml +205 -0
  78. data/solr/etc/webdefault.xml +379 -0
  79. data/solr/lib/easymock.jar +0 -0
  80. data/solr/lib/jetty-6.1.3.jar +0 -0
  81. data/solr/lib/jetty-util-6.1.3.jar +0 -0
  82. data/solr/lib/jsp-2.1/ant-1.6.5.jar +0 -0
  83. data/solr/lib/jsp-2.1/core-3.1.1.jar +0 -0
  84. data/solr/lib/jsp-2.1/jsp-2.1.jar +0 -0
  85. data/solr/lib/jsp-2.1/jsp-api-2.1.jar +0 -0
  86. data/solr/lib/servlet-api-2.4.jar +0 -0
  87. data/solr/lib/servlet-api-2.5-6.1.3.jar +0 -0
  88. data/solr/lib/xpp3-1.1.3.4.O.jar +0 -0
  89. data/solr/logs/.empty-dir-for-git +0 -0
  90. data/solr/solr/README.txt +52 -0
  91. data/solr/solr/bin/abc +176 -0
  92. data/solr/solr/bin/abo +176 -0
  93. data/solr/solr/bin/backup +108 -0
  94. data/solr/solr/bin/backupcleaner +142 -0
  95. data/solr/solr/bin/commit +128 -0
  96. data/solr/solr/bin/optimize +129 -0
  97. data/solr/solr/bin/readercycle +129 -0
  98. data/solr/solr/bin/rsyncd-disable +77 -0
  99. data/solr/solr/bin/rsyncd-enable +76 -0
  100. data/solr/solr/bin/rsyncd-start +145 -0
  101. data/solr/solr/bin/rsyncd-stop +105 -0
  102. data/solr/solr/bin/scripts-util +83 -0
  103. data/solr/solr/bin/snapcleaner +148 -0
  104. data/solr/solr/bin/snapinstaller +168 -0
  105. data/solr/solr/bin/snappuller +248 -0
  106. data/solr/solr/bin/snappuller-disable +77 -0
  107. data/solr/solr/bin/snappuller-enable +77 -0
  108. data/solr/solr/bin/snapshooter +109 -0
  109. data/solr/solr/conf/admin-extra.html +31 -0
  110. data/solr/solr/conf/protwords.txt +21 -0
  111. data/solr/solr/conf/schema.xml +126 -0
  112. data/solr/solr/conf/scripts.conf +24 -0
  113. data/solr/solr/conf/solrconfig.xml +458 -0
  114. data/solr/solr/conf/stopwords.txt +57 -0
  115. data/solr/solr/conf/synonyms.txt +31 -0
  116. data/solr/solr/conf/xslt/example.xsl +132 -0
  117. data/solr/solr/conf/xslt/example_atom.xsl +63 -0
  118. data/solr/solr/conf/xslt/example_rss.xsl +62 -0
  119. data/solr/start.jar +0 -0
  120. data/solr/tmp/.empty-dir-for-git +0 -0
  121. data/solr/webapps/solr.war +0 -0
  122. data/test/config/solr.yml +2 -0
  123. data/test/db/connections/mysql/connection.rb +10 -0
  124. data/test/db/connections/sqlite/connection.rb +8 -0
  125. data/test/db/migrate/001_create_books.rb +15 -0
  126. data/test/db/migrate/002_create_movies.rb +12 -0
  127. data/test/db/migrate/003_create_categories.rb +11 -0
  128. data/test/db/migrate/004_create_electronics.rb +16 -0
  129. data/test/db/migrate/005_create_authors.rb +12 -0
  130. data/test/db/migrate/006_create_postings.rb +9 -0
  131. data/test/db/migrate/007_create_posts.rb +13 -0
  132. data/test/db/migrate/008_create_gadgets.rb +11 -0
  133. data/test/fixtures/authors.yml +9 -0
  134. data/test/fixtures/books.yml +13 -0
  135. data/test/fixtures/categories.yml +7 -0
  136. data/test/fixtures/db_definitions/mysql.sql +41 -0
  137. data/test/fixtures/electronics.yml +49 -0
  138. data/test/fixtures/movies.yml +9 -0
  139. data/test/fixtures/postings.yml +10 -0
  140. data/test/functional/acts_as_solr_test.rb +413 -0
  141. data/test/functional/association_indexing_test.rb +37 -0
  142. data/test/functional/faceted_search_test.rb +163 -0
  143. data/test/functional/multi_solr_search_test.rb +51 -0
  144. data/test/models/author.rb +10 -0
  145. data/test/models/book.rb +10 -0
  146. data/test/models/category.rb +8 -0
  147. data/test/models/electronic.rb +21 -0
  148. data/test/models/gadget.rb +9 -0
  149. data/test/models/movie.rb +17 -0
  150. data/test/models/novel.rb +2 -0
  151. data/test/models/post.rb +3 -0
  152. data/test/models/posting.rb +11 -0
  153. data/test/test_helper.rb +51 -0
  154. data/test/unit/acts_methods_shoulda.rb +70 -0
  155. data/test/unit/class_methods_shoulda.rb +90 -0
  156. data/test/unit/common_methods_shoulda.rb +112 -0
  157. data/test/unit/instance_methods_shoulda.rb +326 -0
  158. data/test/unit/lazy_document_shoulda.rb +35 -0
  159. data/test/unit/parser_instance.rb +19 -0
  160. data/test/unit/parser_methods_shoulda.rb +279 -0
  161. data/test/unit/solr_instance.rb +46 -0
  162. data/test/unit/test_helper.rb +26 -0
  163. metadata +259 -0
@@ -0,0 +1,10 @@
1
+ # Table fields for 'books'
2
+ # - id
3
+ # - category_id
4
+ # - name
5
+ # - author
6
+
7
+ class Book < ActiveRecord::Base
8
+ belongs_to :category
9
+ acts_as_solr :include => [:category]
10
+ end
@@ -0,0 +1,8 @@
1
+ # Table fields for 'categories'
2
+ # - id
3
+ # - name
4
+
5
+ class Category < ActiveRecord::Base
6
+ has_many :books
7
+ acts_as_solr :include => [:books]
8
+ end
@@ -0,0 +1,21 @@
1
+ # Table fields for 'electronics'
2
+ # - id
3
+ # - name
4
+ # - manufacturer
5
+ # - features
6
+ # - category
7
+ # - price
8
+ # - created_on
9
+
10
+ class Electronic < ActiveRecord::Base
11
+ acts_as_solr :facets => [:category, :manufacturer],
12
+ :fields => [:name, :manufacturer, :features, :category, {:created_at => :date}, {:updated_at => :date}, {:price => {:type => :range_float, :boost => 10.0}}],
13
+ :boost => 5.0,
14
+ :exclude_fields => [:features]
15
+
16
+ # The following example would also convert the :price field type to :range_float
17
+ #
18
+ # acts_as_solr :facets => [:category, :manufacturer],
19
+ # :fields => [:name, :manufacturer, :features, :category, {:price => :range_float}],
20
+ # :boost => 5.0
21
+ end
@@ -0,0 +1,9 @@
1
+ class Gadget < ActiveRecord::Base
2
+ cattr_accessor :search_disabled
3
+
4
+ acts_as_solr :offline => proc {|record| Gadget.search_disabled?}, :format => :ids
5
+
6
+ def self.search_disabled?
7
+ search_disabled
8
+ end
9
+ end
@@ -0,0 +1,17 @@
1
+ # Table fields for 'movies'
2
+ # - id
3
+ # - name
4
+ # - description
5
+
6
+ class Movie < ActiveRecord::Base
7
+ acts_as_solr :additional_fields => [:current_time, {:time_on_xml => :date}]
8
+
9
+ def current_time
10
+ Time.now.to_s
11
+ end
12
+
13
+ def time_on_xml
14
+ Time.now
15
+ end
16
+
17
+ end
@@ -0,0 +1,2 @@
1
+ class Novel < Book
2
+ end
@@ -0,0 +1,3 @@
1
+ class Post < ActiveRecord::Base
2
+ acts_as_solr
3
+ end
@@ -0,0 +1,11 @@
1
+ # Table fields for 'movies'
2
+ # - guid
3
+ # - name
4
+ # - description
5
+
6
+ class Posting < ActiveRecord::Base
7
+
8
+ set_primary_key 'guid'
9
+ acts_as_solr({},{:primary_key_field => 'pk_s'})
10
+
11
+ end
@@ -0,0 +1,51 @@
1
+ require 'rubygems'
2
+ require 'test/unit'
3
+ require 'active_record'
4
+ require 'active_record/fixtures'
5
+
6
+ begin
7
+ require 'active_support/test_case'
8
+ rescue
9
+ end
10
+
11
+ RAILS_ROOT = File.dirname(__FILE__) unless defined? RAILS_ROOT
12
+ RAILS_ENV = 'test' unless defined? RAILS_ENV
13
+
14
+ require File.dirname(__FILE__) + '/../lib/acts_as_solr'
15
+ require File.dirname(__FILE__) + '/../config/solr_environment.rb'
16
+
17
+ # Load Models
18
+ models_dir = File.join(File.dirname( __FILE__ ), 'models')
19
+ Dir[ models_dir + '/*.rb'].each { |m| require m }
20
+
21
+ if defined?(ActiveSupport::TestCase)
22
+ class ActiveSupport::TestCase
23
+ include ActiveRecord::TestFixtures
24
+ self.fixture_path = File.dirname(__FILE__) + "/fixtures/"
25
+ end unless ActiveSupport::TestCase.respond_to?(:fixture_path=)
26
+ else
27
+ Test::Unit::TestCase.fixture_path = File.dirname(__FILE__) + "/fixtures/"
28
+ end
29
+
30
+ class Test::Unit::TestCase
31
+ def self.fixtures(*table_names)
32
+ fixture_path = defined?(ActiveSupport::TestCase) ? ActiveSupport::TestCase.fixture_path : Test::Unit::TestCase.fixture_path
33
+ if block_given?
34
+ Fixtures.create_fixtures(fixture_path, table_names) { yield }
35
+ else
36
+ Fixtures.create_fixtures(fixture_path, table_names)
37
+ end
38
+ table_names.each do |table_name|
39
+ clear_from_solr(table_name)
40
+ klass = instance_eval table_name.to_s.capitalize.singularize
41
+ klass.find(:all).each{|content| content.solr_save}
42
+ end
43
+
44
+ clear_from_solr(:novels)
45
+ end
46
+
47
+ private
48
+ def self.clear_from_solr(table_name)
49
+ ActsAsSolr::Post.execute(Solr::Request::Delete.new(:query => "type_s:#{table_name.to_s.capitalize.singularize}"))
50
+ end
51
+ end
@@ -0,0 +1,70 @@
1
+ require File.dirname(__FILE__) + '/test_helper'
2
+ require 'acts_methods'
3
+ require 'mocha'
4
+
5
+ class ActsMethodsTest < Test::Unit::TestCase
6
+ class Model
7
+ attr_accessor :birthdate
8
+
9
+ def initialize(birthdate)
10
+ @birthdate = birthdate
11
+ end
12
+
13
+ def self.configuration
14
+ @configuration ||= {:solr_fields => {}}
15
+ end
16
+
17
+ def self.columns_hash=(columns_hash)
18
+ @columns_hash = columns_hash
19
+ end
20
+
21
+ def self.columns_hash
22
+ @columns_hash
23
+ end
24
+
25
+ def [](key)
26
+ @birthday
27
+ end
28
+
29
+ self.extend ActsAsSolr::ActsMethods
30
+ end
31
+
32
+
33
+ context "when getting field values" do
34
+ setup do
35
+ Model.columns_hash = {"birthdate" => stub("column", :type => :date)}
36
+ Model.send(:get_field_value, :birthdate)
37
+ end
38
+
39
+ should "define an accessor methods for a solr converted value" do
40
+ assert Model.instance_methods.include?("birthdate_for_solr")
41
+ end
42
+
43
+ context "for date types" do
44
+ setup do
45
+ @model = Model.new(Date.today)
46
+ end
47
+
48
+ should "return nil when field is nil" do
49
+ @model.birthdate = nil
50
+ assert_nil @model.birthdate_for_solr
51
+ end
52
+
53
+ should "return the formatted date" do
54
+ assert_equal Date.today.strftime("%Y-%m-%dT%H:%M:%SZ"), @model.birthdate_for_solr
55
+ end
56
+ end
57
+
58
+ context "for timestamp types" do
59
+ setup do
60
+ @now = Time.now
61
+ @model = Model.new(@now)
62
+ end
63
+
64
+ should "return a formatted timestamp string for timestamps" do
65
+ assert_equal @now.utc.strftime("%Y-%m-%dT%H:%M:%SZ"), @model.birthdate_for_solr
66
+ end
67
+ end
68
+ end
69
+
70
+ end
@@ -0,0 +1,90 @@
1
+ require File.dirname(__FILE__) + '/test_helper'
2
+ require 'class_methods'
3
+ require 'search_results'
4
+ require 'active_support'
5
+
6
+ class User
7
+ attr_accessor :name, :id
8
+ def self.find(*args)
9
+ @paul ||= User.new
10
+ @paul.name = "Paul"
11
+ @paul.id = 1
12
+ @paul
13
+ end
14
+
15
+ def self.find_by_id(id)
16
+ find
17
+ end
18
+
19
+ def self.primary_key
20
+ "id"
21
+ end
22
+ end
23
+
24
+ class ClassMethodsTest < Test::Unit::TestCase
25
+ include ActsAsSolr::ClassMethods
26
+
27
+ def solr_configuration
28
+ @solr_configuration ||= {:type_field => "type_t", :primary_key_field => "id"}
29
+ end
30
+
31
+ context "when multi-searching" do
32
+ setup do
33
+ stubs(:name).returns("User")
34
+ end
35
+
36
+ should "include the type field in the query" do
37
+ expects(:parse_query).with("name:paul", {:results_format => :objects}, "AND (type_t:User)")
38
+ multi_solr_search("name:paul")
39
+ end
40
+
41
+ should "add all models in the query" do
42
+ expects(:parse_query).with("name:paul", {:results_format => :objects, :models => ["Movie", "DVD"]}, "AND (type_t:User OR type_t:Movie OR type_t:DVD)")
43
+ multi_solr_search("name:paul", :models => ["Movie", "DVD"])
44
+ end
45
+
46
+ should "return an empty result set if no data was returned" do
47
+ stubs(:parse_query).returns(nil)
48
+ result = multi_solr_search("name:paul")
49
+ assert_equal 0, result.docs.size
50
+ end
51
+
52
+ should "return an empty result set if no results were found" do
53
+ stubs(:parse_query).returns(stub(:total_hits => 0, :hits => []))
54
+ result = multi_solr_search("name:paul")
55
+ assert_equal 0, result.docs.size
56
+ end
57
+
58
+ context "with results" do
59
+ should "find the objects in the database" do
60
+ stubs(:parse_query).returns(stub(:total_hits => 1, :hits => ["score" => 0.12956427, "id" => ["User:1"]]))
61
+ result = multi_solr_search("name:paul")
62
+
63
+ assert_equal(User.find, result.docs.first)
64
+ assert_equal 1, result.docs.size
65
+ end
66
+
67
+ context "when requesting ids" do
68
+ should "return only ids" do
69
+ loudly do
70
+ stubs(:parse_query).returns(stub(:total_hits => 1, :hits => ["score" => 0.12956427, "id" => ["User:1"]]))
71
+ result = multi_solr_search("name:paul", :results_format => :ids)
72
+ assert_equal "User:1", result.docs.first["id"]
73
+ end
74
+ end
75
+ end
76
+
77
+ context "with scores" do
78
+ setup do
79
+ solr_configuration[:primary_key_field] = nil
80
+ end
81
+
82
+ should "add an accessor with the solr score" do
83
+ stubs(:parse_query).returns(stub(:total_hits => 1, :hits => ["score" => 0.12956427, "id" => ["User:1"]]))
84
+ result = multi_solr_search("name:paul", :scores => true)
85
+ assert_equal 0.12956427, result.docs.first.solr_score
86
+ end
87
+ end
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,112 @@
1
+ require 'test_helper'
2
+ require 'common_methods'
3
+
4
+ class CommonMethodsTest < Test::Unit::TestCase
5
+ include ActsAsSolr::CommonMethods
6
+
7
+ class << self
8
+ def primary_key
9
+ "id"
10
+ end
11
+ end
12
+
13
+ def id
14
+ 10
15
+ end
16
+
17
+ context "when determining the field type" do
18
+ setup do
19
+ end
20
+
21
+ should "return i for an integer" do
22
+ assert_equal "i", get_solr_field_type(:integer)
23
+ end
24
+
25
+ should "return f for a float" do
26
+ assert_equal "f", get_solr_field_type(:float)
27
+ end
28
+
29
+ should "return b for a boolean" do
30
+ assert_equal "b", get_solr_field_type(:boolean)
31
+ end
32
+
33
+ should "return s for a string" do
34
+ assert_equal "s", get_solr_field_type(:string)
35
+ end
36
+
37
+ should "return t for a text" do
38
+ assert_equal "t", get_solr_field_type(:text)
39
+ end
40
+
41
+ should "return d for a date" do
42
+ assert_equal "d", get_solr_field_type(:date)
43
+ end
44
+
45
+ should "return ri for a range_integer" do
46
+ assert_equal "ri", get_solr_field_type(:range_integer)
47
+ end
48
+
49
+ should "return rf for a range_float" do
50
+ assert_equal "rf", get_solr_field_type(:range_float)
51
+ end
52
+
53
+ should "return facet for a facet field" do
54
+ assert_equal "facet", get_solr_field_type(:facet)
55
+ end
56
+
57
+ should "return the string if one was given as an argument" do
58
+ assert_equal "string", get_solr_field_type("string")
59
+ end
60
+
61
+ should "raise an error if invalid field type was specified" do
62
+ assert_raise(RuntimeError) {get_solr_field_type(:something)}
63
+ end
64
+
65
+ should "raise an error if argument is not symbol or string" do
66
+ assert_raise(RuntimeError) {get_solr_field_type(123)}
67
+ end
68
+ end
69
+
70
+ context "when determining a default value for a field when it's nil" do
71
+ should "return 0.00 for a float" do
72
+ assert_equal 0.00, set_value_if_nil("f")
73
+ assert_equal 0.00, set_value_if_nil(:float)
74
+ assert_equal 0.00, set_value_if_nil("rf")
75
+ assert_equal 0.00, set_value_if_nil(:range_float)
76
+ end
77
+
78
+ should "return 0 for an integer" do
79
+ assert_equal 0, set_value_if_nil(:integer)
80
+ assert_equal 0, set_value_if_nil(:range_integer)
81
+ assert_equal 0, set_value_if_nil("i")
82
+ assert_equal 0, set_value_if_nil("ri")
83
+ end
84
+
85
+ should "return false for a boolean" do
86
+ assert_equal "false", set_value_if_nil(:boolean)
87
+ assert_equal "false", set_value_if_nil("b")
88
+ end
89
+
90
+ should "return empty string for strings and text" do
91
+ assert_equal "", set_value_if_nil(:string)
92
+ assert_equal "", set_value_if_nil(:text)
93
+ assert_equal "", set_value_if_nil("t")
94
+ assert_equal "", set_value_if_nil("s")
95
+ end
96
+
97
+ should "return an empty string for a date" do
98
+ assert_equal "", set_value_if_nil(:date)
99
+ assert_equal "", set_value_if_nil("d")
100
+ end
101
+
102
+ should "return an empty string for everything else" do
103
+ assert_equal "", set_value_if_nil("something")
104
+ end
105
+ end
106
+
107
+ context "when determining the record id" do
108
+ should "return the primary key value" do
109
+ assert_equal 10, record_id(self)
110
+ end
111
+ end
112
+ end