predicate 1.3.4 → 2.0.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e429a75b5eeee0831bc034adf4f541277eff98aa
4
- data.tar.gz: 7186388fb19923f92f5617a7c33e9e070111630f
3
+ metadata.gz: 95da7e03712cd1ef82ff2668c4411005c006e8b4
4
+ data.tar.gz: 1e65d370752b431a2a6da2d8aee641a37529c4ce
5
5
  SHA512:
6
- metadata.gz: b3e1045f4fca26cc8eb11786bf211617f128294a2dbef01843061f16afed69395ba06c69a19e1e8762c81c6881d9fea535586609fac496f0c55659cdae89d59b
7
- data.tar.gz: 5ff49f5827934a546e8df8b39e8dc95d8af354ccd82d0fef368d7bfa4e41ac3843ea95148e0305c84488103d4a9c6dec02826aff94039a4d8464503fa0256fc4
6
+ metadata.gz: 97451f6bf7310bc89fe7093c08a8ae33d2032d243b54f8db20457b12511d70645329581ffde5e440da076ee8dbc269ddea09e039ee616a364e55274eedb9e581
7
+ data.tar.gz: b2d8cbd6d1986176745fdda9db7c9e66621e48324f02163e3021c42bb122c95fe57e385c899c2513496a637763a97f7ed86afb3e374c6a71b0ad4773cade69fc
@@ -77,6 +77,10 @@ class Predicate
77
77
  _factor_predicate([:literal, literal])
78
78
  end
79
79
 
80
+ def match(left, right, options = nil)
81
+ _factor_predicate([:match, sexpr(left), sexpr(right)] + (options.nil? ? [] : [options]))
82
+ end
83
+
80
84
  def native(arg)
81
85
  _factor_predicate([:native, arg])
82
86
  end
@@ -31,4 +31,5 @@ require_relative 'nodes/lte'
31
31
  require_relative 'nodes/in'
32
32
  require_relative 'nodes/intersect'
33
33
  require_relative 'nodes/literal'
34
+ require_relative 'nodes/match'
34
35
  require_relative 'nodes/native'
@@ -14,6 +14,7 @@ rules:
14
14
  - gte
15
15
  - in
16
16
  - intersect
17
+ - match
17
18
  - native
18
19
  tautology:
19
20
  - [ true ]
@@ -45,6 +46,8 @@ rules:
45
46
  - [ varref, values ]
46
47
  intersect:
47
48
  - [ varref, values ]
49
+ match:
50
+ - [ term, term, options ]
48
51
  term:
49
52
  - varref
50
53
  - literal
@@ -57,5 +60,7 @@ rules:
57
60
  - "::Object"
58
61
  values:
59
62
  - "::Object"
63
+ options:
64
+ - "::Hash"
60
65
  name:
61
66
  !ruby/regexp /^[a-zA-Z0-9_]+[?!]?$/
@@ -81,20 +81,11 @@ class Predicate
81
81
  {}
82
82
  end
83
83
 
84
- def to_ruby_code(scope = 't')
85
- code = ToRubyCode.call(self, scope: scope)
86
- "->(t){ #{code} }"
87
- end
88
-
89
84
  def to_s(scope = nil)
90
85
  ToS.call(self, scope: scope)
91
86
  end
92
87
  alias :inspect :to_s
93
88
 
94
- def to_proc(scope = 't')
95
- Kernel.eval(to_ruby_code(scope))
96
- end
97
-
98
89
  def sexpr(arg)
99
90
  Factory.sexpr(arg)
100
91
  end
@@ -0,0 +1,54 @@
1
+ class Predicate
2
+ module Match
3
+ include Expr
4
+
5
+ DEFAULT_OPTIONS = {
6
+ case_sensitive: true
7
+ }
8
+
9
+ def priority
10
+ 80
11
+ end
12
+
13
+ def left
14
+ self[1]
15
+ end
16
+
17
+ def right
18
+ self[2]
19
+ end
20
+
21
+ def options
22
+ @options ||= DEFAULT_OPTIONS.merge(self[3] || {})
23
+ end
24
+
25
+ def case_sentitive?
26
+ options[:case_sensitive]
27
+ end
28
+
29
+ def free_variables
30
+ @free_variables ||= left.free_variables | right.free_variables
31
+ end
32
+
33
+ def dyadic_priority
34
+ 800
35
+ end
36
+
37
+ def evaluate(tuple)
38
+ l = left.evaluate(tuple)
39
+ r = right.evaluate(tuple)
40
+ if l.nil? or r.nil?
41
+ nil
42
+ elsif l.is_a?(Regexp)
43
+ l =~ r.to_s
44
+ elsif r.is_a?(Regexp)
45
+ r =~ l.to_s
46
+ elsif options[:case_sensitive]
47
+ l.to_s.include?(r.to_s)
48
+ else
49
+ l.to_s.downcase.include?(r.to_s.downcase)
50
+ end
51
+ end
52
+
53
+ end
54
+ end
@@ -24,18 +24,6 @@ class Predicate
24
24
  { nil => self }
