sunspot 0.9.7

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 (101) hide show
  1. data/History.txt +83 -0
  2. data/LICENSE +18 -0
  3. data/README.rdoc +154 -0
  4. data/Rakefile +9 -0
  5. data/TODO +9 -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 +469 -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/dsl.rb +3 -0
  16. data/lib/sunspot/dsl/field_query.rb +72 -0
  17. data/lib/sunspot/dsl/fields.rb +86 -0
  18. data/lib/sunspot/dsl/query.rb +59 -0
  19. data/lib/sunspot/dsl/query_facet.rb +31 -0
  20. data/lib/sunspot/dsl/restriction.rb +25 -0
  21. data/lib/sunspot/dsl/scope.rb +193 -0
  22. data/lib/sunspot/dsl/search.rb +30 -0
  23. data/lib/sunspot/facet.rb +16 -0
  24. data/lib/sunspot/facet_data.rb +120 -0
  25. data/lib/sunspot/facet_row.rb +10 -0
  26. data/lib/sunspot/field.rb +157 -0
  27. data/lib/sunspot/field_factory.rb +126 -0
  28. data/lib/sunspot/indexer.rb +123 -0
  29. data/lib/sunspot/instantiated_facet.rb +42 -0
  30. data/lib/sunspot/instantiated_facet_row.rb +22 -0
  31. data/lib/sunspot/query.rb +191 -0
  32. data/lib/sunspot/query/base_query.rb +90 -0
  33. data/lib/sunspot/query/connective.rb +126 -0
  34. data/lib/sunspot/query/dynamic_query.rb +69 -0
  35. data/lib/sunspot/query/field_facet.rb +151 -0
  36. data/lib/sunspot/query/field_query.rb +63 -0
  37. data/lib/sunspot/query/pagination.rb +39 -0
  38. data/lib/sunspot/query/query_facet.rb +73 -0
  39. data/lib/sunspot/query/query_facet_row.rb +19 -0
  40. data/lib/sunspot/query/query_field_facet.rb +13 -0
  41. data/lib/sunspot/query/restriction.rb +233 -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/schema.rb +165 -0
  46. data/lib/sunspot/search.rb +219 -0
  47. data/lib/sunspot/search/hit.rb +66 -0
  48. data/lib/sunspot/session.rb +201 -0
  49. data/lib/sunspot/setup.rb +271 -0
  50. data/lib/sunspot/type.rb +200 -0
  51. data/lib/sunspot/util.rb +164 -0
  52. data/solr/etc/jetty.xml +212 -0
  53. data/solr/etc/webdefault.xml +379 -0
  54. data/solr/lib/jetty-6.1.3.jar +0 -0
  55. data/solr/lib/jetty-util-6.1.3.jar +0 -0
  56. data/solr/lib/jsp-2.1/ant-1.6.5.jar +0 -0
  57. data/solr/lib/jsp-2.1/core-3.1.1.jar +0 -0
  58. data/solr/lib/jsp-2.1/jsp-2.1.jar +0 -0
  59. data/solr/lib/jsp-2.1/jsp-api-2.1.jar +0 -0
  60. data/solr/lib/servlet-api-2.5-6.1.3.jar +0 -0
  61. data/solr/solr/conf/elevate.xml +36 -0
  62. data/solr/solr/conf/protwords.txt +21 -0
  63. data/solr/solr/conf/schema.xml +50 -0
  64. data/solr/solr/conf/solrconfig.xml +696 -0
  65. data/solr/solr/conf/stopwords.txt +57 -0
  66. data/solr/solr/conf/synonyms.txt +31 -0
  67. data/solr/start.jar +0 -0
  68. data/solr/webapps/solr.war +0 -0
  69. data/spec/api/adapters_spec.rb +33 -0
  70. data/spec/api/build_search_spec.rb +1039 -0
  71. data/spec/api/indexer_spec.rb +311 -0
  72. data/spec/api/query_spec.rb +153 -0
  73. data/spec/api/search_retrieval_spec.rb +362 -0
  74. data/spec/api/session_spec.rb +157 -0
  75. data/spec/api/spec_helper.rb +1 -0
  76. data/spec/api/sunspot_spec.rb +18 -0
  77. data/spec/integration/dynamic_fields_spec.rb +55 -0
  78. data/spec/integration/faceting_spec.rb +169 -0
  79. data/spec/integration/keyword_search_spec.rb +83 -0
  80. data/spec/integration/scoped_search_spec.rb +289 -0
  81. data/spec/integration/spec_helper.rb +1 -0
  82. data/spec/integration/stored_fields_spec.rb +10 -0
  83. data/spec/integration/test_pagination.rb +32 -0
  84. data/spec/mocks/adapters.rb +32 -0
  85. data/spec/mocks/blog.rb +3 -0
  86. data/spec/mocks/comment.rb +19 -0
  87. data/spec/mocks/connection.rb +84 -0
  88. data/spec/mocks/mock_adapter.rb +30 -0
  89. data/spec/mocks/mock_record.rb +48 -0
  90. data/spec/mocks/photo.rb +8 -0
  91. data/spec/mocks/post.rb +73 -0
  92. data/spec/mocks/user.rb +8 -0
  93. data/spec/spec_helper.rb +47 -0
  94. data/tasks/gemspec.rake +25 -0
  95. data/tasks/rcov.rake +28 -0
  96. data/tasks/rdoc.rake +22 -0
  97. data/tasks/schema.rake +19 -0
  98. data/tasks/spec.rake +24 -0
  99. data/tasks/todo.rake +4 -0
  100. data/templates/schema.xml.haml +24 -0
  101. metadata +246 -0
