predicated 0.1.0 → 0.2.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 (51) hide show
  1. data/README.markdown +183 -1
  2. data/lib/predicated.rb +1 -3
  3. data/lib/predicated/constrain.rb +2 -0
  4. data/lib/predicated/evaluate.rb +25 -6
  5. data/lib/predicated/from/callable_object.rb +7 -8
  6. data/lib/predicated/from/json.rb +59 -0
  7. data/lib/predicated/from/{ruby_string.rb → ruby_code_string.rb} +13 -5
  8. data/lib/predicated/from/{url_fragment.rb → url_part.rb} +17 -10
  9. data/lib/predicated/from/xml.rb +61 -0
  10. data/lib/predicated/predicate.rb +62 -43
  11. data/lib/predicated/print.rb +28 -16
  12. data/lib/predicated/selectable.rb +102 -0
  13. data/lib/predicated/simple_templated_predicate.rb +79 -0
  14. data/lib/predicated/string_utils.rb +20 -0
  15. data/lib/predicated/to/arel.rb +28 -22
  16. data/lib/predicated/to/json.rb +48 -0
  17. data/lib/predicated/to/sentence.rb +17 -14
  18. data/lib/predicated/to/solr.rb +15 -0
  19. data/lib/predicated/to/xml.rb +67 -0
  20. data/lib/predicated/version.rb +2 -2
  21. data/test/canonical_transform_cases.rb +67 -0
  22. data/test/constrain_test.rb +20 -11
  23. data/test/enumerable_test.rb +6 -34
  24. data/test/equality_test.rb +15 -4
  25. data/test/evaluate_test.rb +31 -26
  26. data/test/from/callable_object_canonical_test.rb +43 -0
  27. data/test/from/callable_object_test.rb +16 -40
  28. data/test/from/json_test.rb +83 -0
  29. data/test/from/ruby_code_string_canonical_test.rb +37 -0
  30. data/test/from/ruby_code_string_test.rb +103 -0
  31. data/test/from/{url_fragment_parser_test.rb → url_part_parser_test.rb} +20 -13
  32. data/test/from/url_part_test.rb +48 -0
  33. data/test/from/xml_test.rb +57 -0
  34. data/test/json_conversion_test.rb +33 -0
  35. data/test/print_test.rb +26 -25
  36. data/test/selectable_test.rb +123 -0
  37. data/test/simple_templated_predicate_test.rb +39 -0
  38. data/test/suite.rb +2 -4
  39. data/test/test_helper.rb +26 -4
  40. data/test/test_helper_with_wrong.rb +3 -2
  41. data/test/to/arel_test.rb +71 -31
  42. data/test/to/json_test.rb +74 -0
  43. data/test/to/sentence_test.rb +41 -34
  44. data/test/to/solr_test.rb +39 -0
  45. data/test/to/xml_test.rb +72 -0
  46. data/test/xml_conversion_test.rb +34 -0
  47. metadata +44 -16
  48. data/lib/predicated/selector.rb +0 -55
  49. data/test/from/ruby_string_test.rb +0 -135
  50. data/test/from/url_fragment_test.rb +0 -37
  51. data/test/selector_test.rb +0 -82
@@ -1,11 +1,11 @@
1
- require "test/test_helper_with_wrong"
1
+ require "./test/test_helper_with_wrong"
2
2
 
3
3
  require "predicated/evaluate"
4
4
  include Predicated
5
5
 
6
- apropos "evaluate a predicate as boolean logic in ruby. change the context by providing and optional binding." do
6
+ regarding "evaluate a predicate as boolean logic in ruby. change the context by providing and optional binding." do
7
7
 
8
- apropos "proving out basic operations" do
8
+ regarding "proving out basic operations" do
9
9
  test "equals" do
10
10
  assert { Predicate { Eq(1, 1) }.evaluate }
11
11
  deny { Predicate { Eq(1, 2) }.evaluate }
