blacklight_advanced_search 6.0.2 → 6.1.0

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 (61) hide show
  1. checksums.yaml +4 -4
  2. data/.rspec +2 -0
  3. data/.rubocop.yml +15 -0
  4. data/.rubocop_todo.yml +351 -0
  5. data/.solr_wrapper.yml +5 -0
  6. data/.travis.yml +4 -7
  7. data/Gemfile +18 -11
  8. data/Rakefile +24 -34
  9. data/VERSION +1 -1
  10. data/app/controllers/advanced_controller.rb +5 -7
  11. data/app/controllers/blacklight_advanced_search/advanced_controller.rb +5 -8
  12. data/app/helpers/advanced_helper.rb +4 -6
  13. data/blacklight_advanced_search.gemspec +11 -8
  14. data/lib/blacklight_advanced_search.rb +29 -34
  15. data/lib/blacklight_advanced_search/advanced_query_parser.rb +12 -13
  16. data/lib/blacklight_advanced_search/advanced_search_builder.rb +28 -32
  17. data/lib/blacklight_advanced_search/catalog_helper_override.rb +11 -34
  18. data/lib/blacklight_advanced_search/controller.rb +1 -1
  19. data/lib/blacklight_advanced_search/filter_parser.rb +7 -9
  20. data/lib/blacklight_advanced_search/parsing_nesting_parser.rb +5 -8
  21. data/lib/blacklight_advanced_search/redirect_legacy_params_filter.rb +23 -25
  22. data/lib/blacklight_advanced_search/render_constraints_override.rb +46 -33
  23. data/lib/blacklight_advanced_search/version.rb +0 -1
  24. data/lib/generators/blacklight_advanced_search/assets_generator.rb +4 -8
  25. data/lib/generators/blacklight_advanced_search/blacklight_advanced_search_generator.rb +0 -2
  26. data/lib/generators/blacklight_advanced_search/install_generator.rb +9 -5
  27. data/lib/generators/blacklight_advanced_search/templates/advanced_controller.rb +0 -2
  28. data/lib/parsing_nesting/grammar.rb +22 -25
  29. data/lib/parsing_nesting/tree.rb +156 -168
  30. data/solr/conf/_rest_managed.json +3 -0
  31. data/solr/conf/admin-extra.html +31 -0
  32. data/solr/conf/elevate.xml +36 -0
  33. data/solr/conf/mapping-ISOLatin1Accent.txt +246 -0
  34. data/solr/conf/protwords.txt +21 -0
  35. data/solr/conf/schema.xml +635 -0
  36. data/solr/conf/scripts.conf +24 -0
  37. data/solr/conf/solrconfig.xml +411 -0
  38. data/solr/conf/spellings.txt +2 -0
  39. data/solr/conf/stopwords.txt +58 -0
  40. data/solr/conf/stopwords_en.txt +58 -0
  41. data/solr/conf/synonyms.txt +31 -0
  42. data/solr/conf/xslt/example.xsl +132 -0
  43. data/solr/conf/xslt/example_atom.xsl +67 -0
  44. data/solr/conf/xslt/example_rss.xsl +66 -0
  45. data/solr/conf/xslt/luke.xsl +337 -0
  46. data/solr/sample_solr_documents.yml +2692 -0
  47. data/spec/features/blacklight_advanced_search_form_spec.rb +0 -2
  48. data/spec/helpers/advanced_helper_spec.rb +0 -2
  49. data/spec/integration/blacklight_stub_spec.rb +0 -2
  50. data/spec/lib/advanced_search_builder_spec.rb +7 -14
  51. data/spec/lib/blacklight_advanced_search/render_constraints_override_spec.rb +39 -0
  52. data/spec/lib/deep_merge_spec.rb +109 -34
  53. data/spec/lib/filter_parser_spec.rb +8 -14
  54. data/spec/parsing_nesting/build_tree_spec.rb +73 -81
  55. data/spec/parsing_nesting/consuming_spec.rb +2 -12
  56. data/spec/parsing_nesting/to_solr_spec.rb +93 -130
  57. data/spec/spec_helper.rb +0 -3
  58. data/spec/test_app_templates/app/controllers/catalog_controller.rb +3 -3
  59. data/spec/test_app_templates/lib/generators/test_app_generator.rb +3 -3
  60. metadata +63 -13
  61. data/spec/spec.opts +0 -4
