boolean-expression 0.0.1.2 → 0.0.2

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