predicate 2.3.2 → 2.6.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 (78) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +4 -0
  3. data/LICENSE.md +17 -19
  4. data/README.md +435 -0
  5. data/bin/g +2 -0
  6. data/lib/predicate/dsl.rb +138 -0
  7. data/lib/predicate/factory.rb +142 -37
  8. data/lib/predicate/grammar.rb +11 -2
  9. data/lib/predicate/grammar.sexp.yml +29 -0
  10. data/lib/predicate/nodes/${op_name}.rb.jeny +12 -0
  11. data/lib/predicate/nodes/and.rb +9 -0
  12. data/lib/predicate/nodes/binary_func.rb +20 -0
  13. data/lib/predicate/nodes/contradiction.rb +2 -7
  14. data/lib/predicate/nodes/dyadic_comp.rb +1 -3
  15. data/lib/predicate/nodes/empty.rb +14 -0
  16. data/lib/predicate/nodes/eq.rb +11 -3
  17. data/lib/predicate/nodes/expr.rb +9 -3
  18. data/lib/predicate/nodes/has_size.rb +14 -0
  19. data/lib/predicate/nodes/identifier.rb +1 -3
  20. data/lib/predicate/nodes/in.rb +7 -6
  21. data/lib/predicate/nodes/intersect.rb +3 -23
  22. data/lib/predicate/nodes/literal.rb +1 -3
  23. data/lib/predicate/nodes/match.rb +1 -21
  24. data/lib/predicate/nodes/nadic_bool.rb +1 -3
  25. data/lib/predicate/nodes/native.rb +1 -3
  26. data/lib/predicate/nodes/not.rb +1 -3
  27. data/lib/predicate/nodes/opaque.rb +1 -3
  28. data/lib/predicate/nodes/qualified_identifier.rb +1 -3
  29. data/lib/predicate/nodes/set_op.rb +26 -0
  30. data/lib/predicate/nodes/subset.rb +11 -0
  31. data/lib/predicate/nodes/superset.rb +11 -0
  32. data/lib/predicate/nodes/tautology.rb +6 -7
  33. data/lib/predicate/nodes/unary_func.rb +16 -0
  34. data/lib/predicate/nodes/var.rb +46 -0
  35. data/lib/predicate/processors/qualifier.rb +4 -0
  36. data/lib/predicate/processors/renamer.rb +4 -0
  37. data/lib/predicate/processors/to_s.rb +28 -0
  38. data/lib/predicate/processors/unqualifier.rb +21 -0
  39. data/lib/predicate/processors.rb +1 -0
  40. data/lib/predicate/sequel/to_sequel.rb +4 -1
  41. data/lib/predicate/sugar.rb +47 -0
  42. data/lib/predicate/version.rb +2 -2
  43. data/lib/predicate.rb +26 -2
  44. data/spec/dsl/test_dsl.rb +204 -0
  45. data/spec/dsl/test_evaluate.rb +65 -0
  46. data/spec/dsl/test_respond_to_missing.rb +35 -0
  47. data/spec/dsl/test_to_skake_case.rb +38 -0
  48. data/spec/factory/shared/a_comparison_factory_method.rb +1 -0
  49. data/spec/factory/test_${op_name}.rb.jeny +12 -0
  50. data/spec/factory/test_comp.rb +28 -5
  51. data/spec/factory/test_empty.rb +11 -0
  52. data/spec/factory/test_has_size.rb +11 -0
  53. data/spec/factory/test_match.rb +1 -0
  54. data/spec/factory/test_set_ops.rb +18 -0
  55. data/spec/factory/test_var.rb +22 -0
  56. data/spec/factory/test_vars.rb +27 -0
  57. data/spec/nodes/${op_name}.jeny/test_evaluate.rb.jeny +19 -0
  58. data/spec/nodes/empty/test_evaluate.rb +42 -0
  59. data/spec/nodes/has_size/test_evaluate.rb +44 -0
  60. data/spec/predicate/test_and_split.rb +18 -0
  61. data/spec/predicate/test_attr_split.rb +18 -0
  62. data/spec/predicate/test_constant_variables.rb +24 -2
  63. data/spec/predicate/test_constants.rb +24 -0
  64. data/spec/predicate/test_evaluate.rb +205 -3
  65. data/spec/predicate/test_free_variables.rb +1 -1
  66. data/spec/predicate/test_to_hash.rb +40 -0
  67. data/spec/predicate/test_to_s.rb +37 -0
  68. data/spec/predicate/test_unqualify.rb +18 -0
  69. data/spec/sequel/test_to_sequel.rb +25 -0
  70. data/spec/shared/a_predicate.rb +30 -0
  71. data/spec/spec_helper.rb +1 -0
  72. data/spec/test_predicate.rb +78 -33
  73. data/spec/test_readme.rb +80 -0
  74. data/spec/test_sugar.rb +48 -0
  75. data/tasks/test.rake +3 -3
  76. metadata +45 -14
  77. data/spec/factory/test_between.rb +0 -12
  78. data/spec/factory/test_intersect.rb +0 -12
