blacklight_advanced_search 1.0.0pre1

Sign up to get free protection for your applications and to get access to all the features.
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