UnderpantsGnome-sunspot 0.9.1.1

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 (103) hide show
  1. data/History.txt +39 -0
  2. data/LICENSE +18 -0
  3. data/README.rdoc +154 -0
  4. data/Rakefile +9 -0
  5. data/TODO +4 -0
  6. data/VERSION.yml +4 -0
  7. data/bin/sunspot-configure-solr +46 -0
  8. data/bin/sunspot-solr +62 -0
  9. data/lib/light_config.rb +40 -0
  10. data/lib/sunspot.rb +470 -0
  11. data/lib/sunspot/adapters.rb +265 -0
  12. data/lib/sunspot/composite_setup.rb +186 -0
  13. data/lib/sunspot/configuration.rb +38 -0
  14. data/lib/sunspot/data_extractor.rb +47 -0
  15. data/lib/sunspot/date_facet.rb +36 -0
  16. data/lib/sunspot/date_facet_row.rb +17 -0
  17. data/lib/sunspot/dsl.rb +3 -0
  18. data/lib/sunspot/dsl/field_query.rb +72 -0
  19. data/lib/sunspot/dsl/fields.rb +86 -0
  20. data/lib/sunspot/dsl/query.rb +59 -0
  21. data/lib/sunspot/dsl/query_facet.rb +31 -0
  22. data/lib/sunspot/dsl/restriction.rb +25 -0
  23. data/lib/sunspot/dsl/scope.rb +193 -0
  24. data/lib/sunspot/dsl/search.rb +30 -0
  25. data/lib/sunspot/facet.rb +51 -0
  26. data/lib/sunspot/facet_row.rb +34 -0
  27. data/lib/sunspot/field.rb +157 -0
  28. data/lib/sunspot/field_factory.rb +126 -0
  29. data/lib/sunspot/indexer.rb +127 -0
  30. data/lib/sunspot/instantiated_facet.rb +38 -0
  31. data/lib/sunspot/instantiated_facet_row.rb +12 -0
  32. data/lib/sunspot/query.rb +190 -0
  33. data/lib/sunspot/query/base_query.rb +90 -0
  34. data/lib/sunspot/query/connective.rb +77 -0
  35. data/lib/sunspot/query/dynamic_query.rb +69 -0
  36. data/lib/sunspot/query/field_facet.rb +149 -0
  37. data/lib/sunspot/query/field_query.rb +57 -0
  38. data/lib/sunspot/query/pagination.rb +39 -0
  39. data/lib/sunspot/query/query_facet.rb +72 -0
  40. data/lib/sunspot/query/query_facet_row.rb +19 -0
  41. data/lib/sunspot/query/restriction.rb +225 -0
  42. data/lib/sunspot/query/scope.rb +165 -0
  43. data/lib/sunspot/query/sort.rb +36 -0
  44. data/lib/sunspot/query/sort_composite.rb +33 -0
  45. data/lib/sunspot/query_facet.rb +33 -0
  46. data/lib/sunspot/query_facet_row.rb +21 -0
  47. data/lib/sunspot/schema.rb +165 -0
  48. data/lib/sunspot/search.rb +222 -0
  49. data/lib/sunspot/search/hit.rb +62 -0
  50. data/lib/sunspot/session.rb +201 -0
  51. data/lib/sunspot/setup.rb +271 -0
  52. data/lib/sunspot/type.rb +200 -0
  53. data/lib/sunspot/util.rb +164 -0
  54. data/solr/etc/jetty.xml +212 -0
  55. data/solr/etc/webdefault.xml +379 -0
  56. data/solr/lib/jetty-6.1.3.jar +0 -0
  57. data/solr/lib/jetty-util-6.1.3.jar +0 -0
  58. data/solr/lib/jsp-2.1/ant-1.6.5.jar +0 -0
  59. data/solr/lib/jsp-2.1/core-3.1.1.jar +0 -0
  60. data/solr/lib/jsp-2.1/jsp-2.1.jar +0 -0
  61. data/solr/lib/jsp-2.1/jsp-api-2.1.jar +0 -0
  62. data/solr/lib/servlet-api-2.5-6.1.3.jar +0 -0
  63. data/solr/solr/conf/elevate.xml +36 -0
  64. data/solr/solr/conf/protwords.txt +21 -0
  65. data/solr/solr/conf/schema.xml +50 -0
  66. data/solr/solr/conf/solrconfig.xml +696 -0
  67. data/solr/solr/conf/stopwords.txt +57 -0
  68. data/solr/solr/conf/synonyms.txt +31 -0
  69. data/solr/start.jar +0 -0
  70. data/solr/webapps/solr.war +0 -0
  71. data/spec/api/adapters_spec.rb +33 -0
  72. data/spec/api/build_search_spec.rb +918 -0
  73. data/spec/api/indexer_spec.rb +311 -0
  74. data/spec/api/query_spec.rb +153 -0
  75. data/spec/api/search_retrieval_spec.rb +325 -0
  76. data/spec/api/session_spec.rb +157 -0
  77. data/spec/api/spec_helper.rb +1 -0
  78. data/spec/api/sunspot_spec.rb +18 -0
  79. data/spec/integration/dynamic_fields_spec.rb +55 -0
  80. data/spec/integration/faceting_spec.rb +169 -0
  81. data/spec/integration/keyword_search_spec.rb +83 -0
  82. data/spec/integration/scoped_search_spec.rb +188 -0
  83. data/spec/integration/spec_helper.rb +1 -0
  84. data/spec/integration/stored_fields_spec.rb +10 -0
  85. data/spec/integration/test_pagination.rb +32 -0
  86. data/spec/mocks/adapters.rb +32 -0
  87. data/spec/mocks/blog.rb +3 -0
  88. data/spec/mocks/comment.rb +19 -0
  89. data/spec/mocks/connection.rb +84 -0
  90. data/spec/mocks/mock_adapter.rb +30 -0
  91. data/spec/mocks/mock_record.rb +41 -0
  92. data/spec/mocks/photo.rb +8 -0
  93. data/spec/mocks/post.rb +70 -0
  94. data/spec/mocks/user.rb +8 -0
  95. data/spec/spec_helper.rb +47 -0
  96. data/tasks/gemspec.rake +25 -0
  97. data/tasks/rcov.rake +28 -0
  98. data/tasks/rdoc.rake +21 -0
  99. data/tasks/schema.rake +19 -0
  100. data/tasks/spec.rake +24 -0
  101. data/tasks/todo.rake +4 -0
  102. data/templates/schema.xml.haml +24 -0
  103. metadata +245 -0
