nxa-sunspot 0.10.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (142) hide show
  1. data/History.txt +153 -0
  2. data/LICENSE +18 -0
  3. data/README.rdoc +191 -0
  4. data/Rakefile +9 -0
  5. data/TODO +14 -0
  6. data/VERSION.yml +4 -0
  7. data/bin/sunspot-configure-solr +40 -0
  8. data/bin/sunspot-solr +95 -0
  9. data/lib/light_config.rb +40 -0
  10. data/lib/sunspot.rb +488 -0
  11. data/lib/sunspot/adapters.rb +265 -0
  12. data/lib/sunspot/composite_setup.rb +188 -0
  13. data/lib/sunspot/configuration.rb +56 -0
  14. data/lib/sunspot/data_extractor.rb +50 -0
  15. data/lib/sunspot/dsl.rb +4 -0
  16. data/lib/sunspot/dsl/field_query.rb +150 -0
  17. data/lib/sunspot/dsl/fields.rb +100 -0
  18. data/lib/sunspot/dsl/fulltext.rb +228 -0
  19. data/lib/sunspot/dsl/query.rb +162 -0
  20. data/lib/sunspot/dsl/query_facet.rb +36 -0
  21. data/lib/sunspot/dsl/restriction.rb +25 -0
  22. data/lib/sunspot/dsl/scope.rb +225 -0
  23. data/lib/sunspot/dsl/search.rb +30 -0
  24. data/lib/sunspot/field.rb +181 -0
  25. data/lib/sunspot/field_factory.rb +144 -0
  26. data/lib/sunspot/indexer.rb +133 -0
  27. data/lib/sunspot/query.rb +9 -0
  28. data/lib/sunspot/query/abstract_field_facet.rb +43 -0
  29. data/lib/sunspot/query/boost_query.rb +20 -0
  30. data/lib/sunspot/query/connective.rb +189 -0
  31. data/lib/sunspot/query/date_field_facet.rb +14 -0
  32. data/lib/sunspot/query/dismax.rb +88 -0
  33. data/lib/sunspot/query/field_facet.rb +9 -0
  34. data/lib/sunspot/query/highlighting.rb +55 -0
  35. data/lib/sunspot/query/local.rb +27 -0
  36. data/lib/sunspot/query/pagination.rb +38 -0
  37. data/lib/sunspot/query/query.rb +86 -0
  38. data/lib/sunspot/query/query_facet.rb +16 -0
  39. data/lib/sunspot/query/restriction.rb +254 -0
  40. data/lib/sunspot/query/scope.rb +9 -0
  41. data/lib/sunspot/query/sort.rb +105 -0
  42. data/lib/sunspot/query/sort_composite.rb +33 -0
  43. data/lib/sunspot/query/text_field_boost.rb +15 -0
  44. data/lib/sunspot/schema.rb +147 -0
  45. data/lib/sunspot/search.rb +216 -0
  46. data/lib/sunspot/search/date_facet.rb +35 -0
  47. data/lib/sunspot/search/facet_row.rb +27 -0
  48. data/lib/sunspot/search/field_facet.rb +44 -0
  49. data/lib/sunspot/search/highlight.rb +38 -0
  50. data/lib/sunspot/search/hit.rb +117 -0
  51. data/lib/sunspot/search/query_facet.rb +62 -0
  52. data/lib/sunspot/session.rb +236 -0
  53. data/lib/sunspot/setup.rb +323 -0
  54. data/lib/sunspot/text_field_setup.rb +29 -0
  55. data/lib/sunspot/type.rb +204 -0
  56. data/lib/sunspot/util.rb +210 -0
  57. data/solr/etc/jetty.xml +212 -0
  58. data/solr/etc/webdefault.xml +379 -0
  59. data/solr/lib/jetty-6.1.3.jar +0 -0
  60. data/solr/lib/jetty-util-6.1.3.jar +0 -0
  61. data/solr/lib/jsp-2.1/ant-1.6.5.jar +0 -0
  62. data/solr/lib/jsp-2.1/core-3.1.1.jar +0 -0
  63. data/solr/lib/jsp-2.1/jsp-2.1.jar +0 -0
  64. data/solr/lib/jsp-2.1/jsp-api-2.1.jar +0 -0
  65. data/solr/lib/servlet-api-2.5-6.1.3.jar +0 -0
  66. data/solr/solr/conf/elevate.xml +36 -0
  67. data/solr/solr/conf/protwords.txt +21 -0
  68. data/solr/solr/conf/schema.xml +64 -0
  69. data/solr/solr/conf/solrconfig.xml +725 -0
  70. data/solr/solr/conf/stopwords.txt +57 -0
  71. data/solr/solr/conf/synonyms.txt +31 -0
  72. data/solr/solr/lib/geoapi-nogenerics-2.1-M2.jar +0 -0
  73. data/solr/solr/lib/gt2-referencing-2.3.1.jar +0 -0
  74. data/solr/solr/lib/jsr108-0.01.jar +0 -0
  75. data/solr/solr/lib/locallucene.jar +0 -0
  76. data/solr/solr/lib/localsolr.jar +0 -0
  77. data/solr/start.jar +0 -0
  78. data/solr/webapps/solr.war +0 -0
  79. data/spec/api/adapters_spec.rb +33 -0
  80. data/spec/api/indexer/attributes_spec.rb +110 -0
  81. data/spec/api/indexer/batch_spec.rb +46 -0
  82. data/spec/api/indexer/dynamic_fields_spec.rb +33 -0
  83. data/spec/api/indexer/fixed_fields_spec.rb +57 -0
  84. data/spec/api/indexer/fulltext_spec.rb +43 -0
  85. data/spec/api/indexer/removal_spec.rb +46 -0
  86. data/spec/api/indexer/spec_helper.rb +1 -0
  87. data/spec/api/indexer_spec.rb +4 -0
  88. data/spec/api/query/adjust_params_spec.rb +37 -0
  89. data/spec/api/query/connectives_spec.rb +176 -0
  90. data/spec/api/query/dsl_spec.rb +12 -0
  91. data/spec/api/query/dynamic_fields_spec.rb +149 -0
  92. data/spec/api/query/faceting_spec.rb +296 -0
  93. data/spec/api/query/fulltext_spec.rb +281 -0
  94. data/spec/api/query/highlighting_spec.rb +225 -0
  95. data/spec/api/query/local_spec.rb +62 -0
  96. data/spec/api/query/ordering_pagination_spec.rb +95 -0
  97. data/spec/api/query/scope_spec.rb +266 -0
  98. data/spec/api/query/spec_helper.rb +1 -0
  99. data/spec/api/query/text_field_scoping_spec.rb +30 -0
  100. data/spec/api/query/types_spec.rb +20 -0
  101. data/spec/api/search/dynamic_fields_spec.rb +27 -0
  102. data/spec/api/search/faceting_spec.rb +242 -0
  103. data/spec/api/search/highlighting_spec.rb +65 -0
  104. data/spec/api/search/hits_spec.rb +67 -0
  105. data/spec/api/search/results_spec.rb +52 -0
  106. data/spec/api/search/search_spec.rb +23 -0
  107. data/spec/api/search/spec_helper.rb +1 -0
  108. data/spec/api/session_spec.rb +198 -0
  109. data/spec/api/spec_helper.rb +1 -0
  110. data/spec/api/sunspot_spec.rb +18 -0
  111. data/spec/helpers/indexer_helper.rb +29 -0
  112. data/spec/helpers/query_helper.rb +13 -0
  113. data/spec/helpers/search_helper.rb +78 -0
  114. data/spec/integration/dynamic_fields_spec.rb +55 -0
  115. data/spec/integration/faceting_spec.rb +188 -0
  116. data/spec/integration/highlighting_spec.rb +22 -0
  117. data/spec/integration/indexing_spec.rb +7 -0
  118. data/spec/integration/keyword_search_spec.rb +245 -0
  119. data/spec/integration/local_search_spec.rb +56 -0
  120. data/spec/integration/scoped_search_spec.rb +303 -0
  121. data/spec/integration/spec_helper.rb +7 -0
  122. data/spec/integration/stored_fields_spec.rb +10 -0
  123. data/spec/integration/test_pagination.rb +32 -0
  124. data/spec/mocks/adapters.rb +32 -0
  125. data/spec/mocks/blog.rb +3 -0
  126. data/spec/mocks/comment.rb +19 -0
  127. data/spec/mocks/connection.rb +106 -0
  128. data/spec/mocks/mock_adapter.rb +30 -0
  129. data/spec/mocks/mock_record.rb +48 -0
  130. data/spec/mocks/photo.rb +11 -0
  131. data/spec/mocks/post.rb +75 -0
  132. data/spec/mocks/super_class.rb +2 -0
  133. data/spec/mocks/user.rb +8 -0
  134. data/spec/spec_helper.rb +68 -0
  135. data/tasks/gemspec.rake +42 -0
  136. data/tasks/rcov.rake +28 -0
  137. data/tasks/rdoc.rake +22 -0
  138. data/tasks/schema.rake +19 -0
  139. data/tasks/spec.rake +24 -0
  140. data/tasks/todo.rake +4 -0
  141. data/templates/schema.xml.erb +36 -0
  142. metadata +319 -0