@@ -0,0 +1,38 @@
1
+ module Sunspot
2
+ # The Sunspot::Configuration module provides a factory method for Sunspot
3
+ # configuration objects. Available properties are:
4
+ #
5
+ # Sunspot.config.http_client::
6
+ # The client to use for HTTP communication with Solr. Available options are
7
+ # :net_http, which is the default and uses Ruby's built-in pure-Ruby HTTP
8
+ # library; and :curb, which uses Ruby's libcurl bindings and requires
9
+ # installation of the 'curb' gem.
10
+ # Sunspot.config.solr.url::
11
+ # The URL at which to connect to Solr
12
+ # (default: 'http://localhost:8983/solr')
13
+ # Sunspot.config.pagination.default_per_page::
14
+ # Solr always paginates its results. This sets Sunspot's default result
15
+ # count per page if it is not explicitly specified in the query.
16
+ #
17
+ module Configuration
18
+ class <<self
19
+ # Factory method to build configuration instances.
20
+ #
21
+ # ==== Returns
22
+ #
23
+ # LightConfig::Configuration:: new configuration instance with defaults
24
+ #
25
+ def build #:nodoc:
26
+ LightConfig.build do
27
+ http_client :net_http
28
+ solr do
29
+ url 'http://127.0.0.1:8983/solr'
30
+ end
31
+ pagination do
32
+ default_per_page 30
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,47 @@
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
+ class Constant
38
+ def initialize(value)
39
+ @value = value
40
+ end
41
+
42
+ def value_for(object)
43
+ @value
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,3 @@
1
+ %w(fields scope field_query query query_facet restriction search).each do |file|
2
+ require File.join(File.dirname(__FILE__), 'dsl', file)
3
+ end
@@ -0,0 +1,72 @@
1
+ module Sunspot
2
+ module DSL
3
+ #
4
+ # Provides an API for areas of the query DSL that operate on specific
5
+ # fields. This functionality is provided by the query DSL and the dynamic
6
+ # query DSL.
7
+ #
8
+ class FieldQuery < Scope
9
+ # Specify the order that results should be returned in. This method can
10
+ # be called multiple times; precedence will be in the order given.
11
+ #
12
+ # ==== Parameters
13
+ #
14
+ # field_name<Symbol>:: the field to use for ordering
15
+ # direction<Symbol>:: :asc or :desc (default :asc)
16
+ #
17
+ def order_by(field_name, direction = nil)
18
+ @query.order_by(field_name, direction)
19
+ end
20
+
21
+ #
22
+ # Order results randomly. This will (generally) return the results in a
23
+ # different order each time a search is called.
24
+ #
25
+ def order_by_random
26
+ @query.order_by_random
27
+ end
28
+
29
+ # Request facets on the given field names. If the last argument is a hash,
30
+ # the given options will be applied to all specified fields. See
31
+ # Sunspot::Search#facet and Sunspot::Facet for information on what is
32
+ # returned.
33
+ #
34
+ # ==== Parameters
35
+ #
36
+ # field_names...<Symbol>:: fields for which to return field facets
37
+ #
38
+ # ==== Options
39
+ #
40
+ # :sort<Symbol>::
41
+ # Either :count (values matching the most terms first) or :index (lexical)
42
+ # :limit<Integer>::
43
+ # The maximum number of facet rows to return
44
+ # :minimum_count<Integer>::
45
+ # The minimum count a facet row must have to be returned
46
+ # :zeros<Boolean>::
47
+ # Return facet rows for which there are no matches (equivalent to
48
+ # :minimum_count => 0). Default is false.
49
+ #
50
+ def facet(*field_names, &block)
51
+ if block
52
+ if field_names.length != 1
53
+ raise(
54
+ ArgumentError,
55
+ "wrong number of arguments (#{field_names.length} for 1)"
56
+ )
57
+ end
58
+ name = field_names.first
59
+ DSL::QueryFacet.new(@query.add_query_facet(name)).instance_eval(&block)
60
+ else
61
+ options =
62
+ if field_names.last.is_a?(Hash)
63
+ field_names.pop
64
+ end
65
+ for field_name in field_names
66
+ @query.add_field_facet(field_name, options)
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,86 @@
1
+ module Sunspot
2
+ module DSL #:nodoc:
3
+ # The Fields class provides a DSL for specifying field definitions in the
4
+ # Sunspot.setup block. As well as the #text method, which creates fulltext
5
+ # fields, uses #method_missing to allow definition of typed fields. The
6
+ # available methods are determined by the constants defined in
7
+ # Sunspot::Type - in theory (though this is untested), plugin developers
8
+ # should be able to add support for new types simply by creating new
9
+ # implementations in Sunspot::Type
10
+ #
11
+ class Fields
12
+ def initialize(setup) #:nodoc:
13
+ @setup = setup
14
+ end
15
+
16
+ # Add a text field. Text fields are tokenized before indexing and are
17
+ # the only fields searched in fulltext searches. If a block is passed,
18
+ # create a virtual field; otherwise create an attribute field.
19
+ #
20
+ # If options are passed, they will be applied to all the given fields.
21
+ #
22
+ # ==== Parameters
23
+ #
24
+ # names...<Symbol>:: One or more field names
25
+ #
26
+ # ==== Options
27
+ #
28
+ # :boost<Float>::
29
+ # Boost that should be applied to this field for keyword search
30
+ #
31
+ def text(*names, &block)
32
+ options = names.pop if names.last.is_a?(Hash)
33
+ for name in names
34
+ @setup.add_text_field_factory(
35
+ name,
36
+ options || {},
37
+ &block
38
+ )
39
+ end
40
+ end
41
+
42
+ #
43
+ # Specify a document-level boost. As with fields, you have the option of
44
+ # passing an attribute name which will be called on each model, or a block
45
+ # to be evaluated in the model's context. As well as these two options,
46
+ # this method can also take a constant number, meaning that all indexed
47
+ # documents of this class will have the specified boost.
48
+ #
49
+ # ==== Parameters
50
+ #
51
+ # attr_name<Symbol,~.to_f>:: Attribute name to call or a numeric constant
52
+ #
53
+ def boost(attr_name = nil, &block)
54
+ @setup.add_document_boost(attr_name, &block)
55
+ end
56
+
57
+ # method_missing is used to provide access to typed fields, because
58
+ # developers should be able to add new Sunspot::Type implementations
59
+ # dynamically and have them recognized inside the Fields DSL. Like #text,
60
+ # these methods will create a VirtualField if a block is passed, or an
61
+ # AttributeField if not.
62
+ #
63
+ # ==== Example
64
+ #
65
+ # Sunspot.setup(File) do
66
+ # time :mtime
67
+ # end
68
+ #
69
+ # The call to +time+ will create a field of type Sunspot::Types::TimeType
70
+ #
71
+ def method_missing(method, *args, &block)
72
+ begin
73
+ type = Type.const_get("#{Util.camel_case(method.to_s.sub(/^dynamic_/, ''))}Type")
74
+ rescue(NameError)
75
+ super(method.to_sym, *args, &block) and return
76
+ end
77
+ name = args.shift
78
+ if method.to_s =~ /^dynamic_/
79
+ @setup.add_dynamic_field_factory(name, type, *args, &block)
80
+ else
81
+ @setup.add_field_factory(name, type, *args, &block)
82
+ end
83
+ end
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,59 @@
1
+ module Sunspot
2
+ module DSL #:nodoc:
3
+ #
4
+ # This class presents a DSL for constructing queries using the
5
+ # Sunspot.search method. Methods of this class are available inside the
6
+ # search block. Much of the DSL's functionality is implemented by this
7
+ # class's superclasses, Sunspot::DSL::FieldQuery and Sunspot::DSL::Scope
8
+ #
9
+ # See Sunspot.search for usage examples
10
+ #
11
+ class Query < FieldQuery
12
+ # Specify a phrase that should be searched as fulltext. Only +text+
13
+ # fields are searched - see DSL::Fields.text
14
+ #
15
+ # Keyword search is executed using Solr's dismax handler, which strikes
16
+ # a good balance between powerful and foolproof. In particular,
17
+ # well-matched quotation marks can be used to group phrases, and the
18
+ # + and - modifiers work as expected. All other special Solr boolean
19
+ # syntax is escaped, and mismatched quotes are ignored entirely.
20
+ #
21
+ # ==== Parameters
22
+ #
23
+ # keywords<String>:: phrase to perform fulltext search on
24
+ #
25
+ # ==== Options
26
+ #
27
+ # :fields<Array>::
28
+ # List of fields that should be searched for keywords. Defaults to all
29
+ # fields configured for the types under search.
30
+ #
31
+ def keywords(keywords, options = {})
32
+ @query.set_keywords(keywords, options)
33
+ end
34
+
35
+ # Paginate your search. This works the same way as WillPaginate's
36
+ # paginate().
37
+ #
38
+ # Note that Solr searches are _always_ paginated. Not calling #paginate is
39
+ # the equivalent of calling:
40
+ #
41
+ # paginate(:page => 1, :per_page => Sunspot.config.pagination.default_per_page)
42
+ #
43
+ # ==== Options (options)
44
+ #
45
+ # :page<Integer>:: The requested page (required)
46
+ #
47
+ # :per_page<Integer>::
48
+ # How many results to return per page. The default is the value in
49
+ # +Sunspot.config.pagination.default_per_page+
50
+ #
51
+ def paginate(options = {})
52
+ page = options.delete(:page) || raise(ArgumentError, "paginate requires a :page argument")
53
+ per_page = options.delete(:per_page)
54
+ raise ArgumentError, "unknown argument #{options.keys.first.inspect} passed to paginate" unless options.empty?
55
+ @query.paginate(page, per_page)
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,31 @@
1
+ module Sunspot
2
+ module DSL
3
+ #
4
+ # This tiny DSL class implements the DSL for the FieldQuery.facet
5
+ # method.
6
+ #
7
+ class QueryFacet
8
+ def initialize(query_facet) #:nodoc:
9
+ @query_facet = query_facet
10
+ end
11
+
12
+ #
13
+ # Add a row to this query facet. The label argument can be anything; it's
14
+ # simply the value that's passed into the Sunspot::QueryFacetRow object
15
+ # corresponding to the row that's created. Use whatever seems most
16
+ # intuitive.
17
+ #
18
+ # The block is evaluated in the context of a Sunspot::DSL::Scope, meaning
19
+ # any restrictions can be placed on the documents matching this facet row.
20
+ #
21
+ # ==== Parameters
22
+ #
23
+ # label<Object>::
24
+ # An object used to identify this facet row in the results.
25
+ #
26
+ def row(label, &block)
27
+ Scope.new(@query_facet.add_row(label)).instance_eval(&block)
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,25 @@
1
+ module Sunspot
2
+ module DSL #:nodoc:
3
+ #
4
+ # This class presents an API for building restrictions in the query DSL. The
5
+ # methods exposed are the snake-cased names of the classes defined in the
6
+ # Restriction module, with the exception of Base and SameAs. All methods
7
+ # take a single argument, which is the value to be applied to the
8
+ # restriction.
9
+ #
10
+ class Restriction #:nodoc:
11
+ def initialize(field_name, query, negative)
12
+ @field_name, @query, @negative = field_name, query, negative
13
+ end
14
+
15
+ Sunspot::Query::Restriction.names.each do |class_name|
16
+ method_name = Util.snake_case(class_name.to_s)
17
+ module_eval(<<-RUBY, __FILE__, __LINE__ + 1)
18
+ def #{method_name}(value)
19
+ @query.add_restriction(@field_name, Sunspot::Query::Restriction::#{class_name}, value, @negative)
20
+ end
21
+ RUBY
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,193 @@
1
+ module Sunspot
2
+ module DSL #:nodoc:
3
+ #
4
+ # This DSL presents methods for constructing restrictions and other query
5
+ # elements that are specific to fields. As well as being a superclass of
6
+ # Sunspot::DSL::Query, which presents the main query block, this DSL class
7
+ # is also used directly inside the #dynamic() block, which only allows
8
+ # operations on specific fields.
9
+ #
10
+ class Scope
11
+ NONE = Object.new
12
+
13
+ def initialize(query) #:nodoc:
14
+ @query = query
15
+ end
16
+
17
+ #
18
+ # Build a positive restriction. With one argument, this method returns
19
+ # another DSL object which presents methods for attaching various
20
+ # restriction types. With two arguments, this creates a shorthand
21
+ # restriction: if the second argument is a scalar, an equality restriction
22
+ # is created; if it is a Range, a between restriction will be created; and
23
+ # if it is an Array, an any_of restriction will be created.
24
+ #
25
+ # ==== Parameters
26
+ #
27
+ # field_name<Symbol>:: Name of the field on which to place the restriction
28
+ # value<Object,Range,Array>::
29
+ # If passed, creates an equality, range, or any-of restriction based on
30
+ # the type of value passed.
31
+ #
32
+ # ==== Returns
33
+ #
34
+ # Sunspot::DSL::Query::Restriction::
35
+ # Restriction DSL object (if only one argument is passed)
36
+ #
37
+ # ==== Examples
38
+ #
39
+ # An equality restriction:
40
+ #
41
+ # Sunspot.search do
42
+ # with(:blog_id, 1)
43
+ # end
44
+ #
45
+ # Restrict by range:
46
+ #
47
+ # Sunspot.search do
48
+ # with(:average_rating, 3.0..5.0)
49
+ # end
50
+ #
51
+ # Restrict by a set of allowed values:
52
+ #
53
+ # Sunspot.search do
54
+ # with(:category_ids, [1, 5, 9])
55
+ # end
56
+ #
57
+ # Other restriction types:
58
+ #
59
+ # Sunspot.search(Post) do
60
+ # with(:average_rating).greater_than(3.0)
61
+ # end
62
+ #
63
+ def with(field_name, value = NONE)
64
+ if value == NONE
65
+ DSL::Restriction.new(field_name.to_sym, @query, false)
66
+ else
67
+ @query.add_shorthand_restriction(field_name, value)
68
+ end
69
+ end
70
+
71
+ #
72
+ # Build a negative restriction (exclusion). This method can take three
73
+ # forms: equality exclusion, exclusion by another restriction, or identity
74
+ # exclusion. The first two forms work the same way as the #with method;
75
+ # the third excludes a specific instance from the search results.
76
+ #
77
+ # ==== Parameters (exclusion by field value)
78
+ #
79
+ # field_name<Symbol>:: Name of the field on which to place the exclusion
80
+ # value<Symbol>::
81
+ # If passed, creates an equality exclusion with this value
82
+ #
83
+ # ==== Parameters (exclusion by identity)
84
+ #
85
+ # args<Object>...::
86
+ # One or more instances that should be excluded from the results
87
+ #
88
+ # ==== Examples
89
+ #
90
+ # An equality exclusion:
91
+ #
92
+ # Sunspot.search(Post) do
93
+ # without(:blog_id, 1)
94
+ # end
95
+ #
96
+ # Other restriction types:
97
+ #
98
+ # Sunspot.search(Post) do
99
+ # without(:average_rating).greater_than(3.0)
100
+ # end
101
+ #
102
+ # Exclusion by identity:
103
+ #
104
+ # Sunspot.search(Post) do
105
+ # without(some_post_instance)
106
+ # end
107
+ #
108
+ def without(*args)
109
+ case args.first
110
+ when String, Symbol
111
+ field_name = args[0]
112
+ value = args.length > 1 ? args[1] : NONE
113
+ if value == NONE
114
+ DSL::Restriction.new(field_name.to_sym, @query, true)
115
+ else
116
+ @query.add_negated_shorthand_restriction(field_name, value)
117
+ end
118
+ else
119
+ instances = args
120
+ for instance in instances.flatten
121
+ @query.exclude_instance(instance)
122
+ end
123
+ end
124
+ end
125
+
126
+ #
127
+ # Create a disjunction, scoping the results to documents that match any
128
+ # of the enclosed restrictions.
129
+ #
130
+ # ==== Example
131
+ #
132
+ # Sunspot.search(Post) do
133
+ # any_of do
134
+ # with(:expired_at).greater_than Time.now
135
+ # with :expired_at, nil
136
+ # end
137
+ # end
138
+ #
139
+ # This will return all documents who either have an expiration time in the
140
+ # future, or who do not have any expiration time at all.
141
+ #
142
+ def any_of(&block)
143
+ Util.instance_eval_or_call(Scope.new(@query.add_disjunction), &block)
144
+ end
145
+
146
+ #
147
+ # Create a conjunction, scoping the results to documents that match all of
148
+ # the enclosed restrictions. When called from the top level of a search
149
+ # block, this has no effect, but can be useful for grouping a conjunction
150
+ # inside a disjunction.
151
+ #
152
+ # ==== Example
153
+ #
154
+ # Sunspot.search(Post) do
155
+ # any_of do
156
+ # with(:blog_id, 1)
157
+ # all_of do
158
+ # with(:blog_id, 2)
159
+ # with(:category_ids, 3)
160
+ # end
161
+ # end
162
+ # end
163
+ #
164
+ def all_of(&block)
165
+ Util.instance_eval_or_call(Scope.new(@query.add_conjunction), &block)
166
+ end
167
+
168
+ #
169
+ # Apply restrictions, facets, and ordering to dynamic field instances.
170
+ # The block API is implemented by Sunspot::DSL::FieldQuery, which is a
171
+ # superclass of the Query DSL (thus providing a subset of the API, in
172
+ # particular only methods that refer to particular fields).
173
+ #
174
+ # ==== Parameters
175
+ #
176
+ # base_name<Symbol>:: The base name for the dynamic field definition
177
+ #
178
+ # ==== Example
179
+ #
180
+ # Sunspot.search Post do
181
+ # dynamic :custom do
182
+ # with :cuisine, 'Pizza'
183
+ # facet :atmosphere
184
+ # order_by :chef_name
185
+ # end
186
+ # end
187
+ #
188
+ def dynamic(base_name, &block)
189
+ FieldQuery.new(@query.dynamic_query(base_name)).instance_eval(&block)
190
+ end
191
+ end
192
+ end
193
+ end