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
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: '07778e150b98d73bf35ce337d9874395f1f58e1c'
|
4
|
+
data.tar.gz: 9d0e523c2f41b8b5c530e67a14a69f3dbdf31914
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 84111b7fe5dc17da15f9cb3afb1cee966cedb9a29ed2e420348071c348d6f7c0cd94265c116afc7cae987ca7a96f6f29e52035c9540db85b817ee219da958c59
|
7
|
+
data.tar.gz: cb5d7863db1db730e22b7fd6fe1b7023b89a8a2ef442333d8762ff1fe0b585805d10a2dd832ab07fc98453d7186daeac793c8963e4e38da2ea94fdb94c73db3a
|
data/Gemfile
ADDED
data/LICENSE.md
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
# The MIT Licence
|
2
|
+
|
3
|
+
Copyright (c) 2017 - Enspirit SPRL (Bernard Lambeau)
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
@@ -0,0 +1,107 @@
|
|
1
|
+
class Predicate
|
2
|
+
module Factory
|
3
|
+
|
4
|
+
def tautology
|
5
|
+
_factor_predicate([:tautology, true])
|
6
|
+
end
|
7
|
+
|
8
|
+
def contradiction
|
9
|
+
_factor_predicate([:contradiction, false])
|
10
|
+
end
|
11
|
+
|
12
|
+
def identifier(name)
|
13
|
+
_factor_predicate([:identifier, name])
|
14
|
+
end
|
15
|
+
|
16
|
+
def qualified_identifier(qualifier, name)
|
17
|
+
_factor_predicate([:qualified_identifier, qualifier, name])
|
18
|
+
end
|
19
|
+
|
20
|
+
def and(left, right = nil)
|
21
|
+
_factor_predicate([:and, sexpr(left), sexpr(right)])
|
22
|
+
end
|
23
|
+
|
24
|
+
def or(left, right = nil)
|
25
|
+
_factor_predicate([:or, sexpr(left), sexpr(right)])
|
26
|
+
end
|
27
|
+
|
28
|
+
def not(operand)
|
29
|
+
_factor_predicate([:not, sexpr(operand)])
|
30
|
+
end
|
31
|
+
|
32
|
+
def relation(r)
|
33
|
+
tuples = r.to_a
|
34
|
+
case tuples.size
|
35
|
+
when 0 then contradiction
|
36
|
+
when 1 then eq(tuples.first)
|
37
|
+
else
|
38
|
+
if tuples.first.size==1
|
39
|
+
k = tuples.first.keys.first
|
40
|
+
self.in(k, tuples.map{|t| t[k]})
|
41
|
+
else
|
42
|
+
tuples.inject(contradiction){|p,t| p | eq(t) }
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def in(identifier, values)
|
48
|
+
identifier = sexpr(identifier) if identifier.is_a?(Symbol)
|
49
|
+
_factor_predicate([:in, identifier, values])
|
50
|
+
end
|
51
|
+
alias :among :in
|
52
|
+
|
53
|
+
def comp(op, h)
|
54
|
+
h = h.to_hash
|
55
|
+
if h.empty?
|
56
|
+
return tautology
|
57
|
+
elsif h.size==1
|
58
|
+
_factor_predicate [op, sexpr(h.keys.first), sexpr(h.values.last)]
|
59
|
+
else
|
60
|
+
terms = h.to_a.inject([:and]) do |anded,pair|
|
61
|
+
anded << ([op] << sexpr(pair.first) << sexpr(pair.last))
|
62
|
+
end
|
63
|
+
_factor_predicate terms
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
[ :eq, :neq, :lt, :lte, :gt, :gte ].each do |m|
|
68
|
+
define_method(m) do |left, right=nil|
|
69
|
+
return comp(m, left) if TupleLike===left && right.nil?
|
70
|
+
_factor_predicate([m, sexpr(left), sexpr(right)])
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def between(middle, lower_bound, upper_bound)
|
75
|
+
_factor_predicate [:and, [:gte, sexpr(middle), sexpr(lower_bound)],
|
76
|
+
[:lte, sexpr(middle), sexpr(upper_bound)]]
|
77
|
+
end
|
78
|
+
|
79
|
+
def literal(literal)
|
80
|
+
_factor_predicate([:literal, literal])
|
81
|
+
end
|
82
|
+
|
83
|
+
def native(arg)
|
84
|
+
_factor_predicate([:native, arg])
|
85
|
+
end
|
86
|
+
|
87
|
+
def sexpr(expr)
|
88
|
+
case expr
|
89
|
+
when Expr then expr
|
90
|
+
when Predicate then expr.expr
|
91
|
+
when TrueClass then Grammar.sexpr([:tautology, true])
|
92
|
+
when FalseClass then Grammar.sexpr([:contradiction, false])
|
93
|
+
when Symbol then Grammar.sexpr([:identifier, expr])
|
94
|
+
when Proc then Grammar.sexpr([:native, expr])
|
95
|
+
when Array then Grammar.sexpr(expr)
|
96
|
+
else
|
97
|
+
Grammar.sexpr([:literal, expr])
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def _factor_predicate(arg)
|
102
|
+
sexpr(arg)
|
103
|
+
end
|
104
|
+
|
105
|
+
extend(self)
|
106
|
+
end # module Factory
|
107
|
+
end # class Predicate
|
@@ -0,0 +1,33 @@
|
|
1
|
+
class Predicate
|
2
|
+
Grammar = Sexpr.load File.expand_path('../grammar.sexp.yml', __FILE__)
|
3
|
+
module Grammar
|
4
|
+
|
5
|
+
def tagging_reference
|
6
|
+
Predicate
|
7
|
+
end
|
8
|
+
|
9
|
+
def default_tagging_module
|
10
|
+
Expr
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
14
|
+
end # class Predicate
|
15
|
+
require_relative 'nodes/expr'
|
16
|
+
require_relative 'nodes/dyadic_comp'
|
17
|
+
require_relative 'nodes/nadic_bool'
|
18
|
+
require_relative 'nodes/tautology'
|
19
|
+
require_relative 'nodes/contradiction'
|
20
|
+
require_relative 'nodes/identifier'
|
21
|
+
require_relative 'nodes/qualified_identifier'
|
22
|
+
require_relative 'nodes/and'
|
23
|
+
require_relative 'nodes/or'
|
24
|
+
require_relative 'nodes/not'
|
25
|
+
require_relative 'nodes/eq'
|
26
|
+
require_relative 'nodes/neq'
|
27
|
+
require_relative 'nodes/gt'
|
28
|
+
require_relative 'nodes/gte'
|
29
|
+
require_relative 'nodes/lt'
|
30
|
+
require_relative 'nodes/lte'
|
31
|
+
require_relative 'nodes/in'
|
32
|
+
require_relative 'nodes/literal'
|
33
|
+
require_relative 'nodes/native'
|
@@ -0,0 +1,58 @@
|
|
1
|
+
rules:
|
2
|
+
predicate:
|
3
|
+
- tautology
|
4
|
+
- contradiction
|
5
|
+
- identifier
|
6
|
+
- not
|
7
|
+
- and
|
8
|
+
- or
|
9
|
+
- eq
|
10
|
+
- neq
|
11
|
+
- lt
|
12
|
+
- lte
|
13
|
+
- gt
|
14
|
+
- gte
|
15
|
+
- in
|
16
|
+
- native
|
17
|
+
tautology:
|
18
|
+
- [ true ]
|
19
|
+
contradiction:
|
20
|
+
- [ false ]
|
21
|
+
identifier:
|
22
|
+
- [ name ]
|
23
|
+
qualified_identifier:
|
24
|
+
- [ name, name ]
|
25
|
+
not:
|
26
|
+
- [ predicate ]
|
27
|
+
and:
|
28
|
+
- [ predicate+ ]
|
29
|
+
or:
|
30
|
+
- [ predicate+ ]
|
31
|
+
eq:
|
32
|
+
- [ term, term ]
|
33
|
+
neq:
|
34
|
+
- [ term, term ]
|
35
|
+
lt:
|
36
|
+
- [ term, term ]
|
37
|
+
lte:
|
38
|
+
- [ term, term ]
|
39
|
+
gt:
|
40
|
+
- [ term, term ]
|
41
|
+
gte:
|
42
|
+
- [ term, term ]
|
43
|
+
in:
|
44
|
+
- [ varref, values ]
|
45
|
+
term:
|
46
|
+
- varref
|
47
|
+
- literal
|
48
|
+
varref:
|
49
|
+
- qualified_identifier
|
50
|
+
- identifier
|
51
|
+
native:
|
52
|
+
- [ "::Proc" ]
|
53
|
+
literal:
|
54
|
+
- "::Object"
|
55
|
+
values:
|
56
|
+
- "::Object"
|
57
|
+
name:
|
58
|
+
!ruby/regexp /^[a-zA-Z0-9_]+[?!]?$/
|
@@ -0,0 +1,23 @@
|
|
1
|
+
class Predicate
|
2
|
+
module And
|
3
|
+
include NadicBool
|
4
|
+
|
5
|
+
def operator_symbol
|
6
|
+
:'&&'
|
7
|
+
end
|
8
|
+
|
9
|
+
def and_split(attr_list)
|
10
|
+
sexpr_body.inject([tautology, tautology]) do |(top,down),term|
|
11
|
+
pair = term.and_split(attr_list)
|
12
|
+
[top & pair.first, down & pair.last]
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def constant_variables
|
17
|
+
sexpr_body.inject([]) do |cvars,expr|
|
18
|
+
cvars | expr.constant_variables
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
class Predicate
|
2
|
+
module Contradiction
|
3
|
+
include Expr
|
4
|
+
|
5
|
+
def contradiction?
|
6
|
+
true
|
7
|
+
end
|
8
|
+
|
9
|
+
def !
|
10
|
+
tautology
|
11
|
+
end
|
12
|
+
|
13
|
+
def &(other)
|
14
|
+
self
|
15
|
+
end
|
16
|
+
|
17
|
+
def |(other)
|
18
|
+
other
|
19
|
+
end
|
20
|
+
|
21
|
+
def priority
|
22
|
+
100
|
23
|
+
end
|
24
|
+
|
25
|
+
def free_variables
|
26
|
+
@free_variables ||= []
|
27
|
+
end
|
28
|
+
|
29
|
+
def and_split(*args)
|
30
|
+
[tautology, self]
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
class Predicate
|
2
|
+
module DyadicComp
|
3
|
+
include Expr
|
4
|
+
|
5
|
+
def priority
|
6
|
+
50
|
7
|
+
end
|
8
|
+
|
9
|
+
def !
|
10
|
+
Factory.send(OP_NEGATIONS[first], self[1], self[2])
|
11
|
+
end
|
12
|
+
|
13
|
+
def left
|
14
|
+
self[1]
|
15
|
+
end
|
16
|
+
|
17
|
+
def right
|
18
|
+
self[2]
|
19
|
+
end
|
20
|
+
|
21
|
+
def free_variables
|
22
|
+
@free_variables ||= left.free_variables | right.free_variables
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
class Predicate
|
2
|
+
module Expr
|
3
|
+
include Factory
|
4
|
+
|
5
|
+
OP_NEGATIONS = {
|
6
|
+
:eq => :neq,
|
7
|
+
:neq => :eq,
|
8
|
+
:lt => :gte,
|
9
|
+
:lte => :gt,
|
10
|
+
:gt => :lte,
|
11
|
+
:gte => :lt
|
12
|
+
}
|
13
|
+
|
14
|
+
def tautology?
|
15
|
+
false
|
16
|
+
end
|
17
|
+
|
18
|
+
def contradiction?
|
19
|
+
false
|
20
|
+
end
|
21
|
+
|
22
|
+
def !
|
23
|
+
sexpr([:not, self])
|
24
|
+
end
|
25
|
+
|
26
|
+
def &(other)
|
27
|
+
return other if other.contradiction?
|
28
|
+
return self if other.tautology?
|
29
|
+
sexpr([:and, self, other])
|
30
|
+
end
|
31
|
+
|
32
|
+
def |(other)
|
33
|
+
return other if other.tautology?
|
34
|
+
return self if other.contradiction?
|
35
|
+
sexpr([:or, self, other])
|
36
|
+
end
|
37
|
+
|
38
|
+
def and_split(attr_list)
|
39
|
+
(free_variables & attr_list).empty? ? [ tautology, self ] : [ self, tautology ]
|
40
|
+
end
|
41
|
+
|
42
|
+
def rename(renaming)
|
43
|
+
Renamer.call(self, :renaming => renaming)
|
44
|
+
end
|
45
|
+
|
46
|
+
def qualify(qualifier)
|
47
|
+
Qualifier.new(qualifier).call(self)
|
48
|
+
end
|
49
|
+
|
50
|
+
def constant_variables
|
51
|
+
[]
|
52
|
+
end
|
53
|
+
|
54
|
+
def to_ruby_code(scope = 't')
|
55
|
+
code = ToRubyCode.call(self, scope: scope)
|
56
|
+
"->(t){ #{code} }"
|
57
|
+
end
|
58
|
+
|
59
|
+
def to_proc(scope = 't')
|
60
|
+
Kernel.eval(to_ruby_code(scope))
|
61
|
+
end
|
62
|
+
|
63
|
+
def sexpr(arg)
|
64
|
+
Factory.sexpr(arg)
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
class Predicate
|
2
|
+
module In
|
3
|
+
include Expr
|
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
|
+
values.size == 1 ? free_variables : []
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
class Predicate
|
2
|
+
module Native
|
3
|
+
include Expr
|
4
|
+
|
5
|
+
def priority
|
6
|
+
90
|
7
|
+
end
|
8
|
+
|
9
|
+
def proc
|
10
|
+
self[1]
|
11
|
+
end
|
12
|
+
|
13
|
+
def to_ruby_code(scope = 't')
|
14
|
+
if proc.respond_to?(:source_code)
|
15
|
+
code = proc.source_code
|
16
|
+
return code if code
|
17
|
+
end
|
18
|
+
raise NotSupportedError
|
19
|
+
end
|
20
|
+
|
21
|
+
def to_proc(scope = 't')
|
22
|
+
proc
|
23
|
+
end
|
24
|
+
|
25
|
+
def free_variables
|
26
|
+
raise NotSupportedError
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
class Predicate
|
2
|
+
module QualifiedIdentifier
|
3
|
+
include Expr
|
4
|
+
|
5
|
+
def priority
|
6
|
+
100
|
7
|
+
end
|
8
|
+
|
9
|
+
def qualifier
|
10
|
+
self[1]
|
11
|
+
end
|
12
|
+
|
13
|
+
def name
|
14
|
+
self[2]
|
15
|
+
end
|
16
|
+
|
17
|
+
def free_variables
|
18
|
+
@free_variables ||= [ name ]
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
class Predicate
|
2
|
+
module Tautology
|
3
|
+
include Expr
|
4
|
+
|
5
|
+
def tautology?
|
6
|
+
true
|
7
|
+
end
|
8
|
+
|
9
|
+
def !
|
10
|
+
contradiction
|
11
|
+
end
|
12
|
+
|
13
|
+
def &(other)
|
14
|
+
other
|
15
|
+
end
|
16
|
+
|
17
|
+
def |(other)
|
18
|
+
self
|
19
|
+
end
|
20
|
+
|
21
|
+
def priority
|
22
|
+
100
|
23
|
+
end
|
24
|
+
|
25
|
+
def free_variables
|
26
|
+
@free_variables ||= []
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
end
|