blacklight_advanced_search 6.0.2 → 6.1.0

Sign up to get free protection for your applications and to get access to all the features.
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,53 +1,30 @@
1
1
  module BlacklightAdvancedSearch::CatalogHelperOverride
2
-
3
-
4
-
5
- def remove_advanced_keyword_query(field, my_params = params)
6
- my_params = my_params.dup
7
- my_params.delete(field)
8
- return my_params
9
- end
10
-
11
- def remove_advanced_filter_group(field, my_params = params)
12
- if (my_params[:f_inclusive])
13
- my_params = my_params.dup
14
- my_params[:f_inclusive] = my_params[:f_inclusive].dup
15
- my_params[:f_inclusive].delete(field)
16
-
17
- if my_params[:f_inclusive].empty?
18
- my_params.delete :f_inclusive
19
- end
20
- end
21
- my_params
22
- end
23
-
24
2
  # Special display for facet limits that include adv search inclusive
25
3
  # or limits.
26
4
  def facet_partial_name(display_facet = nil)
27
- return "blacklight_advanced_search/facet_limit" if advanced_query && advanced_query.filters.keys.include?( display_facet.name )
28
- super
5
+ return "blacklight_advanced_search/facet_limit" if advanced_query && advanced_query.filters.keys.include?(display_facet.name)
6
+ super
29
7
  end
30
8
 
31
9
  def remove_advanced_facet_param(field, value, my_params = params)
