predicate 2.4.0 → 2.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (72) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +4 -0
  3. data/LICENSE.md +17 -19
  4. data/README.md +433 -0
  5. data/bin/g +2 -0
  6. data/lib/predicate.rb +15 -2
  7. data/lib/predicate/dsl.rb +138 -0
  8. data/lib/predicate/factory.rb +130 -33
  9. data/lib/predicate/grammar.rb +11 -2
  10. data/lib/predicate/grammar.sexp.yml +29 -0
  11. data/lib/predicate/nodes/${op_name}.rb.jeny +12 -0
  12. data/lib/predicate/nodes/binary_func.rb +20 -0
  13. data/lib/predicate/nodes/contradiction.rb +2 -7
  14. data/lib/predicate/nodes/dyadic_comp.rb +1 -3
  15. data/lib/predicate/nodes/empty.rb +14 -0
  16. data/lib/predicate/nodes/eq.rb +1 -3
  17. data/lib/predicate/nodes/expr.rb +1 -3
  18. data/lib/predicate/nodes/has_size.rb +14 -0
  19. data/lib/predicate/nodes/identifier.rb +1 -3
  20. data/lib/predicate/nodes/in.rb +2 -6
  21. data/lib/predicate/nodes/intersect.rb +3 -23
  22. data/lib/predicate/nodes/literal.rb +1 -3
  23. data/lib/predicate/nodes/match.rb +1 -21
  24. data/lib/predicate/nodes/nadic_bool.rb +1 -3
  25. data/lib/predicate/nodes/native.rb +1 -3
  26. data/lib/predicate/nodes/not.rb +1 -3
  27. data/lib/predicate/nodes/opaque.rb +1 -3
  28. data/lib/predicate/nodes/qualified_identifier.rb +1 -3
  29. data/lib/predicate/nodes/set_op.rb +26 -0
  30. data/lib/predicate/nodes/subset.rb +11 -0
  31. data/lib/predicate/nodes/superset.rb +11 -0
  32. data/lib/predicate/nodes/tautology.rb +2 -7
  33. data/lib/predicate/nodes/unary_func.rb +16 -0
  34. data/lib/predicate/nodes/var.rb +46 -0
  35. data/lib/predicate/processors/qualifier.rb +4 -0
  36. data/lib/predicate/processors/renamer.rb +4 -0
  37. data/lib/predicate/processors/to_s.rb +28 -0
  38. data/lib/predicate/processors/unqualifier.rb +4 -0
  39. data/lib/predicate/sequel/to_sequel.rb +3 -0
  40. data/lib/predicate/sugar.rb +47 -0
  41. data/lib/predicate/version.rb +1 -1
  42. data/spec/dsl/test_dsl.rb +204 -0
  43. data/spec/dsl/test_evaluate.rb +65 -0
  44. data/spec/dsl/test_respond_to_missing.rb +35 -0
  45. data/spec/dsl/test_to_skake_case.rb +38 -0
  46. data/spec/factory/shared/a_comparison_factory_method.rb +1 -0
  47. data/spec/factory/test_${op_name}.rb.jeny +12 -0
  48. data/spec/factory/test_empty.rb +11 -0
  49. data/spec/factory/test_has_size.rb +11 -0
  50. data/spec/factory/test_match.rb +1 -0
  51. data/spec/factory/test_set_ops.rb +18 -0
  52. data/spec/factory/test_var.rb +22 -0
  53. data/spec/factory/test_vars.rb +27 -0
  54. data/spec/nodes/${op_name}.jeny/test_evaluate.rb.jeny +19 -0
  55. data/spec/nodes/empty/test_evaluate.rb +42 -0
  56. data/spec/nodes/has_size/test_evaluate.rb +44 -0
  57. data/spec/predicate/test_and_split.rb +18 -0
  58. data/spec/predicate/test_attr_split.rb +18 -0
  59. data/spec/predicate/test_constant_variables.rb +24 -2
  60. data/spec/predicate/test_constants.rb +24 -0
  61. data/spec/predicate/test_evaluate.rb +205 -3
  62. data/spec/predicate/test_to_s.rb +37 -0
  63. data/spec/sequel/test_to_sequel.rb +16 -0
  64. data/spec/shared/a_predicate.rb +30 -0
  65. data/spec/spec_helper.rb +1 -0
  66. data/spec/test_predicate.rb +68 -33
  67. data/spec/test_readme.rb +80 -0
  68. data/spec/test_sugar.rb +48 -0
  69. data/tasks/test.rake +3 -3
  70. metadata +40 -12
  71. data/spec/factory/test_between.rb +0 -12
  72. data/spec/factory/test_intersect.rb +0 -12