25
25
  end
26
26
 
27
- def to_ruby_code(scope = 't')
28
- if proc.respond_to?(:source_code)
29
- code = proc.source_code
30
- return code if code
31
- end
32
- raise NotSupportedError
33
- end
34
-
35
- def to_proc(scope = 't')
36
- proc
37
- end
38
-
39
27
  def evaluate(tuple)
40
28
  proc.call(tuple)
41
29
  end
@@ -61,6 +61,10 @@ class Predicate
61
61
  to_literal(sexpr.last)
62
62
  end
63
63
 
64
+ def on_match(sexpr)
65
+ "#{apply(sexpr.left)} =~ #{apply(sexpr.right)}"
66
+ end
67
+
64
68
  def on_native(sexpr)
65
69
  sexpr.last.inspect
66
70
  end
@@ -1,4 +1,3 @@
1
1
  require_relative "processors/to_s"
2
- require_relative "processors/to_ruby_code"
3
2
  require_relative "processors/renamer"
4
3
  require_relative "processors/qualifier"
@@ -1,72 +1,85 @@
1
1
  class Predicate
2
2
  class ToSequel < Sexpr::Processor
3
+ module Methods
4
+ def on_identifier(sexpr)
5
+ ::Sequel.identifier(sexpr.last)
6
+ end
3
7
 
4
- def on_identifier(sexpr)
5
- ::Sequel.identifier(sexpr.last)
6
- end
8
+ def on_qualified_identifier(sexpr)
9
+ ::Sequel.identifier(sexpr.name).qualify(sexpr.qualifier)
10
+ end
7
11
 
8
- def on_qualified_identifier(sexpr)
9
- ::Sequel.identifier(sexpr.name).qualify(sexpr.qualifier)
10
- end
12
+ def on_literal(sexpr)
13
+ sexpr.last.nil? ? nil : ::Sequel.expr(sexpr.last)
14
+ end
11
15
 
12
- def on_literal(sexpr)
13
- sexpr.last.nil? ? nil : ::Sequel.expr(sexpr.last)
14
- end
16
+ ###
15
17
 
16
- ###
18
+ def on_tautology(sexpr)
19
+ ::Sequel::SQL::BooleanConstant.new(true)
20
+ end
17
21
 
18
- def on_tautology(sexpr)
19
- ::Sequel::SQL::BooleanConstant.new(true)
20
- end
22
+ def on_contradiction(sexpr)
23
+ ::Sequel::SQL::BooleanConstant.new(false)
24
+ end
21
25
 
22
- def on_contradiction(sexpr)
23
- ::Sequel::SQL::BooleanConstant.new(false)
24
- end
26
+ def on_eq(sexpr)
27
+ left, right = apply(sexpr.left), apply(sexpr.right)
28
+ ::Sequel.expr(left => right)
29
+ end
25
30
 
26
- def on_eq(sexpr)
27
- left, right = apply(sexpr.left), apply(sexpr.right)
28
- ::Sequel.expr(left => right)
29
- end
31
+ def on_neq(sexpr)
32
+ left, right = apply(sexpr.left), apply(sexpr.right)
33
+ ~::Sequel.expr(left => right)
34
+ end
30
35
 
31
- def on_neq(sexpr)
32
- left, right = apply(sexpr.left), apply(sexpr.right)
33
- ~::Sequel.expr(left => right)
34
- end
36
+ def on_dyadic_comp(sexpr)
37
+ left, right = apply(sexpr.left), apply(sexpr.right)
38
+ left.send(sexpr.operator_symbol, right)
39
+ end
40
+ alias :on_lt :on_dyadic_comp
41
+ alias :on_lte :on_dyadic_comp
42
+ alias :on_gt :on_dyadic_comp
43
+ alias :on_gte :on_dyadic_comp
35
44
 
36
- def on_dyadic_comp(sexpr)
37
- left, right = apply(sexpr.left), apply(sexpr.right)
38
- left.send(sexpr.operator_symbol, right)
39
- end
40
- alias :on_lt :on_dyadic_comp
41
- alias :on_lte :on_dyadic_comp
42
- alias :on_gt :on_dyadic_comp
43
- alias :on_gte :on_dyadic_comp
45
+ def on_in(sexpr)
46
+ left, right = apply(sexpr.identifier), sexpr.last
47
+ right = [right] if !right.is_a?(Array) && right.respond_to?(:sql_literal)
48
+ ::Sequel.expr(left => right)
49
+ end
44
50
 