@@ -0,0 +1,38 @@
1
+ require 'spec_helper'
2
+
3
+ class Predicate
4
+ describe Dsl, "to_snake_case" do
5
+
6
+ def snake(str)
7
+ Dsl.new.__send__(:to_snake_case, str)
8
+ end
9
+
10
+ it 'works on snake case already' do
11
+ {
12
+ "snake" => "snake",
13
+ "snake_case" => "snake_case"
14
+ }.each_pair do |k,v|
15
+ expect(snake(k)).to eq(v)
16
+ end
17
+ end
18
+
19
+ it 'works on camelCase already' do
20
+ {
21
+ "camelCase" => "camel_case",
22
+ "theCamelCase" => "the_camel_case"
23
+ }.each_pair do |k,v|
24
+ expect(snake(k)).to eq(v)
25
+ end
26
+ end
27
+
28
+ it 'works on PascalCase already' do
29
+ {
30
+ "PascalCase" => "pascal_case",
31
+ "ThePascalCase" => "the_pascal_case"
32
+ }.each_pair do |k,v|
33
+ expect(snake(k)).to eq(v)
34
+ end
35
+ end
36
+
37
+ end
38
+ end
@@ -1,6 +1,7 @@
1
1
  require_relative 'a_predicate_ast_node'
2
2
  shared_examples_for "a comparison factory method" do
3
3
  include Predicate::Factory
4
+ include Predicate::Sugar
4
5
 
5
6
  context 'with two operands' do
6
7
  subject{ self.send(method, true, true) }
@@ -0,0 +1,12 @@
1
+ #jeny(predicate)
2
+ require_relative 'shared/a_predicate_ast_node'
3
+ class Predicate
4
+ describe Factory, '${op_name}' do
5
+ include Factory
6
+ subject{ ${op_name}(TODO) }
7
+
8
+ it_should_behave_like "a predicate AST node"
9
+
10
+ it{ should be_a(${OpName}) }
11
+ end
12
+ end
@@ -10,7 +10,15 @@ class Predicate
10
10
  it{ should eq(Factory.tautology) }
11
11
  end
12
12
 
13
- context "when the hash is singleton" do
13
+ context "when the hash is a singelton" do
14
+ let(:h){ {:x => 12} }
15
+
16
+ it_should_behave_like "a predicate AST node"
17
+ it{ should be_a(Eq) }
18
+ it{ should eq([:eq, [:identifier, :x], [:literal, 12]]) }
19
+ end
20
+
21
+ context "when the hash is not singleton" do
14
22
  let(:h){ {:x => 12, :y => :z} }
