predicate 1.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 +7 -0
- data/Gemfile +2 -0
- data/LICENSE.md +22 -0
- data/Rakefile +11 -0
- data/lib/predicate/factory.rb +107 -0
- data/lib/predicate/grammar.rb +33 -0
- data/lib/predicate/grammar.sexp.yml +58 -0
- data/lib/predicate/nodes/and.rb +23 -0
- data/lib/predicate/nodes/contradiction.rb +34 -0
- data/lib/predicate/nodes/dyadic_comp.rb +26 -0
- data/lib/predicate/nodes/eq.rb +15 -0
- data/lib/predicate/nodes/expr.rb +68 -0
- data/lib/predicate/nodes/gt.rb +10 -0
- data/lib/predicate/nodes/gte.rb +10 -0
- data/lib/predicate/nodes/identifier.rb +18 -0
- data/lib/predicate/nodes/in.rb +26 -0
- data/lib/predicate/nodes/literal.rb +18 -0
- data/lib/predicate/nodes/lt.rb +10 -0
- data/lib/predicate/nodes/lte.rb +10 -0
- data/lib/predicate/nodes/nadic_bool.rb +16 -0
- data/lib/predicate/nodes/native.rb +30 -0
- data/lib/predicate/nodes/neq.rb +10 -0
- data/lib/predicate/nodes/not.rb +22 -0
- data/lib/predicate/nodes/or.rb +10 -0
- data/lib/predicate/nodes/qualified_identifier.rb +22 -0
- data/lib/predicate/nodes/tautology.rb +30 -0
- data/lib/predicate/processors/qualifier.rb +23 -0
- data/lib/predicate/processors/renamer.rb +25 -0
- data/lib/predicate/processors/to_ruby_code.rb +71 -0
- data/lib/predicate/processors.rb +3 -0
- data/lib/predicate/version.rb +8 -0
- data/lib/predicate.rb +113 -0
- data/spec/expr/test_to_proc.rb +16 -0
- data/spec/expr/test_to_ruby_code.rb +152 -0
- data/spec/factory/shared/a_comparison_factory_method.rb +35 -0
- data/spec/factory/shared/a_predicate_ast_node.rb +20 -0
- data/spec/factory/test_and.rb +13 -0
- data/spec/factory/test_between.rb +12 -0
- data/spec/factory/test_comp.rb +35 -0
- data/spec/factory/test_contradiction.rb +11 -0
- data/spec/factory/test_eq.rb +9 -0
- data/spec/factory/test_factor_predicate.rb +50 -0
- data/spec/factory/test_gt.rb +9 -0
- data/spec/factory/test_gte.rb +9 -0
- data/spec/factory/test_identifier.rb +13 -0
- data/spec/factory/test_in.rb +12 -0
- data/spec/factory/test_literal.rb +13 -0
- data/spec/factory/test_lt.rb +9 -0
- data/spec/factory/test_lte.rb +9 -0
- data/spec/factory/test_native.rb +19 -0
- data/spec/factory/test_neq.rb +9 -0
- data/spec/factory/test_not.rb +13 -0
- data/spec/factory/test_or.rb +13 -0
- data/spec/factory/test_qualified_identifier.rb +15 -0
- data/spec/factory/test_tautology.rb +12 -0
- data/spec/grammar/test_match.rb +93 -0
- data/spec/grammar/test_sexpr.rb +103 -0
- data/spec/nodes/and/test_and_split.rb +66 -0
- data/spec/nodes/dyadic_comp/test_and_split.rb +45 -0
- data/spec/nodes/identifier/test_and_split.rb +23 -0
- data/spec/nodes/identifier/test_free_variables.rb +12 -0
- data/spec/nodes/identifier/test_name.rb +12 -0
- data/spec/nodes/nadic_bool/test_free_variables.rb +14 -0
- data/spec/nodes/qualified_identifier/test_and_split.rb +23 -0
- data/spec/nodes/qualified_identifier/test_free_variables.rb +12 -0
- data/spec/nodes/qualified_identifier/test_name.rb +12 -0
- data/spec/nodes/qualified_identifier/test_qualifier.rb +12 -0
- data/spec/predicate/test_and_split.rb +57 -0
- data/spec/predicate/test_bool_and.rb +34 -0
- data/spec/predicate/test_bool_not.rb +68 -0
- data/spec/predicate/test_bool_or.rb +34 -0
- data/spec/predicate/test_coerce.rb +75 -0
- data/spec/predicate/test_constant_variables.rb +52 -0
- data/spec/predicate/test_contradiction.rb +24 -0
- data/spec/predicate/test_evaluate.rb +66 -0
- data/spec/predicate/test_factory_methods.rb +77 -0
- data/spec/predicate/test_free_variables.rb +14 -0
- data/spec/predicate/test_hash_and_equal.rb +26 -0
- data/spec/predicate/test_qualify.rb +34 -0
- data/spec/predicate/test_rename.rb +76 -0
- data/spec/predicate/test_tautology.rb +24 -0
- data/spec/predicate/test_to_proc.rb +14 -0
- data/spec/predicate/test_to_ruby_code.rb +20 -0
- data/spec/spec_helper.rb +12 -0
- data/spec/test_predicate.rb +127 -0
- data/tasks/test.rake +11 -0
- metadata +186 -0
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
class Predicate
|
3
|
+
describe Predicate, "|" do
|
4
|
+
|
5
|
+
let(:left) { Predicate.coerce(x: 2) }
|
6
|
+
|
7
|
+
subject{ left | right }
|
8
|
+
|
9
|
+
before do
|
10
|
+
subject.should be_a(Predicate)
|
11
|
+
end
|
12
|
+
|
13
|
+
context 'with itself' do
|
14
|
+
let(:right){ left }
|
15
|
+
|
16
|
+
it{ should be(left) }
|
17
|
+
end
|
18
|
+
|
19
|
+
context 'with the same expression' do
|
20
|
+
let(:right){ Predicate.coerce(x: 2) }
|
21
|
+
|
22
|
+
it{ should be(left) }
|
23
|
+
end
|
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
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
class Predicate
|
3
|
+
describe Predicate, ".coerce" do
|
4
|
+
|
5
|
+
subject{ Predicate.coerce(arg) }
|
6
|
+
|
7
|
+
describe "from Predicate" do
|
8
|
+
let(:arg){ Predicate.new(Factory.tautology) }
|
9
|
+
|
10
|
+
it{ should be(arg) }
|
11
|
+
end
|
12
|
+
|
13
|
+
describe "from true" do
|
14
|
+
let(:arg){ true }
|
15
|
+
|
16
|
+
specify{
|
17
|
+
subject.expr.should be_a(Tautology)
|
18
|
+
}
|
19
|
+
end
|
20
|
+
|
21
|
+
describe "from false" do
|
22
|
+
let(:arg){ false }
|
23
|
+
|
24
|
+
specify{
|
25
|
+
subject.expr.should be_a(Contradiction)
|
26
|
+
}
|
27
|
+
end
|
28
|
+
|
29
|
+
describe "from Symbol" do
|
30
|
+
let(:arg){ :status }
|
31
|
+
|
32
|
+
specify{
|
33
|
+
subject.expr.should be_a(Identifier)
|
34
|
+
subject.expr.name.should eq(arg)
|
35
|
+
}
|
36
|
+
end
|
37
|
+
|
38
|
+
describe "from Proc" do
|
39
|
+
let(:arg){ lambda{ status == 10 } }
|
40
|
+
|
41
|
+
specify{
|
42
|
+
subject.expr.should be_a(Native)
|
43
|
+
subject.to_proc.should be(arg)
|
44
|
+
}
|
45
|
+
end
|
46
|
+
|
47
|
+
describe "from String" do
|
48
|
+
let(:arg){ "status == 10" }
|
49
|
+
|
50
|
+
it 'raises an error' do
|
51
|
+
lambda{
|
52
|
+
subject
|
53
|
+
}.should raise_error(ArgumentError)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
describe "from Hash (single)" do
|
58
|
+
let(:arg){ {status: 10} }
|
59
|
+
|
60
|
+
specify{
|
61
|
+
subject.expr.should be_a(Eq)
|
62
|
+
subject.expr.should eq([:eq, [:identifier, :status], [:literal, 10]])
|
63
|
+
}
|
64
|
+
end
|
65
|
+
|
66
|
+
describe "from Hash (multiple)" do
|
67
|
+
let(:arg){ {status: 10, name: "Jones"} }
|
68
|
+
|
69
|
+
specify{
|
70
|
+
subject.should eq(Predicate.eq(status: 10) & Predicate.eq(name: "Jones"))
|
71
|
+
}
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
class Predicate
|
3
|
+
describe Predicate, "constant_variables" do
|
4
|
+
|
5
|
+
subject{ p.constant_variables }
|
6
|
+
|
7
|
+
describe "on a comp(:eq)" do
|
8
|
+
let(:p){ Predicate.coerce(x: 2, y: 3) }
|
9
|
+
|
10
|
+
it{ expect(subject).to eql([:x, :y]) }
|
11
|
+
end
|
12
|
+
|
13
|
+
describe "on a in with one value" do
|
14
|
+
let(:p){ Predicate.in(:x, [2]) }
|
15
|
+
|
16
|
+
it{ expect(subject).to eql([:x]) }
|
17
|
+
end
|
18
|
+
|
19
|
+
describe "on a in with mutiple values" do
|
20
|
+
let(:p){ Predicate.in(:x, [2, 3]) }
|
21
|
+
|
22
|
+
it{ expect(subject).to eql([]) }
|
23
|
+
end
|
24
|
+
|
25
|
+
describe "on a NOT" do
|
26
|
+
let(:p){ !Predicate.coerce(x: 2) }
|
27
|
+
|
28
|
+
it{ expect(subject).to eql([]) }
|
29
|
+
end
|
30
|
+
|
31
|
+
describe "on a AND" do
|
32
|
+
let(:p){ Predicate.coerce(x: 2) & Predicate.coerce(y: 3) }
|
33
|
+
|
34
|
+
it{ expect(subject).to eql([:x, :y]) }
|
35
|
+
end
|
36
|
+
|
37
|
+
describe "on a OR" do
|
38
|
+
let(:p){ Predicate.coerce(x: 2) | Predicate.coerce(y: 3) }
|
39
|
+
|
40
|
+
it{ expect(subject).to eql([]) }
|
41
|
+
end
|
42
|
+
|
43
|
+
describe "on a negated OR" do
|
44
|
+
let(:p){ !(Predicate.coerce(x: 2) | Predicate.coerce(y: 3)) }
|
45
|
+
|
46
|
+
pending("NNF would make constant_variables smarter"){
|
47
|
+
expect(subject).to eql([:x, :y])
|
48
|
+
}
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
class Predicate
|
3
|
+
describe Predicate, "contradiction?" do
|
4
|
+
|
5
|
+
context "tautology" do
|
6
|
+
subject{ Predicate.tautology }
|
7
|
+
|
8
|
+
it{ expect(subject.contradiction?).to be(false) }
|
9
|
+
end
|
10
|
+
|
11
|
+
context "contradiction" do
|
12
|
+
subject{ Predicate.contradiction }
|
13
|
+
|
14
|
+
it{ expect(subject.contradiction?).to be(true) }
|
15
|
+
end
|
16
|
+
|
17
|
+
context "identifier" do
|
18
|
+
subject{ Predicate.identifier(:x) }
|
19
|
+
|
20
|
+
it{ expect(subject.contradiction?).to be(false) }
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
class Predicate
|
3
|
+
describe Predicate, "evaluate" do
|
4
|
+
|
5
|
+
context 'on a native predicate of arity 1, used through tuple#[]' do
|
6
|
+
let(:predicate){
|
7
|
+
Predicate.native(->(t){ t[:name] =~ /foo/ })
|
8
|
+
}
|
9
|
+
|
10
|
+
context 'on a matching tuple' do
|
11
|
+
let(:scope){ { :name => "foo" } }
|
12
|
+
|
13
|
+
it{ expect(predicate.evaluate(scope)).to be_truthy }
|
14
|
+
end
|
15
|
+
|
16
|
+
context 'on a non-matching tuple' do
|
17
|
+
let(:scope){ { :name => "bar" } }
|
18
|
+
|
19
|
+
it{ expect(predicate.evaluate(scope)).to be_falsy }
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
context 'on a native predicate of arity 1, used through tuple[:xxx]' do
|
24
|
+
let(:predicate){
|
25
|
+
Predicate.native(->(t){ t[:name] =~ /foo/ })
|
26
|
+
}
|
27
|
+
|
28
|
+
context 'on a matching tuple' do
|
29
|
+
let(:scope){ { :name => "foo" } }
|
30
|
+
|
31
|
+
it{ expect(predicate.evaluate(scope)).to be_truthy }
|
32
|
+
end
|
33
|
+
|
34
|
+
context 'on a non-matching tuple' do
|
35
|
+
let(:scope){ { :name => "bar" } }
|
36
|
+
|
37
|
+
it{ expect(predicate.evaluate(scope)).to be_falsy }
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
context 'on a factored predicate' do
|
42
|
+
let(:predicate){
|
43
|
+
Predicate.new(Factory.lte(:x => 2))
|
44
|
+
}
|
45
|
+
|
46
|
+
describe "on x == 2" do
|
47
|
+
let(:scope){ { :x => 2 } }
|
48
|
+
|
49
|
+
it{ expect(predicate.evaluate(scope)).to be_truthy }
|
50
|
+
end
|
51
|
+
|
52
|
+
describe "on x == 1" do
|
53
|
+
let(:scope){ { :x => 1 } }
|
54
|
+
|
55
|
+
it{ expect(predicate.evaluate(scope)).to be_truthy }
|
56
|
+
end
|
57
|
+
|
58
|
+
describe "on x == 3" do
|
59
|
+
let(:scope){ { :x => 3 } }
|
60
|
+
|
61
|
+
it{ expect(predicate.evaluate(scope)).to be_falsy }
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,77 @@
|
|
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
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
class Predicate
|
3
|
+
describe Predicate, "hash and ==" do
|
4
|
+
|
5
|
+
subject{ left == right }
|
6
|
+
|
7
|
+
after do
|
8
|
+
left.hash.should eq(right.hash) if subject
|
9
|
+
end
|
10
|
+
|
11
|
+
describe "on equal predicates" do
|
12
|
+
let(:left) { Predicate.coerce(:x => 2) }
|
13
|
+
let(:right){ Predicate.coerce(:x => 2) }
|
14
|
+
|
15
|
+
it{ should be(true) }
|
16
|
+
end
|
17
|
+
|
18
|
+
describe "on non equal predicates" do
|
19
|
+
let(:left) { Predicate.coerce(:x => 2) }
|
20
|
+
let(:right){ Predicate.coerce(:x => 3) }
|
21
|
+
|
22
|
+
it{ should be(false) }
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
class Predicate
|
3
|
+
describe Predicate, "qualify" do
|
4
|
+
|
5
|
+
let(:p){ Predicate }
|
6
|
+
|
7
|
+
subject{ predicate.qualify(qualifier) }
|
8
|
+
|
9
|
+
let(:qualifier) { {:x => :t} }
|
10
|
+
|
11
|
+
context 'on a full AST predicate' do
|
12
|
+
let(:predicate){ p.in(:x, [2]) & p.eq(:y, 3) }
|
13
|
+
|
14
|
+
it{ should eq(p.in(Factory.qualified_identifier(:t, :x), [2]) & p.eq(:y, 3)) }
|
15
|
+
|
16
|
+
specify "it should tag expressions correctly" do
|
17
|
+
subject.expr.should be_a(Sexpr)
|
18
|
+
subject.expr.should be_a(Expr)
|
19
|
+
subject.expr.should be_a(And)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
context 'on a predicate that contains natives' do
|
24
|
+
let(:predicate){ p.in(:x, [2]) & p.native(lambda{}) }
|
25
|
+
|
26
|
+
it 'raises an error' do
|
27
|
+
lambda{
|
28
|
+
subject
|
29
|
+
}.should raise_error(NotSupportedError)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
class Predicate
|
3
|
+
describe Predicate, "rename" do
|
4
|
+
|
5
|
+
let(:p){ Predicate }
|
6
|
+
|
7
|
+
subject{ predicate.rename(renaming) }
|
8
|
+
|
9
|
+
context 'on a pure renaming hash' do
|
10
|
+
let(:renaming) { {:x => :z} }
|
11
|
+
|
12
|
+
context 'on a full AST predicate' do
|
13
|
+
let(:predicate){ p.in(:x, [2]) & p.eq(:y, 3) }
|
14
|
+
|
15
|
+
it{ should eq(p.in(:z, [2]) & p.eq(:y, 3)) }
|
16
|
+
|
17
|
+
specify "it should tag expressions correctly" do
|
18
|
+
subject.expr.should be_a(Sexpr)
|
19
|
+
subject.expr.should be_a(Expr)
|
20
|
+
subject.expr.should be_a(And)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
context 'on a predicate that contains natives' do
|
25
|
+
let(:predicate){ p.in(:x, [2]) & p.native(lambda{}) }
|
26
|
+
|
27
|
+
it 'raises an error' do
|
28
|
+
lambda{
|
29
|
+
subject
|
30
|
+
}.should raise_error(NotSupportedError)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
context 'on a predicate that contains qualified identifiers' do
|
35
|
+
let(:predicate){ p.eq(Factory.qualified_identifier(:t, :x), 3) }
|
36
|
+
|
37
|
+
it 'renames correctly' do
|
38
|
+
subject.should eq(p.eq(Factory.qualified_identifier(:t, :z), 3))
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
context 'when the renamer is a Proc returning identifiers' do
|
44
|
+
let(:renaming){ ->(a){ Grammar.sexpr([:identifier, :y]) } }
|
45
|
+
|
46
|
+
context "on an identifier" do
|
47
|
+
let(:predicate){ p.eq(:x, 2) }
|
48
|
+
|
49
|
+
it{ should eq(p.eq(:y, 2)) }
|
50
|
+
end
|
51
|
+
|
52
|
+
context "on a qualifier identifier" do
|
53
|
+
let(:predicate){ p.eq(Factory.qualified_identifier(:t, :x), 2) }
|
54
|
+
|
55
|
+
it{ should eq(p.eq(:y, 2)) }
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
context 'when the renamer is a Proc returning qualified identifiers' do
|
60
|
+
let(:renaming){ ->(a){ Grammar.sexpr([:qualified_identifier, :t, :y]) } }
|
61
|
+
|
62
|
+
context 'on an identifier' do
|
63
|
+
let(:predicate){ p.eq(:x, 2) }
|
64
|
+
|
65
|
+
it{ should eq(p.eq(Factory.qualified_identifier(:t, :y), 2)) }
|
66
|
+
end
|
67
|
+
|
68
|
+
context 'on a qualified' do
|
69
|
+
let(:predicate){ p.eq(Factory.qualified_identifier(:t, :x), 2) }
|
70
|
+
|
71
|
+
it{ should eq(p.eq(Factory.qualified_identifier(:t, :y), 2)) }
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
class Predicate
|
3
|
+
describe Predicate, "tautology?" do
|
4
|
+
|
5
|
+
context "tautology" do
|
6
|
+
subject{ Predicate.tautology }
|
7
|
+
|
8
|
+
it{ expect(subject.tautology?).to be(true) }
|
9
|
+
end
|
10
|
+
|
11
|
+
context "contradiction" do
|
12
|
+
subject{ Predicate.contradiction }
|
13
|
+
|
14
|
+
it{ expect(subject.tautology?).to be(false) }
|
15
|
+
end
|
16
|
+
|
17
|
+
context "identifier" do
|
18
|
+
subject{ Predicate.identifier(:x) }
|
19
|
+
|
20
|
+
it{ expect(subject.tautology?).to be(false) }
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,20 @@
|
|
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
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,127 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
shared_examples_for "a predicate" do
|
4
|
+
|
5
|
+
let(:x){ 12 }
|
6
|
+
let(:y){ 13 }
|
7
|
+
|
8
|
+
it 'provides a proc for easy evaluation' do
|
9
|
+
got = subject.to_proc.call(x: 12, y: 13)
|
10
|
+
[ TrueClass, FalseClass ].should include(got.class)
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'can be negated easily' do
|
14
|
+
(!subject).should be_a(Predicate)
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'detects stupid AND' do
|
18
|
+
(subject & Predicate.tautology).should be(subject)
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'detects stupid OR' do
|
22
|
+
(subject | Predicate.contradiction).should be(subject)
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'has free variables' do
|
26
|
+
(fv = subject.free_variables).should be_a(Array)
|
27
|
+
(fv - [ :x, :y ]).should be_empty
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'always splits around and trivially when no free variables are touched' do
|
31
|
+
top, down = subject.and_split([:z])
|
32
|
+
top.should be_tautology
|
33
|
+
down.should eq(subject)
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
|
38
|
+
describe 'Predicate.tautology' do
|
39
|
+
subject{ Predicate.tautology }
|
40
|
+
|
41
|
+
it_should_behave_like "a predicate"
|
42
|
+
end
|
43
|
+
|
44
|
+
describe 'Predicate.contradiction' do
|
45
|
+
subject{ Predicate.contradiction }
|
46
|
+
|
47
|
+
it_should_behave_like "a predicate"
|
48
|
+
end
|
49
|
+
|
50
|
+
describe "Predicate.comp" do
|
51
|
+
subject{ Predicate.comp(:lt, {:x => 2}) }
|
52
|
+
|
53
|
+
it_should_behave_like "a predicate"
|
54
|
+
end
|
55
|
+
|
56
|
+
describe "Predicate.in" do
|
57
|
+
subject{ Predicate.in(:x, [2, 3]) }
|
58
|
+
|
59
|
+
it_should_behave_like "a predicate"
|
60
|
+
end
|
61
|
+
|
62
|
+
describe "Predicate.among" do
|
63
|
+
subject{ Predicate.among(:x, [2, 3]) }
|
64
|
+
|
65
|
+
it_should_behave_like "a predicate"
|
66
|
+
end
|
67
|
+
|
68
|
+
describe "Predicate.eq" do
|
69
|
+
subject{ Predicate.eq(:x, 2) }
|
70
|
+
|
71
|
+
it_should_behave_like "a predicate"
|
72
|
+
end
|
73
|
+
|
74
|
+
describe "Predicate.neq" do
|
75
|
+
subject{ Predicate.neq(:x, 2) }
|
76
|
+
|
77
|
+
it_should_behave_like "a predicate"
|
78
|
+
end
|
79
|
+
|
80
|
+
describe "Predicate.gt" do
|
81
|
+
subject{ Predicate.gt(:x, 2) }
|
82
|
+
|
83
|
+
it_should_behave_like "a predicate"
|
84
|
+
end
|
85
|
+
|
86
|
+
describe "Predicate.gte" do
|
87
|
+
subject{ Predicate.gte(:x, 2) }
|
88
|
+
|
89
|
+
it_should_behave_like "a predicate"
|
90
|
+
end
|
91
|
+
|
92
|
+
describe "Predicate.lt" do
|
93
|
+
subject{ Predicate.lt(:x, 2) }
|
94
|
+
|
95
|
+
it_should_behave_like "a predicate"
|
96
|
+
end
|
97
|
+
|
98
|
+
describe "Predicate.lte" do
|
99
|
+
subject{ Predicate.lte(:x, 2) }
|
100
|
+
|
101
|
+
it_should_behave_like "a predicate"
|
102
|
+
end
|
103
|
+
|
104
|
+
describe "Predicate.between" do
|
105
|
+
subject{ Predicate.between(:x, 2, 3) }
|
106
|
+
|
107
|
+
it_should_behave_like "a predicate"
|
108
|
+
end
|
109
|
+
|
110
|
+
describe "Predicate.and" do
|
111
|
+
subject{ Predicate.and(Predicate.eq(:x, 12), Predicate.eq(:y, 12)) }
|
112
|
+
|
113
|
+
it_should_behave_like "a predicate"
|
114
|
+
end
|
115
|
+
|
116
|
+
describe "Predicate.or" do
|
117
|
+
subject{ Predicate.or(Predicate.eq(:x, 12), Predicate.eq(:y, 12)) }
|
118
|
+
|
119
|
+
it_should_behave_like "a predicate"
|
120
|
+
end
|
121
|
+
|
122
|
+
describe "Predicate.not" do
|
123
|
+
subject{ Predicate.not(Predicate.in(:x, [12])) }
|
124
|
+
|
125
|
+
it_should_behave_like "a predicate"
|
126
|
+
end
|
127
|
+
|
data/tasks/test.rake
ADDED