@@ -0,0 +1,162 @@
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
+ # This method can optionally take a block, which is evaluated by the
22
+ # Fulltext DSL class, and exposes several powerful dismax features.
23
+ #
24
+ # ==== Parameters
25
+ #
26
+ # keywords<String>:: phrase to perform fulltext search on
27
+ #
28
+ # ==== Options
29
+ #
30
+ # :fields<Array>::
31
+ # List of fields that should be searched for keywords. Defaults to all
32
+ # fields configured for the types under search.
33
+ # :highlight<Boolean,Array>::
34
+ # If true, perform keyword highlighting on all searched fields. If an
35
+ # array of field names, perform highlighting on the specified fields.
36
+ # This can also be called from within the fulltext block.
37
+ # :minimum_match<Integer>::
38
+ # The minimum number of search terms that a result must match. By
39
+ # default, all search terms must match; if the number of search terms
40
+ # is less than this number, the default behavior applies.
41
+ # :tie<Float>::
42
+ # A tiebreaker coefficient for scores derived from subqueries that are
43
+ # lower-scoring than the maximum score subquery. Typically a near-zero
44
+ # value is useful. See
45
+ # http://wiki.apache.org/solr/DisMaxRequestHandler#tie_.28Tie_breaker.29
46
+ # for more information.
47
+ # :query_phrase_slop<Integer>::
48
+ # The number of words that can appear between the words in a
49
+ # user-entered phrase (i.e., keywords in quotes) and still match. For
50
+ # instance, in a search for "\"great pizza\"" with a phrase slop of 1,
51
+ # "great pizza" and "great big pizza" will match, but "great monster of
52
+ # a pizza" will not. Default behavior is a query phrase slop of zero.
53
+ #
54
+ def fulltext(keywords, options = {}, &block)
55
+ if keywords && !(keywords.to_s =~ /^\s*$/)
56
+ fulltext_query = @query.set_fulltext(keywords)
57
+ if field_names = options.delete(:fields)
58
+ Util.Array(field_names).each do |field_name|
59
+ @setup.text_fields(field_name).each do |field|
60
+ fulltext_query.add_fulltext_field(field, field.default_boost)
61
+ end
62
+ end
63
+ end
64
+ if minimum_match = options.delete(:minimum_match)
65
+ fulltext_query.minimum_match = minimum_match.to_i
66
+ end
67
+ if tie = options.delete(:tie)
68
+ fulltext_query.tie = tie.to_f
69
+ end
70
+ if query_phrase_slop = options.delete(:query_phrase_slop)
71
+ fulltext_query.query_phrase_slop = query_phrase_slop.to_i
72
+ end
73
+ if highlight_field_names = options.delete(:highlight)
74
+ if highlight_field_names == true
75
+ fulltext_query.add_highlight
76
+ else
77
+ highlight_fields = []
78
+ Util.Array(highlight_field_names).each do |field_name|
79
+ highlight_fields.concat(@setup.text_fields(field_name))
80
+ end
81
+ fulltext_query.add_highlight(highlight_fields)
82
+ end
83
+ end
84
+ if block && fulltext_query
85
+ fulltext_dsl = Fulltext.new(fulltext_query, @setup)
86
+ Util.instance_eval_or_call(
87
+ fulltext_dsl,
88
+ &block
89
+ )
90
+ end
91
+ if !field_names && (!fulltext_dsl || !fulltext_dsl.fields_added?)
92
+ @setup.all_text_fields.each do |field|
93
+ unless fulltext_query.has_fulltext_field?(field)
94
+ unless fulltext_dsl && fulltext_dsl.exclude_fields.include?(field.name)
95
+ fulltext_query.add_fulltext_field(field, field.default_boost)
96
+ end
97
+ end
98
+ end
99
+ end
100
+ end
101
+ end
102
+ alias_method :keywords, :fulltext
103
+
104
+ # Paginate your search. This works the same way as WillPaginate's
105
+ # paginate().
106
+ #
107
+ # Note that Solr searches are _always_ paginated. Not calling #paginate is
108
+ # the equivalent of calling:
109
+ #
110
+ # paginate(:page => 1, :per_page => Sunspot.config.pagination.default_per_page)
111
+ #
112
+ # ==== Options (options)
113
+ #
114
+ # :page<Integer,String>:: The requested page. The default is 1.
115
+ #
116
+ # :per_page<Integer,String>::
117
+ # How many results to return per page. The default is the value in
118
+ # +Sunspot.config.pagination.default_per_page+
119
+ #
120
+ def paginate(options = {})
121
+ page = options.delete(:page)
122
+ per_page = options.delete(:per_page)
123
+ raise ArgumentError, "unknown argument #{options.keys.first.inspect} passed to paginate" unless options.empty?
124
+ @query.paginate(page, per_page)
125
+ end
126
+
127
+ # <strong>Expert:</strong> Adjust or reset the parameters passed to Solr.
128
+ # The adjustment will take place just before sending the params to solr,
129
+ # after Sunspot builds the Solr params based on the methods called in the
130
+ # DSL.
131
+ #
132
+ # Under normal circumstances, using this method should not be necessary;
133
+ # if you find that it is, please consider submitting a feature request.
134
+ # Using this method requires knowledge of Sunspot's internal Solr schema
135
+ # and Solr query representations, which are not part of Sunspot's public
136
+ # API; they could change at any time. <strong>This method is unsupported
137
+ # and your mileage may vary.</strong>
138
+ #
139
+ # ==== Example
140
+ #
141
+ # Sunspot.search(Post) do
142
+ # adjust_solr_params do |params|
143
+ # params[:q] += ' AND something_s:more'
144
+ # end
145
+ # end
146
+ #
147
+ def adjust_solr_params( &block )
148
+ @query.set_solr_parameter_adjustment( block )
149
+ end
150
+
151
+ #
152
+ # Scope the search by geographical distance from a given point.
153
+ # +coordinates+ should either respond to #first and #last (e.g. a
154
+ # two-element array), or to #lat and one of #lng, #lon, or #long.
155
+ # +miles+ is the radius around the point for which to return documents.
156
+ #
157
+ def near(coordinates, miles)
158
+ @query.add_location_restriction(coordinates, miles)
159
+ end
160
+ end
161
+ end
162
+ end
@@ -0,0 +1,36 @@
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, setup, facet) #:nodoc:
9
+ @query, @setup, @facet = query, setup, 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
+ query_facet = Sunspot::Query::QueryFacet.new
28
+ Sunspot::Util.instance_eval_or_call(
29
+ Scope.new(@query.add_query_facet(query_facet), @setup),
30
+ &block
31
+ )
32
+ @facet.add_row(label, query_facet.to_boolean_phrase)
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,25 @@
1
+ module Sunspot
2
+ module DSL
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
+ # Sunspot::Restriction module, with the exception of Base. All
7
+ # methods take a single argument, which is the value to be applied to the
8
+ # restriction.
9
+ #
10
+ class Restriction
11
+ def initialize(field_name, query, negative) #:nodoc:
12
+ @field_name, @scope, @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
+ @scope.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,225 @@
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(scope, setup) #:nodoc:
14
+ @scope, @setup = scope, setup
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(@setup.field(field_name.to_sym), @scope, false)
66
+ else
67
+ @scope.add_shorthand_restriction(@setup.field(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(@setup.field(field_name.to_sym), @scope, true)
115
+ else
116
+ @scope.add_negated_shorthand_restriction(@setup.field(field_name.to_sym), value)
117
+ end
118
+ else
119
+ instances = args
120
+ instances.flatten.each do |instance|
121
+ @scope.add_negated_restriction(
122
+ IdField.instance,
123
+ Sunspot::Query::Restriction::EqualTo,
124
+ Sunspot::Adapters::InstanceAdapter.adapt(instance).index_id
125
+ )
126
+ end
127
+ end
128
+ end
129
+
130
+ #
131
+ # Create a disjunction, scoping the results to documents that match any
132
+ # of the enclosed restrictions.
133
+ #
134
+ # ==== Example
135
+ #
136
+ # Sunspot.search(Post) do
137
+ # any_of do
138
+ # with(:expired_at).greater_than Time.now
139
+ # with :expired_at, nil
140
+ # end
141
+ # end
142
+ #
143
+ # This will return all documents who either have an expiration time in the
144
+ # future, or who do not have any expiration time at all.
145
+ #
146
+ def any_of(&block)
147
+ Util.instance_eval_or_call(Scope.new(@scope.add_disjunction, @setup), &block)
148
+ end
149
+
150
+ #
151
+ # Create a conjunction, scoping the results to documents that match all of
152
+ # the enclosed restrictions. When called from the top level of a search
153
+ # block, this has no effect, but can be useful for grouping a conjunction
154
+ # inside a disjunction.
155
+ #
156
+ # ==== Example
157
+ #
158
+ # Sunspot.search(Post) do
159
+ # any_of do
160
+ # with(:blog_id, 1)
161
+ # all_of do
162
+ # with(:blog_id, 2)
163
+ # with(:category_ids, 3)
164
+ # end
165
+ # end
166
+ # end
167
+ #
168
+ def all_of(&block)
169
+ Util.instance_eval_or_call(Scope.new(@scope.add_conjunction, @setup), &block)
170
+ end
171
+
172
+ #
173
+ # Apply restrictions, facets, and ordering to dynamic field instances.
174
+ # The block API is implemented by Sunspot::DSL::FieldQuery, which is a
175
+ # superclass of the Query DSL (thus providing a subset of the API, in
176
+ # particular only methods that refer to particular fields).
177
+ #
178
+ # ==== Parameters
179
+ #
180
+ # base_name<Symbol>:: The base name for the dynamic field definition
181
+ #
182
+ # ==== Example
183
+ #
184
+ # Sunspot.search Post do
185
+ # dynamic :custom do
186
+ # with :cuisine, 'Pizza'
187
+ # facet :atmosphere
188
+ # order_by :chef_name
189
+ # end
190
+ # end
191
+ #
192
+ def dynamic(base_name, &block)
193
+ Sunspot::Util.instance_eval_or_call(
194
+ Scope.new(@scope, @setup.dynamic_field_factory(base_name)),
195
+ &block
196
+ )
197
+ end
198
+
199
+ #
200
+ # Apply scope-type restrictions on fulltext fields. In certain situations,
201
+ # it may be desirable to place logical restrictions on text fields.
202
+ # Remember that text fields are tokenized; your mileage may very.
203
+ #
204
+ # The block works exactly like a normal scope, except that the field names
205
+ # refer to text fields instead of attribute fields.
206
+ #
207
+ # === Example
208
+ #
209
+ # Sunspot.search(Post) do
210
+ # text_fields do
211
+ # with :body, nil
212
+ # end
213
+ # end
214
+ #
215
+ # This will return all documents that do not have a body.
216
+ #
217
+ def text_fields(&block)
218
+ Sunspot::Util.instance_eval_or_call(
219
+ Scope.new(@scope, TextFieldSetup.new(@setup)),
220
+ &block
221
+ )
222
+ end
223
+ end
224
+ end
225
+ end