@@ -1,5 +1,3 @@
1
- require 'spec_helper'
2
-
3
1
  describe "Blacklight Advanced Search Form" do
4
2
  before(:all) do
5
3
  AdvancedController.copy_blacklight_config_from(CatalogController)
@@ -1,5 +1,3 @@
1
- require 'spec_helper'
2
-
3
1
  describe AdvancedHelper do
4
2
  describe '#advanced_search_facet_partial_name' do
5
3
  let(:field) { double(name: "field_name") }
@@ -1,5 +1,3 @@
1
- require 'spec_helper'
2
-
3
1
  describe 'Blacklight Test Application' do
4
2
  it "should have a Blacklight module" do
5
3
  expect(Blacklight).to be_a_kind_of(Module)
@@ -1,12 +1,8 @@
1
- require 'spec_helper'
2
-
3
1
  describe BlacklightAdvancedSearch::AdvancedSearchBuilder do
4
-
5
2
  describe "#add_advanced_parse_q_to_solr" do
6
-
7
3
  let(:blacklight_config) do
8
4
  Blacklight::Configuration.new do |config|
9
- config.advanced_search = { }
5
+ config.advanced_search = {}
10
6
  config.add_search_field "all_fields"
11
7
  config.add_search_field "special_field" do |field|
12
8
  field.advanced_parse = false
@@ -19,7 +15,7 @@ describe BlacklightAdvancedSearch::AdvancedSearchBuilder do
19
15
  cattr_accessor :blacklight_config
20
16
  include Blacklight::SearchHelper
21
17
  include BlacklightAdvancedSearch::AdvancedSearchBuilder
22
- def initialize blacklight_config
18
+ def initialize(blacklight_config)
23
19
  self.blacklight_config = blacklight_config
24
20
  end
25
21
  end
@@ -30,20 +26,20 @@ describe BlacklightAdvancedSearch::AdvancedSearchBuilder do
30
26
  let(:solr_params) { {} }
31
27
 
32
28
  describe "a simple example" do
33
- let(:params) { double("params", params: {:q => "one two AND three OR four"} ) }
29
+ let(:params) { double("params", params: { :q => "one two AND three OR four" }) }
34
30
  before { allow(obj).to receive(:scope).and_return(params) }
35
31
  it "catches the query" do
36
- obj.add_advanced_parse_q_to_solr(solr_params)
32
+ obj.add_advanced_parse_q_to_solr(solr_params)
37
33
  expect(solr_params[:defType]).to eq("lucene")
38
34
  # We're not testing succesful parsing here, just that it's doing
39
- # something that looks like we expect with subqueries.
35
+ # something that looks like we expect with subqueries.
40
36
  expect(solr_params[:q]).to start_with("_query_:")
41
37
  end
42
38
  end
43
39
 
44
40
  describe "an unparseable example" do
45
41
  let(:unparseable_q) { "foo bar\'s AND" }
46
- let(:params) { double("params", params: {:q => unparseable_q} ) }
42
+ let(:params) { double("params", params: { :q => unparseable_q }) }
47
43
  before { allow(obj).to receive(:scope).and_return(params) }
48
44
  it "passes through" do
49
45
  obj.add_advanced_parse_q_to_solr(solr_params)
@@ -52,16 +48,13 @@ describe BlacklightAdvancedSearch::AdvancedSearchBuilder do
52
48
  end
53
49
 
54
50
  context "when advanced_parse is false" do
55
- let(:params) { double("params", params: { :search_field => "special_field", :q => "one two AND three OR four" } ) }
51
+ let(:params) { double("params", params: { :search_field => "special_field", :q => "one two AND three OR four" }) }
56
52
  before { allow(obj).to receive(:scope).and_return(params) }
57
53
  it "ignores fields" do
58
54
  obj.add_advanced_parse_q_to_solr(solr_params)
59
55
  expect(solr_params).not_to have_key(:q)