32
- my_params = my_params.dup
33
- if (my_params[:f_inclusive] &&
10
+ my_params = Blacklight::SearchState.new(my_params, blacklight_config).to_h
11
+ if (my_params[:f_inclusive] &&
34
12
  my_params[:f_inclusive][field] &&
35
13
  my_params[:f_inclusive][field].include?(value))
36
-
14
+
37
15
  my_params[:f_inclusive] = my_params[:f_inclusive].dup
38
16
  my_params[:f_inclusive][field] = my_params[:f_inclusive][field].dup
39
17
  my_params[:f_inclusive][field].delete(value)
40
-
41
- my_params[:f_inclusive].delete(field) if my_params[:f_inclusive][field].length == 0
42
-
43
- my_params.delete(:f_inclusive) if my_params[:f_inclusive].length == 0
18
+
19
+ my_params[:f_inclusive].delete(field) if my_params[:f_inclusive][field].empty?
20
+
21
+ my_params.delete(:f_inclusive) if my_params[:f_inclusive].empty?
44
22
  end
45
23
 
46
- my_params.delete_if do |key, value|
24
+ my_params.delete_if do |key, _value|
47
25
  [:page, :id, :counter, :commit].include?(key)
48
26
  end
49
-
27
+
50
28
  my_params
51
29
  end
52
-
53
30
  end
@@ -12,7 +12,7 @@ module BlacklightAdvancedSearch::Controller
12
12
  helper_method :is_advanced_search?, :advanced_query
13
13
  end
14
14
 
15
- def is_advanced_search? req_params = params
15
+ def is_advanced_search?(req_params = params)
16
16
  (req_params[:search_field] == blacklight_config.advanced_search[:url_key]) ||
17
17
  req_params[:f_inclusive]
18
18
  end
@@ -1,13 +1,11 @@
1
1
  module BlacklightAdvancedSearch::FilterParser
2
2
  # Returns an array of solr :fq params. taking advanced search inclusive
3
- # facet value lists out of params.
3
+ # facet value lists out of params.
4
4
  def generate_solr_fq
5
- filter_queries = []
6
- filters.each do |solr_field, value_list|
7
- filter_queries << "#{solr_field}:(" +
8
- value_list.collect {|v| '"' + v.gsub('"', '\"') +'"' }.join(" OR ") +
9
- ")"
10
- end
11
- return filter_queries
5
+ filters.map do |solr_field, value_list|
6
+ "#{solr_field}:(" +
7
+ Array(value_list).collect { |v| '"' + v.gsub('"', '\"') + '"' }.join(" OR ") +
8
+ ")"
9
+ end
12
10
  end
13
- end
11
+ end
@@ -1,18 +1,15 @@
1
1
  require 'parsing_nesting/tree'
2
2
  module BlacklightAdvancedSearch::ParsingNestingParser
3
-
4
- def process_query(params,config)
5
- queries = []
6
- keyword_queries.each do |field,query|
7
- queries << ParsingNesting::Tree.parse(query, config.advanced_search[:query_parser]).to_query( local_param_hash(field, config) )
3
+ def process_query(_params, config)
4
+ queries = keyword_queries.map do |field, query|
5
+ ParsingNesting::Tree.parse(query, config.advanced_search[:query_parser]).to_query(local_param_hash(field, config))
8
6
  end
9
- queries.join( ' ' + keyword_op + ' ')
7
+ queries.join(" #{keyword_op} ")
10
8
  end
11
-
9
+
12
10
  def local_param_hash(key, config)
13
11
  field_def = config.search_fields[key]
14
12
 
15
13
  (field_def[:solr_parameters] || {}).merge(field_def[:solr_local_parameters] || {})
16
14
  end
17
-
18
15
  end
@@ -1,32 +1,30 @@
1
1
  # Returns a lambda that you can use with a before_filter in your
2
- # CatalogController to catch and redirect query params using the old
3
- # style, used prior to blacklight_advanced_search 5.0.
4
- #
5
- # This can be used to keep any old bookmarked URLs still working.
6
- #
7
- # before_filter BlacklightAdvancedSearch::RedirectLegacyParamsFilter, :only => :index
8
- #
9
- module BlacklightAdvancedSearch
10
- class RedirectLegacyParamsFilter
2
+ # CatalogController to catch and redirect query params using the old
3
+ # style, used prior to blacklight_advanced_search 5.0.
4
+ #
5
+ # This can be used to keep any old bookmarked URLs still working.
6
+ #
7
+ # before_filter BlacklightAdvancedSearch::RedirectLegacyParamsFilter, :only => :index
8
+ #
9
+ module BlacklightAdvancedSearch
10
+ class RedirectLegacyParamsFilter
11
+ def self.before(controller)
12
+ params = controller.send(:params)
11
13
 
12
- def self.before(controller)
13
- params = controller.send(:params)
14
+ if params[:f_inclusive] && params[:f_inclusive].respond_to?(:each_pair)
15
+ legacy_converted = false
14
16
 
15
- if params[:f_inclusive] && params[:f_inclusive].respond_to?(:each_pair)
16
- legacy_converted = false
17
-
18
- params[:f_inclusive].each_pair do |field, value|
19
- if value.kind_of? Hash
20
- # old style! convert!
21
- legacy_converted = true
22
- params[:f_inclusive][field] = value.keys
23
- end
24
- end
17
+ params[:f_inclusive].each_pair do |field, value|
18
+ next unless value.is_a? Hash
19
+ # old style! convert!
20
+ legacy_converted = true
21
+ params[:f_inclusive][field] = value.keys
22
+ end
25
23
 
26
- if legacy_converted
27
- controller.send(:redirect_to, params, :status => :moved_permanently)
28
- end
24
+ if legacy_converted
25
+ controller.send(:redirect_to, params, :status => :moved_permanently)
29
26
  end
30
27
  end
31
28
  end
32
- end
29
+ end
30
+ end
@@ -2,19 +2,18 @@
2
2
  # certain methods from RenderConstraintsHelper (newish in BL),
3
3
  # to effect constraints rendering and search history rendering,
4
4
  module BlacklightAdvancedSearch::RenderConstraintsOverride
5
-
6
5
  def query_has_constraints?(localized_params = params)
7
6
  if is_advanced_search? localized_params
8
7
  true
9
8
  else
10
- !(localized_params[:q].blank? and localized_params[:f].blank? and localized_params[:f_inclusive].blank?)
9
+ !(localized_params[:q].blank? && localized_params[:f].blank? && localized_params[:f_inclusive].blank?)
11
10
  end
12
11
  end
13
12
 
14
- #Over-ride of Blacklight method, provide advanced constraints if needed,
13
+ # Over-ride of Blacklight method, provide advanced constraints if needed,
15
14
  # otherwise call super.
16
15
  def render_constraints_query(my_params = params)
17
- if (advanced_query.nil? || advanced_query.keyword_queries.empty? )
16
+ if (advanced_query.nil? || advanced_query.keyword_queries.empty?)
18
17
  return super(my_params)
19
18
  else
20
19
  content = []
@@ -28,58 +27,56 @@ module BlacklightAdvancedSearch::RenderConstraintsOverride
28
27
  end
29
28
  if (advanced_query.keyword_op == "OR" &&
30
29
  advanced_query.keyword_queries.length > 1)
31
- content.unshift content_tag(:span, "Any of:", class:'operator')
30
+ content.unshift content_tag(:span, "Any of:", class: 'operator')
32
31
  content_tag :span, class: "inclusive_or appliedFilter well" do
33
32
  safe_join(content.flatten, "\n")
34
33
  end
35
34
  else
36
- safe_join(content.flatten, "\n")
35
+ safe_join(content.flatten, "\n")
37
36
  end
38
37
  end
39
38
  end
40
39
 
41
- #Over-ride of Blacklight method, provide advanced constraints if needed,
40
+ # Over-ride of Blacklight method, provide advanced constraints if needed,
42
41
  # otherwise call super.
43
42
  def render_constraints_filters(my_params = params)
44
43
  content = super(my_params)
45
44
 
46
- if (advanced_query)
45
+ if advanced_query
47
46
  advanced_query.filters.each_pair do |field, value_list|
48
47
  label = facet_field_label(field)
49
48
  content << render_constraint_element(label,
50
- safe_join(value_list, " <strong class='text-muted constraint-connector'>OR</strong> ".html_safe),
51
- :remove => search_action_path( remove_advanced_filter_group(field, my_params).except(:controller, :action) )
52
- )
49
+ safe_join(Array(value_list), " <strong class='text-muted constraint-connector'>OR</strong> ".html_safe),
50
+ :remove => search_action_path(remove_advanced_filter_group(field, my_params).except(:controller, :action))
51
+ )
53
52
  end