45
- def on_in(sexpr)
46
- left, right = apply(sexpr.identifier), sexpr.last
47
- right = [right] if !right.is_a?(Array) && right.respond_to?(:sql_literal)
48
- ::Sequel.expr(left => right)
49
- end
51
+ def on_not(sexpr)
52
+ ~apply(sexpr.last)
53
+ end
50
54
 
51
- def on_not(sexpr)
52
- ~apply(sexpr.last)
53
- end
55
+ def on_and(sexpr)
56
+ body = sexpr.sexpr_body
57
+ body[1..-1].inject(apply(body.first)){|f,t| f & apply(t) }
58
+ end
54
59
 
55
- def on_and(sexpr)
56
- body = sexpr.sexpr_body
57
- body[1..-1].inject(apply(body.first)){|f,t| f & apply(t) }
58
- end
60
+ def on_or(sexpr)
61
+ body = sexpr.sexpr_body
62
+ body[1..-1].inject(apply(body.first)){|f,t| f | apply(t) }
63
+ end
59
64
 
60
- def on_or(sexpr)
61
- body = sexpr.sexpr_body
62
- body[1..-1].inject(apply(body.first)){|f,t| f | apply(t) }
63
- end
65
+ def on_match(sexpr)
66
+ left, right = sexpr.left, sexpr.right
67
+ left = [ left.first, "%#{left.last}%" ] if left.first == :literal && !left.last.is_a?(Regexp)
68
+ right = [ right.first, "%#{right.last}%" ] if right.first == :literal && !right.last.is_a?(Regexp)
69
+ left, right = apply(left), apply(right)
70
+ if sexpr.case_sentitive?
71
+ left.like(right)
72
+ else
73
+ left.ilike(right)
74
+ end
75
+ end
64
76
 
65
- def on_unsupported(sexpr)
66
- raise NotSupportedError
77
+ def on_unsupported(sexpr)
78
+ raise NotSupportedError
79
+ end
80
+ alias :on_native :on_unsupported
81
+ alias :on_intersect :on_unsupported
67
82
  end
68
- alias :on_native :on_unsupported
69
- alias :on_intersect :on_unsupported
70
-
83
+ include Methods
71
84
  end # class ToSequel
72
85
  end # class Predicate
@@ -1,8 +1,8 @@
1
1
  class Predicate
2
2
  module Version
3
- MAJOR = 1
4
- MINOR = 3
5
- TINY = 4
3
+ MAJOR = 2
4
+ MINOR = 0
5
+ TINY = 0
6
6
  end
7
7
  VERSION = "#{Version::MAJOR}.#{Version::MINOR}.#{Version::TINY}"
8
8
  end
data/lib/predicate.rb CHANGED
@@ -122,16 +122,8 @@ class Predicate
122
122
  expr.hash
123
123
  end
124
124
 
125
- def to_ruby_code(scope = "t")
126
- expr.to_ruby_code(scope)
127
- end
128
-
129
125
  def to_s(scope = nil)
130
126
  expr.to_s(scope)
131
127
  end
132
128
 
133
- def to_proc
134
- @proc ||= expr.to_proc("t")
135
- end
136
-
137
129
  end # class Predicate
@@ -0,0 +1,27 @@
1
+ require_relative 'shared/a_predicate_ast_node'
2
+ class Predicate
3
+ describe Factory, 'match' do
4
+ include Factory
5
+
6
+ context 'without options' do
7
+ subject{ match(:name, "London") }
8
+
9
+ it_should_behave_like "a predicate AST node"
10
+
11
+ it{ should be_a(Match) }
12
+
13
+ it{ should eql([:match, [:identifier, :name], [:literal, "London"]]) }
14
+ end
15
+
16
+ context 'with options' do
17
+ subject{ match(:name, "London", case_sensitive: false) }
18
+
19
+ it_should_behave_like "a predicate AST node"
20
+
21
+ it{ should be_a(Match) }
22
+
23
+ it{ should eql([:match, [:identifier, :name], [:literal, "London"], {case_sensitive: false}]) }
24
+ end
25
+
26
+ end
27
+ end
@@ -78,6 +78,18 @@ class Predicate
78
78
  end
79
79
  end
80
80
 
81
+ context "match" do
82
+ subject{ Grammar[:match] }
83
+
84
+ it 'matches valid ASTs' do
85
+ subject.should be_match([:match, [:identifier, :name], [:literal, "London"], {}])
86
+ subject.should be_match([:match, [:identifier, :name], [:literal, /London/], {}])
87
+ end
88
+ it 'does not match invalid ASTs' do
89
+ subject.should_not be_match([:native, 12])
90
+ end
91
+ end
92
+
81
93
  context "native" do
82
94
  subject{ Grammar[:native] }
83
95
 
