veritas 0.0.5 → 0.0.6

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 (75) hide show
  1. data/.travis.yml +5 -4
  2. data/Gemfile +16 -14
  3. data/Guardfile +0 -4
  4. data/README.md +188 -0
  5. data/Rakefile +2 -2
  6. data/TODO +0 -16
  7. data/config/flay.yml +1 -1
  8. data/config/flog.yml +1 -1
  9. data/config/roodi.yml +4 -4
  10. data/config/site.reek +7 -3
  11. data/lib/veritas/aggregate.rb +18 -0
  12. data/lib/veritas/algebra/extension.rb +2 -29
  13. data/lib/veritas/algebra/projection.rb +2 -29
  14. data/lib/veritas/algebra/rename/aliases.rb +4 -32
  15. data/lib/veritas/algebra/rename.rb +2 -29
  16. data/lib/veritas/algebra/restriction.rb +2 -29
  17. data/lib/veritas/algebra/summarization.rb +2 -31
  18. data/lib/veritas/attribute/time.rb +1 -1
  19. data/lib/veritas/attribute.rb +20 -40
  20. data/lib/veritas/function/binary.rb +2 -3
  21. data/lib/veritas/function/connective/negation.rb +1 -1
  22. data/lib/veritas/function/predicate/enumerable.rb +19 -0
  23. data/lib/veritas/function/predicate/exclusion.rb +1 -1
  24. data/lib/veritas/function/predicate/match.rb +1 -1
  25. data/lib/veritas/function/unary.rb +5 -3
  26. data/lib/veritas/function.rb +1 -41
  27. data/lib/veritas/relation/base.rb +2 -29
  28. data/lib/veritas/relation/empty.rb +30 -2
  29. data/lib/veritas/relation/header.rb +17 -31
  30. data/lib/veritas/relation/materialized.rb +0 -12
  31. data/lib/veritas/relation/operation/limit.rb +2 -29
  32. data/lib/veritas/relation/operation/offset.rb +2 -29
  33. data/lib/veritas/relation/operation/order/direction.rb +3 -29
  34. data/lib/veritas/relation/operation/order/direction_set.rb +18 -34
  35. data/lib/veritas/relation/operation/order.rb +4 -56
  36. data/lib/veritas/relation.rb +8 -36
  37. data/lib/veritas/support/aliasable.rb +20 -7
  38. data/lib/veritas/support/comparator.rb +81 -0
  39. data/lib/veritas/support/evaluator.rb +1 -1
  40. data/lib/veritas/support/immutable.rb +22 -49
  41. data/lib/veritas/support/operation/binary.rb +3 -30
  42. data/lib/veritas/support/operation/unary.rb +3 -29
  43. data/lib/veritas/tuple.rb +19 -29
  44. data/lib/veritas/version.rb +1 -1
  45. data/lib/veritas.rb +1 -0
  46. data/spec/integration/veritas/relation/efficient_enumerable_spec.rb +3 -3
  47. data/spec/shared/hash_method_behavior.rb +7 -2
  48. data/spec/unit/date/pred_spec.rb +1 -1
  49. data/spec/unit/veritas/aggregate/equal_value_spec.rb +52 -0
  50. data/spec/unit/veritas/aggregate/hash_spec.rb +15 -0
  51. data/spec/unit/veritas/aliasable/inheritable_alias_spec.rb +1 -1
  52. data/spec/unit/veritas/comparator/compare_spec.rb +40 -0
  53. data/spec/unit/veritas/comparator/methods/eql_spec.rb +48 -0
  54. data/spec/unit/veritas/evaluator/context/respond_to_spec.rb +1 -1
  55. data/spec/unit/veritas/function/predicate/enumerable/call_spec.rb +36 -0
  56. data/spec/unit/veritas/function/unary/hash_spec.rb +18 -0
  57. data/spec/unit/veritas/immutable/freeze_spec.rb +2 -2
  58. data/spec/unit/veritas/immutable/memoize_spec.rb +13 -0
  59. data/spec/unit/veritas/immutable/module_methods/memoize_spec.rb +1 -1
  60. data/spec/unit/veritas/relation/empty/class_methods/new_spec.rb +30 -0
  61. data/spec/unit/veritas/relation/empty/each_spec.rb +20 -5
  62. data/spec/unit/veritas/relation/empty/size_spec.rb +11 -0
  63. data/spec/unit/veritas/relation/header/hash_spec.rb +1 -1
  64. data/spec/unit/veritas/relation/materialized/empty_spec.rb +0 -10
  65. data/spec/unit/veritas/relation/operation/order/direction_set/class_methods/coerce_spec.rb +12 -3
  66. data/tasks/metrics/heckle.rake +2 -3
  67. data/veritas.gemspec +21 -18
  68. metadata +36 -33
  69. data/README.rdoc +0 -143
  70. data/spec/unit/veritas/function/eql_spec.rb +0 -14
  71. data/spec/unit/veritas/function/equal_value_spec.rb +0 -14
  72. data/spec/unit/veritas/function/hash_spec.rb +0 -13
  73. data/spec/unit/veritas/immutable/memory/element_reference_spec.rb +0 -26
  74. data/spec/unit/veritas/immutable/memory/element_set_spec.rb +0 -19
  75. data/spec/unit/veritas/relation/operation/order/methods/order_spec.rb +0 -54