@@ -36,7 +36,7 @@ apropos "evaluate a predicate as boolean logic in ruby. change the context by p
36
36
  end
37
37
  end
38
38
 
39
- apropos "comparing values of different data types" do
39
+ regarding "comparing values of different data types" do
40
40
  test "strings" do
41
41
  assert { Predicate { Eq("1", "1") }.evaluate }
42
42
  deny { Predicate { Eq("1", 1) }.evaluate }
@@ -62,17 +62,6 @@ apropos "evaluate a predicate as boolean logic in ruby. change the context by p
62
62
  deny { Predicate { Eq(1, nil) }.evaluate }
63
63
  end
64
64
 
65
- class Color
66
- attr_reader :name
67
- def initialize(name)
68
- @name = name
69
- end
70
-
71
- def ==(other)
72
- other.is_a?(Color) && @name == other.name
73
- end
74
- end
75
-
76
65
  test "objects" do
77
66
  assert { Predicate { Eq(Color.new("red"), Color.new("red")) }.evaluate }
78
67
  deny { Predicate { Eq(Color.new("red"), Color.new("BLUE")) }.evaluate }
@@ -83,7 +72,7 @@ apropos "evaluate a predicate as boolean logic in ruby. change the context by p
83
72
  end
84
73
 
85
74
 
86
- apropos "and" do
75
+ regarding "and" do
87
76
  test "left and right must be true" do
88
77
  assert { Predicate { And( Eq(1, 1), Eq(2, 2) ) }.evaluate }
89
78
  deny { Predicate { And( Eq(99, 1), Eq(2, 2) ) }.evaluate }
@@ -104,7 +93,7 @@ apropos "evaluate a predicate as boolean logic in ruby. change the context by p
104
93
  end
105
94
  end
106
95
 
107
- apropos "or" do
96
+ regarding "or" do
108
97
  test "one of left or right must be true" do
109
98
  assert { Predicate { Or(true, true) }.evaluate }
110
99
  assert { Predicate { Or(true, false) }.evaluate }
@@ -113,32 +102,48 @@ apropos "evaluate a predicate as boolean logic in ruby. change the context by p
113
102
  end
114
103
  end
115
104
 
116
- apropos "evaluate adds a generic 'call' class. that is, object.message(args)" do
105
+ regarding "not" do
106
+ test "simple negation" do
107
+ assert { Predicate { Not(Eq(3, 2)) }.evaluate }
108
+ deny { Predicate { Not(Eq(2, 2)) }.evaluate }
109
+ end
110
+
111
+ test "complex" do
112
+ assert { Predicate { Not( And(Eq(2, 2),false) ) }.evaluate }
113
+ deny { Predicate { Not( And(Eq(2, 2),true) ) }.evaluate }
114
+ end
115
+ end
116
+
117
+ regarding "evaluate adds a generic 'call' class. that is, object.message(args)" do
117
118
  test "evaluate simple calls" do
118
119
  assert { Predicate { Call("abc", :include?, "bc") }.evaluate }
119
- deny { Predicate { Call("abc", :include?, "ZZ") }.evaluate }
120
+ deny { Predicate { Call("abc", :include?, "ZZ") }.evaluate }
120
121
  end
121
122
 
122
123
  test "nil call. call defaults to no args if none are specified" do
123
124
  assert { Predicate { Call(nil, :nil?, []) }.evaluate }
124
- deny { Predicate { Call("abc", :nil?, []) }.evaluate }
125
+ deny { Predicate { Call("abc", :nil?, []) }.evaluate }
125
126
 
126
127
  assert { Predicate { Call(nil, :nil?) }.evaluate }
127
- deny { Predicate { Call("abc", :nil?) }.evaluate }
128
+ deny { Predicate { Call("abc", :nil?) }.evaluate }
128
129
  end
129
130
 
130
131
  test "inspect" do