@@ -0,0 +1,12 @@
1
+ #jeny(predicate)
2
+ class Predicate
3
+ module ${OpName}
4
+ include ${Arity}Func
5
+
6
+ def evaluate(tuple)
7
+ # TODO: implement this
8
+ raise NotImplementedError
9
+ end
10
+
11
+ end
12
+ end
@@ -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
@@ -18,13 +18,8 @@ class Predicate
18
18
  other
19
19
  end
20
20
 
21
- def dyadic_priority
22
- 1000
23
- end
24
-
25
- def priority
26
- 100
27
- end
21
+ def dyadic_priority; 1000; end
22
+ def priority; 100; end
28
23
 
29
24
  def free_variables
30
25
  @free_variables ||= []
@@ -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])
@@ -0,0 +1,14 @@
1
+ class Predicate
2
+ module Empty
3
+ include UnaryFunc
4
+
5
+ def evaluate(tuple)
6
+ value = operand.evaluate(tuple)
7
+ unless value.respond_to?(:empty?)
8
+ raise TypeError, "Expected #{value} to respond to empty?"
9
+ end
10
+ value.empty?
11
+ end
12
+
13
+ end
14
+ end
@@ -40,9 +40,7 @@ class Predicate
40
40
  end
41
41
  end
42
42
 
43
- def dyadic_priority
44
- 900
45
- end
43
+ def dyadic_priority; 900; end
46
44
 
47
45
  def evaluate(tuple)
48
46
  left.evaluate(tuple) == right.evaluate(tuple)
@@ -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?
@@ -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
@@ -2,9 +2,7 @@ class Predicate
2
2
  module Identifier
3
3
  include Expr
4
4
 
5
- def priority
6
- 100
7
- end
5
+ def priority; 100; end
8
6
 
9
7
  def name
10
8
  self[1]
@@ -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)
@@ -1,30 +1,10 @@
1
1
  class Predicate
2
2
  module Intersect
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
- []
23
- end
3
+ include SetOp
24
4
 
25
5
  def evaluate(tuple)
26
- t_x = identifier.evaluate(tuple)
27
- t_x && !(t_x & values).empty?
6
+ x, y = left.evaluate(tuple), right.evaluate(tuple)
7
+ x && y && !(x & y).empty?
28
8
  end
29
9
 
30
10
  end
@@ -2,9 +2,7 @@ class Predicate
2
2
  module Literal
3
3
  include Expr
4
4
 
5
- def priority
6
- 100
7
- end
5
+ def priority; 100; end
8
6
 
9
7
  def free_variables
10
8
  @free_variables ||= []
@@ -1,23 +1,11 @@
1
1
  class Predicate
2
2
  module Match
3
- include Expr
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)
@@ -2,9 +2,7 @@ class Predicate
2
2
  module NadicBool
3
3
  include Expr
4
4
 
5
- def priority
6
- 60
7
- end
5
+ def priority; 60; end
8
6
 
9
7
  def free_variables