@@ -7,6 +7,8 @@ module Veritas
7
7
  class Summarization < Relation
8
8
  include Relation::Operation::Unary
9
9
 
10
+ compare :operand, :summarize_per, :summarizers
11
+
10
12
  # The relation to summarize with
11
13
  #
12
14
  # @return [Relation]
@@ -99,35 +101,6 @@ module Veritas
99
101
  self
100
102
  end
101
103
 
102
- # Compare the Summarization with other relation for equality
103
- #
104
- # @example
105
- # summarization.eql?(other) # => true or false
106
- #
107
- # @param [Relation] other
108
- # the other relation to compare with
109
- #
110
- # @return [Boolean]
111
- #
112
- # @api public
113
- def eql?(other)
114
- super &&
115
- summarize_per.eql?(other.summarize_per) &&
116
- summarizers.eql?(other.summarizers)
117
- end
118
-
119
- # Return the hash of the summarization
120
- #
121
- # @example
122
- # hash = summarization.hash
123
- #
124
- # @return [Fixnum]
125
- #
126
- # @api public
127
- def hash
128
- super ^ summarize_per.hash ^ summarizers.hash
129
- end
130
-
131
104
  private
132
105
 
133
106
  # Return the current summaries
@@ -209,8 +182,6 @@ module Veritas
209
182
 
210
183
  Relation.class_eval { include Methods }
211
184
 
212
- memoize :hash
213
-
214
185
  end # class Summarization
215
186
  end # module Algebra
216
187
  end # module Veritas
@@ -7,7 +7,7 @@ module Veritas
7
7
  class Time < Object
8
8
  include Comparable
9
9
 
10
- DEFAULT_RANGE = (::Time.at(0)..::Time.at(2**31-1)).freeze
10
+ DEFAULT_RANGE = (::Time.at(0)..::Time.at(2 ** 31-1)).freeze
11
11
 
12
12
  # The Time primitive
13
13
  #
@@ -4,9 +4,11 @@ module Veritas
4
4
 
5
5
  # Abstract base class representing a type of data in a relation tuple
6
6
  class Attribute
7
- extend Aliasable
7
+ extend Aliasable, Comparator
8
8
  include AbstractClass, Immutable, ::Comparable, Visitable
9
9
 
10
+ compare :name, :options
11
+
10
12
  # The attribute name
11
13
  #
12
14
  # @return [Symbol]
@@ -91,11 +93,11 @@ module Veritas
91
93
  # @api private
92
94
  def self.infer_type(operand)
93
95
  case operand