@@ -17,10 +17,6 @@ class Predicate
17
17
  expect(subject).to be_a(And)
18
18
  expect(subject.size).to eql(4)
19
19
  end
20
-
21
- it 'is as expected' do
22
- expect(subject.to_ruby_code).to eql("->(t){ (t[:x] == 2) && (t[:y] == 3) && (t[:z] == 4) }")
23
- end
24
20
  end
25
21
 
26
22
  context 'with another and' do
@@ -32,10 +28,6 @@ class Predicate
32
28
  expect(subject).to be_a(And)
33
29
  expect(subject.size).to eql(5)
34
30
  end
35
-
36
- it 'is as expected' do
37
- expect(subject.to_ruby_code).to eql("->(t){ (t[:x] == 2) && (t[:y] == 3) && (t[:w] == 5) && (t[:z] == 4) }")
38
- end
39
31
  end
40
32
 
41
33
  end
@@ -53,5 +53,23 @@ class Predicate
53
53
  it{ should eq([ p.tautology, pred ]) }
54
54
  end
55
55
 
56
+ context "on match (included)" do
57
+ let(:pred){ p.match(:x, "London") }
58
+
59
+ it{ should eq([ pred, p.tautology ]) }
60
+ end
61
+
62
+ context "on match (excluded)" do
63
+ let(:pred){ p.match(:y, "London") }
64
+
65
+ it{ should eq([ p.tautology, pred ]) }
66
+ end
67
+
68
+ context "on match (included on right)" do
69
+ let(:pred){ p.match(:y, :x) }
70
+
71
+ it{ should eq([ pred, p.tautology ]) }
72
+ end
73
+
56
74
  end
57
75
  end
@@ -35,5 +35,17 @@ class Predicate
35
35
  it{ should eq({ x: pred }) }
36
36
  end
37
37
 
38
+ context "on match" do
39
+ let(:pred){ p.match(:x, "London") }
40
+
41
+ it{ should eq({ x: pred }) }
42
+ end
43
+
44
+ context "on match with two identifiers" do
45
+ let(:pred){ p.match(:x, :y) }
46
+
47
+ it{ should eq({ nil => pred }) }
48
+ end
49
+
38
50
  end
39
51
  end
@@ -22,14 +22,6 @@ class Predicate
22
22
  it{ should be(left) }
23
23
  end
24
24
 
25
- context 'with another predicate' do
26
- let(:right){ Predicate.coerce(y: 3) }
27
-
28
- it 'should be a expected' do
29
- subject.to_ruby_code.should eq("->(t){ (t[:x] == 2) && (t[:y] == 3) }")
30
- end
31
- end
32
-
33
25
  context 'with tautology' do
34
26
  let(:right){ Predicate.tautology }
35
27
 
@@ -22,13 +22,5 @@ class Predicate
22
22
  it{ should be(left) }
23
23
  end
24
24
 
25
- context 'with another predicate' do
26
- let(:right){ Predicate.coerce(y: 3) }
27
-
28
- it 'should be a expected' do
29
- subject.to_ruby_code.should eq("->(t){ (t[:x] == 2) || (t[:y] == 3) }")
30
- end
31
- end
32
-
33
25
  end
34
26
  end
@@ -40,7 +40,6 @@ class Predicate
40
40
 
41
41
  specify{
42
42
  subject.expr.should be_a(Native)
43
- subject.to_proc.should be(arg)
44
43
  }
45
44
  end
46
45
 
@@ -101,6 +101,12 @@ class Predicate
101
101
  it{ should eq({}) }
102
102
  end
103
103
 
104
+ context "on match" do
105
+ let(:pred){ p.match(:x, "London") }
106
+
107
+ it{ should eq({}) }
108
+ end
109
+
104
110
  context "on native" do
105
111
  let(:pred){ p.native(->(t){}) }
106
112
 
@@ -98,5 +98,123 @@ class Predicate
98
98
  end
99
99
  end
100
100
 
101
+ context 'on a match against a string' do
102
+ let(:predicate){
103
+ Predicate.match(:x, "12")
104
+ }
105
+
106
+ it "matches when expected" do
107
+ [
108
+ { x: 12 },
109
+ { x: "12" },
110
+ { x: "Once upon a time, in 12" },
111
+ { x: "Once upon a time, in 12!" },
112
+ ].each do |tuple|
113
+ expect(predicate.evaluate(tuple)).to be_truthy
114
+ end
115
+ end
116
+
117
+ it "does not match when not expected" do
118
+ [
119
+ { x: 17 },
120
+ { x: nil },
121
+ { x: "Londan" },
122
+ { x: "london" },
123
+ { x: "Once upon a time, in Londan" },
124
+ { x: "Once upon a time, in Londan!" },
125
+ { },
126
+ { y: "London" }
127
+ ].each do |tuple|
128
+ expect(predicate.evaluate(tuple)).to be_falsy
129
+ end
130
+ end
131
+ end
132
+
133
+ context 'on a match against a string, case insensitive' do
134
+ let(:predicate){
135
+ Predicate.match(:x, "London", case_sensitive: false)
136
+ }
137
+
138
+ it "matches when expected" do
139
+ [
140
+ { x: "London" },
141
+ { x: "london" },
142
+ { x: "Once upon a time, in London" },
143
+ { x: "Once upon a time, in London!" },
144
+ { x: "Once upon a time, in london!" },
145
+ ].each do |tuple|
146
+ expect(predicate.evaluate(tuple)).to be_truthy
147
+ end
148
+ end
149
+
150
+ it "does not match when not expected" do
151
+ [
152
+ { x: "Londan" },
153
+ { x: "Once upon a time, in Londan" },
154
+ { x: "Once upon a time, in Londan!" },
155
+ { },
156
+ { y: "London" }
157
+ ].each do |tuple|
158
+ expect(predicate.evaluate(tuple)).to be_falsy
159
+ end
160
+ end
161
+ end
162
+
163
+ context 'on a match against a regexp' do
164
+ let(:predicate){
165
+ Predicate.match(:x, /London/i)
166
+ }
167
+
168
+ it "matches when expected" do
169
+ [
170
+ { x: "London" },
171
+ { x: "london" },
172
+ { x: "Once upon a time, in London" },
173
+ { x: "Once upon a time, in London!" },
174
+ { x: "Once upon a time, in london!" },
175
+ ].each do |tuple|
176
+ expect(predicate.evaluate(tuple)).to be_truthy
177
+ end
178
+ end
179
+
180
+ it "does not match when not expected" do
181
+ [
182
+ { x: 17 },
183
+ { x: "Londan" },
184
+ { x: "Once upon a time, in Londan" },
185
+ { x: "Once upon a time, in Londan!" },
186
+ { },
187
+ { y: "London" }
188
+ ].each do |tuple|
189
+ expect(predicate.evaluate(tuple)).to be_falsy
190
+ end
191
+ end
192
+ end
193
+
194
+ context 'on a match against a another attribute' do
195
+ let(:predicate){
196
+ Predicate.match(:x, :y)
197
+ }
198
+
199
+ it "matches when expected" do
200
+ [
201
+ { x: "London", y: "London" },
202
+ { x: "Once upon a time in London", y: "London" },
203
+ ].each do |tuple|
204
+ expect(predicate.evaluate(tuple)).to be_truthy
205
+ end
206
+ end
207
+
208
+ it "does not match when not expected" do
209
+ [
210
+ { x: 17 },
211
+ { x: "Londan", y: "London" },
212
+ { x: "London", y: "Once upon a time in London" },
213
+ ].each do |tuple|
214
+ expect(predicate.evaluate(tuple)).to be_falsy
215
+ end
216
+ end
217
+ end
218
+
101
219
  end
102
220
  end
@@ -140,6 +140,39 @@ class Predicate
140
140
  end
141
141
  end
142
142
 
143
+ context 'match' do
144
+ let(:predicate) { Predicate.match(left, right, options) }
145
+ let(:options){ nil }
146
+
147
+ context '(attr, String)' do
148
+ let(:left){ :x }
149
+ let(:right){ "London" }
150
+
151
+ it 'works as expected' do
152
+ expect(subject).to eql("SELECT * FROM `items` WHERE (`x` LIKE '%London%' ESCAPE '\\')")
153
+ end
154
+ end
155
+
156
+ context '(attr, String, case_sensitive: false)' do
157
+ let(:left){ :x }
158
+ let(:right){ "London" }
159
+ let(:options){ { case_sensitive: false } }
160
+
161
+ it 'works as expected' do
162
+ expect(subject).to eql("SELECT * FROM `items` WHERE (UPPER(`x`) LIKE UPPER('%London%') ESCAPE '\\')")
163
+ end
164
+ end
165
+
166
+ context '(attr, Regexp)' do
167
+ let(:left){ :x }
168
+ let(:right){ /London/i }
169
+
170
+ pending 'works as expected' do
171
+ expect(subject).to eql("SELECT * FROM `items` WHERE (`x` LIKE '%London%' ESCAPE '\\')")
172
+ end
173
+ end
174
+ end
175
+
143
176
  context 'native' do
144
177
  let(:predicate) { Predicate.native(->(t){ false }) }
145
178
 
@@ -6,11 +6,6 @@ shared_examples_for "a predicate" do
6
6
  let(:x){ 12 }
7
7
  let(:y){ 13 }
8
8
 
9
- it 'provides a proc for easy evaluation' do
10
- got = subject.to_proc.call(w: w, x: x, y: y)
11
- [ TrueClass, FalseClass ].should include(got.class)
12
- end
13
-
14
9
  it 'can be negated easily' do
15
10
  (!subject).should be_a(Predicate)
16
11
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: predicate
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.4
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bernard Lambeau
@@ -107,6 +107,7 @@ files:
107
107
  - lib/predicate/nodes/literal.rb
108
108
  - lib/predicate/nodes/lt.rb
109
109
  - lib/predicate/nodes/lte.rb
110
+ - lib/predicate/nodes/match.rb
110
111
  - lib/predicate/nodes/nadic_bool.rb
111
112
  - lib/predicate/nodes/native.rb
112
113
  - lib/predicate/nodes/neq.rb
@@ -117,13 +118,10 @@ files:
117
118
  - lib/predicate/processors.rb
118
119
  - lib/predicate/processors/qualifier.rb
119
120
  - lib/predicate/processors/renamer.rb
120
- - lib/predicate/processors/to_ruby_code.rb
121
121
  - lib/predicate/processors/to_s.rb
122
122
  - lib/predicate/sequel.rb
123
123
  - lib/predicate/sequel/to_sequel.rb
124
124
  - lib/predicate/version.rb
125
- - spec/expr/test_to_proc.rb
126
- - spec/expr/test_to_ruby_code.rb
127
125
  - spec/factory/shared/a_comparison_factory_method.rb
128
126
  - spec/factory/shared/a_predicate_ast_node.rb
129
127
  - spec/factory/test_and.rb
@@ -141,6 +139,7 @@ files:
141
139
  - spec/factory/test_literal.rb
142
140
  - spec/factory/test_lt.rb
143
141
  - spec/factory/test_lte.rb
142
+ - spec/factory/test_match.rb
144
143
  - spec/factory/test_native.rb
145
144
  - spec/factory/test_neq.rb
146
145
  - spec/factory/test_not.rb
@@ -174,14 +173,11 @@ files:
174
173
  - spec/predicate/test_constants.rb
175
174
  - spec/predicate/test_contradiction.rb
176
175
  - spec/predicate/test_evaluate.rb
177
- - spec/predicate/test_factory_methods.rb
178
176
  - spec/predicate/test_free_variables.rb
179
177
  - spec/predicate/test_hash_and_equal.rb
180
178
  - spec/predicate/test_qualify.rb
181
179
  - spec/predicate/test_rename.rb
182
180
  - spec/predicate/test_tautology.rb
183
- - spec/predicate/test_to_proc.rb
184
- - spec/predicate/test_to_ruby_code.rb
185
181
  - spec/sequel/test_to_sequel.rb
186
182
  - spec/spec_helper.rb
187
183
  - spec/test_predicate.rb
@@ -1,76 +0,0 @@
1
- class Predicate
2
- class ToRubyCode < Sexpr::Processor
3
-
4
- def on_tautology(sexpr)
5
- "true"
6
- end
7
-
8
- def on_contradiction(sexpr)
9
- "false"
10
- end
11
-
12
- def on_qualified_identifier(sexpr)
13
- "#{sexpr.qualifier}[:#{sexpr.name}]"
14
- end
15
-
16
- def on_identifier(sexpr)
17
- if s = options[:scope]
18
- "#{s}[:#{sexpr.last.to_s}]"
19
- else
20
- sexpr.last.to_s
21
- end
22
- end
23
-
24
- def on_not(sexpr)
25
- "#{sexpr.operator_symbol}" << apply(sexpr.last, sexpr)
26
- end
27
-
28
- def on_nadic_bool(sexpr)
29
- sexpr.sexpr_body.map{|term|
30
- apply(term, sexpr)
31
- }.join(" #{sexpr.operator_symbol} ")
32
- end
33
- alias :on_and :on_nadic_bool
34
- alias :on_or :on_nadic_bool
35
-
36
- def on_dyadic(sexpr)
37
- sexpr.sexpr_body.map{|term|
38
- apply(term, sexpr)
39
- }.join(" #{sexpr.operator_symbol} ")
40
- end
41
- alias :on_eq :on_dyadic
42
- alias :on_neq :on_dyadic
43
- alias :on_lt :on_dyadic
44
- alias :on_lte :on_dyadic
45
- alias :on_gt :on_dyadic
46
- alias :on_gte :on_dyadic
47
-
48
- def on_in(sexpr)
49
- "#{to_ruby_literal(sexpr.values)}.include?(#{apply(sexpr.identifier)})"
50
- end
51
-
52
- def on_intersect(sexpr)
53
- t_x = apply(sexpr.identifier)
54
- "!#{t_x}.nil? && !(#{t_x} & #{to_ruby_literal(sexpr.values)}).empty?"
55
- end
56
-
57
- def on_literal(sexpr)
58
- to_ruby_literal(sexpr.last)
59
- end
60
-
61
- protected
62
-
63
- def to_ruby_literal(x)
64
- x.inspect
65
- end
66
-
67
- def apply(sexpr, parent = nil)
68
- code = super(sexpr)
69
- if parent && (parent.priority >= sexpr.priority)
70
- code = "(" << code << ")"
71
- end
72
- code
73
- end
74
-
75
- end
76
- end
@@ -1,16 +0,0 @@
1
- require 'spec_helper'
2
- class Predicate
3
- describe Expr, "to_proc" do
4
-
5
- let(:expr){ Factory.lte(:x, 2) }
6
-
7
- subject{ expr.to_proc }
8
-
9
- it{ should be_a(Proc) }
10
-
11
- it 'has arity 1' do
12
- subject.arity.should eq(1)
13
- end
14
-
15
- end
16
- end
@@ -1,152 +0,0 @@
1
- require 'spec_helper'
2
- class Predicate
3
- describe Expr, "to_ruby_code" do
4
-
5
- let(:f){ Factory }
6
-
7
- subject{ expr.to_ruby_code }
8
-
9
- after do
10
- unless expr.is_a?(Native)
11
- lambda{
12
- eval(subject)
13
- }.should_not raise_error
14
- end
15
- end
16
-
17
- context 'tautology' do
18
- let(:expr){ f.tautology }
19
-
20
- it{ should eq("->(t){ true }") }
21
- end
22
-
23
- context 'contradiction' do
24
- let(:expr){ f.contradiction }
25
-
26
- it{ should eq("->(t){ false }") }
27
- end
28
-
29
- describe "identifier" do
30
- let(:expr){ f.identifier(:name) }
31
-
32
- it{ should eq("->(t){ t[:name] }") }
33
- end
34
-
35
- describe "and" do
36
- let(:expr){ f.and(f.contradiction, f.contradiction) }
37
-
38
- it{ should eq("->(t){ false && false }") }
39
- end
40
-
41
- describe "or" do
42
- let(:expr){ f.or(f.contradiction, f.contradiction) }
43
-
44
- it{ should eq("->(t){ false || false }") }
45
- end
46
-
47
- describe "not" do
48
- let(:expr){ f.not(f.contradiction) }
49
-
50
- it{ should eq("->(t){ !false }") }
51
- end
52
-
53
- describe "comp" do
54
- let(:expr){ f.comp(:lt, {:x => 2}) }
55
-
56
- it{ should eq("->(t){ t[:x] < 2 }") }
57
- end
58
-
59
- describe "eq" do
60
- let(:expr){ f.eq(:x, 2) }
61
-
62
- it{ should eq("->(t){ t[:x] == 2 }") }
63
- end
64
-
65
- describe "eq (parentheses required)" do
66
- let(:expr){ f.eq(f.eq(:y, 2), true) }
67
-
68
- it{ should eq("->(t){ (t[:y] == 2) == true }") }
69
- end
70
-
71
- describe "comp (multiple)" do
72
- let(:expr){ f.comp(:eq, :x => 2, :y => 3) }
73
-
74
- it{ should eq("->(t){ (t[:x] == 2) && (t[:y] == 3) }") }
75
- end
76
-
77
- describe "in" do
78
- let(:expr){ f.in(:x, [2, 3]) }
79
-
80
- it{ should eq("->(t){ [2, 3].include?(t[:x]) }") }
81
- end
82
-
83
- describe "neq" do
84
- let(:expr){ f.neq(:x, 2) }
85
-
86
- it{ should eq("->(t){ t[:x] != 2 }") }
87
- end
88
-
89
- describe "gt" do
90
- let(:expr){ f.gt(:x, 2) }
91
-
92
- it{ should eq("->(t){ t[:x] > 2 }") }
93
- end
94
-
95
- describe "gte" do
96
- let(:expr){ f.gte(:x, 2) }
97
-
98
- it{ should eq("->(t){ t[:x] >= 2 }") }
99
- end
100
-
101
- describe "lt" do
102
- let(:expr){ f.lt(:x, 2) }
103
-
104
- it{ should eq("->(t){ t[:x] < 2 }") }
105
- end
106
-
107
- describe "lte" do
108
- let(:expr){ f.lte(:x, 2) }
109
-
110
- it{ should eq("->(t){ t[:x] <= 2 }") }
111
- end
112
-
113
- describe "literal" do
114
- let(:expr){ f.literal(12) }
115
-
116
- it{ should eq("->(t){ 12 }") }
117
- end
118
-
119
- describe "native" do
120
- let(:expr){ f.native(lambda{}) }
121
-
122
- specify{
123
- lambda{ subject }.should raise_error(NotSupportedError)
124
- }
125
- end
126
-
127
- describe "conjunction of two eqs" do
128
- let(:expr){
129
- f.and(f.eq(:x, 2), f.eq(:y, 3))
130
- }
131
-
132
- it{ should eq("->(t){ (t[:x] == 2) && (t[:y] == 3) }") }
133
- end
134
-
135
- describe "conjunction of two comps" do
136
- let(:expr){
137
- f.and(f.comp(:eq, :x => 2), f.comp(:eq, :y => 3))
138
- }
139
-
140
- it{ should eq("->(t){ (t[:x] == 2) && (t[:y] == 3) }") }
141
- end
142
-
143
- describe "or and and" do
144
- let(:expr){
145
- f.and(f.eq(:x, 2), f.or(true, false))
146
- }
147
-
148
- it{ should eq("->(t){ (t[:x] == 2) && (true || false) }") }
149
- end
150
-
151
- end
152
- end
@@ -1,83 +0,0 @@
1
- require 'spec_helper'
2
- class Predicate
3
- describe Predicate, "factory methods" do
4
-
5
- before do
6
- subject.should be_a(Predicate)
7
- subject.expr.should be_a(Expr)
8
- end
9
-
10
- context "tautology" do
11
- subject{ Predicate.tautology }
12
-
13
- specify{ subject.to_ruby_code.should eq("->(t){ true }") }
14
- end
15
-
16
- context "contradiction" do
17
- subject{ Predicate.contradiction }
18
-
19
- specify{ subject.to_ruby_code.should eq("->(t){ false }") }
20
- end
21
-
22
- context "identifier" do
23
- subject{ Predicate.identifier(:x) }
24
-
25
- specify{ subject.to_ruby_code.should eq("->(t){ t[:x] }") }
26
- end
27
-
28
- context "eq" do
29
- subject{ Predicate.eq(:x, 2) }
30
-
31
- specify{ subject.to_ruby_code.should eq("->(t){ t[:x] == 2 }") }
32
- end
33
-
34
- context "neq" do
35
- subject{ Predicate.neq(:x, 2) }
36
-
37
- specify{ subject.to_ruby_code.should eq("->(t){ t[:x] != 2 }") }
38
- end
39
-
40
- context "lt" do
41
- subject{ Predicate.lt(:x, 2) }
42
-
43
- specify{ subject.to_ruby_code.should eq("->(t){ t[:x] < 2 }") }
44
- end
45
-
46
- context "lte" do
47
- subject{ Predicate.lte(:x, 2) }
48
-
49
- specify{ subject.to_ruby_code.should eq("->(t){ t[:x] <= 2 }") }
50
- end
51
-
52
- context "gt" do
53
- subject{ Predicate.gt(:x, 2) }
54
-
55
- specify{ subject.to_ruby_code.should eq("->(t){ t[:x] > 2 }") }
56
- end
57
-
58
- context "gte" do
59
- subject{ Predicate.gte(:x, 2) }
60
-
61
- specify{ subject.to_ruby_code.should eq("->(t){ t[:x] >= 2 }") }
62
- end
63
-
64
- context "literal" do
65
- subject{ Predicate.literal(2) }
66
-
67
- specify{ subject.to_ruby_code.should eq("->(t){ 2 }") }
68
- end
69
-
70
- context "native" do
71
- subject{ Predicate.native(lambda{}) }
72
-
73
- specify{ subject.expr.should be_a(Native) }
74
- end
75
-
76
- context 'intersect' do
77
- subject{ Predicate.intersect(:x, [7,8]) }
78
-
79
- specify{ subject.to_ruby_code.should eq("->(t){ !t[:x].nil? && !(t[:x] & [7, 8]).empty? }") }
80
- end
81
-
82
- end
83
- end
@@ -1,14 +0,0 @@
1
- require 'spec_helper'
2
- class Predicate
3
- describe Predicate, "to_proc" do
4
-
5
- subject{ p.to_proc }
6
-
7
- describe "on a comp(:eq)" do
8
- let(:p){ Predicate.coerce(:x => 2) }
9
-
10
- it{ should be_a(Proc) }
11
- end
12
-
13
- end
14
- end
@@ -1,20 +0,0 @@
1
- require 'spec_helper'
2
- class Predicate
3
- describe Predicate, "to_ruby_code" do
4
-
5
- subject{ p.to_ruby_code }
6
-
7
- describe "on a comp(:eq)" do
8
- let(:p){ Predicate.coerce(:x => 2) }
9
-
10
- it{ should eq("->(t){ t[:x] == 2 }") }
11
- end
12
-
13
- describe "with qualified identifiers" do
14
- let(:p){ Predicate.eq(Factory.qualified_identifier(:t, :y), 2) }
15
-
16
- it{ should eq("->(t){ t[:y] == 2 }") }
17
- end
18
-
19
- end
20
- end