15
23
  let(:expected){
16
24
  [:and,
@@ -23,12 +31,27 @@ class Predicate
23
31
  it{ should eq(expected) }
24
32
  end
25
33
 
26
- context "when the hash is not singelton" do
27
- let(:h){ {:x => 12} }
34
+ context "when the value is a Regexp" do
35
+ let(:rx){ /[a-z]+/ }
36
+ let(:h){ {:x => /[a-z]+/} }
28
37
 
29
38
  it_should_behave_like "a predicate AST node"
30
- it{ should be_a(Eq) }
31
- it{ should eq([:eq, [:identifier, :x], [:literal, 12]]) }
39
+ it{ should be_a(Match) }
40
+ it{ should eq([:match, [:identifier, :x], [:literal, rx]]) }
41
+ end
42
+
43
+ context "when the hash mixes value types" do
44
+ let(:rx){ /[a-z]+/ }
45
+ let(:h){ {:x => 12, :y => rx} }
46
+ let(:expected){
47
+ [:and,
48
+ [:eq, [:identifier, :x], [:literal, 12]],
49
+ [:match, [:identifier, :y], [:literal, rx]]]
50
+ }
51
+
52
+ it_should_behave_like "a predicate AST node"
53
+ it{ should be_a(And) }
54
+ it{ should eq(expected) }
32
55
  end
33
56
 
34
57
  end
@@ -0,0 +1,11 @@
1
+ require_relative 'shared/a_predicate_ast_node'
2
+ class Predicate
3
+ describe Factory, 'empty' do
4
+ include Factory
5
+ subject{ empty(:x) }
6
+
7
+ it_should_behave_like "a predicate AST node"
8
+
9
+ it{ should be_a(Empty) }
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ require_relative 'shared/a_predicate_ast_node'
2
+ class Predicate
3
+ describe Factory, 'has_size' do
4
+ include Factory
5
+ subject{ has_size(:x, 1..10) }
6
+
7
+ it_should_behave_like "a predicate AST node"
8
+
9
+ it{ should be_a(HasSize) }
10
+ end
11
+ end
@@ -2,6 +2,7 @@ require_relative 'shared/a_predicate_ast_node'
2
2
  class Predicate
3
3
  describe Factory, 'match' do
4
4
  include Factory
5
+ include Sugar
5
6
 
6
7
  context 'without options' do
7
8
  subject{ match(:name, "London") }
@@ -0,0 +1,18 @@
1
+ require_relative "shared/a_comparison_factory_method"
2
+ class Predicate
3
+ [
4
+ [ :intersect, Intersect ],
5
+ [ :subset, Subset ],
6
+ [ :superset, Superset ],
7
+ ].each do |op_name, op_class|
8
+ describe Factory, op_name do
9
+
10
+ subject{ Factory.send(op_name, :x, [2, 3]) }
11
+
12
+ it{ should be_a(op_class) }
13
+
14
+ it{ should eq([op_name, [:identifier, :x], [:literal, [2, 3]]]) }
15
+
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,22 @@
1
+ require_relative 'shared/a_predicate_ast_node'
2
+ class Predicate
3
+ describe Factory, 'var' do
4
+ include Factory
5
+
6
+ context 'when used with a string' do
7
+ subject{ var("a.b.c", :dig) }
8
+
9
+ it_should_behave_like "a predicate AST node"
10
+ it{ should be_a(Var) }
11
+ it{ should eql([:var, "a.b.c", :dig]) }
12
+ end
13
+
14
+ context 'when used with an array' do
15
+ subject{ var([:a, :b, :c], :dig) }
16
+
17
+ it_should_behave_like "a predicate AST node"
18
+ it{ should be_a(Var) }
19
+ it{ should eql([:var, [:a, :b, :c], :dig]) }
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,27 @@
1
+ require_relative 'shared/a_predicate_ast_node'
2
+ class Predicate
3
+ describe Factory, 'vars' do
4
+ include Factory
5
+
6
+ context 'when used without semantics' do
7
+ subject{ vars("a.b.c", "d.e.f") }
8
+
9
+ it 'works as expected' do
10
+ expect(subject).to be_a(Array)
11
+ expect(subject.size).to eql(2)
12
+ expect(subject.all?{|p| p.is_a?(Var) && p.semantics == :dig })
13
+ end
14
+ end
15
+
16
+ context 'when used with semantics' do
17
+ subject{ vars("a.b.c", "d.e.f", :jsonpath) }
18
+
19
+ it 'works as expected' do
20
+ expect(subject).to be_a(Array)
21
+ expect(subject.size).to eql(2)
22
+ expect(subject.all?{|p| p.is_a?(Var) && p.semantics == :jsonpath })
23
+ end
24
+ end
25
+
26
+ end
27
+ end
@@ -0,0 +1,19 @@
1
+ #jeny(predicate)
2
+ require 'spec_helper'
3
+ class Predicate
4
+ describe ${OpName}, "evaluate" do
5
+
6
+ let(:predicate){ Factory.${op_name}(TODO) }
7
+
8
+ subject{ predicate.evaluate(context) }
9
+
10
+ context "on TODO" do
11
+ let(:context){ TODO }
12
+
13
+ it 'works as expected' do
14
+ TODO
15
+ end
16
+ end
17
+
18
+ end
19
+ end
@@ -0,0 +1,42 @@
1
+ require 'spec_helper'
2
+ class Predicate
3
+ describe Empty, "evaluate" do
4
+
5
+ let(:predicate){ Factory.empty(:x) }
6
+
7
+ subject{ predicate.evaluate(context) }
8
+
9
+ context "on an empty array" do
10
+ let(:context){ { x: [] } }
11
+
12
+ it{ expect(subject).to eq(true) }
13
+ end
14
+
15
+ context "on a non empty array" do
16
+ let(:context){ { x: [1, 2, 3] } }
17
+
18
+ it{ expect(subject).to eq(false) }
19
+ end
20
+
21
+ context "on a empty string" do
22
+ let(:context){ { x: "" } }
23
+
24
+ it{ expect(subject).to eq(true) }
25
+ end
26
+
27
+ context "on a non empty string" do
28
+ let(:context){ { x: "1233" } }
29
+
30
+ it{ expect(subject).to eq(false) }
31
+ end
32
+
33
+ context "on an object that does not respond to empty?" do
34
+ let(:context){ { x: 14567 } }
35
+
36
+ it{
37
+ expect{ subject }.to raise_error(TypeError, "Expected 14567 to respond to empty?")
38
+ }
39
+ end
40
+
41
+ end
42
+ end
@@ -0,0 +1,44 @@
1
+ require 'spec_helper'
2
+ class Predicate
3
+ describe HasSize, "evaluate" do
4
+
5
+ let(:predicate){
6
+ Factory.has_size(:x, y)
7
+ }
8
+
9
+ subject{ predicate.evaluate(context) }
10
+
11
+ context 'against a Range' do
12
+ let(:y){ 1..10 }
13
+
14
+ context "on a match x" do
15
+ let(:context){ { x: "1234567" } }
16
+
17
+ it{ expect(subject).to eq(true) }
18
+ end
19
+
20
+ context "on a non matching x" do
21
+ let(:context){ { x: "1234567891011" } }
22
+
23
+ it{ expect(subject).to eq(false) }
24
+ end
25
+ end
26
+
27
+ context 'against an Integer' do
28
+ let(:y){ 10 }
29
+
30
+ context "on a match x" do
31
+ let(:context){ { x: "0123456789" } }
32
+
33
+ it{ expect(subject).to eq(true) }
34
+ end
35
+
36
+ context "on a non matching x" do
37
+ let(:context){ { x: "1234567891011" } }
38
+
39
+ it{ expect(subject).to eq(false) }
40
+ end
41
+ end
42
+
43
+ end
44
+ end
@@ -83,5 +83,23 @@ class Predicate
83
83
  it{ should eq([ pred, p.tautology ]) }
84
84
  end
85
85
 
86
+ context "on intersect" do
87
+ let(:pred){ p.intersect(:x, [1, 2]) }
88
+
89
+ it{ should eq([ pred, p.tautology ]) }
90
+ end
91
+
92
+ context "on subset" do
93
+ let(:pred){ p.subset(:x, [1, 2]) }
94
+
95
+ it{ should eq([ pred, p.tautology ]) }
96
+ end
97
+
98
+ context "on superset" do
99
+ let(:pred){ p.superset(:x, [1, 2]) }
100
+
101
+ it{ should eq([ pred, p.tautology ]) }
102
+ end
103
+
86
104
  end
87
105
  end
@@ -47,6 +47,24 @@ class Predicate
47
47
  it{ should eq({ x: pred }) }
48
48
  end
49
49
 
50
+ context "on intersect" do
51
+ let(:pred){ p.intersect(:x, [2]) }
52
+
53
+ it{ should eq({ x: pred }) }
54
+ end
55
+
56
+ context "on subset" do
57
+ let(:pred){ p.subset(:x, [2]) }
58
+
59
+ it{ should eq({ x: pred }) }
60
+ end
61
+
62
+ context "on superset" do
63
+ let(:pred){ p.superset(:x, [2]) }
64
+
65
+ it{ should eq({ x: pred }) }
66
+ end
67
+
50
68
  context "on match" do
51
69
  let(:pred){ p.match(:x, "London") }
52
70
 
@@ -37,14 +37,36 @@ class Predicate
37
37
  describe "on an intersect with one value" do
38
38
  let(:p){ Predicate.intersect(:x, [2]) }
39
39
 
40
- # TODO: is that correct?
41
40
  it{ expect(subject).to eql([]) }
42
41
  end
43
42
 
44
43
  describe "on an intersect with a placeholder" do
45
44
  let(:p){ Predicate.intersect(:x, Predicate.placeholder) }
46
45
 
47
- # TODO: is that correct?
46
+ it{ expect(subject).to eql([]) }
47
+ end
48
+
49
+ describe "on an subset with one value" do
50
+ let(:p){ Predicate.subset(:x, [2]) }
51
+
52
+ it{ expect(subject).to eql([]) }
53
+ end
54
+
55
+ describe "on an subset with a placeholder" do
56
+ let(:p){ Predicate.subset(:x, Predicate.placeholder) }
57
+
58
+ it{ expect(subject).to eql([]) }
59
+ end
60
+
61
+ describe "on an superset with one value" do
62
+ let(:p){ Predicate.superset(:x, [2]) }
63
+
64
+ it{ expect(subject).to eql([]) }
65
+ end
66
+
67
+ describe "on an superset with a placeholder" do
68
+ let(:p){ Predicate.superset(:x, Predicate.placeholder) }
69
+
48
70
  it{ expect(subject).to eql([]) }
49
71
  end
50
72
 
@@ -119,6 +119,30 @@ class Predicate
119
119
  it{ should eq({}) }
120
120
  end
121
121
 
122
+ context "on subset" do
123
+ let(:pred){ p.subset(:x, [4,8]) }
124
+
125
+ it{ should eq({}) }
126
+ end
127
+
128
+ context "on subset with placeholder" do
129
+ let(:pred){ p.subset(:x, p.placeholder) }
130
+
131
+ it{ should eq({}) }
132
+ end
133
+
134
+ context "on superset" do
135
+ let(:pred){ p.superset(:x, [4,8]) }
136
+
137
+ it{ should eq({}) }
138
+ end
139
+
140
+ context "on superset with placeholder" do
141
+ let(:pred){ p.superset(:x, p.placeholder) }
142
+
143
+ it{ should eq({}) }
144
+ end
145
+
122
146
  context "on or (two eqs)" do
123
147
  let(:pred){ p.eq(:x, 2) | p.eq(:y, 4) }
124
148
 
@@ -40,7 +40,7 @@ class Predicate
40
40
 
41
41
  context 'on a factored predicate' do
42
42
  let(:predicate){
43
- Predicate.new(Factory.lte(:x => 2))
43
+ Predicate.lte(:x => 2)
44
44
  }
45
45
 
46
46
  describe "on x == 2" do
@@ -80,7 +80,7 @@ class Predicate
80
80
  end
81
81
  end
82
82
 
83
- context 'on an intersect predicate' do
83
+ context 'on an intersect predicate, with array literal' do
84
84
  let(:predicate){
85
85
  Predicate.intersect(:x, [8,9])
86
86
  }
@@ -98,6 +98,168 @@ class Predicate
98
98
  end
99
99
  end
100
100
 
101
+ context 'on an intersect predicate, with two variables' do
102
+ let(:predicate){
103
+ Predicate.intersect(:x, :y)
104
+ }
105
+
106
+ describe "on x == [2]" do
107
+ let(:scope){ { :x => [2], :y => [8,9] } }
108
+
109
+ it{ expect(predicate.evaluate(scope)).to be_falsy }
110
+ end
111
+
112
+ describe "on x == [9,12]" do
113
+ let(:scope){ { :x => [9,12], :y => [8,9] } }
114
+
115
+ it{ expect(predicate.evaluate(scope)).to be_truthy }
116
+ end
117
+ end
118
+
119
+ context 'on an subset predicate, with an array literal' do
120
+ let(:predicate){
121
+ Predicate.subset(:x, [8,9])
122
+ }
123
+
124
+ describe "on x == [2]" do
125
+ let(:scope){ { :x => [2] } }
126
+
127
+ it{ expect(predicate.evaluate(scope)).to be_falsy }
128
+ end
129
+
130
+ describe "on x == []" do
131
+ let(:scope){ { :x => [] } }
132
+
133
+ it{ expect(predicate.evaluate(scope)).to be_truthy }
134
+ end
135
+
136
+ describe "on x == [9]" do
137
+ let(:scope){ { :x => [9] } }
138
+
139
+ it{ expect(predicate.evaluate(scope)).to be_truthy }
140
+ end
141
+
142
+ describe "on x == [8, 9]" do
143
+ let(:scope){ { :x => [8, 9] } }
144
+
145
+ it{ expect(predicate.evaluate(scope)).to be_truthy }
146
+ end
147
+
148
+ describe "on x == [8, 9, 10]" do
149
+ let(:scope){ { :x => [8, 9, 19] } }
150
+
151
+ it{ expect(predicate.evaluate(scope)).to be_falsy }
152
+ end
153
+ end
154
+
155
+ context 'on an subset predicate, with two variables' do
156
+ let(:predicate){
157
+ Predicate.subset(:x, :y)
158
+ }
159
+
160
+ describe "on x == [2]" do
161
+ let(:scope){ { :x => [2], :y => [8,9] } }
162
+
163
+ it{ expect(predicate.evaluate(scope)).to be_falsy }
164
+ end
165
+
166
+ describe "on x == []" do
167
+ let(:scope){ { :x => [], :y => [8,9] } }
168
+
169
+ it{ expect(predicate.evaluate(scope)).to be_truthy }
170
+ end
171
+
172
+ describe "on x == [9]" do
173
+ let(:scope){ { :x => [9], :y => [8,9] } }
174
+
175
+ it{ expect(predicate.evaluate(scope)).to be_truthy }
176
+ end
177
+
178
+ describe "on x == [8, 9]" do
179
+ let(:scope){ { :x => [8, 9], :y => [8,9] } }
180
+
181
+ it{ expect(predicate.evaluate(scope)).to be_truthy }
182
+ end
183
+
184
+ describe "on x == [8, 9, 10]" do
185
+ let(:scope){ { :x => [8, 9, 19], :y => [8,9] } }
186
+
187
+ it{ expect(predicate.evaluate(scope)).to be_falsy }
188
+ end
189
+ end
190
+
191
+ context 'on an superset predicate, with an array literal' do
192
+ let(:predicate){
193
+ Predicate.superset(:x, [8,9])
194
+ }
195
+
196
+ describe "on x == [2]" do
197
+ let(:scope){ { :x => [2] } }
198
+
199
+ it{ expect(predicate.evaluate(scope)).to be_falsy }
200
+ end
201
+
202
+ describe "on x == []" do
203
+ let(:scope){ { :x => [] } }
204
+
205
+ it{ expect(predicate.evaluate(scope)).to be_falsy }
206
+ end
207
+
208
+ describe "on x == [9]" do
209
+ let(:scope){ { :x => [9] } }
210
+
211
+ it{ expect(predicate.evaluate(scope)).to be_falsy }
212
+ end
213
+
214
+ describe "on x == [8, 9]" do
215
+ let(:scope){ { :x => [8, 9] } }
216
+
217
+ it{ expect(predicate.evaluate(scope)).to be_truthy }
218
+ end
219
+
220
+ describe "on x == [8, 9, 10]" do
221
+ let(:scope){ { :x => [8, 9, 19] } }
222
+
223
+ it{ expect(predicate.evaluate(scope)).to be_truthy }
224
+ end
225
+ end
226
+
227
+ context 'on an superset predicate, with two variables' do
228
+ let(:predicate){
229
+ Predicate.superset(:x, :y)
230
+ }
231
+
232
+ describe "on x == [2]" do
233
+ let(:scope){ { :x => [2], :y => [8,9] } }
234
+
235
+ it{ expect(predicate.evaluate(scope)).to be_falsy }
236
+ end
237
+
238
+ describe "on x == []" do
239
+ let(:scope){ { :x => [], :y => [8,9] } }
240
+
241
+ it{ expect(predicate.evaluate(scope)).to be_falsy }
242
+ end
243
+
244
+ describe "on x == [9]" do
245
+ let(:scope){ { :x => [9], :y => [8,9] } }
246
+
247
+ it{ expect(predicate.evaluate(scope)).to be_falsy }
248
+ end
249
+
250
+ describe "on x == [8, 9]" do
251
+ let(:scope){ { :x => [8, 9], :y => [8,9] } }
252
+
253
+ it{ expect(predicate.evaluate(scope)).to be_truthy }
254
+ end
255
+
256
+ describe "on x == [8, 9, 10]" do
257
+ let(:scope){ { :x => [8, 9, 19], :y => [8,9] } }
258
+
259
+ it{ expect(predicate.evaluate(scope)).to be_truthy }
260
+ end
261
+ end
262
+
101
263
  context 'on a match against a string' do
102
264
  let(:predicate){
103
265
  Predicate.match(:x, "12")
@@ -228,12 +390,52 @@ class Predicate
228
390
 
229
391
  context 'has a call alias' do
230
392
  let(:predicate){
231
- Predicate.new(Factory.gte(:x => 0))
393
+ Predicate.gte(:x => 0)
232
394
  }
233
395
 
234
396
  let(:scope){ { x: 2 } }
235
397
 
236
398
  it{ expect(predicate.call(scope)).to be(true) }
237
399
  end
400
+
401
+ context "on a var, build with a dotted string" do
402
+ let(:predicate){
403
+ Predicate.var("x.0.y")
404
+ }
405
+
406
+ let(:scope){ { x: [{ y: 2 }] } }
407
+
408
+ it{ expect(predicate.call(scope)).to eql(2) }
409
+ end
410
+
411
+ context "on a var, build with a . string" do
412
+ let(:predicate){
413
+ Predicate.var(".")
414
+ }
415
+
416
+ let(:scope){ { x: [{ y: 2 }] } }
417
+
418
+ it{ expect(predicate.call(scope)).to be(scope) }
419
+ end
420
+
421
+ context "on a var, build with an array for terms" do
422
+ let(:predicate){
423
+ Predicate.var([:x, 0, :y])
424
+ }
425
+
426
+ let(:scope){ { x: [{ y: 2 }] } }
427
+
428
+ it{ expect(predicate.call(scope)).to eql(2) }
429
+ end
430
+
431
+ context "on a var, build with an empty array" do
432
+ let(:predicate){
433
+ Predicate.var([])
434
+ }
435
+
436
+ let(:scope){ { x: [{ y: 2 }] } }
437
+
438
+ it{ expect(predicate.call(scope)).to be(scope) }
439
+ end
238
440
  end
239
441
  end
@@ -9,6 +9,6 @@ class Predicate
9
9
 
10
10
  it{ should eq([:x]) }
11
11
  end
12
-
12
+
13
13
  end
14
14
  end