94
- when Attribute, Function, Aggregate then operand.type
95
- when FalseClass then Boolean
96
- else
97
- type = operand.class
98
- descendants.detect { |descendant| type <= descendant.primitive }
96
+ when Attribute, Function, Aggregate then operand.type
97
+ when FalseClass then Boolean
98
+ else
99
+ type = operand.class
100
+ descendants.detect { |descendant| type <= descendant.primitive }
99
101
  end
100
102
  end
101
103
 
@@ -227,38 +229,7 @@ module Veritas
227
229
  #
228
230
  # @api public
229
231
  def ==(other)
230
- other = Attribute.coerce(other)
231
- name.equal?(other.name) &&
232
- options == other.options
233
- end
234
-
235
- # Compare the attribute with other attribute for equality
236
- #
237
- # @example
238
- # attribute.eql?(other) # => true or false
239
- #
240
- # @param [Attribute] other
241
- # the other attribute to compare with
242
- #
243
- # @return [Boolean]
244
- #
245
- # @api public
246
- def eql?(other)
247
- instance_of?(other.class) &&
248
- name.equal?(other.name) &&
249
- options.eql?(other.options)
250
- end
251
-
252
- # Return the hash of the attribute
253
- #
254
- # @example
255
- # hash = attribute.hash
256
- #
257
- # @return [Fixnum]
258
- #
259
- # @api public
260
- def hash
261
- self.class.hash ^ name.hash ^ options.hash
232
+ cmp?(__method__, coerce(other))
262
233
  end
263
234
 
264
235
  # Return a string representing the attribute
@@ -286,10 +257,19 @@ module Veritas
286
257
  #
287
258
  # @api private
288
259
  def valid_or_optional?(value)
289
- value.nil? ? !required? : yield
260
+ value.nil? ? ! required? : yield
290
261
  end
291
262
 
292
- memoize :hash
263
+ # Coerce the object into an Attribute
264
+ #
265
+ # @param [Attribute, Array] object
266
+ #
267
+ # @return [Attribute]
268
+ #
269
+ # @api private
270
+ def coerce(object)
271
+ Attribute.coerce(object)
272
+ end
293
273
 
294
274
  end # class Attribute
295
275
  end # module Veritas
@@ -7,7 +7,7 @@ module Veritas
7
7
  module Binary
8
8
  include Operation::Binary
9
9
 
10
- # Evaluate the binary connective using the tuple
10
+ # Evaluate the binary function using the tuple
11
11
  #
12
12
  # @example
13
13
  # binary.call(tuple) # => true or false
@@ -98,8 +98,7 @@ module Veritas
98
98
  #
99
99
  # @api public
100
100
  def inverse
101
- self.class.inverse.new(left, right).
102
- memoize(:inverse, self)
101
+ self.class.inverse.new(left, right).memoize(:inverse, self)
103
102
  end
104
103
 
105
104
  end # module Invertible
@@ -22,7 +22,7 @@ module Veritas
22
22
  #
23
23
  # @api public
24
24
  def self.call(operand)
25
- !operand
25
+ ! operand
26
26
  end
27
27
 
28
28
  # Return the operand
@@ -32,6 +32,25 @@ module Veritas
32
32
  super(left, Immutable.freeze_object(right))
33
33
  end
34
34
 
35
+ # Evaluate the enumerable function using the tuple
36
+ #
37
+ # @example
38
+ # enumerable.call(tuple) # => true or false
39
+ #
40
+ # @param [Tuple] tuple
41
+ # the tuple to pass to #call in the left and right operands
42
+ #
43
+ # @return [Boolean]
44
+ #
45
+ # @api public
46
+ def call(tuple)
47
+ util = self.class
48
+ util.call(
49
+ util.extract_value(left, tuple),
50
+ right.map { |entry| util.extract_value(entry, tuple) }
51
+ )
52
+ end
53
+
35
54
  end # module Enumerable
36
55
  end # class Predicate
37
56
  end # class Function
@@ -22,7 +22,7 @@ module Veritas
22
22
  #
23
23
  # @api public
24
24
  def self.call(left, right)
25
- !right.send(Enumerable.compare_method(right), left)
25
+ ! right.send(Enumerable.compare_method(right), left)
26
26
  end
27
27
 