54
53
  end
55
54
 
56
- return content
55
+ content
57
56
  end
58
57
 
59
58
  # override of BL method, so our inclusive facet selections
60
59
  # are still recgonized for eg highlighting facet with selected
61
- # values.
60
+ # values.
62
61
  def facet_field_in_params?(field)
63
62
  return true if super
64
63
 
65
64
  # otherwise use our own logic.
66
- query = BlacklightAdvancedSearch::QueryParser.new(params, self.blacklight_config )
67
- if query.filters.keys.include?( field )
68
- return true
69
- end
65
+ query = BlacklightAdvancedSearch::QueryParser.new(params, self.blacklight_config)
66
+ return true if query.filters.keys.include?(field)
70
67
 
71
- return false
68
+ false
72
69
  end
73
70
 
74
71
  def render_search_to_s_filters(my_params)
75
72
  content = super(my_params)
76
73
 
77
- advanced_query = BlacklightAdvancedSearch::QueryParser.new(my_params, blacklight_config )
74
+ advanced_query = BlacklightAdvancedSearch::QueryParser.new(my_params, blacklight_config)
78
75
 
79
- if (advanced_query.filters.length > 0)
76
+ unless advanced_query.filters.empty?
80
77
  advanced_query.filters.each_pair do |field, values|
81
78
  # old-style, may still be in history
