veritas 0.0.5 → 0.0.6

Sign up to get free protection for your applications and to get access to all the features.
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