131
- assert{ Call.new("abc", :include?, "bc").inspect == "Call('abc'.include?('bc'))" }
132
+ assert { Call.new("abc", :include?, "bc").inspect == "Call('abc'.include?('bc'))" }
133
+ end
134
+
135
+ test "inspect, empty right hand side" do
136
+ assert { Call.new("abc", :nil?).inspect == "Call('abc'.nil?)" }
132
137
  end
133
138
 
134
139
  test "call equality" do
135
140
  assert { Call.new("abc", :include?, "bc") == Call.new("abc", :include?, "bc") }
136
- deny { Call.new("ZZZ", :include?, "bc") == Call.new("abc", :include?, "bc") }
137
- deny { Call.new("abc", :zzz, "bc") == Call.new("abc", :include?, "bc") }
138
- deny { Call.new("abc", :include?, "ZZZ") == Call.new("abc", :include?, "bc") }
141
+ deny { Call.new("ZZZ", :include?, "bc") == Call.new("abc", :include?, "bc") }
142
+ deny { Call.new("abc", :zzz, "bc") == Call.new("abc", :include?, "bc") }
143
+ deny { Call.new("abc", :include?, "ZZZ") == Call.new("abc", :include?, "bc") }
139
144
  end
140
145
 
141
146
 
142
147
  end
143
148
 
144
- end
149
+ end
@@ -0,0 +1,43 @@
1
+ require "./test/test_helper_with_wrong"
2
+ require "./test/canonical_transform_cases"
3
+
4
+ if RUBY_VERSION =~/^1.9/
5
+ puts "skipping callable object-related tests in 1.9"
6
+ else
7
+
8
+ require "predicated/from/callable_object"
9
+ include Predicated
10
+
11
+ regarding "callable object - canoical transform cases" do
12
+ include CanonicalTransformCases
13
+
14
+ @expectations = {
15
+ "simple operations" => {
16
+ "eq" => Predicate.from_callable_object{"a"==3},
17
+ "gt" => Predicate.from_callable_object{"a">3},
18
+ "lt" => Predicate.from_callable_object{"a"<3},
19
+ "gte" => Predicate.from_callable_object{"a">=3},
20
+ "lte" => Predicate.from_callable_object{"a"<=3}
21
+ },
22
+ "primitive types" => {
23
+ "false" => Predicate.from_callable_object{"a"==false},
24
+ "true" => Predicate.from_callable_object{"a"==true},
25
+ "string" => Predicate.from_callable_object{"a"=="yyy"}
26
+ },
27
+ "not" => {
28
+ "simple" => Predicate.from_callable_object{!("a"==true)}
29
+ },
30
+ "simple and / or" => {
31
+ #parens are necessary around AND's in solr in order to force precedence
32
+ "and" => Predicate.from_callable_object{"a"==1 && "b"==2},
33
+ "or" => Predicate.from_callable_object{"a"==1 || "b"==2}
34
+ },
35
+ "complex and / or" => {
36
+ "or and" => Predicate.from_callable_object{"a"==1 && "b"==2 || "c"==3}
37
+ }
38
+ }
39
+
40
+ create_canonical_tests(@expectations)
41
+ end
42
+
43
+ end
@@ -1,25 +1,17 @@
1
- require "test/test_helper"
1
+ require "./test/test_helper"
2
+ require "./test/canonical_transform_cases"
2
3
 
3
- require "predicated/from/callable_object"
4
- include Predicated
5
4
 
6
- apropos "convert a ruby callable object - a proc or lambda - into a predicate" do
5
+ if RUBY_VERSION =~/^1.9/
6
+ puts "skipping callable object-related tests in 1.9"
7
+ else
7
8
 
8
- apropos "basic operations" do
9
+ require "predicated/from/callable_object"
10
+ include Predicated
11
+
12
+ regarding "convert a ruby callable object - a proc or lambda - into a predicate" do
9
13
 
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
14
+ regarding "basic operations" do
23
15
 