28
28
  # Return the inverse predicate class
@@ -17,7 +17,7 @@ module Veritas
17
17
  #
18
18
  # @api public
19
19
  def self.call(*)
20
- !!super
20
+ super ? true : false
21
21
  end
22
22
 
23
23
  # Return the Match operation
@@ -5,8 +5,11 @@ module Veritas
5
5
 
6
6
  # Mixin for unary functions
7
7
  module Unary
8
+ extend Comparator
8
9
  include Operation::Unary
9
10
 
11
+ compare :operand
12
+
10
13
  # Evaluate the unary connective using the tuple
11
14
  #
12
15
  # @example
@@ -64,7 +67,7 @@ module Veritas
64
67
  # @api public
65
68
  def ==(other)
66
69
  (kind_of?(other.class) || other.kind_of?(self.class)) &&
67
- operand == other.operand
70
+ cmp?(__method__, other)
68
71
  end
69
72
 
70
73
  # Mixin for invertable unary functions
@@ -94,8 +97,7 @@ module Veritas
94
97
  #
95
98
  # @api public
96
99
  def inverse
97
- self.class.inverse.new(operand).
98
- memoize(:inverse, self)
100
+ self.class.inverse.new(operand).memoize(:inverse, self)
99
101
  end
100
102
 
101
103
  end # module Invertible
@@ -18,7 +18,7 @@ module Veritas
18
18
  #
19
19
  # @api private
20
20
  def self.rename_attributes(operand, aliases)
21
- if operand.respond_to?(:rename) && !operand.kind_of?(Attribute)
21
+ if operand.respond_to?(:rename) && ! operand.kind_of?(Attribute)
22
22
  operand.rename(aliases)
23
23
  else
24
24
  aliases[operand]
@@ -75,46 +75,6 @@ module Veritas
75
75
  raise NotImplementedError, "#{self.class}#type must be implemented"
76
76
  end
77
77
 
78
- # Compare the function with other function for equivalency
79
- #
80
- # @example
81
- # function == other # => true or false
82
- #
83
- # @param [Function] other
84
- #
85
- # @return [Boolean]
86
- #
87
- # @api public
88
- def ==(other)
89
- raise NotImplementedError, "#{self.class}#== must be implemented"
90
- end
91
-
92
- # Compare the function with other function for equality
93
- #
94
- # @example
95
- # function.eql?(other) # => true or false
96
- #
97
- # @param [Function] other
98
- #
99
- # @return [Boolean]
100
- #
101
- # @api public
102
- def eql?(other)
103
- raise NotImplementedError, "#{self.class}#eql? must be implemented"
104
- end
105
-
106
- # Return the hash of the function
107
- #
108
- # @example
109
- # hash = function.hash
110
- #
111
- # @return [Fixnum]
112
- #
113
- # @api public
114
- def hash
115
- raise NotImplementedError, "#{self.class}#hash must be implemented"
116
- end
117
-
118
78
  # Return a string representing the function
119
79
  #
120
80
  # @example
@@ -6,6 +6,8 @@ module Veritas
6
6
  # A class that represents a base relation
7
7
  class Base < Relation
8
8
 
9
+ compare :header, :to_set, :name
10
+
9
11
  # The base relation name
10
12
  #
11
13
  # @example
@@ -33,35 +35,6 @@ module Veritas
33
35
  @name = Immutable.freeze_object(name.to_s)
34
36
  end
35
37
 
36
- # Compare the base relation with other relation for equality
37
- #
38
- # @example
39
- # base.eql?(other) # => true or false
40
- #
41
- # @param [Relation] other
42
- # the other relation to compare with
43
- #
44
- # @return [Boolean]
45
- #
46
- # @api public
47
- def eql?(other)
48
- super && name.eql?(other.name)
49
- end
50
-
51
- # Return the hash of the base relation
52
- #
53
- # @example
54
- # hash = base.hash
55
- #
56
- # @return [Fixnum]
57
- #
58
- # @api public
59
- def hash
60
- super ^ name.hash
61
- end
62
-
63
- memoize :hash
64
-
65
38
  end # class Base