10
8
  @free_variables ||= sexpr_body.inject([]){|list,term|
@@ -2,9 +2,7 @@ class Predicate
2
2
  module Native
3
3
  include Expr
4
4
 
5
- def priority
6
- 90
7
- end
5
+ def priority; 90; end
8
6
 
9
7
  def proc
10
8
  self[1]
@@ -6,9 +6,7 @@ class Predicate
6
6
  :'!'
7
7
  end
8
8
 
9
- def priority
10
- 90
11
- end
9
+ def priority; 90; end
12
10
 
13
11
  def !
14
12
  last
@@ -2,9 +2,7 @@ class Predicate
2
2
  module Opaque
3
3
  include Expr
4
4
 
5
- def priority
6
- 100
7
- end
5
+ def priority; 100; end
8
6
 
9
7
  def free_variables
10
8
  @free_variables ||= []
@@ -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]
@@ -0,0 +1,26 @@
1
+ class Predicate
2
+ module SetOp
3
+ include Expr
4
+
5
+ def priority; 80; end
6
+
7
+ def left
8
+ self[1]
9
+ end
10
+ alias :identifier :left
11
+
12
+ def right
13
+ self[2]
14
+ end
15
+ alias :values :right
16
+
17
+ def free_variables
18
+ @free_variables ||= left.free_variables | right.free_variables
19
+ end
20
+
21
+ def constant_variables
22
+ []
23
+ end
24
+
25
+ end
26
+ end
@@ -0,0 +1,11 @@
1
+ class Predicate
2
+ module Subset
3
+ include SetOp
4
+
5
+ def evaluate(tuple)
6
+ x, y = left.evaluate(tuple), right.evaluate(tuple)
7
+ x && y && (x & y == x)
8
+ end
9
+
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ class Predicate
2
+ module Superset
3
+ include SetOp
4
+
5
+ def evaluate(tuple)
6
+ x, y = left.evaluate(tuple), right.evaluate(tuple)
7
+ x && y && (x & y == y)
8
+ end
9
+
10
+ end
11
+ end
@@ -18,13 +18,8 @@ class Predicate
18
18
  self
19
19
  end
20
20
 
21
- def dyadic_priority
22
- 1000
23
- end
24
-
25
- def priority
26
- 100
27
- end
21
+ def dyadic_priority; 1000; end
22
+ def priority; 100; end
28
23
 
29
24
  def free_variables
30
25
  @free_variables ||= []
@@ -0,0 +1,16 @@
1
+ class Predicate
2
+ module UnaryFunc
3
+ include Expr
4
+
5
+ def priority; 80; end
6
+
7
+ def operand
8
+ self[1]
9
+ end
10
+
11
+ def free_variables
12
+ @free_variables ||= operand.free_variables
13
+ end
14
+
15
+ end
16
+ end
@@ -0,0 +1,46 @@
1
+ class Predicate
2
+ module Var
3
+ include Expr
4
+
5
+ def priority; 100; end
6
+
7
+ def formaldef
8
+ self[1]
9
+ end
10
+
11
+ def semantics
12
+ self[2]
13
+ end
14
+
15
+ def free_variables
16
+ @free_variables ||= [ [formaldef, semantics] ]
17
+ end
18
+
19
+ def dig_terms
20
+ @dig_terms ||= case formaldef
21
+ when String
22
+ formaldef.split(".").map{|elm|
23
+ elm =~ /^\d+$/ ? elm.to_i : elm.to_sym
24
+ }
25
+ when Array
26
+ formaldef
27
+ else
28
+ raise ArgumentError, "Unrecognized variable def `#{formaldef}`"
29
+ end
30
+ end
31
+
32
+ def evaluate(on)
33
+ case semantics
34
+ when :dig
35
+ dig_terms.inject(on){|ctx,elm| ctx.dig(elm) }
36
+ when :send
37
+ dig_terms.inject(on){|ctx,elm| ctx.__send__(elm.to_sym) }
38
+ when :public_send
39
+ dig_terms.inject(on){|ctx,elm| ctx.public_send(elm.to_sym) }
40
+ else
41
+ raise ArgumentError, "Unrecognized variable semantics `#{semantics}`"
42
+ end
43
+ end
44
+
45
+ end
46
+ end
@@ -22,6 +22,10 @@ class Predicate
22
22
  raise NotSupportedError
23
23
  end
24
24
 
25
+ def on_var(sexpr)
26
+ raise NotSupportedError
27
+ end
28
+
25
29
  alias :on_missing :copy_and_apply
26
30
 
27
31
  end
@@ -19,6 +19,10 @@ class Predicate
19
19
  raise NotSupportedError
20
20
  end
21
21
 
22
+ def on_var(sexpr)
23
+ raise NotSupportedError
24
+ end
25
+
22
26
  alias :on_missing :copy_and_apply
23
27
 
24
28
  end