predicate 2.3.0 → 2.5.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 +4 -4
- data/Gemfile +4 -0
- data/LICENSE.md +17 -19
- data/README.md +433 -0
- data/bin/g +2 -0
- data/lib/predicate.rb +26 -2
- data/lib/predicate/dsl.rb +138 -0
- data/lib/predicate/factory.rb +130 -33
- data/lib/predicate/grammar.rb +11 -2
- data/lib/predicate/grammar.sexp.yml +29 -0
- data/lib/predicate/nodes/${op_name}.rb.jeny +12 -0
- data/lib/predicate/nodes/and.rb +9 -0
- data/lib/predicate/nodes/binary_func.rb +20 -0
- data/lib/predicate/nodes/contradiction.rb +2 -7
- data/lib/predicate/nodes/dyadic_comp.rb +3 -5
- data/lib/predicate/nodes/empty.rb +14 -0
- data/lib/predicate/nodes/eq.rb +13 -6
- data/lib/predicate/nodes/expr.rb +9 -3
- data/lib/predicate/nodes/has_size.rb +14 -0
- data/lib/predicate/nodes/identifier.rb +1 -3
- data/lib/predicate/nodes/in.rb +9 -8
- data/lib/predicate/nodes/intersect.rb +3 -23
- data/lib/predicate/nodes/literal.rb +1 -3
- data/lib/predicate/nodes/match.rb +1 -21
- data/lib/predicate/nodes/nadic_bool.rb +1 -3
- data/lib/predicate/nodes/native.rb +1 -3
- data/lib/predicate/nodes/not.rb +1 -3
- data/lib/predicate/nodes/opaque.rb +1 -3
- data/lib/predicate/nodes/qualified_identifier.rb +2 -4
- data/lib/predicate/nodes/set_op.rb +26 -0
- data/lib/predicate/nodes/subset.rb +11 -0
- data/lib/predicate/nodes/superset.rb +11 -0
- data/lib/predicate/nodes/tautology.rb +6 -7
- data/lib/predicate/nodes/unary_func.rb +16 -0
- data/lib/predicate/nodes/var.rb +46 -0
- data/lib/predicate/processors.rb +1 -0
- data/lib/predicate/processors/qualifier.rb +4 -0
- data/lib/predicate/processors/renamer.rb +4 -0
- data/lib/predicate/processors/to_s.rb +28 -0
- data/lib/predicate/processors/unqualifier.rb +21 -0
- data/lib/predicate/sequel/to_sequel.rb +4 -1
- data/lib/predicate/sugar.rb +47 -0
- data/lib/predicate/version.rb +1 -1
- data/spec/dsl/test_dsl.rb +204 -0
- data/spec/dsl/test_evaluate.rb +65 -0
- data/spec/dsl/test_respond_to_missing.rb +35 -0
- data/spec/dsl/test_to_skake_case.rb +38 -0
- data/spec/factory/shared/a_comparison_factory_method.rb +1 -0
- data/spec/factory/test_${op_name}.rb.jeny +12 -0
- data/spec/factory/test_empty.rb +11 -0
- data/spec/factory/test_has_size.rb +11 -0
- data/spec/factory/test_match.rb +1 -0
- data/spec/factory/test_set_ops.rb +18 -0
- data/spec/factory/test_var.rb +22 -0
- data/spec/factory/test_vars.rb +27 -0
- data/spec/nodes/${op_name}.jeny/test_evaluate.rb.jeny +19 -0
- data/spec/nodes/empty/test_evaluate.rb +42 -0
- data/spec/nodes/eq/test_and.rb +6 -0
- data/spec/nodes/has_size/test_evaluate.rb +44 -0
- data/spec/nodes/qualified_identifier/test_and_split.rb +1 -1
- data/spec/nodes/qualified_identifier/test_free_variables.rb +1 -1
- data/spec/predicate/test_and_split.rb +18 -0
- data/spec/predicate/test_attr_split.rb +18 -0
- data/spec/predicate/test_bool_and.rb +11 -0
- data/spec/predicate/test_constant_variables.rb +24 -2
- data/spec/predicate/test_constants.rb +24 -0
- data/spec/predicate/test_evaluate.rb +205 -3
- data/spec/predicate/test_free_variables.rb +1 -1
- data/spec/predicate/test_to_hash.rb +40 -0
- data/spec/predicate/test_to_s.rb +37 -0
- data/spec/predicate/test_unqualify.rb +18 -0
- data/spec/sequel/test_to_sequel.rb +16 -0
- data/spec/shared/a_predicate.rb +30 -0
- data/spec/spec_helper.rb +1 -0
- data/spec/test_predicate.rb +68 -33
- data/spec/test_readme.rb +80 -0
- data/spec/test_sugar.rb +48 -0
- data/tasks/test.rake +3 -3
- metadata +43 -13
- data/spec/factory/test_between.rb +0 -12
- data/spec/factory/test_intersect.rb +0 -12
@@ -3,6 +3,8 @@ rules:
|
|
3
3
|
- tautology
|
4
4
|
- contradiction
|
5
5
|
- identifier
|
6
|
+
- qualified_identifier
|
7
|
+
- var
|
6
8
|
- not
|
7
9
|
- and
|
8
10
|
- or
|
@@ -14,8 +16,13 @@ rules:
|
|
14
16
|
- gte
|
15
17
|
- in
|
16
18
|
- intersect
|
19
|
+
- subset
|
20
|
+
- superset
|
17
21
|
- match
|
18
22
|
- native
|
23
|
+
- empty
|
24
|
+
- has_size
|
25
|
+
#jeny(predicate) - ${op_name}
|
19
26
|
tautology:
|
20
27
|
- [ true ]
|
21
28
|
contradiction:
|
@@ -24,6 +31,8 @@ rules:
|
|
24
31
|
- [ name ]
|
25
32
|
qualified_identifier:
|
26
33
|
- [ name, name ]
|
34
|
+
var:
|
35
|
+
- [ formaldef, semantics ]
|
27
36
|
not:
|
28
37
|
- [ predicate ]
|
29
38
|
and:
|
@@ -46,8 +55,18 @@ rules:
|
|
46
55
|
- [ varref, term ]
|
47
56
|
intersect:
|
48
57
|
- [ term, term ]
|
58
|
+
subset:
|
59
|
+
- [ term, term ]
|
60
|
+
superset:
|
61
|
+
- [ term, term ]
|
49
62
|
match:
|
50
63
|
- [ term, term, options ]
|
64
|
+
empty:
|
65
|
+
- [ term ]
|
66
|
+
has_size:
|
67
|
+
- [ term, term ]
|
68
|
+
#jeny(predicate) ${op_name}:
|
69
|
+
#jeny(predicate) - [ TODO ]
|
51
70
|
term:
|
52
71
|
- varref
|
53
72
|
- literal
|
@@ -56,6 +75,7 @@ rules:
|
|
56
75
|
varref:
|
57
76
|
- qualified_identifier
|
58
77
|
- identifier
|
78
|
+
- var
|
59
79
|
native:
|
60
80
|
- [ "::Proc" ]
|
61
81
|
literal:
|
@@ -68,3 +88,12 @@ rules:
|
|
68
88
|
- "::Hash"
|
69
89
|
name:
|
70
90
|
!ruby/regexp /^[a-zA-Z0-9_]+[?!]?$/
|
91
|
+
semantics:
|
92
|
+
!ruby/regexp /^(dig)$/
|
93
|
+
formaldef:
|
94
|
+
- string_formaldef
|
95
|
+
- array_formaldef
|
96
|
+
string_formaldef:
|
97
|
+
- "::String"
|
98
|
+
array_formaldef:
|
99
|
+
- "::Array"
|
data/lib/predicate/nodes/and.rb
CHANGED
@@ -0,0 +1,20 @@
|
|
1
|
+
class Predicate
|
2
|
+
module BinaryFunc
|
3
|
+
include Expr
|
4
|
+
|
5
|
+
def priority; 80; end
|
6
|
+
|
7
|
+
def left
|
8
|
+
self[1]
|
9
|
+
end
|
10
|
+
|
11
|
+
def right
|
12
|
+
self[2]
|
13
|
+
end
|
14
|
+
|
15
|
+
def free_variables
|
16
|
+
@free_variables ||= left.free_variables | right.free_variables
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
end
|
@@ -2,9 +2,7 @@ class Predicate
|
|
2
2
|
module DyadicComp
|
3
3
|
include Expr
|
4
4
|
|
5
|
-
def priority
|
6
|
-
50
|
7
|
-
end
|
5
|
+
def priority; 50; end
|
8
6
|
|
9
7
|
def !
|
10
8
|
Factory.send(OP_NEGATIONS[first], self[1], self[2])
|
@@ -22,8 +20,8 @@ class Predicate
|
|
22
20
|
@free_variables ||= left.free_variables | right.free_variables
|
23
21
|
end
|
24
22
|
|
25
|
-
def
|
26
|
-
left.identifier? && right.literal?
|
23
|
+
def var_against_literal_value?
|
24
|
+
left.identifier? && right.literal? && !right.has_placeholder?
|
27
25
|
end
|
28
26
|
|
29
27
|
end
|
data/lib/predicate/nodes/eq.rb
CHANGED
@@ -13,9 +13,8 @@ class Predicate
|
|
13
13
|
return self if constants == other.constants
|
14
14
|
return contradiction
|
15
15
|
when In
|
16
|
-
return super unless
|
17
|
-
mine = self.right.value
|
18
|
-
hers = other.right.value
|
16
|
+
return super unless var_against_literal_value? && other.var_against_literal_value?
|
17
|
+
mine, hers = self.right.value, other.right.value
|
19
18
|
return self if hers.include?(mine)
|
20
19
|
contradiction
|
21
20
|
else
|
@@ -41,13 +40,21 @@ class Predicate
|
|
41
40
|
end
|
42
41
|
end
|
43
42
|
|
44
|
-
def dyadic_priority
|
45
|
-
900
|
46
|
-
end
|
43
|
+
def dyadic_priority; 900; end
|
47
44
|
|
48
45
|
def evaluate(tuple)
|
49
46
|
left.evaluate(tuple) == right.evaluate(tuple)
|
50
47
|
end
|
51
48
|
|
49
|
+
def to_hash
|
50
|
+
if left.identifier? && right.literal? && !right.has_placeholder?
|
51
|
+
{ left.name => right.value }
|
52
|
+
elsif right.identifier? && left.literal? && !left.has_placeholder?
|
53
|
+
{ right.name => left.value }
|
54
|
+
else
|
55
|
+
super
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
52
59
|
end
|
53
60
|
end
|
data/lib/predicate/nodes/expr.rb
CHANGED
@@ -35,9 +35,7 @@ class Predicate
|
|
35
35
|
sexpr([:not, self])
|
36
36
|
end
|
37
37
|
|
38
|
-
def dyadic_priority
|
39
|
-
0
|
40
|
-
end
|
38
|
+
def dyadic_priority; 0; end
|
41
39
|
|
42
40
|
def &(other)
|
43
41
|
return other if other.contradiction?
|
@@ -77,6 +75,10 @@ class Predicate
|
|
77
75
|
Qualifier.new(qualifier).call(self)
|
78
76
|
end
|
79
77
|
|
78
|
+
def unqualify
|
79
|
+
Unqualifier.new.call(self)
|
80
|
+
end
|
81
|
+
|
80
82
|
def bind(binding)
|
81
83
|
Binder.new(binding).call(self)
|
82
84
|
end
|
@@ -93,6 +95,10 @@ class Predicate
|
|
93
95
|
ToS.call(self, scope: scope)
|
94
96
|
end
|
95
97
|
|
98
|
+
def to_hash
|
99
|
+
raise ArgumentError, "Unable to represent #{self} to a Hash"
|
100
|
+
end
|
101
|
+
|
96
102
|
def sexpr(arg)
|
97
103
|
Factory.sexpr(arg)
|
98
104
|
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
class Predicate
|
2
|
+
module HasSize
|
3
|
+
include BinaryFunc
|
4
|
+
|
5
|
+
def evaluate(tuple)
|
6
|
+
l, r = left.evaluate(tuple), right.evaluate(tuple)
|
7
|
+
r = r..r if r.is_a?(Integer)
|
8
|
+
raise Error, "Expected Range, got #{r}" unless r.is_a?(Range)
|
9
|
+
raise Error, "Expected #{l} to respond to :size" unless l.respond_to?(:size)
|
10
|
+
r === l.size
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
14
|
+
end
|
data/lib/predicate/nodes/in.rb
CHANGED
@@ -2,9 +2,7 @@ class Predicate
|
|
2
2
|
module In
|
3
3
|
include Expr
|
4
4
|
|
5
|
-
def priority
|
6
|
-
80
|
7
|
-
end
|
5
|
+
def priority; 80; end
|
8
6
|
|
9
7
|
def left
|
10
8
|
self[1]
|
@@ -61,9 +59,7 @@ class Predicate
|
|
61
59
|
end
|
62
60
|
end
|
63
61
|
|
64
|
-
def dyadic_priority
|
65
|
-
800
|
66
|
-
end
|
62
|
+
def dyadic_priority; 800; end
|
67
63
|
|
68
64
|
def evaluate(tuple)
|
69
65
|
values = right.evaluate(tuple)
|
@@ -71,8 +67,13 @@ class Predicate
|
|
71
67
|
values.include?(identifier.evaluate(tuple))
|
72
68
|
end
|
73
69
|
|
74
|
-
def
|
75
|
-
left.identifier? && right.literal?
|
70
|
+
def var_against_literal_value?
|
71
|
+
left.identifier? && right.literal? && !right.has_placeholder?
|
72
|
+
end
|
73
|
+
|
74
|
+
def to_hash
|
75
|
+
return super unless var_against_literal_value?
|
76
|
+
{ identifier.name => right.value }
|
76
77
|
end
|
77
78
|
|
78
79
|
end
|
@@ -1,30 +1,10 @@
|
|
1
1
|
class Predicate
|
2
2
|
module Intersect
|
3
|
-
include
|
4
|
-
|
5
|
-
def priority
|
6
|
-
80
|
7
|
-
end
|
8
|
-
|
9
|
-
def identifier
|
10
|
-
self[1]
|
11
|
-
end
|
12
|
-
|
13
|
-
def values
|
14
|
-
self[2]
|
15
|
-
end
|
16
|
-
|
17
|
-
def free_variables
|
18
|
-
@free_variables ||= identifier.free_variables
|
19
|
-
end
|
20
|
-
|
21
|
-
def constant_variables
|
22
|
-
[]
|
23
|
-
end
|
3
|
+
include SetOp
|
24
4
|
|
25
5
|
def evaluate(tuple)
|
26
|
-
|
27
|
-
|
6
|
+
x, y = left.evaluate(tuple), right.evaluate(tuple)
|
7
|
+
x && y && !(x & y).empty?
|
28
8
|
end
|
29
9
|
|
30
10
|
end
|
@@ -1,23 +1,11 @@
|
|
1
1
|
class Predicate
|
2
2
|
module Match
|
3
|
-
include
|
3
|
+
include BinaryFunc
|
4
4
|
|
5
5
|
DEFAULT_OPTIONS = {
|
6
6
|
case_sensitive: true
|
7
7
|
}
|
8
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
9
|
def options
|
22
10
|
@options ||= DEFAULT_OPTIONS.merge(self[3] || {})
|
23
11
|
end
|
@@ -26,14 +14,6 @@ class Predicate
|
|
26
14
|
options[:case_sensitive]
|
27
15
|
end
|
28
16
|
|
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
17
|
def evaluate(tuple)
|
38
18
|
l = left.evaluate(tuple)
|
39
19
|
r = right.evaluate(tuple)
|
data/lib/predicate/nodes/not.rb
CHANGED
@@ -2,9 +2,7 @@ class Predicate
|
|
2
2
|
module QualifiedIdentifier
|
3
3
|
include Expr
|
4
4
|
|
5
|
-
def priority
|
6
|
-
100
|
7
|
-
end
|
5
|
+
def priority; 100; end
|
8
6
|
|
9
7
|
def qualifier
|
10
8
|
self[1]
|
@@ -15,7 +13,7 @@ class Predicate
|
|
15
13
|
end
|
16
14
|
|
17
15
|
def free_variables
|
18
|
-
@free_variables ||= [ name ]
|
16
|
+
@free_variables ||= [ :"#{qualifier}.#{name}" ]
|
19
17
|
end
|
20
18
|
|
21
19
|
def evaluate(tuple)
|