82
- values = values.keys if values.kind_of? Hash
79
+ values = values.keys if values.is_a? Hash
83
80
 
84
81
  label = facet_field_label(field)
85
82
 
@@ -89,27 +86,27 @@ module BlacklightAdvancedSearch::RenderConstraintsOverride
89
86
  )
90
87
  end
91
88
  end
92
- return content
89
+ content
93
90
  end
94
91
 
95
92
  def render_search_to_s_q(my_params)
96
93
  content = super(my_params)
97
94
 
98
- advanced_query = BlacklightAdvancedSearch::QueryParser.new(my_params, blacklight_config )
95
+ advanced_query = BlacklightAdvancedSearch::QueryParser.new(my_params, blacklight_config)
99
96
 
100
97
  if (advanced_query.keyword_queries.length > 1 &&
101
98
  advanced_query.keyword_op == "OR")
102
- # Need to do something to make the inclusive-or search clear
99
+ # Need to do something to make the inclusive-or search clear
103
100
 
104
- display_as = advanced_query.keyword_queries.collect do |field, query|
105
- h( search_field_def_for_key(field)[:label] + ": " + query )
106
- end.join(" ; ")
101
+ display_as = advanced_query.keyword_queries.collect do |field, query|
102
+ h(search_field_def_for_key(field)[:label] + ": " + query)
103
+ end.join(" ; ")
107
104
 
108
- content << render_search_to_s_element("Any of",
109
- display_as,
110
- :escape_value => false
111
- )
112
- elsif (advanced_query.keyword_queries.length > 0)
105
+ content << render_search_to_s_element("Any of",
106
+ display_as,
107
+ :escape_value => false
108
+ )
109
+ elsif !advanced_query.keyword_queries.empty?
113
110
  advanced_query.keyword_queries.each_pair do |field, query|
114
111
  label = search_field_def_for_key(field)[:label]
115
112
 
@@ -117,7 +114,23 @@ module BlacklightAdvancedSearch::RenderConstraintsOverride
117
114
  end
118
115
  end
119
116
 
120
- return content
117
+ content
118
+ end
119
+
120
+ def remove_advanced_keyword_query(field, my_params = params)
121
+ my_params = Blacklight::SearchState.new(my_params, blacklight_config).to_h
122
+ my_params.delete(field)
123
+ my_params
121
124
  end
122
125
 
126
+ def remove_advanced_filter_group(field, my_params = params)
127
+ if (my_params[:f_inclusive])
128
+ my_params = Blacklight::SearchState.new(my_params, blacklight_config).to_h
129
+ my_params[:f_inclusive] = my_params[:f_inclusive].dup
130
+ my_params[:f_inclusive].delete(field)
131
+
132
+ my_params.delete :f_inclusive if my_params[:f_inclusive].empty?
133
+ end
134
+ my_params
135
+ end
123
136
  end
@@ -7,4 +7,3 @@ module BlacklightAdvancedSearch
7
7
  VERSION = self.version
8
8
  end
9
9
  end
10
-
@@ -1,4 +1,4 @@
1
- # Copy BlacklightAdvancedSearch assets to public folder in current app.
1
+ # Copy BlacklightAdvancedSearch assets to public folder in current app.
2
2
  # If you want to do this on application startup, you can
3
3
  # add this next line to your one of your environment files --
4
4
  # generally you'd only want to do this in 'development', and can
@@ -6,9 +6,8 @@
6
6
  # require File.join(BlacklightAdvancedSearch.root, "lib", "generators", "blacklight", "assets_generator.rb")
7
7
  # BlacklightAdvancedSearch::AssetsGenerator.start(["--force", "--quiet"])
8
8
 
9
-
10
9
  # Need the requires here so we can call the generator from environment.rb
11
- # as suggested above.
10
+ # as suggested above.
12
11
  require 'rails/generators'
13
12
  require 'rails/generators/base'
14
13
  module BlacklightAdvancedSearch