66
39
  end # class Relation
67
40
  end # module Veritas
@@ -11,12 +11,40 @@ module Veritas
11
11
  #
12
12
  # @param [Header] header
13
13
  # the header for the empty relation
14
+ # @param [#each] tuples
15
+ # optional original tuples
14
16
  #
15
17
  # @return [undefined]
16
18
  #
17
19
  # @api public
18
- def initialize(header)
19
- super(header, ZERO_TUPLE)
20
+ def initialize(header, tuples = ZERO_TUPLE)
21
+ super
22
+ end
23
+
24
+ # Noop #each method
25
+ #
26
+ # @example
27
+ # empty = Empty.new(header)
28
+ # empty.each { ... }
29
+ #
30
+ # @return [self]
31
+ #
32
+ # @api public
33
+ def each
34
+ return to_enum unless block_given?
35
+ self
36
+ end
37
+
38
+ # Return the number of tuples
39
+ #
40
+ # @example
41
+ # empty.size # => 0
42
+ #
43
+ # @return [0]
44
+ #
45
+ # @api public
46
+ def size
47
+ 0
20
48
  end
21
49
 
22
50
  end # class Empty
@@ -5,9 +5,11 @@ module Veritas
5
5
 
6
6
  # A set of attributes that correspond to values in each tuple
7
7
  class Header
8
- extend Aliasable
8
+ extend Aliasable, Comparator
9
9
  include Enumerable, Immutable
10
10
 
