blacklight_advanced_search 1.0.0pre1

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 (46) hide show
  1. data/.gitignore +5 -0
  2. data/LICENSE +14 -0
  3. data/README.rdoc +172 -0
  4. data/Rakefile +6 -0
  5. data/VERSION +1 -0
  6. data/app/controllers/advanced_controller.rb +61 -0
  7. data/app/controllers/application_controller.rb +5 -0
  8. data/app/helpers/advanced_helper.rb +40 -0
  9. data/app/views/advanced/_advanced_search_facets.html.erb +16 -0
  10. data/app/views/advanced/_advanced_search_fields.html.erb +6 -0
  11. data/app/views/advanced/_advanced_search_form.html.erb +48 -0
  12. data/app/views/advanced/_advanced_search_help.html.erb +22 -0
  13. data/app/views/advanced/index.html.erb +10 -0
  14. data/app/views/blacklight_advanced_search/_facet_limit.html.erb +25 -0
  15. data/blacklight_advanced_search.gemspec +24 -0
  16. data/config/routes.rb +3 -0
  17. data/install.rb +0 -0
  18. data/lib/blacklight_advanced_search/advanced_query_parser.rb +61 -0
  19. data/lib/blacklight_advanced_search/catalog_helper_override.rb +53 -0
  20. data/lib/blacklight_advanced_search/controller.rb +101 -0
  21. data/lib/blacklight_advanced_search/engine.rb +47 -0
  22. data/lib/blacklight_advanced_search/filter_parser.rb +13 -0
  23. data/lib/blacklight_advanced_search/parsing_nesting_parser.rb +18 -0
  24. data/lib/blacklight_advanced_search/render_constraints_override.rb +96 -0
  25. data/lib/blacklight_advanced_search/version.rb +10 -0
  26. data/lib/blacklight_advanced_search.rb +74 -0
  27. data/lib/generators/blacklight_advanced_search/assets_generator.rb +25 -0
  28. data/lib/generators/blacklight_advanced_search/blacklight_advanced_search_generator.rb +11 -0
  29. data/lib/generators/blacklight_advanced_search/templates/_search_form.html.erb +13 -0
  30. data/lib/generators/blacklight_advanced_search/templates/blacklight_advanced_search_config.rb +86 -0
  31. data/lib/generators/blacklight_advanced_search/templates/public/javascripts/blacklight_advanced_search_javascript.js +62 -0
  32. data/lib/generators/blacklight_advanced_search/templates/public/stylesheets/advanced_results.css +41 -0
  33. data/lib/generators/blacklight_advanced_search/templates/public/stylesheets/blacklight_advanced_search_styles.css +129 -0
  34. data/lib/parsing_nesting/Readme.rdoc +160 -0
  35. data/lib/parsing_nesting/grammar.rb +78 -0
  36. data/lib/parsing_nesting/tree.rb +457 -0
  37. data/spec/lib/filter_parser_spec.rb +28 -0
  38. data/spec/parsing_nesting/build_tree_spec.rb +238 -0
  39. data/spec/parsing_nesting/consuming_spec.rb +49 -0
  40. data/spec/parsing_nesting/to_solr_spec.rb +360 -0
  41. data/spec/rcov.opts +3 -0
  42. data/spec/spec.opts +4 -0
  43. data/spec/spec_helper.rb +9 -0
  44. data/spec/support/blacklight_mock.rb +5 -0
  45. data/uninstall.rb +1 -0
  46. metadata +164 -0