@@ -26,12 +25,11 @@ module BlacklightAdvancedSearch
26
25
  original_css = File.binread(application_css_location)
27
26
  if original_css.include?("require 'blacklight_advanced_search'")
28
27
  say_status("skipped", "insert into app/assets/stylesheets/application.css", :yellow)
29
- else
28
+ else
30
29
  insert_into_file application_css_location, :before => "*/" do
31
30
  "\n *= require 'blacklight_advanced_search'\n\n"
32
31
  end
33
32
  end
34
-
35
33
  end
36
34
 
37
35
  def js_asset
@@ -41,7 +39,7 @@ module BlacklightAdvancedSearch
41
39
  say_status "skipped", "Can not find an application.js, did not insert our require", :red
42
40
  return
43
41
  end
44
-
42
+
45
43
  original_js = File.binread(application_js_location)
46
44
  if original_js.include?("require 'blacklight_advanced_search'")
47
45
  say_status("skipped", "insert into app/assets/javascripts/application.js", :yellow)
@@ -51,7 +49,5 @@ module BlacklightAdvancedSearch
51
49
  end
52
50
  end
53
51
  end
54
-
55
52
  end
56
53
  end
57
-
@@ -1,10 +1,8 @@
1
1
  require 'rails/generators'
2
2
 
3
3
  class BlacklightAdvancedSearchGenerator < Rails::Generators::Base
4
-
5
4
  def inject_asset_requires
6
5
  say "`rails g blacklight_advanced_search` is deprecated; use blacklight_advanced_search:install instead", :red
7
6
  generate "blacklight_advanced_search:install"
8
7
  end
9
-
10
8
  end
@@ -47,16 +47,20 @@ module BlacklightAdvancedSearch
47
47
  end
48
48
 
49
49
  def install_localized_search_form
50
- if options[:force] or yes?("Install local search form with advanced link? (y/N)", :green)
50
+ if options[:force] || yes?("Install local search form with advanced link? (y/N)", :green)
51
51
  # We're going to copy the search from from actual currently loaded
52
- # Blacklight into local app as custom local override -- but add our link at the end too.
52
+ # Blacklight into local app as custom local override -- but add our link at the end too.
53
53
  source_file = File.read(File.join(Blacklight.root, "app/views/catalog/_search_form.html.erb"))
54
54
 
55
- new_file_contents = source_file + "\n\n<%= link_to 'More options', blacklight_advanced_search_engine.advanced_search_path(params.except(:controller, :action)), class: 'advanced_search'%>"
55
+ new_file_contents = source_file + <<-EOF.strip_heredoc
56
+ \n\n
57
+ <div class="navbar-form">
58
+ <%= link_to 'More options', blacklight_advanced_search_engine.advanced_search_path(search_state.to_h), class: 'advanced_search btn btn-default'%>
59
+ </div>
60
+ EOF
56
61
 
57
- create_file("app/views/catalog/_search_form.html.erb", new_file_contents)
62
+ create_file("app/views/catalog/_search_form.html.erb", new_file_contents)
58
63
  end
59
64
  end
60
65
  end
61
-
62
66
  end
@@ -1,5 +1,4 @@
1
1
  class AdvancedController < BlacklightAdvancedSearch::AdvancedController
2
-
3
2
  blacklight_config.configure do |config|
4
3
  # name of Solr request handler, leave unset to use the same one your Blacklight
5
4
  # is ordinarily using (recommended if possible)
@@ -54,5 +53,4 @@ class AdvancedController < BlacklightAdvancedSearch::AdvancedController
54
53
  }
55
54
  end
56
55
  end
57
-
58
56
  end
@@ -1,78 +1,75 @@
1
1
  require 'rubygems'
2
2
  require 'parslet'
3
3
 
4
- # Parslet uses Object#tap, which is in ruby 1.8.7+, but not 1.8.6.
4
+ # Parslet uses Object#tap, which is in ruby 1.8.7+, but not 1.8.6.
5
5
  # But it's easy enough to implement in pure ruby, let's monkey patch
