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,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