predicate 2.4.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.
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