6
6
  # it in if it's not there, so we'll still work with 1.8.6
7
7
  unless Object.method_defined?(:tap)
8
8
  class Object
9
9
  def tap
10
10
  yield(self)
11
- return self
11
+ self
12
12
  end
13
13
  end
14
14
  end
15
15
  module ParsingNesting
16
16
  class Grammar < Parslet::Parser
17
17
  root :query
18
-
19
- # query is actually a list of expressions.
18
+
19
+ # query is actually a list of expressions.
20
20
  rule :query do
21
- (spacing? >> (expression | paren_unit ) >> spacing?).repeat
21
+ (spacing? >> (expression | paren_unit) >> spacing?).repeat
22
22
  end
23
-
23
+
24
24
  rule :paren_list do
25
25
  (str('(') >> query >> str(')')).as(:list)
26
26
  end
27
-
27
+
28
28
  rule :paren_unit do
29
- (str('(') >> spacing? >> (expression ) >> spacing? >> str(')')) |
29
+ (str('(') >> spacing? >> expression >> spacing? >> str(')')) |
30
30
  paren_list
31
31
  end
32
-
32
+
33
33
  # Note well: It was tricky to parse the thing we want where you can
34
34
  # have a flat list with boolean operators, but where 'OR' takes precedence.
35
35
  # eg "A AND B OR C AND C" or "A OR B AND C OR D". Tricky to parse at all,
36
36
  # tricky to make precedence work. Important things that seem to make it work:
37
37
  # and_list comes BEFORE or_list in :expression.
38
38
  # and_list's operand can be an or_list, but NOT vice versa
39
- # There are others, it was an iterative process with testing.
39
+ # There are others, it was an iterative process with testing.
40
40
  rule :expression do
41
- (and_list | or_list | unary_expression )
41
+ (and_list | or_list | unary_expression)
42
42
  end
43
-
43
+
44
44
  rule :and_list do
45
- ((or_list | unary_expression | paren_unit) >>
46
- (spacing >> str("AND") >> spacing >> (or_list | unary_expression | paren_unit)).repeat(1)).as(:and_list)
45
+ ((or_list | unary_expression | paren_unit) >>
46
+ (spacing >> str("AND") >> spacing >> (or_list | unary_expression | paren_unit)).repeat(1)).as(:and_list)
47
47
  end
48
-
48
+
49
49
  rule :or_list do
50
- ((unary_expression | paren_unit) >>
51
- (spacing >> str("OR") >> spacing >> (unary_expression | paren_unit)).repeat(1)).as(:or_list)
50
+ ((unary_expression | paren_unit) >>
51
+ (spacing >> str("OR") >> spacing >> (unary_expression | paren_unit)).repeat(1)).as(:or_list)
52
52
  end
53
-
53
+
54
54
  rule :unary_expression do
55
55
  (str('+') >> (phrase | token)).as(:mandatory) |
56
56
  (str('-') >> (phrase | token)).as(:excluded) |
57
57
  (str('NOT') >> spacing? >> (unary_expression | paren_unit)).as(:not_expression) |
58
58
  (phrase | token)
59
59
  end
60
-
60
+
61
61
  rule :token do
62
62
  match['^ ")('].repeat(1).as(:token)
63
63
  end
64
64
  rule :phrase do
65
- match('"') >> match['^"'].repeat(1).as(:phrase) >> match('"')
65
+ match('"') >> match['^"'].repeat(1).as(:phrase) >> match('"')
66
66
  end
67
-
68
-
67
+
69
68
  rule :spacing do
70
- match[' '].repeat(1)
69
+ match[' '].repeat(1)
71
70
  end
72
71
  rule :spacing? do
73
72
  spacing.maybe
74
73
  end
75
74
  end
76
-
77
-
78
75
  end