60
56
  end
61
57
  end
62
-
63
58
  end
64
-
65
59
  end
66
-
67
60
  end
@@ -0,0 +1,39 @@
1
+ describe BlacklightAdvancedSearch::RenderConstraintsOverride, type: :helper do
2
+ let(:blacklight_config) do
3
+ Blacklight::Configuration.new do |config|
4
+ config.add_facet_field 'type'
5
+ end
6
+ end
7
+
8
+ let(:advanced_query) do
9
+ BlacklightAdvancedSearch::QueryParser.new(params, blacklight_config)
10
+ end
11
+
12
+ describe "#render_constraints_filters" do
13
+ before do
14
+ allow(helper).to receive(:blacklight_config).and_return(blacklight_config)
15
+ allow(helper).to receive(:advanced_query).and_return(advanced_query)
16
+ allow(helper).to receive(:search_action_path) do |*args|
17
+ search_catalog_path(*args)
18
+ end
19
+ end
20
+
21
+ subject(:rendered) { helper.render_constraints_filters({}) }
22
+
23
+ context 'with an array of facet params' do
24
+ let(:params) { ActionController::Parameters.new f_inclusive: { 'type' => ['a'] } }
25
+
26
+ it "renders nothing" do
27
+ expect(rendered).to have_text 'Remove constraint Type: a'
28
+ end
29
+ end
30
+
31
+ context 'with scalar facet limit params' do
32
+ let(:params) { ActionController::Parameters.new f_inclusive: { 'type' => 'a' } }
33
+
34
+ it "renders the scalar value" do
35
+ expect(rendered).to have_text 'Remove constraint Type: a'
36
+ end
37
+ end
38
+ end
39
+ end
@@ -1,45 +1,120 @@
1
- require 'spec_helper'
2
-
3
- describe "BlacklightAdvancedSearch#deep_merge!" do
4
- before do
5
- @ahash = {"a" => "a", "b" => "b",
6
- "array1" => [1,2], "array2" => [3,4],
7
- "hash1" => {"a" => "a", "array" => [1], "b" => "b"},
8
- "hash2" => {"a2" => "a2", "array2" => [12], "b2" => "b2"}
1
+ describe 'BlacklightAdvancedSearch#deep_merge' do
2
+ let(:hash_X) do
3
+ {
4
+ 'a' => 'a',
5
+ 'b' => 'b',
6
+ 'array1' => [1, 2],
7
+ 'array2' => [3, 4],
8
+ 'hash1' => { 'a' => 'a', 'array' => [1], 'b' => 'b' },
9
+ 'hash2' => { 'a2' => 'a2', 'array2' => [12], 'b2' => 'b2' }
10
+ }
11
+ end
12
+ let(:hash_Y) do
13
+ {
14
+ 'a' => 'NEW A',
15
+ 'c' => 'NEW C',
16
+ 'array1' => [3, 4],
17
+ 'hash1' => { 'array' => [2], 'b' => 'NEW B' }
9
18
  }
10
-
11
- BlacklightAdvancedSearch.deep_merge!(@ahash, {
12
- "a" => "NEW A",
13
- "array1" => [3, 4],
14
- "hash1" => {
15
- "array" => [2],
16
- "b" => "NEW B"
17
- },
18
- "c" => "NEW C"
19
- })
20
19
  end
20
+ let(:ahash) do
21
+ BlacklightAdvancedSearch.deep_merge(hash_x, hash_y)
22
+ end
23
+
24
+ RSpec.shared_examples 'Mergable Parameters' do # this name referenced below
25
+ it 'does not modify the param hashes' do
26
+ dup_x = hash_x.dup
27
+ dup_y = hash_y.dup
28
+ expect(ahash).not_to eq hash_x # this was the old behavior
29
+ expect(dup_x).to eq hash_x
30
+ expect(dup_y).to eq hash_y
31
+ end
32
+
33
+ it 'leaves un-collided content alone' do
34
+ expect(ahash['b']).to eq('b')
35
+ expect(ahash['array2']).to eq([3, 4])
36
+ expect(ahash['hash2']).to eq('a2' => 'a2', 'array2' => [12], 'b2' => 'b2')
37
+ end
38
+
39
+ it 'adds new content' do
40
+ expect(ahash['c']).to eq('NEW C')
41
+ end
42
+
43
+ it 'merges a hash, recursive like' do
44
+ expect(ahash['hash1']).to eq('a' => 'a', 'array' => [1, 2], 'b' => 'NEW B')
45
+ end
46
+
47
+ it 'merges boolean values (false)' do
48
+ expect(BlacklightAdvancedSearch.deep_merge({ a: false }, a: true)).to eq(a: true)
49
+ expect(BlacklightAdvancedSearch.deep_merge({ a: true }, a: false)).to eq(a: false)
50
+ end
21
51
 
52
+ it 'does not merge nil values over existing keys' do
53
+ expect(BlacklightAdvancedSearch.deep_merge({ a: 1 }, a: nil)).to eq(a: 1)
54
+ end
22
55
 
23
- it "leaves un-collided content alone" do
24
- expect(@ahash["b"]).to eq("b")
25
- expect(@ahash["array2"]).to eq([3,4])
26
- expect(@ahash["hash2"]).to eq({"a2" => "a2", "array2" => [12], "b2" => "b2"})
56
+ it 'does merge nil values when the key is not yet present' do
57
+ expect(BlacklightAdvancedSearch.deep_merge({}, a: nil)).to eq(a: nil)
58
+ end
59
+
60
+ it 'does not merge empty strings over existing keys' do
61
+ expect(BlacklightAdvancedSearch.deep_merge({ a: 1 }, a: '')).to eq(a: 1)
62
+ expect(BlacklightAdvancedSearch.deep_merge({ a: nil }, a: '')).to eq(a: nil)
63
+ end
64
+
65
+ it 'does not merge empty strings when the key is not yet present' do
66
+ expect(BlacklightAdvancedSearch.deep_merge({}, a: '')).to eq(a: '')
67
+ end
68
+
69
+ context 'Arrays' do
70
+ it 'merges an array' do
71
+ expect(ahash['array1']).to eq([1, 2, 3, 4])
72
+ end
73
+
74
+ it 'collapse to uniq values when merging' do
75
+ expect(BlacklightAdvancedSearch.deep_merge({ a: [1, 1, 2, 1] }, a: [3, 2])).to eq(a: [1, 2, 3])
76
+ end
77
+
78
+ it 'does not collapse to uniq values if not merging' do
79
+ expect(BlacklightAdvancedSearch.deep_merge({ a: [1, 1, 2, 1] }, a: [])).to eq(a: [1, 1, 2, 1])
80
+ end
81
+ end
82
+ end
83
+
84
+ describe Hash do
85
+ it_behaves_like 'Mergable Parameters' do
86
+ let(:hash_x) { hash_X }
87
+ let(:hash_y) { hash_Y }
88
+ end
27
89
  end
28
90
 
29
- it "adds new content" do
30
- expect(@ahash["c"]).to eq("NEW C")
91
+ describe HashWithIndifferentAccess do
92
+ it_behaves_like 'Mergable Parameters' do
93
+ let(:hash_x) { hash_X.with_indifferent_access }
94
+ let(:hash_y) { hash_Y.with_indifferent_access }
95
+ end
31
96
  end
32
97
 
33
- it "merges an array" do
34
- expect(@ahash["array1"]).to eq([1,2,3,4])
98
+ describe 'Mixed Hash and HWIA' do
99
+ it_behaves_like 'Mergable Parameters' do
100
+ let(:hash_x) { hash_X }
101
+ let(:hash_y) { hash_Y.with_indifferent_access }
102
+ end
103
+
104
+ it_behaves_like 'Mergable Parameters' do
105
+ let(:hash_x) { hash_X.with_indifferent_access }
106
+ let(:hash_y) { hash_Y }
107
+ end
35
108
  end
36
109
 
37
- it "merges a hash, recursive like" do
38
- expect(@ahash["hash1"]).to eq({
39
- "a" => "a",
40
- "array" => [1,2],
41
- "b" => "NEW B"
42
- })
110
+ # from http://apidock.com/rails/v4.2.1/Hash/deep_merge
111
+ describe 'reference example' do
112
+ it 'gives the same result as Rails Hash .deep_merge' do
113
+ h1 = { a: true, b: { c: [1, 2, 3] } }
114
+ h2 = { a: false, b: { x: [3, 4, 5] } }
115
+ merged = { a: false, b: { c: [1, 2, 3], x: [3, 4, 5] } }
116
+ expect(h1.deep_merge(h2)).to eq(merged)
117
+ expect(BlacklightAdvancedSearch.deep_merge(h1, h2)).to eq(merged)
118
+ end
43
119
  end
44
-
45
- end
120
+ end
@@ -1,28 +1,22 @@
1
- require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
-
3
1
  def setFilters(f)
4
2
  @filters = f
5
3
  end
6
4
 
5
+ ## These should be reworked, but attr_reader actually breaks it.
6
+ # rubocop:disable Style/TrivialAccessors
7
7
  def filters
8
8
  @filters
9
9
  end
10
10
 
11
-
12
11
  describe "BlacklightAdvancedSearch::FilterParser" do
13
12
  include BlacklightAdvancedSearch::FilterParser
14
-
13
+
15
14
  describe "filter processing" do
16
15
  it "should generate an appropriate fq param" do
17
- setFilters(:format => ["Book", "Thesis"], :location=>["Online", "Library"])
18
-
16
+ setFilters(:format => %w(Book Thesis), :location => %w(Online Library))
19
17
  fq_params = generate_solr_fq
20
-
21
- expect(fq_params.find {|a| a =~ /format\:\((\"Book\"|\"Thesis\") +OR +(\"Thesis\"|\"Book\")/}).not_to be_nil
22
-
23
- expect(fq_params.find {|a| a =~ /location\:\((\"Library\"|\"Online\") +OR +(\"Library\"|\"Online\")/}).not_to be_nil
24
-
25
-
26
- end
18
+ expect(fq_params.find { |a| a =~ /format\:\((\"Book\"|\"Thesis\") +OR +(\"Thesis\"|\"Book\")/ }).not_to be_nil
19
+ expect(fq_params.find { |a| a =~ /location\:\((\"Library\"|\"Online\") +OR +(\"Library\"|\"Online\")/ }).not_to be_nil
20
+ end
27
21
  end
28
- end
22
+ end
@@ -1,58 +1,57 @@
1
- require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
-
3
1
  require 'parsing_nesting/grammar'
4
2
  require 'parsing_nesting/tree'
5
3
 
6
-
7
4
  module ParseTreeSpecHelper
8
5
  include ParsingNesting::Tree
9
-
6
+
10
7
  def parse(s)
11
8
  ParsingNesting::Tree.parse(s)
12
9
  end
13
-
14
- # for things expected to be a one-element list,
10
+
11
+ # for things expected to be a one-element list,
15
12
  # make sure they are and return the element
16
13
  def parse_one_element(s)
17
14
  l = parse(s)
18
- expect(l).to be_kind_of( List )
15
+ expect(l).to be_kind_of(List)
19
16
  expect(l.list.length).to eq(1)
20
- return l.list.first
17
+ l.list.first
21
18
  end
22
-
19
+
23
20
  def should_be_and_list(graph)
24
- expect(graph).to be_kind_of( AndList )
21
+ expect(graph).to be_kind_of(AndList)
25
22
  yield graph.list if block_given?
26
23
  end
27
-
24
+
28
25
  def should_be_list(graph)
29
- expect(graph).to be_kind_of( List)
26
+ expect(graph).to be_kind_of(List)
30
27
  yield graph.list if block_given?
31
28
  end
32
-
29
+
33
30
  def should_be_or_list(graph)
34
- expect(graph).to be_kind_of( OrList )
31
+ expect(graph).to be_kind_of(OrList)
35
32
  yield graph.list if block_given?
36
33
  end
37
-
34
+
38
35
  def should_be_term(graph, value)
39
- expect(graph).to be_kind_of( Term )
36
+ expect(graph).to be_kind_of(Term)
40
37
  expect(graph.value).to eq(value)
41
38
  end
42
-
39
+
43
40
  def should_be_phrase(graph, value)
44
- expect(graph).to be_kind_of( Phrase )
41
+ expect(graph).to be_kind_of(Phrase)
45
42
  expect(graph.value).to eq(value)
46
43
  end
47
-
44
+
48
45
  def should_be_mandatory(graph)
49
46
  expect(graph).to be_kind_of(MandatoryClause)
50
47
  yield graph.operand if block_given?
51
48
  end
49
+
52
50
  def should_be_excluded(graph)
53
51
  expect(graph).to be_kind_of(ExcludedClause)
54
52
  yield graph.operand if block_given?
55
53
  end
54
+
56
55
  def should_be_not_expression(graph)
57
56
  expect(graph).to be_kind_of(NotExpression)
58
57
  yield graph.operand if block_given?
@@ -60,38 +59,37 @@ module ParseTreeSpecHelper
60
59
  end
61
60
 
62
61
  describe "NestingParser" do
63
- describe "Building an Object parse tree" do
62
+ describe "Building an Object parse tree" do
64
63
  include ParseTreeSpecHelper
65
-
66
-
64
+
67
65
  it "should build for term list" do
68
- should_be_list parse("one two three") do |list|
66
+ should_be_list parse("one two three") do |list|
69
67
  expect(list.length).to eq(3)
70
68
  should_be_term list[0], "one"
71
69
  should_be_term list[1], "two"
72
- should_be_term list[2], "three"
73
- end
70
+ should_be_term list[2], "three"
71
+ end
74
72
  end
75
-
73
+
76
74
  it "should build AND list" do
77
75
  should_be_and_list parse_one_element("one AND two AND three") do |list|
78
76
  expect(list.length).to eq(3)
79
-
77
+
80
78
  should_be_term list[0], "one"
81
79
  should_be_term list[1], "two"
82
- should_be_term list[2], "three"
80
+ should_be_term list[2], "three"
83
81
  end
84
82
  end
85
-
83
+
86
84
  it "should build OR list" do
87
- should_be_or_list parse_one_element("one OR two OR three") do |list|
85
+ should_be_or_list parse_one_element("one OR two OR three") do |list|
88
86
  expect(list.length).to eq(3)
89
87
  should_be_term list[0], "one"
90
88
  should_be_term list[1], "two"
91
- should_be_term list[2], "three"
92
- end
89
+ should_be_term list[2], "three"
90
+ end
93
91
  end
94
-
92
+
95
93
  it "allows AND list of lists" do
96
94
  should_be_and_list parse_one_element('(one two) AND (blue yellow)') do |and_list|
97
95
  expect(and_list.length).to eq(2)
@@ -100,125 +98,123 @@ describe "NestingParser" do
100
98
  should_be_term(list[1], "two")
101
99
  end
102
100
  should_be_list and_list[1]
103
- end
101
+ end
104
102
  end
105
-
103
+
106
104
  it "should build for mandatory and excluded" do
107
105
  should_be_list parse("+one -two") do |list|
108
106
  expect(list.length).to eq(2)
109
-
107
+
110
108
  should_be_mandatory list[0] do |operand|
111
109
  should_be_term(operand, "one")
112
110
  end
113
-
111
+
114
112
  should_be_excluded list[1] do |operand|
115
113
  should_be_term(operand, "two")
116
114
  end
117
- end
115
+ end
118
116
  end
119
-
117
+
120
118
  it "should build phrases" do
121
119
  should_be_list parse('"quick brown" +"jumps over" -"lazy dog"') do |list|
122
120
  expect(list.length).to eq(3)
123
-
121
+
124
122
  should_be_phrase(list[0], "quick brown")
125
-
123
+
126
124
  should_be_mandatory(list[1]) do |operand|
127
125
  should_be_phrase(operand, "jumps over")
128
- end
126
+ end
129
127
  end
130
128
  end
131
-
129
+
132
130
  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
131
+ phrase_content = "foo+bar -i: '(baz"
132
+ should_be_phrase parse_one_element("\"#{phrase_content}\""), phrase_content
135
133
  end
136
-
134
+
137
135
  it "should build for NOT on term" do
138
136
  should_be_list parse("one two three NOT four") do |list|
139
137
  should_be_not_expression list[3] do |operand|
140
138
  should_be_term(operand, "four")
141
139
  end
142
- end
140
+ end
143
141
  end
144
-
142
+
145
143
  it "should build for NOT on phrase" do
146
144
  should_be_list parse('one two three NOT "quick brown"') do |list|
147
145
  should_be_not_expression list[3] do |operand|
148
146
  should_be_phrase(operand, "quick brown")
149
147
  end
150
- end
148
+ end
151
149
  end
152
-
150
+
153
151
  it "should build NOT on expression" do
154
152
  should_be_list parse('one two NOT (blue OR yellow)') do |list|
155
153
  should_be_not_expression list[2] do |operand|
156
154
  should_be_or_list(operand)
157
155
  end
158
- end
156
+ end
159
157
  end
160
-
158
+
161
159
  it "should build NOT preceded by binary op" do
162
160
  should_be_or_list parse_one_element('one OR NOT two') do |list|
163
161
  should_be_not_expression list[1] do |operand|
164
162
  should_be_term(operand, "two")
165
163
  end
166
- end
164
+ end
167
165
  end
168
-
169
-
166
+
170
167
  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|
168
+ should_be_and_list parse_one_element("grey AND big OR small AND tail") do |list|
172
169
  expect(list.length).to eq(3)
173
-
170
+
174
171
  should_be_term list[0], "grey"
175
-
172
+
176
173
  should_be_or_list list[1] do |or_list|
177
- expect(or_list.length).to eq(2)
178
- should_be_term or_list[0], "big"
179
- should_be_term or_list[1], "small"
174
+ expect(or_list.length).to eq(2)
175
+ should_be_term or_list[0], "big"
176
+ should_be_term or_list[1], "small"
180
177
  end
181
-
178
+
182
179
  should_be_term list[2], "tail"
183
- end
180
+ end
184
181
  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
- expect(list.length).to eq(2)
189
-
182
+
183
+ it "should parse AND'd lists" do
184
+ should_be_and_list parse_one_element("(foo bar one AND two) AND (three four ten OR twelve)") do |list|
185
+ expect(list.length).to eq(2)
186
+
190
187
  should_be_list(list[0]) do |first_half|
191
188
  expect(first_half[0].value).to eq('foo')
192
189
  expect(first_half[1].value).to eq("bar")
193
- should_be_and_list(first_half[2])
190
+ should_be_and_list(first_half[2])
194
191
  end
195
-
192
+
196
193
  should_be_list(list[1]) do |second_half|
197
194
  expect(second_half[0].value).to eq("three")
198
195
  expect(second_half[1].value).to eq("four")
199
- should_be_or_list second_half[2]
196
+ should_be_or_list second_half[2]
200
197
  end
201
198
  end
202
199
  end
203
-
200
+
204
201
  it "should build for a crazy complicated one" do
205
202
  should_be_list parse("mark +twain AND huck OR fun OR ((jim AND river) AND (red -dogs))") do |list|
206
203
  should_be_term list[0], "mark"
207
204
  should_be_and_list list[1] do |and_list|
208
-
209
205
  should_be_mandatory and_list[0] do |operand|
210
206
  should_be_term operand, "twain"
211
207
  end
212
-
208
+
213
209
  should_be_or_list and_list[1] do |or_list|
214
210
  should_be_term or_list[0], "huck"
215
211
  should_be_term or_list[1], "fun"
216
-
212
+
217
213
  should_be_and_list or_list[2] do |and_list|
218
214
  expect(and_list.length).to eq(2)
219
-
215
+
220
216
  should_be_and_list and_list[0]
221
-
217
+
222
218
  should_be_list and_list[1] do |terms|
223
219
  should_be_term terms[0], "red"
224
220
  should_be_excluded terms[1] do |operand|
@@ -226,13 +222,9 @@ describe "NestingParser" do
226
222
  end
227
223
  end
228
224
  end
229
-
230
225
  end
231
226
  end
232
227
  end
233
228
  end
234
-
235
229
  end
236
230
  end
237
-
238
-