11
+ compare :to_set
12
+
11
13
  inheritable_alias(
12
14
  :& => :intersect,
13
15
  :| => :union,
@@ -217,35 +219,7 @@ module Veritas
217
219
  #
218
220
  # @api public
219
221
  def ==(other)
220
- to_set == self.class.coerce(other).to_set
221
- end
222
-
223
- # Compare the header with other header for equality
224
- #
225
- # @example
226
- # header.eql?(other) # => true or false
227
- #
228
- # @param [Header] other
229
- # the other header to compare with
230
- #
231
- # @return [Boolean]
232
- #
233
- # @api public
234
- def eql?(other)
235
- instance_of?(other.class) &&
236
- to_set == other.to_set
237
- end
238
-
239
- # Return the hash of the header
240
- #
241
- # @example
242
- # hash = header.hash
243
- #
244
- # @return [Fixnum]
245
- #
246
- # @api public
247
- def hash
248
- self.class.hash ^ @attributes.hash
222
+ cmp?(__method__, coerce(other))
249
223
  end
250
224
 
251
225
  # Test if there are no attributes
@@ -286,6 +260,18 @@ module Veritas
286
260
  self.class.new(attributes)
287
261
  end
288
262
 
263
+ # Coerce the object into a Header
264
+ #
265
+ # @param [Header, #to_ary]
266
+ # the header or attributes
267
+ #
268
+ # @return [Header]
269
+ #
270
+ # @api private
271
+ def coerce(object)
272
+ self.class.coerce(object)
273
+ end
274
+
289
275
  # Coerce an Array-like object into a Header
290
276
  #
291
277
  # @param [Header, #to_ary]
@@ -298,7 +284,7 @@ module Veritas
298
284
  object.kind_of?(Header) ? object : new(object)
299
285
  end
300
286
 
301
- memoize :hash, :to_ary
287
+ memoize :to_ary
302
288
 
303
289
  end # class Header
304
290
  end # class Relation
@@ -54,18 +54,6 @@ module Veritas
54
54
  true
55
55
  end
56
56
 
57
- # Test if there are no tuples
58
- #
59
- # @example
60
- # materialized.empty? # => true or false
61
- #
62
- # @return [Boolean]
63
- #
64
- # @api public
65
- def empty?
66
- tuples.empty?
67
- end
68
-
69
57
  # Return the number of tuples
70
58
  #
71
59
  # @example
@@ -8,6 +8,8 @@ module Veritas
8
8
  class Limit < Relation
9
9
  include Unary
10
10
 
11
+ compare :operand, :limit
12
+
11
13
  # Return the limit
12
14
  #
13
15
  # @example
@@ -117,33 +119,6 @@ module Veritas
117
119
  self
118
120
  end
119
121
 
120
- # Compare the Limit with other relation for equality
121
- #
122
- # @example
123
- # limited_relation.eql?(other) # => true or false
124
- #
125
- # @param [Relation] other
126
- # the other relation to compare with
127
- #
128
- # @return [Boolean]
129
- #
130
- # @api public
131
- def eql?(other)
132
- super && limit.eql?(other.limit)
133
- end
134
-
135
- # Return the hash of the limit
136
- #
137
- # @example
138
- # hash = limit.hash
139
- #
140
- # @return [Fixnum]
141
- #
142
- # @api public
143
- def hash
144
- super ^ limit.hash
145
- end
146
-
147
122
  module Methods
148
123
 
149
124
  # Return a relation with n tuples
@@ -201,8 +176,6 @@ module Veritas
201
176
 
202
177
  Relation.class_eval { include Methods }
203
178
 
204
- memoize :hash
205
-
206
179
  end # class Limit
207
180
  end # module Operation
208
181
  end # class Relation
@@ -8,6 +8,8 @@ module Veritas
8
8
  class Offset < Relation
9
9
  include Unary
10
10
 
11
+ compare :operand, :offset
12
+
11
13
  # Return the offset
12
14
  #
13
15
  # @example
@@ -116,33 +118,6 @@ module Veritas
116
118
  self
117
119
  end
118
120
 
119
- # Compare the Offset with other relation for equality
120
- #
121
- # @example
122
- # offset_relation.eql?(other) # => true or false
123
- #
124
- # @param [Relation] other
125
- # the other relation to compare with
126
- #
127
- # @return [Boolean]
128
- #
129
- # @api public
130
- def eql?(other)
131
- super && offset.eql?(other.offset)
132
- end
133
-
134
- # Return the hash of the offset
135
- #
136
- # @example
137
- # hash = offset.hash
138
- #
139
- # @return [Fixnum]
140
- #
141
- # @api public
142
- def hash
143
- super ^ offset.hash
144
- end
145
-
146
121
  module Methods
147
122
 
148
123
  # Return a relation with n tuples
@@ -164,8 +139,6 @@ module Veritas
164
139
 
165
140
  Relation.class_eval { include Methods }
166
141
 
167
- memoize :hash
168
-
169
142
  end # class Offset
170
143
  end # module Operation
171
144
  end # class Relation
@@ -7,8 +7,11 @@ module Veritas
7
7
 
8
8
  # Abstract base class for attribute sorting
9
9
  class Direction
10
+ extend Comparator
10
11
  include AbstractClass, Immutable
11
12
 
13
+ compare :attribute
14
+
12
15
  # The attribute to sort on
13
16
  #
14
17
  # @return [Attribute]
@@ -97,33 +100,6 @@ module Veritas
97
100
  eql?(other)
98
101
  end
99
102
 
100
- # Compare the direction with other direction for equality
101
- #
102
- # @example
103
- # direction.eql?(other) # => true or false
104
- #
105
- # @param [Direction] other
106
- #
107
- # @return [Boolean]
108
- #
109
- # @api public
110
- def eql?(other)
111
- instance_of?(other.class) &&
112
- attribute.eql?(other.attribute)
113
- end
114
-
115
- # Return the hash of the direction
116
- #
117
- # @example
118
- # hash = direction.hash
119
- #
120
- # @return [Fixnum]
121
- #
122
- # @api public
123
- def hash
124
- self.class.hash ^ attribute.hash
125
- end
126
-
127
103
  # Coerce an object into a Direction
128
104
  #
129
105
  # @param [Attribute, Direction] object
@@ -136,8 +112,6 @@ module Veritas
136
112
  object.kind_of?(Direction) ? object : new(object)
137
113
  end
138
114
 
139
- memoize :hash
140
-
141
115
  end # class Direction
142
116
 
143
117
  # Represent an attribute sorted ascending