24
16
  test "complex types" do
25
17
  assert_equal Predicate.from_callable_object{Color.new("red")==Color.new("blue")},
@@ -29,24 +21,11 @@ apropos "convert a ruby callable object - a proc or lambda - into a predicate" d
29
21
  Predicate{ Eq({1=>2},{"a"=>"b"}) }
30
22
  end
31
23
 
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)) }
24
+ test "word and / or" do
34
25
  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
26
  assert_equal Predicate.from_callable_object{1==1 or 2==2}, Predicate{ Or(Eq(1,1),Eq(2,2)) }
37
27
  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
-
28
+
50
29
  test "substitute in from the binding" do
51
30
  a = 1
52
31
  b = "1"
@@ -65,11 +44,6 @@ apropos "convert a ruby callable object - a proc or lambda - into a predicate" d
65
44
  end
66
45
 
67
46
 
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
47
  test "parens change precedence" do
74
48
  assert_equal Predicate.from_callable_object{1==1 || 2==2 && 3==3},
75
49
  Predicate{ Or( Eq(1,1), And(Eq(2,2),Eq(3,3)) ) }
@@ -92,11 +66,13 @@ apropos "convert a ruby callable object - a proc or lambda - into a predicate" d
92
66
 
93
67
  end
94
68
 
95
- apropos "errors" do
69
+ regarding "errors" do
96
70
  test "predicates only" do
97
71
  assert_raises(Predicated::Predicate::DontKnowWhatToDoWithThisSexpError) do
98
72
  Predicate.from_callable_object{a=1}
99
73
  end
100
74
  end
101
75
  end
