boolean-expression 0.0.1.2 → 0.0.2

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 (2) hide show
  1. data/lib/boolean/expression.rb +102 -69
  2. metadata +1 -1
@@ -22,92 +22,101 @@ unless defined?(Boolean)
22
22
  end
23
23
 
24
24
  class Boolean::Expression
25
- def self.parse (text)
26
- base = Group.new
27
- name = nil
28
- stack = [base]
29
- logic = nil
30
- string = false
31
- quoted = false
32
-
33
- text.to_s.chars.each_with_index {|char, index|
34
- begin
35
- if !string && char == ')' && stack.length == 1
36
- raise SyntaxError, 'closing an unopened parenthesis'
37
- end
25
+ class << self
26
+ def parse (text)
27
+ base = Group.new
28
+ name = nil
29
+ stack = [base]
30
+ logic = nil
31
+ string = false
32
+ quoted = false
33
+
34
+ text.to_s.chars.each_with_index {|char, index|
35
+ begin
36
+ if !string && char == ')' && stack.length == 1
37
+ raise SyntaxError, 'closing an unopened parenthesis'
38
+ end
38
39
 
39
- if !string && (char.match(/\s|\(|\)/) || (!logic && ['|', '&', '!'].member?(char)))
40
- if logic || (name && name.match(/^(and|or|not)$/i) && !quoted)
41
- stack.last << Logic.new(logic || name)
42
- logic = nil
43
- name = nil
44
- elsif name
45
- if !stack.last.last.nil? && !stack.last.last.is_a?(Logic)
46
- raise SyntaxError, 'you cannot put two names in a row'
40
+ if !string && (char.match(/\s|\(|\)/) || (!logic && ['|', '&', '!'].member?(char)))
41
+ if logic || (name && name.match(/^(and|or|not)$/i) && !quoted)
42
+ stack.last << Logic.new(logic || name)
43
+ logic = nil
44
+ name = nil
45
+ elsif name
46
+ stack.last << Name.new(name)
47
+ name = nil
48
+ quoted = false
47
49
  end
48
-
49
- stack.last << Name.new(name)
50
- name = nil
51
- quoted = false
52
50
  end
53
- end
54
51
 
55
- if name
56
- if char == '"'
57
- string = false
52
+ if name
53
+ if char == '"'
54
+ string = false
55
+ else
56
+ name << char
57
+ end
58
+ elsif logic
59
+ logic << char
58
60
  else
59
- name << char
60
- end
61
- elsif logic
62
- logic << char
63
- else
64
- if char == '"'
65
- string = true
66
- quoted = true
67
-
68
- next
69
- end
61
+ if char == '"'
62
+ string = true
63
+ quoted = true
70
64
 
71
- if string
72
- name = char unless name
73
- else
74
- case char
75
- when '(' then stack.push Group.new
76
- when ')' then stack[-2] << stack.pop
77
- when '|' then logic = '|'
78
- when '&' then logic = '&'
79
- when '!' then stack.last << Logic.new('!')
80
- else name = char if !char.match(/\s/)
65
+ next
66
+ end
67
+
68
+ if string
69
+ name = char unless name
70
+ else
71
+ case char
72
+ when '(' then stack.push Group.new
73
+ when ')' then stack[-2] << stack.pop
74
+ when '|' then logic = '|'
75
+ when '&' then logic = '&'
76
+ when '!' then stack.last << Logic.new('!')
77
+ else name = char if !char.match(/\s/)
78
+ end
81
79
  end
82
80
  end
81
+ rescue SyntaxError => e
82
+ raise "#{e.message} near `#{text[index - 4, 8]}` at character #{index}"
83
83
  end
84
- rescue SyntaxError => e
85
- raise "#{e.message} near `#{text[index - 4, 8]}` at character #{index}"
86
- end
87
- }
84
+ }
88
85
 
89
- raise SyntaxError, 'not all parenthesis are closed' if stack.length != 1
90
-
91
- raise SyntaxError, 'the expression cannot end with a logic operator' if logic
86
+ raise SyntaxError, 'not all parenthesis are closed' if stack.length != 1
87
+
88
+ raise SyntaxError, 'the expression cannot end with a logic operator' if logic
92
89
 
93
- if name
94
- if !stack.last.last.nil? && !stack.last.last.is_a?(Logic)
95
- raise SyntaxError, 'you cannot put two names in a row'
96
- end
90
+ base << Name.new(name) if name
97
91
 
98
- base << Name.new(name)
92
+ base = base.first if base.length == 1 && base.first.is_a?(Group)
93
+
94
+ _check(base)
95
+
96
+ new(base)
99
97
  end
98
+
99
+ alias [] parse
100
100
 
101
- base = base.first if base.length == 1 && base.first.is_a?(Group)
101
+ private
102
+ def _check (group)
103
+ group.each_with_index {|piece, index|
104
+ if piece.is_a?(Group)
105
+ _check(piece)
106
+ end
102
107
 
103
- new(base)
104
- end
108
+ next if index - 1 < 0
105
109
 
106
- def self.[] (*args)
107
- parse(*args)
108
- end
110
+ if piece.is_a?(Logic) && piece.type == :not && !group[index - 1].is_a?(Logic)
111
+ raise SyntaxError, "missing AND/OR before a NOT in: #{group}"
112
+ end
109
113
 
110
- attr_reader :base
114
+ if (piece.is_a?(Name) || piece.is_a?(Group)) && !group[index - 1].is_a?(Logic)
115
+ raise SyntaxError, "missing AND/OR in: #{group}"
116
+ end
117
+ }
118
+ end
119
+ end
111
120
 
112
121
  def initialize (base = Group.new)
113
122
  @base = base
@@ -121,10 +130,22 @@ class Boolean::Expression
121
130
 
122
131
  alias [] evaluate
123
132
 
133
+ def names
134
+ _names(@base).compact.uniq
135
+ end
136
+
124
137
  def to_s
125
138
  @base.inspect
126
139
  end
127
140
 
141
+ def to_group
142
+ @base
143
+ end
144
+
145
+ def to_a
146
+ @base.to_a
147
+ end
148
+
128
149
  private
129
150
  def _evaluate (group, pieces)
130
151
  return false if pieces.empty?
@@ -158,6 +179,18 @@ private
158
179
 
159
180
  values.first
160
181
  end
182
+
183
+ def _names (group, result = [])
184
+ group.each {|piece|
185
+ if piece.is_a?(Name)
186
+ result.push(piece)
187
+ elsif piece.is_a?(Group)
188
+ _names(piece, result)
189
+ end
190
+ }
191
+
192
+ result
193
+ end
161
194
  end
162
195
 
163
196
  require 'boolean/expression/name'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: boolean-expression
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1.2
4
+ version: 0.0.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors: