predicate 1.3.4 → 2.0.0

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