predicated 0.1.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.
@@ -0,0 +1,102 @@
1
+ require "test/test_helper"
2
+
3
+ require "predicated/from/callable_object"
4
+ include Predicated
5
+
6
+ apropos "convert a ruby callable object - a proc or lambda - into a predicate" do
7
+
8
+ apropos "basic operations" do
9
+
10
+ test "simple signs" do
11
+ assert_equal Predicate.from_callable_object{1==1}, Predicate{ Eq(1,1) }
12
+ assert_equal Predicate.from_callable_object{1 == 1}, Predicate{ Eq(1,1) }
13
+ assert_equal Predicate.from_callable_object{0<1}, Predicate{ Lt(0,1) }
14
+ assert_equal Predicate.from_callable_object{2>1}, Predicate{ Gt(2,1) }
15
+ assert_equal Predicate.from_callable_object{1<=1}, Predicate{ Lte(1,1) }
16
+ assert_equal Predicate.from_callable_object{1>=1}, Predicate{ Gte(1,1) }
17
+ end
18
+
19
+ test "primitive types" do
20
+ assert_equal Predicate.from_callable_object{false==true}, Predicate{ Eq(false,true) }
21
+ assert_equal Predicate.from_callable_object{"yyy"=="zzz"}, Predicate{ Eq("yyy","zzz") }
22
+ end
23
+
24
+ test "complex types" do
25
+ assert_equal Predicate.from_callable_object{Color.new("red")==Color.new("blue")},
26
+ Predicate{ Eq(Color.new("red"),Color.new("blue")) }
27
+
28
+ assert_equal Predicate.from_callable_object{ {1=>2}=={"a"=>"b"} },
29
+ Predicate{ Eq({1=>2},{"a"=>"b"}) }
30
+ end
31
+
32
+ test "simple and + or" do
33
+ assert_equal Predicate.from_callable_object{1==1 && 2==2}, Predicate{ And(Eq(1,1),Eq(2,2)) }
34
+ assert_equal Predicate.from_callable_object{1==1 and 2==2}, Predicate{ And(Eq(1,1),Eq(2,2)) }
35
+ assert_equal Predicate.from_callable_object{1==1 || 2==2}, Predicate{ Or(Eq(1,1),Eq(2,2)) }
36
+ assert_equal Predicate.from_callable_object{1==1 or 2==2}, Predicate{ Or(Eq(1,1),Eq(2,2)) }
37
+ end
38
+
39
+ class Color
40
+ attr_reader :name
41
+ def initialize(name)
42
+ @name = name
43
+ end
44
+
45
+ def ==(other)
46
+ other.is_a?(Color) && @name == other.name
47
+ end
48
+ end
49
+
50
+ test "substitute in from the binding" do
51
+ a = 1
52
+ b = "1"
53
+ c = "c"
54
+ d = Color.new("purple")
55
+
56
+ assert_equal Predicate.from_callable_object(binding()){a==1}, Predicate{ Eq(1,1) }
57
+ assert_equal Predicate.from_callable_object(binding()){b==1}, Predicate{ Eq("1",1) }
58
+ assert_equal Predicate.from_callable_object(binding()){c==b}, Predicate{ Eq("c","1") }
59
+ assert_equal Predicate.from_callable_object(binding()){d==d}, Predicate{ Eq(Color.new("purple"),
60
+ Color.new("purple")) }
61
+ assert Predicate.from_callable_object(binding()){d==d}.left === d
62
+
63
+ assert_equal Predicate.from_callable_object(binding()){a==b && b==c},
64
+ Predicate{ And(Eq(1,"1"),Eq("1","c")) }
65
+ end
66
+
67
+
68
+ test "complex and + or" do
69
+ assert_equal Predicate.from_callable_object{1==1 && 2==2 || 3==3},
70
+ Predicate{ Or( And(Eq(1,1),Eq(2,2)), Eq(3,3) ) }
71
+ end
72
+
73
+ test "parens change precedence" do
74
+ assert_equal Predicate.from_callable_object{1==1 || 2==2 && 3==3},
75
+ Predicate{ Or( Eq(1,1), And(Eq(2,2),Eq(3,3)) ) }
76
+
77
+ assert_equal Predicate.from_callable_object{(1==1 || 2==2) && 3==3},
78
+ Predicate{ And( Or(Eq(1,1),Eq(2,2)), Eq(3,3) ) }
79
+ end
80
+
81
+ test "works with procs and lambdas" do
82
+
83
+ assert_equal Predicate.from_callable_object(proc{1<2}), Predicate{ Lt(1,2) }
84
+ assert_equal Predicate.from_callable_object(lambda{1<2}), Predicate{ Lt(1,2) }
85
+
86
+ a = "aaa"
87
+ assert_equal Predicate.from_callable_object(proc{a=="bbb"}, binding()),
88
+ Predicate{ Eq("aaa","bbb") }
89
+ assert_equal Predicate.from_callable_object(lambda{a=="bbb"}, binding()),
90
+ Predicate{ Eq("aaa","bbb") }
91
+ end
92
+
93
+ end
94
+
95
+ apropos "errors" do
96
+ test "predicates only" do
97
+ assert_raises(Predicated::Predicate::DontKnowWhatToDoWithThisSexpError) do
98
+ Predicate.from_callable_object{a=1}
99
+ end
100
+ end
101
+ end
102
+ end
@@ -0,0 +1,135 @@
1
+ require "test/test_helper"
2
+
3
+ require "predicated/from/ruby_string"
4
+ include Predicated
5
+
6
+ apropos "parse a ruby predicate string" do
7
+
8
+ apropos "basic operations" do
9
+
10
+ #'Wrong'-style asserts are specifically avoided here.
11
+ #the circularity between the two projects will make you crazy if you're not careful
12
+
13
+ test "simple signs" do
14
+ assert_equal Predicate.from_ruby_string("1==1"), Predicate{ Eq(1,1) }
15
+ assert_equal Predicate.from_ruby_string(" 1 == 1 "), Predicate{ Eq(1,1) }
16
+ assert_equal Predicate.from_ruby_string("0<1"), Predicate{ Lt(0,1) }
17
+ assert_equal Predicate.from_ruby_string("2>1"), Predicate{ Gt(2,1) }
18
+ assert_equal Predicate.from_ruby_string("1<=1"), Predicate{ Lte(1,1) }
19
+ assert_equal Predicate.from_ruby_string("1>=1"), Predicate{ Gte(1,1) }
20
+ end
21
+
22
+ test "primitive types" do
23
+ assert_equal Predicate.from_ruby_string("false==true"), Predicate{ Eq(false,true) }
24
+ assert_equal Predicate.from_ruby_string("'yyy'=='zzz'"), Predicate{ Eq("yyy","zzz") }
25
+ end
26
+
27
+ test "simple and + or" do
28
+ assert_equal Predicate.from_ruby_string("1==1 && 2==2"), Predicate{ And(Eq(1,1),Eq(2,2)) }
29
+ assert_equal Predicate.from_ruby_string("1==1 and 2==2"), Predicate{ And(Eq(1,1),Eq(2,2)) }
30
+ assert_equal Predicate.from_ruby_string("1==1 || 2==2"), Predicate{ Or(Eq(1,1),Eq(2,2)) }
31
+ end
32
+
33
+ class Color
34
+ attr_reader :name
35
+ def initialize(name)
36
+ @name = name
37
+ end
38
+
39
+ def ==(other)
40
+ other.is_a?(Color) && @name == other.name
41
+ end
42
+ end
43
+
44
+ test "substitute in from the binding" do
45
+ a = 1
46
+ b = "1"
47
+ c = "c"
48
+ d = Color.new("purple")
49
+
50
+ assert_equal Predicate.from_ruby_string("a==1", binding()), Predicate{ Eq(1,1) }
51
+ assert_equal Predicate.from_ruby_string("b==1", binding()), Predicate{ Eq("1",1) }
52
+ assert_equal Predicate.from_ruby_string("c==b", binding()), Predicate{ Eq("c","1") }
53
+ assert_equal Predicate.from_ruby_string("d==d", binding()), Predicate{ Eq(Color.new("purple"),
54
+ Color.new("purple")) }
55
+ assert_equal Predicate.from_ruby_string("d==d", binding()).left, d
56
+
57
+ assert_equal Predicate.from_ruby_string("a==b && b==c", binding()),
58
+ Predicate{ And(Eq(1,"1"),Eq("1","c")) }
59
+ end
60
+
61
+
62
+ test "complex and + or" do
63
+ assert_equal Predicate.from_ruby_string("1==1 && 2==2 || 3==3"),
64
+ Predicate{ Or( And(Eq(1,1),Eq(2,2)), Eq(3,3) ) }
65
+ end
66
+
67
+ test "parens change precedence" do
68
+ assert_equal Predicate.from_ruby_string("1==1 || 2==2 && 3==3"),
69
+ Predicate{ Or( Eq(1,1), And(Eq(2,2),Eq(3,3)) ) }
70
+
71
+ assert_equal Predicate.from_ruby_string("(1==1 || 2==2) && 3==3"),
72
+ Predicate{ And( Or(Eq(1,1),Eq(2,2)), Eq(3,3) ) }
73
+ end
74
+
75
+ apropos "only pay attention to the final line" do
76
+ #might hate myself one day for this. but what else does it make sense to do?
77
+
78
+ test "simple" do
79
+ assert_equal Predicate.from_ruby_string("z=2\nb=5\n1==1"), Predicate{ Eq(1,1) }
80
+ end
81
+
82
+ test "can make use of variables defined earlier in the block" do
83
+ #might hate myself one day for this. but what else does it make sense to do?
84
+ assert_equal Predicate.from_ruby_string("z=2\nb=5\nz==1"), Predicate{ Eq(2,1) }
85
+ end
86
+ end
87
+
88
+ test "a call that returns a boolean result" do
89
+ assert_equal Predicate.from_ruby_string("'abc'.include?('bc')"),
90
+ Predicate{ Call("abc", :include?, "bc") }
91
+
92
+ color = Color.new("purple")
93
+ assert_equal Predicate.from_ruby_string("color.name.include?('rp')", binding()),
94
+ Predicate{ Call("purple", :include?, "rp") }
95
+
96
+ assert_equal Predicate.from_ruby_string("'abc'.nil?"),
97
+ Predicate{ Call("abc", :nil?, nil) }
98
+ end
99
+
100
+ test "use of instance variables" do
101
+ @a = 1
102
+
103
+ assert_equal Predicate.from_ruby_string("@a==1", binding()), Predicate{ Eq(1,1) }
104
+ end
105
+
106
+ test "use of inline assignments" do
107
+ assert_equal Predicate.from_ruby_string("(a=2)==1 && a==1"),
108
+ Predicate{ And(Eq(2,1), Eq(2,1)) }
109
+ end
110
+
111
+ test "use of inline expressions" do
112
+ assert_equal Predicate.from_ruby_string("(2*1)==1"),
113
+ Predicate{ Eq(2,1) }
114
+
115
+ assert_equal Predicate.from_ruby_string("[2,1].first==1"),
116
+ Predicate{ Eq(2,1) }
117
+ end
118
+
119
+
120
+ end
121
+
122
+ apropos "errors" do
123
+ test "can't parse" do
124
+ assert_raises(Racc::ParseError) do
125
+ Predicate.from_ruby_string("bad ruby @@@@@****()(((")
126
+ end
127
+ end
128
+
129
+ test "predicates only" do
130
+ assert_raises(Predicated::Predicate::DontKnowWhatToDoWithThisSexpError) do
131
+ Predicate.from_ruby_string("a=1")
132
+ end
133
+ end
134
+ end
135
+ end
@@ -0,0 +1,116 @@
1
+ require "test/test_helper_with_wrong"
2
+
3
+ require "predicated/predicate"
4
+ require "predicated/from/url_fragment"
5
+ include Predicated
6
+
7
+ apropos "parse a url fragment, the result is a parse tree" do
8
+
9
+ before do
10
+ @parser = TreetopUrlFragmentParser.new
11
+ end
12
+
13
+ apropos "simple operations" do
14
+
15
+ test "parse" do
16
+ tree = @parser.parse("a=1")
17
+
18
+ assert{ tree.is_a?(Predicated::TreetopUrlFragment::OperationNode) }
19
+ assert{ [tree.left_text, tree.sign_text, tree.right_text] == ["a", "=", "1"] }
20
+
21
+ tree = @parser.parse("a>1")
22
+ assert{ [tree.left_text, tree.sign_text, tree.right_text] == ["a", ">", "1"] }
23
+
24
+ tree = @parser.parse("a<1")
25
+ assert{ [tree.left_text, tree.sign_text, tree.right_text] == ["a", "<", "1"] }
26
+
27
+ tree = @parser.parse("a>=1")
28
+ assert{ [tree.left_text, tree.sign_text, tree.right_text] == ["a", ">=", "1"] }
29
+
30
+ tree = @parser.parse("a<=1")
31
+ assert{ [tree.left_text, tree.sign_text, tree.right_text] == ["a", "<=", "1"] }
32
+ end
33
+
34
+ test "...to predicate" do
35
+ assert{ @parser.parse("a=1").to_predicate == Predicate{Eq("a", "1")} }
36
+ assert{ @parser.parse("a>1").to_predicate == Predicate{Gt("a", "1")} }
37
+ assert{ @parser.parse("a<1").to_predicate == Predicate{Lt("a", "1")} }
38
+ assert{ @parser.parse("a>=1").to_predicate == Predicate{Gte("a", "1")} }
39
+ assert{ @parser.parse("a<=1").to_predicate == Predicate{Lte("a", "1")} }
40
+ end
41
+
42
+ end
43
+
44
+ apropos "simple and" do
45
+ test "parse" do
46
+ tree = @parser.parse("a=1&b=2")
47
+
48
+ assert{ tree.is_a?(Predicated::TreetopUrlFragment::AndNode) }
49
+ assert{ [[tree.left.left_text, tree.left.sign_text, tree.left.right_text],
50
+ [tree.right.left_text, tree.right.sign_text, tree.right.right_text]] ==
51
+ [["a", "=", "1"], ["b", "=", "2"]] }
52
+ end
53
+
54
+ test "...to predicate" do
55
+ assert{ @parser.parse("a=1&b=2").to_predicate == Predicate{ And( Eq("a", "1"),Eq("b", "2") ) } }
56
+ end
57
+ end
58
+
59
+ apropos "simple or" do
60
+ test "parse" do
61
+ tree = @parser.parse("a=1|b=2")
62
+
63
+ assert{ tree.is_a?(Predicated::TreetopUrlFragment::OrNode) }
64
+ assert{ [[tree.left.left_text, tree.left.sign_text, tree.left.right_text],
65
+ [tree.right.left_text, tree.right.sign_text, tree.right.right_text]] ==
66
+ [["a", "=", "1"], ["b", "=", "2"]] }
67
+ end
68
+
69
+ test "...to predicate" do
70
+ assert{ @parser.parse("a=1|b=2").to_predicate == Predicate{ Or( Eq("a", "1"),Eq("b", "2") ) } }
71
+ end
72
+ end
73
+
74
+ apropos "complex and/or" do
75
+ test "many or's" do
76
+ assert{ @parser.parse("a=1|b=2|c=3").to_predicate ==
77
+ Predicate{ Or( Eq("a", "1"), Or(Eq("b", "2"),Eq("c", "3")) ) } }
78
+ end
79
+
80
+ test "many and's" do
81
+ assert{ @parser.parse("a=1&b=2&c=3").to_predicate ==
82
+ Predicate{ And( Eq("a", "1"), And(Eq("b", "2"),Eq("c", "3")) ) } }
83
+ end
84
+
85
+ test "mixed and/or" do
86
+ assert{ @parser.parse("a=1|b=2&c=3").to_predicate ==
87
+ Predicate{ Or( Eq("a", "1"), And(Eq("b", "2"),Eq("c", "3")) ) } }
88
+
89
+ assert{ @parser.parse("a=1&b=2|c=3").to_predicate ==
90
+ Predicate{ Or( And(Eq("a", "1"),Eq("b", "2")), Eq("c", "3") ) } }
91
+ end
92
+ end
93
+
94
+ apropos "parens (force higher precedence)" do
95
+ test "no effect" do
96
+ str = "(a=1|b=2)|c=3"
97
+ assert{ @parser.parse(str).to_predicate ==
98
+ Predicate{ Or( Or(Eq("a", "1"),Eq("b", "2")), Eq("c", "3") ) } }
99
+
100
+ str = "((a=1|b=2))|c=3"
101
+ assert{ @parser.parse(str).to_predicate ==
102
+ Predicate{ Or( Or(Eq("a", "1"),Eq("b", "2")), Eq("c", "3") ) } }
103
+ end
104
+
105
+ test "force precedence" do
106
+ #before
107
+ assert{ @parser.parse("a=1|b=2&c=3").to_predicate ==
108
+ Predicate{ Or( Eq("a", "1"), And(Eq("b", "2"),Eq("c", "3")) ) } }
109
+
110
+ #after
111
+ assert{ @parser.parse("(a=1|b=2)&c=3").to_predicate ==
112
+ Predicate{ And( Or(Eq("a", "1"),Eq("b", "2")), Eq("c", "3") ) } }
113
+ end
114
+ end
115
+
116
+ end
@@ -0,0 +1,37 @@
1
+ require "test/test_helper_with_wrong"
2
+
3
+ require "predicated/from/url_fragment"
4
+ include Predicated
5
+
6
+ apropos "parse url fragments and convert them into predicates" do
7
+
8
+ apropos "basic operations" do
9
+
10
+ test "simple signs" do
11
+ assert { Predicate.from_url_fragment("a=1") == Predicate{ Eq("a","1") } }
12
+ assert { Predicate.from_url_fragment("a<1") == Predicate{ Lt("a","1") } }
13
+ assert { Predicate.from_url_fragment("a>1") == Predicate{ Gt("a","1") } }
14
+ assert { Predicate.from_url_fragment("a<=1") == Predicate{ Lte("a","1") } }
15
+ assert { Predicate.from_url_fragment("a>=1") == Predicate{ Gte("a","1") } }
16
+ end
17
+
18
+ test "simple and + or" do
19
+ assert { Predicate.from_url_fragment("a=1&b=2") == Predicate{ And(Eq("a","1"),Eq("b","2")) } }
20
+ assert { Predicate.from_url_fragment("a=1|b=2") == Predicate{ Or(Eq("a","1"),Eq("b","2")) } }
21
+ end
22
+
23
+ test "complex and + or" do
24
+ assert { Predicate.from_url_fragment("a=1&b=2|c=3") ==
25
+ Predicate{ Or( And(Eq("a","1"),Eq("b","2")), Eq("c","3") ) } }
26
+ end
27
+
28
+ test "parens change precedence" do
29
+ assert { Predicate.from_url_fragment("a=1|b=2&c=3") ==
30
+ Predicate{ Or( Eq("a","1"), And(Eq("b","2"),Eq("c","3")) ) } }
31
+
32
+ assert { Predicate.from_url_fragment("(a=1|b=2)&c=3") ==
33
+ Predicate{ And( Or(Eq("a","1"),Eq("b","2")), Eq("c","3") ) } }
34
+ end
35
+
36
+ end
37
+ end
@@ -0,0 +1,65 @@
1
+ require "test/test_helper_with_wrong"
2
+
3
+ require "predicated/predicate"
4
+ include Predicated
5
+
6
+ apropos "a predicate looks nice with you inspect it" do
7
+ test "numbers" do
8
+ assert { Predicate { Eq(1, 1) }.inspect == "Eq(1,1)" }
9
+ assert { Predicate { Lt(1, 2) }.inspect == "Lt(1,2)" }
10
+ end
11
+
12
+ test "booleans" do
13
+ assert { Predicate { Eq(false, true) }.inspect == "Eq(false,true)" }
14
+ end
15
+
16
+ test "strings" do
17
+ assert { Predicate { Eq("foo", "bar") }.inspect == "Eq('foo','bar')" }
18
+ end
19
+
20
+ class Color
21
+ attr_reader :name
22
+ def initialize(name)
23
+ @name = name
24
+ end
25
+
26
+ def to_s
27
+ "name:#{@name}"
28
+ end
29
+ end
30
+
31
+ test "objects" do
32
+ assert { Predicate { Eq(Color.new("red"), Color.new("blue")) }.inspect == "Eq(Color{'name:red'},Color{'name:blue'})" }
33
+ end
34
+
35
+ test "and, or" do
36
+ assert { Predicate { And(true, false) }.inspect == "And(true,false)" }
37
+ assert { Predicate { Or(true, false) }.inspect == "Or(true,false)" }
38
+
39
+ assert { Predicate { And(Eq(1, 1) , Eq(2, 2)) }.inspect == "And(Eq(1,1),Eq(2,2))" }
40
+
41
+ assert { Predicate { And(Eq(1, 1), Or(Eq(2, 2), Eq(3, 3))) }.inspect == "And(Eq(1,1),Or(Eq(2,2),Eq(3,3)))" }
42
+ end
43
+
44
+ end
45
+
46
+ apropos "to_s is like inspect except it's multiline, so you see the tree structure" do
47
+
48
+ test "an uncomplicated predicate prints on one line" do
49
+ assert { Predicate { Eq(1, 1) }.to_s == "Eq(1,1)" }
50
+ end
51
+
52
+ test "complex" do
53
+ assert {
54
+ Predicate { And(Eq(1, 1), Or(Eq(2, 2), Eq(3, 3))) }.to_s ==
55
+ %{And(
56
+ Eq(1,1),
57
+ Or(
58
+ Eq(2,2),
59
+ Eq(3,3)
60
+ )
61
+ )
62
+ }
63
+ }
64
+ end
65
+ end