@@ -0,0 +1,238 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ require 'parsing_nesting/grammar'
4
+ require 'parsing_nesting/tree'
5
+
6
+
7
+ module ParseTreeSpecHelper
8
+ include ParsingNesting::Tree
9
+
10
+ def parse(s)
11
+ ParsingNesting::Tree.parse(s)
12
+ end
13
+
14
+ # for things expected to be a one-element list,
15
+ # make sure they are and return the element
16
+ def parse_one_element(s)
17
+ l = parse(s)
18
+ l.should be_kind_of( List )
19
+ l.list.length.should == 1
20
+ return l.list.first
21
+ end
22
+
23
+ def should_be_and_list(graph)
24
+ graph.should be_kind_of( AndList )
25
+ yield graph.list if block_given?
26
+ end
27
+
28
+ def should_be_list(graph)
29
+ graph.should be_kind_of( List)
30
+ yield graph.list if block_given?
31
+ end
32
+
33
+ def should_be_or_list(graph)
34
+ graph.should be_kind_of( OrList )
35
+ yield graph.list if block_given?
36
+ end
37
+
38
+ def should_be_term(graph, value)
39
+ graph.should be_kind_of( Term )
40
+ graph.value.should == value
41
+ end
42
+
43
+ def should_be_phrase(graph, value)
44
+ graph.should be_kind_of( Phrase )
45
+ graph.value.should == value
46
+ end
47
+
48
+ def should_be_mandatory(graph)
49
+ graph.should be_kind_of(MandatoryClause)
50
+ yield graph.operand if block_given?
51
+ end
52
+ def should_be_excluded(graph)
53
+ graph.should be_kind_of(ExcludedClause)
54
+ yield graph.operand if block_given?
55
+ end
56
+ def should_be_not_expression(graph)
57
+ graph.should be_kind_of(NotExpression)
58
+ yield graph.operand if block_given?
59
+ end
60
+ end
61
+
62
+ describe "NestingParser" do
63
+ describe "Building an Object parse tree" do
64
+ include ParseTreeSpecHelper
65
+
66
+
67
+ it "should build for term list" do
68
+ should_be_list parse("one two three") do |list|
69
+ list.length.should == 3
70
+ should_be_term list[0], "one"
71
+ should_be_term list[1], "two"
72
+ should_be_term list[2], "three"
73
+ end
74
+ end
75
+
76
+ it "should build AND list" do
77
+ should_be_and_list parse_one_element("one AND two AND three") do |list|
78
+ list.length.should == 3
79
+
80
+ should_be_term list[0], "one"
81
+ should_be_term list[1], "two"
82
+ should_be_term list[2], "three"
83
+ end
84
+ end
85
+
86
+ it "should build OR list" do
87
+ should_be_or_list parse_one_element("one OR two OR three") do |list|
88
+ list.length.should == 3
89
+ should_be_term list[0], "one"
90
+ should_be_term list[1], "two"
91
+ should_be_term list[2], "three"
92
+ end
93
+ end
94
+
95
+ it "allows AND list of lists" do
96
+ should_be_and_list parse_one_element('(one two) AND (blue yellow)') do |and_list|
97
+ and_list.length.should == 2
98
+ should_be_list and_list[0] do |list|
99
+ should_be_term(list[0], "one")
100
+ should_be_term(list[1], "two")
101
+ end
102
+ should_be_list and_list[1]
103
+ end
104
+ end
105
+
106
+ it "should build for mandatory and excluded" do
107
+ should_be_list parse("+one -two") do |list|
108
+ list.length.should == 2
109
+
110
+ should_be_mandatory list[0] do |operand|
111
+ should_be_term(operand, "one")
112
+ end
113
+
114
+ should_be_excluded list[1] do |operand|
115
+ should_be_term(operand, "two")
116
+ end
117
+ end
118
+ end
119
+
120
+ it "should build phrases" do
121
+ should_be_list parse('"quick brown" +"jumps over" -"lazy dog"') do |list|
122
+ list.length.should == 3
123
+
124
+ should_be_phrase(list[0], "quick brown")
125
+
126
+ should_be_mandatory(list[1]) do |operand|
127
+ should_be_phrase(operand, "jumps over")
128
+ end
129
+ end
130
+ end
131
+
132
+ it "should leave phrase literals literal, including weird chars" do
133
+ phrase_content = "foo+bar -i: '(baz"
134
+ should_be_phrase parse_one_element("\"#{phrase_content}\""), phrase_content
135
+ end
136
+
137
+ it "should build for NOT on term" do
138
+ should_be_list parse("one two three NOT four") do |list|
139
+ should_be_not_expression list[3] do |operand|
140
+ should_be_term(operand, "four")
141
+ end
142
+ end
143
+ end
144
+
145
+ it "should build for NOT on phrase" do
146
+ should_be_list parse('one two three NOT "quick brown"') do |list|
147
+ should_be_not_expression list[3] do |operand|
148
+ should_be_phrase(operand, "quick brown")
149
+ end
150
+ end
151
+ end
152
+
153
+ it "should build NOT on expression" do
154
+ should_be_list parse('one two NOT (blue OR yellow)') do |list|
155
+ should_be_not_expression list[2] do |operand|
156
+ should_be_or_list(operand)
157
+ end
158
+ end
159
+ end
160
+
161
+ it "should build NOT preceded by binary op" do
162
+ should_be_or_list parse_one_element('one OR NOT two') do |list|
163
+ should_be_not_expression list[1] do |operand|
164
+ should_be_term(operand, "two")
165
+ end
166
+ end
167
+ end
168
+
169
+
170
+ it "should bind OR more tightly than AND" do
171
+ should_be_and_list parse_one_element("grey AND big OR small AND tail") do |list|
172
+ list.length.should == 3
173
+
174
+ should_be_term list[0], "grey"
175
+
176
+ should_be_or_list list[1] do |or_list|
177
+ or_list.length.should == 2
178
+ should_be_term or_list[0], "big"
179
+ should_be_term or_list[1], "small"
180
+ end
181
+
182
+ should_be_term list[2], "tail"
183
+ end
184
+ end
185
+
186
+ it "should parse AND'd lists" do
187
+ should_be_and_list parse_one_element("(foo bar one AND two) AND (three four ten OR twelve)") do |list|
188
+ list.length.should == 2
189
+
190
+ should_be_list(list[0]) do |first_half|
191
+ first_half[0].value.should == 'foo'
192
+ first_half[1].value.should == "bar"
193
+ should_be_and_list(first_half[2])
194
+ end
195
+
196
+ should_be_list(list[1]) do |second_half|
197
+ second_half[0].value.should == "three"
198
+ second_half[1].value.should == "four"
199
+ should_be_or_list second_half[2]
200
+ end
201
+ end
202
+ end
203
+
204
+ it "should build for a crazy complicated one" do
205
+ should_be_list parse("mark +twain AND huck OR fun OR ((jim AND river) AND (red -dogs))") do |list|
206
+ should_be_term list[0], "mark"
207
+ should_be_and_list list[1] do |and_list|
208
+
209
+ should_be_mandatory and_list[0] do |operand|
210
+ should_be_term operand, "twain"
211
+ end
212
+
213
+ should_be_or_list and_list[1] do |or_list|
214
+ should_be_term or_list[0], "huck"
215
+ should_be_term or_list[1], "fun"
216
+
217
+ should_be_and_list or_list[2] do |and_list|
218
+ and_list.length.should == 2
219
+
220
+ should_be_and_list and_list[0]
221
+
222
+ should_be_list and_list[1] do |terms|
223
+ should_be_term terms[0], "red"
224
+ should_be_excluded terms[1] do |operand|
225
+ should_be_term operand, "dogs"
226
+ end
227
+ end
228
+ end
229
+
230
+ end
231
+ end
232
+ end
233
+ end
234
+
235
+ end
236
+ end
237
+
238
+
@@ -0,0 +1,49 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+ #require 'rubygems'
3
+ #require 'parslet'
4
+ #require 'spec'
5
+ #require 'spec/autorun'
6
+
7
+ #load '../../nesting_parser/grammar.rb'
8
+ #load '../../nesting_parser/tree.rb'
9
+
10
+ describe "NestingParser" do
11
+ describe "Consuming" do
12
+ before do
13
+ @parser = ParsingNesting::Grammar.new
14
+ end
15
+ # Whole bunch of things we just want to make sure they are consumed
16
+ # without error, not checking the generated tree yet.
17
+ ["foo",
18
+ "foo bar",
19
+ " foo bar ",
20
+ " foo bar baz ",
21
+ "+foo",
22
+ "-foo",
23
+ "+foo -bar",
24
+ "one +two three -four five",
25
+ "foo AND bar",
26
+ "one AND two AND three AND four",
27
+ "one OR two OR three OR four",
28
+ "white OR blue AND big OR small",
29
+ "+yes AND book OR -online",
30
+ "(one AND two)",
31
+ " ( one AND two ) ",
32
+ "(one OR two) three +four",
33
+ "(one AND two) OR three",
34
+ "(one AND -two) AND (+three OR (-four AND five))",
35
+ "one two three NOT four",
36
+ "one two three NOT (four OR five)",
37
+ "NOT four",
38
+ "NOT (four five)",
39
+ "(one two three) OR (four five) AND six",
40
+ '"foo+bar (baz"',
41
+ "(foo bar one AND two) AND (three four ten OR twelve)"
42
+ ].each do |query|
43
+ it "should consume<<#{query}>>" do
44
+ lambda {@parser.parse(query)}.should_not raise_error
45
+ end
46
+ end
47
+ end
48
+ end
49
+
@@ -0,0 +1,360 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+ #require 'rubygems'
3
+ #require 'parslet'
4
+ #require 'spec'
5
+ #require 'spec/autorun'
6
+
7
+ #load '../../lib/parsing_nesting/grammar.rb'
8
+ #load '../../lib/parsing_nesting/tree.rb'
9
+
10
+ module SolrQuerySpecHelper
11
+ def parse(s)
12
+ ParsingNesting::Tree.parse(s)
13
+ end
14
+
15
+ # yields localparam string, and the actual internal query
16
+ def local_param_match(query)
17
+ query.should =~ /^ *_query_:\"\{([^}]+)\}(.*)" *$/
18
+ query =~ /^ *_query_:\"\{([^}]+)\}(.*)" *$/
19
+ (param_str = $1).should_not be_nil
20
+ (query = $2).should_not be_nil
21
+
22
+ yield [param_str, query] if block_given?
23
+ end
24
+
25
+ def bare_local_param_match(query)
26
+ query.should =~ / *\{([^}]+)\}(.*)/
27
+ query =~ /\{([^}]+)\}(.*)/
28
+ (param_str = $1).should_not be_nil
29
+ (query = $2).should_not be_nil
30
+ yield [param_str, query] if block_given?
31
+ end
32
+
33
+ # Convenience for matching a lucene query combining nested queries,
34
+ # and getting out the nested queries as matches.
35
+ # pass in a string representing a regexp that uses $QUERY as placeholder where
36
+ # a nested _query_: will be.
37
+ #
38
+ # * Any parens in your passed in regexp will
39
+ # be paren literals, don't escape em yourself -- you can't do your
40
+ # own captures, because if the regexp passes, it'll yield to a block
41
+ # with a list, in order, of nested queries.
42
+ #
43
+ #
44
+ # * Can include $ALL to represent literal "*:*"
45
+ #
46
+ # Yes, the regexp matching isn't as robust as it could be, hard
47
+ # to deal with like escaped end-quotes and stuff in a regexp, but
48
+ # should mostly work.
49
+ def query_template_matcher(top_query, regexp_str)
50
+ nested_re = '(_query_:".+")'
51
+ regexp_str = regexp_str.gsub("(", '\(').gsub(')', '\)').gsub("$QUERY", nested_re).gsub("$ALL", "\\*\\:\\*")
52
+ regexp = Regexp.new('^ *' + regexp_str + ' *$')
53
+
54
+ top_query.should match( regexp )
55
+
56
+ yield *regexp.match(top_query).captures if block_given?
57
+ end
58
+ end
59
+
60
+ describe "NestingParser" do
61
+ describe "Translating to Solr" do
62
+ include SolrQuerySpecHelper
63
+
64
+ describe "with basic simple query" do
65
+ before do
66
+ @query = parse("one two three").to_query(:qf => "field field2^5", :pf=>"$pf_title")
67
+ end
68
+
69
+ it "should insist on dismax for nested query" do
70
+ query = parse("one two three").to_query(:defType => "field", :qf=>"$qf")
71
+ local_param_match(query) do |params, query|
72
+ params.should match(/^\!dismax /)
73
+ params.should_not match(/field/)
74
+ end
75
+ end
76
+
77
+ it "should include LocalParams" do
78
+ local_param_match(@query) do |params, query|
79
+ params.should include("pf=$pf_title")
80
+ params.should include('qf=\'field field2^5\'')
81
+ end
82
+ end
83
+
84
+ it "should include the query" do
85
+ local_param_match(@query) do |params, query|
86
+ query.should == "one two three"
87
+ end
88
+ end
89
+ end
90
+
91
+ describe "with simple mandatory/excluded terms" do
92
+ before do
93
+ @inner_query = 'red +army -"soviet union" germany'
94
+ @full_query = parse(@inner_query).to_query(:qf => "foo", :pf=>"bar")
95
+ end
96
+ it "should include query" do
97
+ local_param_match(@full_query) do |params, query|
98
+ query.should == @inner_query.gsub('"', '\\\\"')
99
+ end
100
+ end
101
+ end
102
+
103
+ describe "with embeddable AND query" do
104
+ before do
105
+ @query = parse("one two AND three").to_query({:qf => "$qf"})
106
+ end
107
+ it "should flatten to one dismax query" do
108
+ local_param_match(@query) do |params, query|
109
+ query.should == "one +two +three"
110
+ end
111
+ end
112
+
113
+ describe ", with mandatory/excluded" do
114
+ before do
115
+ @query = parse("one -two AND +three").to_query({:qf=>"$qf"})
116
+ end
117
+ it "should preserve +/- operators" do
118
+ local_param_match(@query) do |params, query|
119
+ query.should == "one -two +three"
120
+ end
121
+ end
122
+ end
123
+
124
+ describe ", deeply nested" do
125
+ before do
126
+ @query = parse("blue (green AND -violet) AND (+big AND (-small AND medium))").to_query({:qf=>"$qf"})
127
+ end
128
+ it "should flatten into dismax" do
129
+ local_param_match(@query) do |params, query|
130
+ query.should == "blue +green -violet +big -small +medium"
131
+ end
132
+ end
133
+ end
134
+
135
+ it "for simple OR list, forcing mm=1" do
136
+ query = parse("one OR two OR three").to_query(:qf => "$qf", :mm=>"50%")
137
+ local_param_match(query) do |params, query|
138
+ params.should include("mm=1")
139
+ query.should == "one two three"
140
+ end
141
+ end
142
+ end
143
+
144
+
145
+ describe "that needs to create multiple nested queries" do
146
+
147
+
148
+ it "for two lists, OR'd" do
149
+ query = parse("(one two three) OR (red -green +blue)").to_query(:qf => "$qf")
150
+
151
+ query_template_matcher(query, "( *$QUERY +OR +$QUERY *)" ) do |first_half, second_half|
152
+
153
+ local_param_match(first_half) do |params, query|
154
+ params.should include("qf=$qf")
155
+ query.should == "one two three"
156
+ end
157
+
158
+ local_param_match(second_half) do |params, query|
159
+ params.should include("qf=$qf")
160
+ query.should == "red -green +blue"
161
+ end
162
+ end
163
+ end
164
+
165
+ it "for AND list that can not be flattened" do
166
+ params = {:qf=>"$qf", :pf=>"$pf", :mm=>"50%"}
167
+ query = parse("a OR b AND x OR y").to_query( params )
168
+
169
+ query_template_matcher(query, "( *$QUERY +AND +$QUERY *)" ) do |first, second|
170
+ first.should == parse("a OR b").to_query(params)
171
+ second.should == parse("x OR y").to_query(params)
172
+ end
173
+ end
174
+
175
+ it "for AND of two lists" do
176
+ params = {:qf => "$qf", :pf=>"$pf", :mm=>"50%"}
177
+ query = parse("(one +two three) AND (four five -six)").to_query( params )
178
+
179
+ query_template_matcher(query, "( *$QUERY +AND +$QUERY *)" ) do |first, second|
180
+ first.should == parse("one +two three").to_query(params)
181
+ second.should == parse("four five -six").to_query(params)
182
+ end
183
+
184
+ end
185
+
186
+ it "for crazy complicated query" do
187
+ query = parse("red AND dawn OR (-night -afternoon) AND NOT (moscow OR beach) ").to_query(:qf => "$qf", :pf =>"$pf", :mm=>"50%")
188
+
189
+ query_template_matcher(query, "( *$QUERY +AND +( *$QUERY +OR +($ALL AND NOT $QUERY *) *) +AND NOT $QUERY *)") do |red_q, dawn_q, night_q, moscow_q|
190
+
191
+ local_param_match(red_q) { |params, query| query.should == "red" }
192
+
193
+ local_param_match(dawn_q) { |params, query| query.should == "dawn"}
194
+
195
+ local_param_match(night_q) do |params, query|
196
+ params.should include("mm=1")
197
+ query.should == "night afternoon"
198
+ end
199
+
200
+ local_param_match(moscow_q) do |params, query|
201
+ params.should include("mm=1")
202
+ query.should == "moscow beach"
203
+ end
204
+
205
+ end
206
+
207
+ end
208
+
209
+
210
+ end
211
+
212
+ describe "for NOT operator" do
213
+ it "simple" do
214
+ query = parse("NOT frog").to_query
215
+
216
+ query_template_matcher(query, "NOT $QUERY") do |q|
217
+ q.should == parse("frog").to_query
218
+ end
219
+ end
220
+ it "binds tightly" do
221
+ query = parse("one NOT two three").to_query
222
+
223
+ query_template_matcher(query, "$QUERY AND NOT $QUERY") do |q1, q2|
224
+
225
+ local_param_match(q1) do |params, query|
226
+ query.should == "one three"
227
+ end
228
+
229
+ local_param_match(q2) do |params, query|
230
+ query.should == "two"
231
+ end
232
+ end
233
+
234
+ end
235
+ it "complicated operand" do
236
+ query = parse("one OR two NOT (three OR four AND five)").to_query
237
+ #"_query_:'{!dismax mm=1}one two' AND NOT ( _query_:'{!dismax mm=1}three four' AND _query_:'{!dismax }five' )"
238
+ query_template_matcher(query, "$QUERY +AND NOT +( *$QUERY +AND +$QUERY *)") do |external_or, internal_or, internal_term|
239
+ external_or.should == parse("one OR two").to_query
240
+ internal_or.should == parse("three OR four").to_query
241
+ internal_term.should == parse("five").to_query
242
+ end
243
+ end
244
+
245
+ it "uses workaround on NOT as operand to OR" do
246
+ query = parse("two OR (NOT (three))").to_query
247
+ query_template_matcher(query, "( *$QUERY +OR +($ALL +AND +NOT +$QUERY) *)")
248
+ end
249
+
250
+ end
251
+
252
+ describe "for pure negative" do
253
+ it "should convert simple pure negative" do
254
+ query = parse('-one -two -"a phrase"').to_query(:qf => "$qf", :mm => "100%")
255
+
256
+ query_template_matcher(query, " *NOT $QUERY") do |query|
257
+ local_param_match(query) do |params, query|
258
+ params.should include("mm=1")
259
+ query.should == 'one two \\"a phrase\\"'
260
+ end
261
+ end
262
+
263
+ end
264
+
265
+ it "should convert pure negative AND" do
266
+ query = parse("-one AND -two AND -three").to_query(:qf => "$qf", :mm => "100%")
267
+
268
+ query_template_matcher(query, "NOT $QUERY") do |query|
269
+ local_param_match(query) do |params, query|
270
+ params.should =~ /mm=1 |$/
271
+ query.should == 'one two three'
272
+ end
273
+ end
274
+ end
275
+
276
+ it "should convert pure negative OR" do
277
+ query = parse("-one OR -two OR -three").to_query
278
+
279
+ query_template_matcher(query, "NOT $QUERY") do |query|
280
+ local_param_match(query) do |params, query|
281
+ params.should include("mm=100%")
282
+ query.should == "one two three"
283
+ end
284
+ end
285
+
286
+ end
287
+
288
+ it "should convert crazy pure negative combo" do
289
+ query = parse("(-one -two) OR -three OR (-five AND -six)").to_query
290
+
291
+ query_template_matcher(query, "( *($ALL +AND +NOT +$QUERY) +OR +( *$ALL +AND +NOT +$QUERY *) +OR +( *$ALL +AND +NOT +$QUERY *) *)")
292
+ end
293
+ end
294
+
295
+
296
+ # When a single parse will be the whole query, we use
297
+ # different more compact production
298
+ describe "Single Query" do
299
+ before do
300
+ @solr_local_params = {"qf" => "$title_qf", "pf" => "$title_pf"}
301
+ end
302
+ describe "simple search" do
303
+ it "should work with local params" do
304
+ hash = parse("one +two -three").to_single_query_params(@solr_local_params)
305
+ hash[:defType].should == "dismax"
306
+ bare_local_param_match(hash[:q]) do |params, query|
307
+ query.should == "one +two -three"
308
+ params.should include("pf=$title_pf")
309
+ params.should include("qf=$title_qf")
310
+ end
311
+ end
312
+
313
+ it "should work without local params" do
314
+ hash = parse("one +two -three").to_single_query_params({})
315
+ hash[:defType].should == "dismax"
316
+ hash[:q].should == "one +two -three"
317
+ end
318
+ end
319
+ describe "simple pure negative" do
320
+ it "should be nested NOT" do
321
+ hash = parse("-one -two").to_single_query_params({})
322
+ hash[:defType].should == "dismax"
323
+ query_template_matcher(hash[:q], "NOT $QUERY") do |query|
324
+ local_param_match(query) do |params, query|
325
+ query.should == "one two"
326
+ params.should include("mm=1")
327
+ end
328
+ end
329
+ end
330
+ end
331
+ describe "complex query" do
332
+ it "should parse" do
333
+ hash = parse("one AND (two OR three)").to_single_query_params({})
334
+ hash[:defType].should == "lucene"
335
+ query_template_matcher(hash[:q], "( *$QUERY +AND +$QUERY *)") do |first, second|
336
+ local_param_match(first) do |params, query|
337
+ params.should include("dismax")
338
+ query.should == "one"
339
+ end
340
+ local_param_match(second) do |params, query|
341
+ params.should include("mm=1")
342
+ params.should include("dismax")
343
+ query.should == "two three"
344
+ end
345
+ end
346
+ end
347
+ end
348
+
349
+
350
+ end
351
+
352
+
353
+ end
354
+
355
+
356
+
357
+
358
+ end
359
+
360
+
data/spec/rcov.opts ADDED
@@ -0,0 +1,3 @@
1
+ --exclude "spec/*,gems/*,features/*"
2
+ --rails
3
+ --aggregate coverage.data
data/spec/spec.opts ADDED
@@ -0,0 +1,4 @@
1
+ --colour
2
+ --format progress
3
+ --loadby mtime
4
+ --reverse
@@ -0,0 +1,9 @@
1
+ #RAILS_ROOT = "#{File.dirname(__FILE__)}/.."
2
+
3
+ Dir[Pathname.new(File.expand_path("../support/**/*.rb", __FILE__))].each {|f| require f}
4
+ require 'lib/blacklight_advanced_search'
5
+
6
+ RSpec.configure do |config|
7
+
8
+ end
9
+
@@ -0,0 +1,5 @@
1
+ module Blacklight
2
+ module SearchFields
3
+
4
+ end
5
+ end
data/uninstall.rb ADDED
@@ -0,0 +1 @@
1
+ # Uninstall hook code here