102
- end
76
+ end
77
+
78
+ end
@@ -0,0 +1,83 @@
1
+ require "./test/test_helper_with_wrong"
2
+
3
+ require "predicated/from/json"
4
+ require "./test/canonical_transform_cases"
5
+ include Predicated
6
+
7
+ regarding "convert a json string to a predicate" do
8
+ include CanonicalTransformCases
9
+
10
+ @expectations = {
11
+ "simple operations" => {
12
+ "eq" => Predicate.from_json_str(%{["a","==",3]}),
13
+ "gt" => Predicate.from_json_str(%{["a",">",3]}),
14
+ "lt" => Predicate.from_json_str(%{["a","<",3]}),
15
+ "gte" => Predicate.from_json_str(%{["a",">=",3]}),
16
+ "lte" => Predicate.from_json_str(%{["a","<=",3]})
17
+ },
18
+ "primitive types" => {
19
+ "false" => Predicate.from_json_str(%{["a","==",false]}),
20
+ "true" => Predicate.from_json_str(%{["a","==",true]}),
21
+ "string" => Predicate.from_json_str(%{["a","==","yyy"]})
22
+ },
23
+ "not" => {
24
+ "simple" => Predicate.from_json_str(%{{"not":["a","==",true]}})
25
+ },
26
+ "simple and / or" => {
27
+ #parens are necessary around AND's in solr in order to force precedence
28
+ "and" => Predicate.from_json_str(%{{"and":[["a","==",1],["b","==",2]]}}),
29
+ "or" => Predicate.from_json_str(%{{"or":[["a","==",1],["b","==",2]]}})
30
+ },
31
+ "complex and / or" => {
32
+ "or and" => Predicate.from_json_str(%{
33
+ {
34
+ "or":[
35
+ {"and":[["a","==",1],["b","==",2]]},
36
+ ["c","==",3]
37
+ ]
38
+ }
39
+ })
40
+ }
41
+ }
42
+
43
+ create_canonical_tests(@expectations)
44
+
45
+ end
46
+
47
+ regarding "convert a json structure to a predicate" do
48
+ include CanonicalTransformCases
49
+
50
+ @expectations = {
51
+ "simple operations" => {
52
+ "eq" => Predicate.from_json_struct(["a", "==", 3]),
53
+ "gt" => Predicate.from_json_struct(["a", ">", 3]),
54
+ "lt" => Predicate.from_json_struct(["a", "<", 3]),
55
+ "gte" => Predicate.from_json_struct(["a", ">=", 3]),
56
+ "lte" => Predicate.from_json_struct(["a", "<=", 3])
57
+ },
58
+ "primitive types" => {
59
+ "false" => Predicate.from_json_struct(["a", "==", false]),
60
+ "true" => Predicate.from_json_struct(["a", "==", true]),
61
+ "string" => Predicate.from_json_struct(["a", "==", "yyy"])
62
+ },
63
+ "not" => {
64
+ "simple" => Predicate.from_json_struct("not" => ["a", "==", true])
65
+ },
66
+ "simple and / or" => {
67
+ #parens are necessary around AND's in solr in order to force precedence
68
+ "and" => Predicate.from_json_struct("and" => [["a", "==", 1],["b", "==", 2]]),
69
+ "or" => Predicate.from_json_struct("or" => [["a", "==", 1],["b", "==", 2]])
70
+ },
71
+ "complex and / or" => {
72
+ "or and" => Predicate.from_json_struct(
73
+ "or" => [
74
+ {"and" => [["a", "==", 1],["b", "==", 2]]},
75
+ ["c", "==", 3]
76
+ ]
77
+ )
78
+ }
79
+ }
80
+
81
+ create_canonical_tests(@expectations)
82
+
83
+ end
@@ -0,0 +1,37 @@
1
+ require "./test/test_helper_with_wrong"
2
+ require "./test/canonical_transform_cases"
3
+
4
+ require "predicated/from/ruby_code_string"
5
+ include Predicated
6
+
7
+ regarding "ruby code string - canoical transform cases" do
8
+ include CanonicalTransformCases
9
+
10
+ @expectations = {
11
+ "simple operations" => {
12
+ "eq" => Predicate.from_ruby_code_string("'a'==3"),
13
+ "gt" => Predicate.from_ruby_code_string("'a'>3"),
14
+ "lt" => Predicate.from_ruby_code_string("'a'<3"),
15
+ "gte" => Predicate.from_ruby_code_string("'a'>=3"),
16
+ "lte" => Predicate.from_ruby_code_string("'a'<=3")
17
+ },
18
+ "primitive types" => {
19
+ "false" => Predicate.from_ruby_code_string("'a'==false"),
20
+ "true" => Predicate.from_ruby_code_string("'a'==true"),
21
+ "string" => Predicate.from_ruby_code_string("'a'=='yyy'"),
22
+ },
23
+ "not" => {
24
+ "simple" => Predicate.from_ruby_code_string("!('a'==true)")
25
+ },
26
+ "simple and / or" => {
27
+ #parens are necessary around AND's in solr in order to force precedence
28
+ "and" => Predicate.from_ruby_code_string("'a'==1 && 'b'==2"),
29
+ "or" => Predicate.from_ruby_code_string("'a'==1 || 'b'==2")
30
+ },
31
+ "complex and / or" => {
32
+ "or and" => Predicate.from_ruby_code_string("'a'==1 && 'b'==2 || 'c'==3")
33
+ }
34
+ }
35
+
36
+ create_canonical_tests(@expectations)
37
+ end
@@ -0,0 +1,103 @@
1
+ require "./test/test_helper"
2
+
3
+ require "predicated/from/ruby_code_string"
4
+ include Predicated
5
+
6
+ regarding "parse a ruby predicate string" do
7
+
8
+ regarding "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 "word and" do
14
+ assert_equal Predicate.from_ruby_code_string("1==1 and 2==2"), Predicate{ And(Eq(1,1),Eq(2,2)) }
15
+ end
16
+
17
+ test "substitute in from the binding" do
18
+ a = 1
19
+ b = "1"
20
+ c = "c"
21
+ d = Color.new("purple")
22
+
23
+ assert_equal Predicate.from_ruby_code_string("a==1", binding()), Predicate{ Eq(1,1) }
24
+ assert_equal Predicate.from_ruby_code_string("b==1", binding()), Predicate{ Eq("1",1) }
25
+ assert_equal Predicate.from_ruby_code_string("c==b", binding()), Predicate{ Eq("c","1") }
26
+ assert_equal Predicate.from_ruby_code_string("d==d", binding()), Predicate{ Eq(Color.new("purple"),
27
+ Color.new("purple")) }
28
+ assert_equal Predicate.from_ruby_code_string("d==d", binding()).left, d
29
+
30
+ assert_equal Predicate.from_ruby_code_string("a==b && b==c", binding()),
31
+ Predicate{ And(Eq(1,"1"),Eq("1","c")) }
32
+ end
33
+
34
+
35
+ test "parens change precedence" do
36
+ assert_equal Predicate.from_ruby_code_string("1==1 || 2==2 && 3==3"),
37
+ Predicate{ Or( Eq(1,1), And(Eq(2,2),Eq(3,3)) ) }
38
+
39
+ assert_equal Predicate.from_ruby_code_string("(1==1 || 2==2) && 3==3"),
40
+ Predicate{ And( Or(Eq(1,1),Eq(2,2)), Eq(3,3) ) }
41
+ end
42
+
43
+ regarding "only pay attention to the final line" do
44
+ #might hate myself one day for this. but what else does it make sense to do?
45
+
46
+ test "simple" do
47
+ assert_equal Predicate.from_ruby_code_string("z=2\nb=5\n1==1"), Predicate{ Eq(1,1) }
48
+ end
49
+
50
+ test "can make use of variables defined earlier in the block" do
51
+ #might hate myself one day for this. but what else does it make sense to do?
52
+ assert_equal Predicate.from_ruby_code_string("z=2\nb=5\nz==1"), Predicate{ Eq(2,1) }
53
+ end
54
+ end
55
+
56
+ test "a call that returns a boolean result" do
57
+ assert_equal Predicate.from_ruby_code_string("'abc'.include?('bc')"),
58
+ Predicate{ Call("abc", :include?, "bc") }
59
+
60
+ color = Color.new("purple")
61
+ assert_equal Predicate.from_ruby_code_string("color.name.include?('rp')", binding()),
62
+ Predicate{ Call("purple", :include?, "rp") }
63
+
64
+ assert_equal Predicate.from_ruby_code_string("'abc'.nil?"),
65
+ Predicate{ Call("abc", :nil?, nil) }
66
+ end
67
+
68
+ test "use of instance variables" do
69
+ @a = 1
70
+
71
+ assert_equal Predicate.from_ruby_code_string("@a==1", binding()), Predicate{ Eq(1,1) }
72
+ end
73
+
74
+ test "use of inline assignments" do
75
+ assert_equal Predicate.from_ruby_code_string("(a=2)==1 && a==1"),
76
+ Predicate{ And(Eq(2,1), Eq(2,1)) }
77
+ end
78
+
79
+ test "use of inline expressions" do
80
+ assert_equal Predicate.from_ruby_code_string("(2*1)==1"),
81
+ Predicate{ Eq(2,1) }
82
+
83
+ assert_equal Predicate.from_ruby_code_string("[2,1].first==1"),
84
+ Predicate{ Eq(2,1) }
85
+ end
86
+
87
+
88
+ end
89
+
90
+ regarding "errors" do
91
+ test "can't parse" do
92
+ assert_raises(Racc::ParseError) do
93
+ Predicate.from_ruby_code_string("bad ruby @@@@@****()(((")
94
+ end
95
+ end
96
+
97
+ test "predicates only" do
98
+ assert_raises(Predicated::Predicate::DontKnowWhatToDoWithThisSexpError) do
99
+ Predicate.from_ruby_code_string("a=1")
100
+ end
101
+ end
102
+ end
103
+ end