@@ -0,0 +1 @@
1
+ require File.join(File.dirname(__FILE__), '..', 'spec_helper')
@@ -0,0 +1,10 @@
1
+ describe 'stored fields' do
2
+ before :all do
3
+ Sunspot.remove_all
4
+ Sunspot.index!(Post.new(:title => 'A Title'))
5
+ end
6
+
7
+ it 'should return stored fields' do
8
+ Sunspot.search(Post).hits.first.stored(:title).should == 'A Title'
9
+ end
10
+ end
@@ -0,0 +1,32 @@
1
+ require File.join(File.dirname(__FILE__), 'spec_helper')
2
+
3
+ describe 'pagination' do
4
+ before :all do
5
+ Sunspot.remove_all
6
+ @posts = (0..19).map do |i|
7
+ Post.new(:blog_id => i)
8
+ end
9
+ Sunspot.index(*@posts)
10
+ end
11
+
12
+ it 'should return all by default' do
13
+ results = Sunspot.search(Post) { order_by :blog_id }.results
14
+ results.should == @posts
15
+ end
16
+
17
+ it 'should return first page of 10' do
18
+ results = Sunspot.search(Post) do
19
+ order_by :blog_id
20
+ paginate :page => 1, :per_page => 10
21
+ end.results
22
+ results.should == @posts[0,10]
23
+ end
24
+
25
+ it 'should return second page of 10' do
26
+ results = Sunspot.search(Post) do
27
+ order_by :blog_id
28
+ paginate :page => 2, :per_page => 10
29
+ end.results
30
+ results.should == @posts[10,10]
31
+ end
32
+ end
@@ -0,0 +1,32 @@
1
+ class AbstractModel
2
+ end
3
+
4
+ class Model < AbstractModel
5
+ end
6
+
7
+ class AbstractModelInstanceAdapter < Sunspot::Adapters::InstanceAdapter
8
+ end
9
+
10
+ class AbstractModelDataAccessor < Sunspot::Adapters::DataAccessor
11
+ end
12
+
13
+ Sunspot::Adapters::InstanceAdapter.register(AbstractModelInstanceAdapter, AbstractModel)
14
+ Sunspot::Adapters::DataAccessor.register(AbstractModelDataAccessor, AbstractModel)
15
+
16
+
17
+ module MixInModel
18
+ end
19
+
20
+ class MixModel
21
+ include MixInModel
22
+ end
23
+
24
+ class MixInModelInstanceAdapter < Sunspot::Adapters::InstanceAdapter
25
+ end
26
+
27
+ class MixInModelDataAccessor < Sunspot::Adapters::DataAccessor
28
+ end
29
+
30
+ Sunspot::Adapters::InstanceAdapter.register(MixInModelInstanceAdapter, MixInModel)
31
+ Sunspot::Adapters::DataAccessor.register(MixInModelDataAccessor, MixInModel)
32
+
@@ -0,0 +1,3 @@
1
+ class Blog < MockRecord
2
+ attr_accessor :name
3
+ end
@@ -0,0 +1,19 @@
1
+ module Namespaced
2
+ class Comment < MockRecord
3
+ attr_reader :id
4
+ attr_accessor :author_name, :published_at, :body, :average_rating, :boost
5
+
6
+ def custom_string
7
+ @custom_string ||= {}
8
+ end
9
+ end
10
+ end
11
+
12
+ Sunspot.setup(Namespaced::Comment) do
13
+ text :body, :author_name
14
+ string :author_name
15
+ time :published_at
16
+ integer :average_rating
17
+ dynamic_string :custom_string
18
+ boost :boost
19
+ end
@@ -0,0 +1,84 @@
1
+ module Mock
2
+ class ConnectionFactory
3
+ def new(adapter = nil, opts = nil)
4
+ if @instance
5
+ raise('Factory can only create an instance once!')
6
+ else
7
+ @instance = Connection.new(adapter, opts)
8
+ end
9
+ end
10
+
11
+ def instance
12
+ @instance ||= Connection.new
13
+ end
14
+ end
15
+
16
+ class Connection
17
+ attr_reader :adds, :commits, :searches
18
+ attr_accessor :adapter, :opts
19
+
20
+ def initialize(adapter = nil, opts = nil)
21
+ @adapter, @opts = adapter, opts
22
+ @adds, @deletes, @deletes_by_query, @commits, @searches = Array.new(5) { [] }
23
+ end
24
+
25
+ def add(documents)
26
+ @adds << Array(documents)
27
+ end
28
+
29
+ def delete_by_id(*ids)
30
+ @deletes << ids
31
+ end
32
+
33
+ def delete_by_query(query)
34
+ @deletes_by_query << query
35
+ end
36
+
37
+ def commit
38
+ @commits << Time.now
39
+ end
40
+
41
+ def select(params)
42
+ @searches << @last_search = params
43
+ end
44
+
45
+ def has_add_with?(*documents)
46
+ @adds.any? do |add|
47
+ documents.all? do |document|
48
+ add.any? do |added|
49
+ if document.is_a?(Hash)
50
+ document.all? do |field, value|
51
+ added.fields_by_name(field).map do |field|
52
+ field.value
53
+ end == Array(value)
54
+ end
55
+ else
56
+ !added.fields_by_name(document).empty?
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
62
+
63
+ def has_delete?(*ids)
64
+ @deletes.any? do |delete|
65
+ delete & ids == ids
66
+ end
67
+ end
68
+
69
+ def has_delete_by_query?(query)
70
+ @deletes_by_query.include?(query)
71
+ end
72
+
73
+ def has_last_search_with?(params)
74
+ return unless @last_search
75
+ if params.respond_to?(:all?)
76
+ params.all? do |key, value|
77
+ @last_search.has_key?(key) && @last_search[key] == value
78
+ end
79
+ else
80
+ @last_search.has_key?(params)
81
+ end
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,30 @@
1
+ require File.join(File.dirname(__FILE__), 'post')
2
+
3
+ module MockAdapter
4
+ class InstanceAdapter < Sunspot::Adapters::InstanceAdapter
5
+ def id
6
+ @instance.id
7
+ end
8
+ end
9
+
10
+ class DataAccessor < Sunspot::Adapters::DataAccessor
11
+ def load(id)
12
+ @clazz.get(id.to_i)
13
+ end
14
+
15
+ def load_all(ids)
16
+ all = @clazz.get_all(ids.map { |id| id.to_i })
17
+ if @custom_title
18
+ all.each { |item| item.title = @custom_title }
19
+ end
20
+ all
21
+ end
22
+
23
+ def custom_title=(custom_title)
24
+ @custom_title = custom_title
25
+ end
26
+ end
27
+ end
28
+
29
+ Sunspot::Adapters::DataAccessor.register(MockAdapter::DataAccessor, MockRecord)
30
+ Sunspot::Adapters::InstanceAdapter.register(MockAdapter::InstanceAdapter, MockRecord)
@@ -0,0 +1,41 @@
1
+ class MockRecord
2
+ IDS = Hash.new { |h, k| h[k] = 0 }
3
+ QUERY_COUNTS = Hash.new { |h, k| h[k] = 0 }
4
+ INSTANCES = Hash.new { |h, k| h[k] = {} }
5
+
6
+ attr_reader :id
7
+
8
+ def initialize(attrs = {})
9
+ attrs.each_pair do |name, value|
10
+ send(:"#{name}=", value)
11
+ end
12
+ @id = IDS[self.class.name.to_sym] += 1
13
+ INSTANCES[self.class.name.to_sym][@id] = self
14
+ end
15
+
16
+ def self.inherited(base)
17
+ base.extend(ClassMethods)
18
+ end
19
+
20
+ module ClassMethods
21
+ def get(id)
22
+ QUERY_COUNTS[self.name.to_sym] += 1
23
+ get_instance(id)
24
+ end
25
+
26
+ def get_all(ids)
27
+ QUERY_COUNTS[self.name.to_sym] += 1
28
+ ids.map { |id| get_instance(id) }.sort_by { |instance| instance.id }
29
+ end
30
+
31
+ def query_count
32
+ QUERY_COUNTS[self.name.to_sym]
33
+ end
34
+
35
+ private
36
+
37
+ def get_instance(id)
38
+ INSTANCES[self.name.to_sym][id]
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,8 @@
1
+ class Photo < MockRecord
2
+ attr_accessor :caption
3
+ end
4
+
5
+ Sunspot.setup(Photo) do
6
+ text :caption
7
+ boost 0.75
8
+ end
@@ -0,0 +1,70 @@
1
+ require File.join(File.dirname(__FILE__), 'blog')
2
+
3
+ class Post < MockRecord
4
+ attr_accessor :title, :body, :blog_id, :published_at, :ratings_average,
5
+ :author_name, :featured, :expire_date
6
+ alias_method :featured?, :featured
7
+
8
+ def category_ids
9
+ @category_ids ||= []
10
+ end
11
+
12
+ def custom_string
13
+ @custom_string ||= {}
14
+ end
15
+
16
+ def custom_fl
17
+ @custom_fl ||= {}
18
+ end
19
+
20
+ def custom_time
21
+ @custom_time ||= {}
22
+ end
23
+
24
+ def custom_boolean
25
+ @custom_boolean ||= {}
26
+ end
27
+
28
+ private
29
+ attr_writer :category_ids, :custom_string, :custom_fl, :custom_time, :custom_boolean
30
+ end
31
+
32
+ Sunspot.setup(Post) do
33
+ text :title, :boost => 2
34
+ text :body
35
+ text :backwards_title do
36
+ title.reverse if title
37
+ end
38
+ string :title, :stored => true
39
+ integer :blog_id, :references => Blog
40
+ integer :category_ids, :multiple => true
41
+ float :average_rating, :using => :ratings_average
42
+ time :published_at
43
+ date :expire_date
44
+ boolean :featured, :using => :featured?
45
+ string :sort_title do
46
+ title.downcase.sub(/^(a|an|the)\W+/, '') if title
47
+ end
48
+ integer :primary_category_id do |post|
49
+ post.category_ids.first
50
+ end
51
+ time :last_indexed_at, :stored => true do
52
+ Time.now
53
+ end
54
+
55
+ dynamic_string :custom_string
56
+ dynamic_float :custom_float, :multiple => true, :using => :custom_fl
57
+ dynamic_integer :custom_integer do
58
+ category_ids.inject({}) do |hash, category_id|
59
+ hash.merge(category_id => 1)
60
+ end
61
+ end
62
+ dynamic_time :custom_time
63
+ dynamic_boolean :custom_boolean
64
+
65
+ boost do
66
+ if ratings_average
67
+ 1 + (ratings_average - 3.0) / 4.0
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,8 @@
1
+ class User
2
+ attr_accessor :name
3
+ end
4
+
5
+ Sunspot.setup(User) do
6
+ text :name
7
+ string :name
8
+ end
@@ -0,0 +1,47 @@
1
+ using_gems = false
2
+ begin
3
+ require 'spec'
4
+ begin
5
+ require 'ruby-debug'
6
+ rescue LoadError => e
7
+ if using_gems
8
+ module Kernel
9
+ def debugger
10
+ STDERR.puts('Debugger is not available')
11
+ end
12
+ end
13
+ else
14
+ raise(e)
15
+ end
16
+ end
17
+ if ENV['USE_WILL_PAGINATE']
18
+ require 'will_paginate'
19
+ require 'will_paginate/collection'
20
+ end
21
+ rescue LoadError => e
22
+ require 'rubygems'
23
+ if using_gems
24
+ raise(e)
25
+ else
26
+ using_gems = true
27
+ retry
28
+ end
29
+ end
30
+
31
+ unless gem_name = ENV['SUNSPOT_TEST_GEM']
32
+ $:.unshift(File.dirname(__FILE__) + '/../lib')
33
+ else
34
+ gem gem_name
35
+ end
36
+ require 'sunspot'
37
+
38
+ require File.join(File.dirname(__FILE__), 'mocks', 'mock_record.rb')
39
+ Dir.glob(File.join(File.dirname(__FILE__), 'mocks', '**', '*.rb')).each do |file|
40
+ require file unless File.basename(file) == 'mock_record.rb'
41
+ end
42
+
43
+ def without_class(clazz)
44
+ Object.class_eval { remove_const(clazz.name.to_sym) }
45
+ yield
46
+ Object.class_eval { const_set(clazz.name.to_sym, clazz) }
47
+ end
@@ -0,0 +1,25 @@
1
+ begin
2
+ gem 'technicalpickles-jeweler', '~> 1.0.1'
3
+ require 'jeweler'
4
+ Jeweler::Tasks.new do |s|
5
+ s.name = 'sunspot'
6
+ s.executables = 'sunspot-solr'
7
+ s.summary = 'Library for expressive, powerful interaction with the Solr search engine'
8
+ s.email = 'mat@patch.com'
9
+ s.homepage = 'http://github.com/outoftime/sunspot'
10
+ s.description = 'Library for expressive, powerful interaction with the Solr search engine'
11
+ s.authors = ['Mat Brown', 'Peer Allan', 'Dmitriy Dzema', 'Benjamin Krause']
12
+ s.files = FileList['[A-Z]*', '{bin,lib,spec,tasks,templates}/**/*', 'solr/{etc,lib,webapps}/**/*', 'solr/solr/conf/*', 'solr/start.jar']
13
+ s.add_dependency 'mwmitchell-rsolr', '>= 0.8.9'
14
+ s.add_dependency 'daemons', '~> 1.0'
15
+ s.add_dependency 'optiflag', '~> 0.6.5'
16
+ s.add_dependency 'haml', '~> 2.2'
17
+ s.add_development_dependency 'rspec', '~> 1.1'
18
+ s.add_development_dependency 'ruby-debug', '~> 0.10'
19
+ s.extra_rdoc_files = ['README.rdoc']
20
+ s.rdoc_options << '--webcvs=http://github.com/outoftime/sunspot/tree/master/%s' <<
21
+ '--title' << 'Sunspot - Solr-powered search for Ruby objects - API Documentation' <<
22
+ '--main' << 'README.rdoc'
23
+
24
+ end
25
+ end
data/tasks/rcov.rake ADDED
@@ -0,0 +1,28 @@
1
+ require 'rake'
2
+ require 'spec/rake/spectask'
3
+
4
+ desc 'run specs with rcov'
5
+ Spec::Rake::SpecTask.new('rcov') do |t|
6
+ t.spec_files = FileList['spec/**/*_spec.rb']
7
+ t.rcov = true
8
+ t.rcov_dir = File.join('coverage', 'all')
9
+ t.rcov_opts.concat(['--exclude', 'spec', '--sort', 'coverage', '--only-uncovered'])
10
+ end
11
+
12
+ namespace :rcov do
13
+ desc 'run api specs with rcov'
14
+ Spec::Rake::SpecTask.new('api') do |t|
15
+ t.spec_files = FileList['spec/api/*_spec.rb']
16
+ t.rcov = true
17
+ t.rcov_dir = File.join('coverage', 'api')
18
+ t.rcov_opts.concat(['--exclude', 'spec', '--sort', 'coverage', '--only-uncovered'])
19
+ end
20
+
21
+ desc 'run integration specs with rcov'
22
+ Spec::Rake::SpecTask.new('integration') do |t|
23
+ t.spec_files = FileList['spec/integration/*_spec.rb']
24
+ t.rcov = true
25
+ t.rcov_dir = File.join('coverage', 'integration')
26
+ t.rcov_opts.concat(['--exclude', 'spec', '--sort', 'coverage', '--only-uncovered'])
27
+ end
28
+ end