veritas 0.0.4 → 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (244) hide show
  1. data/.travis.yml +4 -2
  2. data/Gemfile +7 -8
  3. data/README.rdoc +17 -18
  4. data/Rakefile +2 -2
  5. data/TODO +18 -14
  6. data/benchmarks/memory.rb +8 -7
  7. data/benchmarks/speed.rb +4 -3
  8. data/config/flay.yml +1 -1
  9. data/lib/veritas/aggregate.rb +3 -0
  10. data/lib/veritas/algebra/join.rb +11 -4
  11. data/lib/veritas/algebra/product.rb +2 -1
  12. data/lib/veritas/algebra/restriction.rb +3 -2
  13. data/lib/veritas/algebra/summarization.rb +8 -3
  14. data/lib/veritas/attribute/string.rb +3 -1
  15. data/lib/veritas/attribute.rb +1 -1
  16. data/lib/veritas/function/binary.rb +1 -0
  17. data/lib/veritas/function/comparable.rb +1 -0
  18. data/lib/veritas/function/connective/negation.rb +2 -0
  19. data/lib/veritas/function/proposition.rb +5 -1
  20. data/lib/veritas/function/unary.rb +1 -0
  21. data/lib/veritas/function.rb +3 -0
  22. data/lib/veritas/relation/base.rb +32 -3
  23. data/lib/veritas/relation/header.rb +2 -2
  24. data/lib/veritas/relation/materialized.rb +12 -0
  25. data/lib/veritas/relation/operation/binary.rb +1 -0
  26. data/lib/veritas/relation/operation/limit.rb +1 -1
  27. data/lib/veritas/relation/operation/offset.rb +1 -1
  28. data/lib/veritas/relation/operation/order/direction_set.rb +67 -5
  29. data/lib/veritas/relation/operation/order.rb +25 -3
  30. data/lib/veritas/relation/operation/set.rb +1 -0
  31. data/lib/veritas/relation.rb +20 -7
  32. data/lib/veritas/support/abstract_class.rb +1 -0
  33. data/lib/veritas/support/evaluator.rb +49 -3
  34. data/lib/veritas/support/immutable.rb +2 -1
  35. data/lib/veritas/tuple.rb +28 -14
  36. data/lib/veritas/version.rb +1 -1
  37. data/lib/veritas.rb +6 -3
  38. data/spec/integration/veritas/algebra/projection_spec.rb +4 -4
  39. data/spec/integration/veritas/relation/efficient_enumerable_spec.rb +1 -1
  40. data/spec/shared/each_method_behaviour.rb +2 -2
  41. data/spec/shared/hash_method_behavior.rb +2 -2
  42. data/spec/spec_helper.rb +1 -0
  43. data/spec/unit/date/pred_spec.rb +3 -3
  44. data/spec/unit/range/overlaps_spec.rb +14 -14
  45. data/spec/unit/range/to_inclusive_spec.rb +2 -2
  46. data/spec/unit/time/pred_spec.rb +3 -3
  47. data/spec/unit/veritas/abstract_class/class_methods/new_spec.rb +1 -1
  48. data/spec/unit/veritas/aggregate/count/class_methods/call_spec.rb +1 -1
  49. data/spec/unit/veritas/aggregate/count/methods/count_spec.rb +1 -1
  50. data/spec/unit/veritas/aggregate/maximum/methods/maximum_spec.rb +1 -1
  51. data/spec/unit/veritas/aggregate/mean/class_methods/call_spec.rb +1 -1
  52. data/spec/unit/veritas/aggregate/mean/methods/mean_spec.rb +1 -1
  53. data/spec/unit/veritas/aggregate/minimum/methods/minimum_spec.rb +1 -1
  54. data/spec/unit/veritas/aggregate/standard_deviation/methods/standard_deviation_spec.rb +1 -1
  55. data/spec/unit/veritas/aggregate/sum/class_methods/call_spec.rb +1 -1
  56. data/spec/unit/veritas/aggregate/sum/methods/sum_spec.rb +1 -1
  57. data/spec/unit/veritas/aggregate/variance/class_methods/call_spec.rb +1 -1
  58. data/spec/unit/veritas/aggregate/variance/methods/variance_spec.rb +1 -1
  59. data/spec/unit/veritas/algebra/difference/methods/difference_spec.rb +2 -2
  60. data/spec/unit/veritas/algebra/extension/class_methods/new_spec.rb +1 -1
  61. data/spec/unit/veritas/algebra/extension/eql_spec.rb +5 -5
  62. data/spec/unit/veritas/algebra/extension/header_spec.rb +1 -1
  63. data/spec/unit/veritas/algebra/extension/methods/extend_spec.rb +1 -1
  64. data/spec/unit/veritas/algebra/intersection/methods/intersect_spec.rb +2 -2
  65. data/spec/unit/veritas/algebra/join/class_methods/new_spec.rb +2 -2
  66. data/spec/unit/veritas/algebra/join/join_header_spec.rb +17 -0
  67. data/spec/unit/veritas/algebra/join/methods/join_spec.rb +2 -2
  68. data/spec/unit/veritas/algebra/product/class_methods/new_spec.rb +1 -1
  69. data/spec/unit/veritas/algebra/product/methods/product_spec.rb +1 -1
  70. data/spec/unit/veritas/algebra/projection/eql_spec.rb +5 -5
  71. data/spec/unit/veritas/algebra/projection/header_spec.rb +1 -1
  72. data/spec/unit/veritas/algebra/projection/methods/project_spec.rb +1 -1
  73. data/spec/unit/veritas/algebra/projection/methods/remove_spec.rb +1 -1
  74. data/spec/unit/veritas/algebra/rename/aliases/class_methods/coerce_spec.rb +4 -4
  75. data/spec/unit/veritas/algebra/rename/aliases/class_methods/new_spec.rb +1 -1
  76. data/spec/unit/veritas/algebra/rename/aliases/eql_spec.rb +4 -4
  77. data/spec/unit/veritas/algebra/rename/aliases/equal_value_spec.rb +4 -4
  78. data/spec/unit/veritas/algebra/rename/aliases/to_hash_spec.rb +1 -1
  79. data/spec/unit/veritas/algebra/rename/aliases/union_spec.rb +10 -10
  80. data/spec/unit/veritas/algebra/rename/directions_spec.rb +3 -3
  81. data/spec/unit/veritas/algebra/rename/eql_spec.rb +5 -5
  82. data/spec/unit/veritas/algebra/rename/header_spec.rb +1 -1
  83. data/spec/unit/veritas/algebra/rename/methods/rename_spec.rb +1 -1
  84. data/spec/unit/veritas/algebra/restriction/eql_spec.rb +5 -5
  85. data/spec/unit/veritas/algebra/restriction/methods/restrict_spec.rb +1 -1
  86. data/spec/unit/veritas/algebra/summarization/class_methods/new_spec.rb +1 -1
  87. data/spec/unit/veritas/algebra/summarization/eql_spec.rb +7 -7
  88. data/spec/unit/veritas/algebra/summarization/header_spec.rb +1 -1
  89. data/spec/unit/veritas/algebra/summarization/methods/summarize_spec.rb +18 -8
  90. data/spec/unit/veritas/algebra/summarization/summaries/summarize_by_spec.rb +3 -3
  91. data/spec/unit/veritas/algebra/summarization/summaries/to_hash_spec.rb +2 -2
  92. data/spec/unit/veritas/algebra/summarization/summary/summarize_by_spec.rb +1 -1
  93. data/spec/unit/veritas/algebra/union/methods/union_spec.rb +2 -2
  94. data/spec/unit/veritas/aliasable/inheritable_alias_spec.rb +2 -2
  95. data/spec/unit/veritas/attribute/class_methods/coerce_spec.rb +4 -4
  96. data/spec/unit/veritas/attribute/class_methods/descendants_spec.rb +2 -6
  97. data/spec/unit/veritas/attribute/class_methods/new_spec.rb +1 -1
  98. data/spec/unit/veritas/attribute/comparable/comparable_spec.rb +3 -3
  99. data/spec/unit/veritas/attribute/eql_spec.rb +4 -4
  100. data/spec/unit/veritas/attribute/equal_value_spec.rb +4 -4
  101. data/spec/unit/veritas/attribute/inspect_spec.rb +1 -1
  102. data/spec/unit/veritas/attribute/joinable_spec.rb +4 -4
  103. data/spec/unit/veritas/attribute/numeric/joinable_spec.rb +3 -3
  104. data/spec/unit/veritas/attribute/options_spec.rb +2 -2
  105. data/spec/unit/veritas/attribute/orderable/asc_spec.rb +1 -1
  106. data/spec/unit/veritas/attribute/orderable/desc_spec.rb +1 -1
  107. data/spec/unit/veritas/attribute/rename_spec.rb +1 -1
  108. data/spec/unit/veritas/attribute/string/joinable_spec.rb +14 -4
  109. data/spec/unit/veritas/evaluator/context/method_missing_spec.rb +29 -0
  110. data/spec/unit/veritas/evaluator/context/respond_to_spec.rb +39 -0
  111. data/spec/unit/veritas/evaluator/context/send_spec.rb +28 -0
  112. data/spec/unit/veritas/evaluator/context/yield_spec.rb +14 -0
  113. data/spec/unit/veritas/function/binary/equal_value_spec.rb +5 -5
  114. data/spec/unit/veritas/function/binary/invertible/inverse_spec.rb +1 -1
  115. data/spec/unit/veritas/function/binary/rename_spec.rb +3 -3
  116. data/spec/unit/veritas/function/connective/conjunction/inverse_spec.rb +1 -1
  117. data/spec/unit/veritas/function/connective/disjunction/inverse_spec.rb +1 -1
  118. data/spec/unit/veritas/function/connective/negation/methods/not_spec.rb +2 -2
  119. data/spec/unit/veritas/function/numeric/absolute/methods/absolute_spec.rb +1 -1
  120. data/spec/unit/veritas/function/numeric/addition/methods/add_spec.rb +1 -1
  121. data/spec/unit/veritas/function/numeric/division/methods/divide_spec.rb +1 -1
  122. data/spec/unit/veritas/function/numeric/exponentiation/inverse_spec.rb +1 -1
  123. data/spec/unit/veritas/function/numeric/exponentiation/methods/exponent_spec.rb +1 -1
  124. data/spec/unit/veritas/function/numeric/modulo/methods/modulo_spec.rb +1 -1
  125. data/spec/unit/veritas/function/numeric/multiplication/methods/multiply_spec.rb +1 -1
  126. data/spec/unit/veritas/function/numeric/square_root/methods/square_root_spec.rb +1 -1
  127. data/spec/unit/veritas/function/numeric/subtraction/methods/subtract_spec.rb +1 -1
  128. data/spec/unit/veritas/function/numeric/unary_minus/methods/unary_minus_spec.rb +1 -1
  129. data/spec/unit/veritas/function/numeric/unary_plus/methods/unary_plus_spec.rb +1 -1
  130. data/spec/unit/veritas/function/predicate/eql_spec.rb +5 -5
  131. data/spec/unit/veritas/function/predicate/equality/inverse_spec.rb +1 -1
  132. data/spec/unit/veritas/function/predicate/equality/methods/eq_spec.rb +1 -1
  133. data/spec/unit/veritas/function/predicate/exclusion/inverse_spec.rb +1 -1
  134. data/spec/unit/veritas/function/predicate/exclusion/methods/exclude_spec.rb +1 -1
  135. data/spec/unit/veritas/function/predicate/greater_than/inverse_spec.rb +1 -1
  136. data/spec/unit/veritas/function/predicate/greater_than/methods/gt_spec.rb +1 -1
  137. data/spec/unit/veritas/function/predicate/greater_than_or_equal_to/inverse_spec.rb +1 -1
  138. data/spec/unit/veritas/function/predicate/greater_than_or_equal_to/methods/gte_spec.rb +1 -1
  139. data/spec/unit/veritas/function/predicate/inclusion/inverse_spec.rb +1 -1
  140. data/spec/unit/veritas/function/predicate/inclusion/methods/include_spec.rb +1 -1
  141. data/spec/unit/veritas/function/predicate/inequality/inverse_spec.rb +1 -1
  142. data/spec/unit/veritas/function/predicate/inequality/methods/ne_spec.rb +1 -1
  143. data/spec/unit/veritas/function/predicate/inverse_spec.rb +1 -1
  144. data/spec/unit/veritas/function/predicate/less_than/inverse_spec.rb +1 -1
  145. data/spec/unit/veritas/function/predicate/less_than/methods/lt_spec.rb +1 -1
  146. data/spec/unit/veritas/function/predicate/less_than_or_equal_to/inverse_spec.rb +1 -1
  147. data/spec/unit/veritas/function/predicate/less_than_or_equal_to/methods/lte_spec.rb +1 -1
  148. data/spec/unit/veritas/function/predicate/match/inverse_spec.rb +1 -1
  149. data/spec/unit/veritas/function/predicate/match/methods/match_spec.rb +1 -1
  150. data/spec/unit/veritas/function/predicate/no_match/inverse_spec.rb +1 -1
  151. data/spec/unit/veritas/function/predicate/no_match/methods/no_match_spec.rb +1 -1
  152. data/spec/unit/veritas/function/proposition/eql_spec.rb +3 -3
  153. data/spec/unit/veritas/function/proposition/equal_value_spec.rb +3 -3
  154. data/spec/unit/veritas/function/string/length/methods/length_spec.rb +1 -1
  155. data/spec/unit/veritas/function/unary/equal_value_spec.rb +4 -4
  156. data/spec/unit/veritas/function/unary/invertible/inverse_spec.rb +1 -1
  157. data/spec/unit/veritas/function/unary/rename_spec.rb +1 -1
  158. data/spec/unit/veritas/immutable/class_methods/freeze_object_spec.rb +7 -1
  159. data/spec/unit/veritas/immutable/class_methods/new_spec.rb +1 -1
  160. data/spec/unit/veritas/immutable/freeze_spec.rb +2 -2
  161. data/spec/unit/veritas/immutable/module_methods/memoize_spec.rb +2 -2
  162. data/spec/unit/veritas/operation/binary/eql_spec.rb +5 -5
  163. data/spec/unit/veritas/operation/unary/eql_spec.rb +4 -4
  164. data/spec/unit/veritas/relation/base/class_methods/new_spec.rb +35 -0
  165. data/spec/unit/veritas/relation/base/eql_spec.rb +100 -0
  166. data/spec/unit/veritas/relation/base/hash_spec.rb +16 -0
  167. data/spec/unit/veritas/relation/class_methods/new_spec.rb +2 -2
  168. data/spec/unit/veritas/relation/directions_spec.rb +1 -1
  169. data/spec/unit/veritas/relation/eql_spec.rb +15 -15
  170. data/spec/unit/veritas/relation/equal_value_spec.rb +16 -16
  171. data/spec/unit/veritas/relation/header/class_methods/coerce_spec.rb +1 -1
  172. data/spec/unit/veritas/relation/header/class_methods/new_spec.rb +2 -2
  173. data/spec/unit/veritas/relation/header/difference_spec.rb +1 -1
  174. data/spec/unit/veritas/relation/header/eql_spec.rb +5 -5
  175. data/spec/unit/veritas/relation/header/equal_value_spec.rb +7 -7
  176. data/spec/unit/veritas/relation/header/inspect_spec.rb +1 -1
  177. data/spec/unit/veritas/relation/header/intersect_spec.rb +1 -1
  178. data/spec/unit/veritas/relation/header/project_spec.rb +1 -1
  179. data/spec/unit/veritas/relation/header/rename_spec.rb +1 -1
  180. data/spec/unit/veritas/relation/header/to_ary_spec.rb +1 -1
  181. data/spec/unit/veritas/relation/header/union_spec.rb +1 -1
  182. data/spec/unit/veritas/relation/materialize_spec.rb +3 -3
  183. data/spec/unit/veritas/relation/materialized/class_methods/new_spec.rb +2 -2
  184. data/spec/unit/veritas/relation/materialized/materialized_spec.rb +15 -0
  185. data/spec/unit/veritas/relation/materialized_spec.rb +15 -0
  186. data/spec/unit/veritas/relation/operation/binary/class_methods/new_spec.rb +6 -6
  187. data/spec/unit/veritas/relation/operation/binary/header_spec.rb +1 -1
  188. data/spec/unit/veritas/relation/operation/combination/header_spec.rb +1 -1
  189. data/spec/unit/veritas/relation/operation/limit/class_methods/new_spec.rb +12 -5
  190. data/spec/unit/veritas/relation/operation/limit/directions_spec.rb +1 -1
  191. data/spec/unit/veritas/relation/operation/limit/each_spec.rb +1 -1
  192. data/spec/unit/veritas/relation/operation/limit/eql_spec.rb +11 -11
  193. data/spec/unit/veritas/relation/operation/limit/hash_spec.rb +1 -1
  194. data/spec/unit/veritas/relation/operation/limit/limit_spec.rb +1 -1
  195. data/spec/unit/veritas/relation/operation/limit/methods/first_spec.rb +3 -3
  196. data/spec/unit/veritas/relation/operation/limit/methods/last_spec.rb +3 -3
  197. data/spec/unit/veritas/relation/operation/limit/methods/take_spec.rb +2 -2
  198. data/spec/unit/veritas/relation/operation/offset/class_methods/new_spec.rb +12 -5
  199. data/spec/unit/veritas/relation/operation/offset/directions_spec.rb +1 -1
  200. data/spec/unit/veritas/relation/operation/offset/each_spec.rb +1 -1
  201. data/spec/unit/veritas/relation/operation/offset/eql_spec.rb +11 -11
  202. data/spec/unit/veritas/relation/operation/offset/hash_spec.rb +1 -1
  203. data/spec/unit/veritas/relation/operation/offset/methods/drop_spec.rb +2 -2
  204. data/spec/unit/veritas/relation/operation/offset/offset_spec.rb +1 -1
  205. data/spec/unit/veritas/relation/operation/order/ascending/reverse_spec.rb +1 -1
  206. data/spec/unit/veritas/relation/operation/order/class_methods/new_spec.rb +3 -7
  207. data/spec/unit/veritas/relation/operation/order/descending/reverse_spec.rb +1 -1
  208. data/spec/unit/veritas/relation/operation/order/direction/class_methods/coerce_spec.rb +1 -1
  209. data/spec/unit/veritas/relation/operation/order/direction/eql_spec.rb +4 -4
  210. data/spec/unit/veritas/relation/operation/order/direction/rename_spec.rb +1 -1
  211. data/spec/unit/veritas/relation/operation/order/direction_set/attributes_spec.rb +1 -1
  212. data/spec/unit/veritas/relation/operation/order/direction_set/class_methods/coerce_spec.rb +4 -4
  213. data/spec/unit/veritas/relation/operation/order/direction_set/class_methods/new_spec.rb +32 -0
  214. data/spec/unit/veritas/relation/operation/order/direction_set/eql_spec.rb +4 -4
  215. data/spec/unit/veritas/relation/operation/order/direction_set/equal_value_spec.rb +6 -6
  216. data/spec/unit/veritas/relation/operation/order/direction_set/project_spec.rb +1 -1
  217. data/spec/unit/veritas/relation/operation/order/direction_set/rename_spec.rb +1 -1
  218. data/spec/unit/veritas/relation/operation/order/direction_set/reverse_spec.rb +2 -2
  219. data/spec/unit/veritas/relation/operation/order/direction_set/sort_tuples_spec.rb +4 -4
  220. data/spec/unit/veritas/relation/operation/order/direction_set/to_ary_spec.rb +1 -1
  221. data/spec/unit/veritas/relation/operation/order/direction_set/union_spec.rb +1 -1
  222. data/spec/unit/veritas/relation/operation/order/eql_spec.rb +5 -5
  223. data/spec/unit/veritas/relation/operation/order/methods/order_spec.rb +24 -4
  224. data/spec/unit/veritas/relation/operation/order/methods/sort_by_spec.rb +28 -0
  225. data/spec/unit/veritas/relation/operation/reverse/class_methods/new_spec.rb +6 -6
  226. data/spec/unit/veritas/relation/operation/reverse/directions_spec.rb +1 -1
  227. data/spec/unit/veritas/relation/operation/reverse/each_spec.rb +1 -1
  228. data/spec/unit/veritas/relation/operation/reverse/methods/reverse_spec.rb +2 -2
  229. data/spec/unit/veritas/relation/operation/set/class_methods/new_spec.rb +1 -1
  230. data/spec/unit/veritas/tuple/class_methods/coerce_spec.rb +1 -1
  231. data/spec/unit/veritas/tuple/data_spec.rb +16 -0
  232. data/spec/unit/veritas/tuple/element_reference_spec.rb +1 -1
  233. data/spec/unit/veritas/tuple/eql_spec.rb +5 -5
  234. data/spec/unit/veritas/tuple/equal_value_spec.rb +7 -7
  235. data/spec/unit/veritas/tuple/extend_spec.rb +3 -3
  236. data/spec/unit/veritas/tuple/hash_spec.rb +1 -1
  237. data/spec/unit/veritas/tuple/inspect_spec.rb +2 -2
  238. data/spec/unit/veritas/tuple/join_spec.rb +1 -1
  239. data/spec/unit/veritas/tuple/predicate_spec.rb +44 -0
  240. data/spec/unit/veritas/tuple/project_spec.rb +1 -1
  241. data/spec/unit/veritas/tuple/to_ary_spec.rb +3 -1
  242. data/tasks/metrics/heckle.rake +1 -0
  243. data/veritas.gemspec +28 -14
  244. metadata +31 -17
@@ -12,18 +12,80 @@ module Veritas
12
12
 
13
13
  inheritable_alias(:| => :union)
14
14
 
15
+ # Instantiate a DirectionSet
16
+ #
17
+ # @example
18
+ # directions = DirectionSet.new(directions)
19
+ #
20
+ # @param [#to_ary] directions
21
+ # optional attributes
22
+ #
23
+ # @return [undefined]
24
+ #
25
+ # @api public
26
+ def self.new(directions)
27
+ directions = coerce_directions(directions.to_ary)
28
+ assert_unique_attributes(directions.map { |direction| direction.attribute })
29
+ super
30
+ end
31
+
32
+ # Coerce the attributes into an Array of Direction objects
33
+ #
34
+ # @param [Array<Direction>] attributes
35
+ #
36
+ # @return [Array<Direction>]
37
+ #
38
+ # @api private
39
+ def self.coerce_directions(directions)
40
+ directions.map { |direction| Ascending.coerce(direction) }
41
+ end
42
+
43
+ # Assert the attributes are unique
44
+ #
45
+ # @param [Array<Attribute>] attributes
46
+ #
47
+ # @return [undefined]
48
+ #
49
+ # @raise [DuplicateAttributeError]
50
+ # raised if the attributes are not unique
51
+ #
52
+ # @api private
53
+ def self.assert_unique_attributes(attributes)
54
+ duplicates = duplicate_attributes(attributes)
55
+ if duplicates
56
+ raise DuplicateAttributeError, "duplicate attributes: #{duplicates.join(', ')}"
57
+ end
58
+ end
59
+
60
+ # Returns the duplicate attribute names, if any
61
+ #
62
+ # @param [Array<Attribute>] attributes
63
+ #
64
+ # @return [Array<Symbol>]
65
+ # returns an array of duplicate attributes
66
+ #
67
+ # @return [nil]
68
+ # returns nil if there are no duplicate attributes
69
+ #
70
+ # @api private
71
+ def self.duplicate_attributes(attributes)
72
+ names = attributes.map { |attribute| attribute.name }
73
+ names.select! { |name| names.count(name) > 1 }
74
+ names.uniq!
75
+ end
76
+
77
+ private_class_method :coerce_directions, :assert_unique_attributes, :duplicate_attributes
78
+
15
79
  # Initialize a DirectionSet
16
80
  #
17
- # @param [Array<Direction, Attribute>] attribute
18
- # the attribute to sort on
81
+ # @param [Array<Direction>] directions
82
+ # the directions to sort with
19
83
  #
20
84
  # @return [undefined]
21
85
  #
22
86
  # @api private
23
87
  def initialize(directions)
24
- @directions = directions.to_ary.map do |direction|
25
- Ascending.coerce(direction)
26
- end
88
+ @directions = directions
27
89
  end
28
90
 
29
91
  EMPTY = new([])
@@ -29,7 +29,6 @@ module Veritas
29
29
  #
30
30
  # @api public
31
31
  def self.new(operand, directions)
32
- directions = operand.header if directions.empty?
33
32
  directions = DirectionSet.coerce(directions)
34
33
  assert_order_by_full_header(operand, directions)
35
34
  super
@@ -123,11 +122,33 @@ module Veritas
123
122
 
124
123
  # Return an ordered relation
125
124
  #
125
+ # @example
126
+ # order = relation.sort_by { |r| [ r.a.desc, r.b ] }
127
+ #
128
+ # @yield [relation]
129
+ # optional block to evaluate for directions
130
+ #
131
+ # @yieldparam [Relation] relation
132
+ #
133
+ # @yieldreturn [Array<Direction>, Header]
134
+ #
135
+ # @return [Order]
136
+ #
137
+ # @api public
138
+ def sort_by
139
+ context = Evaluator::Context.new(header) { |context| yield context }
140
+ Order.new(self, Array(context.yield))
141
+ end
142
+
143
+ # Return an ordered relation (Deprecated)
144
+ #
145
+ # @deprecated Use #sort_by instead
146
+ #
126
147
  # @example with no directions
127
148
  # order = relation.order # sort by the header
128
149
  #
129
150
  # @example with a block
130
- # order = relation.order { |r| [ r[:a].desc, r[:b] ] }
151
+ # order = relation.order { |r| [ r.a.desc, r.b ] }
131
152
  #
132
153
  # @yield [relation]
133
154
  # optional block to evaluate for directions
@@ -140,7 +161,8 @@ module Veritas
140
161
  #
141
162
  # @api public
142
163
  def order
143
- Order.new(self, block_given? ? Array(yield(self)) : header)
164
+ warn "#{self.class}#order is deprecated and will be removed from Veritas 0.0.6"
165
+ sort_by { |context| block_given? ? yield(context) : header }
144
166
  end
145
167
 
146
168
  end # module Methods
@@ -17,6 +17,7 @@ module Veritas
17
17
  #
18
18
  # @api private
19
19
  def self.included(descendant)
20
+ super
20
21
  descendant.extend ClassMethods
21
22
  self
22
23
  end
@@ -13,6 +13,14 @@ module Veritas
13
13
  # @api private
14
14
  attr_reader :header
15
15
 
16
+ # The relation tuples
17
+ #
18
+ # @return [Enumerable]
19
+ #
20
+ # @api private
21
+ attr_reader :tuples
22
+ private :tuples
23
+
16
24
  # The relation sort order
17
25
  #
18
26
  # @return [Operation::Order::DirectionSet]
@@ -118,6 +126,18 @@ module Veritas
118
126
  Materialized.new(header, to_a, directions)
119
127
  end
120
128
 
129
+ # Return false for a non-Materialized relation
130
+ #
131
+ # @example
132
+ # relation.materialized? # => false
133
+ #
134
+ # @return [false]
135
+ #
136
+ # @api public
137
+ def materialized?
138
+ false
139
+ end
140
+
121
141
  # Compare the relation with other relation for equivalency
122
142
  #
123
143
  # @example
@@ -178,13 +198,6 @@ module Veritas
178
198
 
179
199
  private
180
200
 
181
- # The relation tuples
182
- #
183
- # @return [Enumerable]
184
- #
185
- # @api private
186
- attr_reader :tuples
187
-
188
201
  # Coerce an Enumerable into a Relation
189
202
  #
190
203
  # @param [Enumerable] tuples
@@ -12,6 +12,7 @@ module Veritas
12
12
  #
13
13
  # @api private
14
14
  def self.included(descendant)
15
+ super
15
16
  descendant.extend ClassMethods
16
17
  self
17
18
  end
@@ -4,8 +4,7 @@ module Veritas
4
4
  module Evaluator
5
5
 
6
6
  # Provide a context to evaluate a Relation operation block
7
- class Context
8
- include Immutable
7
+ class Context < BasicObject
9
8
 
10
9
  # The functions to evaluate
11
10
  #
@@ -14,6 +13,13 @@ module Veritas
14
13
  # @api private
15
14
  attr_reader :functions
16
15
 
16
+ # Return the block results
17
+ #
18
+ # @return [Object]
19
+ #
20
+ # @api private
21
+ attr_reader :yield
22
+
17
23
  # Initialize a Context
18
24
  #
19
25
  # @param [Header] header
@@ -24,7 +30,7 @@ module Veritas
24
30
  def initialize(header)
25
31
  @header = header
26
32
  @functions = {}
27
- yield self
33
+ @yield = yield self
28
34
  @functions.freeze
29
35
  end
30
36
 
@@ -68,6 +74,46 @@ module Veritas
68
74
  @header[name]
69
75
  end
70
76
 
77
+ # Test if the method is supported on this object
78
+ #
79
+ # @param [Symbol] name
80
+ #
81
+ # @return [Boolean]
82
+ #
83
+ # @api private
84
+ def respond_to?(name, *)
85
+ !!self[name]
86
+ end
87
+
88
+ # Forward a message to the object
89
+ #
90
+ # @param [Array] *args
91
+ #
92
+ # @return [Object]
93
+ #
94
+ # @api private
95
+ def send(*args, &block)
96
+ __send__(*args, &block)
97
+ end
98
+
99
+ private
100
+
101
+ # Lookup the attribute in the header using the attribute name
102
+ #
103
+ # @example
104
+ # attribute = context.id
105
+ #
106
+ # @param [Symbol] name
107
+ #
108
+ # @return [Attribute]
109
+ #
110
+ # @api private
111
+ def method_missing(name, *args)
112
+ return super unless respond_to?(name)
113
+ ::Kernel.raise ::ArgumentError, "wrong number of arguments (#{args.length} for 0)" unless args.empty?
114
+ self[name]
115
+ end
116
+
71
117
  end # class Context
72
118
  end # module Evaluator
73
119
  end # module Veritas
@@ -14,6 +14,7 @@ module Veritas
14
14
  #
15
15
  # @api private
16
16
  def self.included(descendant)
17
+ super
17
18
  descendant.extend ModuleMethods if descendant.kind_of?(Module)
18
19
  descendant.extend ClassMethods if descendant.kind_of?(Class)
19
20
  self
@@ -94,7 +95,7 @@ module Veritas
94
95
  # @api public
95
96
  def self.freeze_object(object)
96
97
  case object
97
- when Numeric, TrueClass, FalseClass, NilClass
98
+ when Numeric, TrueClass, FalseClass, NilClass, Symbol
98
99
  object
99
100
  else
100
101
  freeze_value(object)
data/lib/veritas/tuple.rb CHANGED
@@ -13,6 +13,13 @@ module Veritas
13
13
  # @api private
14
14
  attr_reader :header
15
15
 
16
+ # The tuple data
17
+ #
18
+ # @return [Hash]
19
+ #
20
+ # @api private
21
+ attr_reader :data
22
+
16
23
  # Initialize a Tuple
17
24
  #
18
25
  # @param [Header] header
@@ -39,7 +46,7 @@ module Veritas
39
46
  #
40
47
  # @api public
41
48
  def [](attribute)
42
- @data[header[attribute]]
49
+ data.fetch(header[attribute])
43
50
  end
44
51
 
45
52
  # Return a tuple with only the specified attributes
@@ -54,7 +61,7 @@ module Veritas
54
61
  #
55
62
  # @api public
56
63
  def project(header)
57
- self.class.new(header, @data.values_at(*header))
64
+ self.class.new(header, data.values_at(*header))
58
65
  end
59
66
 
60
67
  # Append values to the tuple and return a new tuple
@@ -94,6 +101,17 @@ module Veritas
94
101
  )
95
102
  end
96
103
 
104
+ # Return the predicate matching the tuple
105
+ #
106
+ # @return [Function]
107
+ #
108
+ # @api private
109
+ def predicate
110
+ header.reduce(Function::Proposition::Tautology.instance) do |predicate, attribute|
111
+ predicate.and(attribute.eq(self[attribute]))
112
+ end
113
+ end
114
+
97
115
  # Convert the Tuple into an Array
98
116
  #
99
117
  # @example
@@ -103,7 +121,7 @@ module Veritas
103
121
  #
104
122
  # @api public
105
123
  def to_ary
106
- @data.values_at(*header).freeze
124
+ data.values_at(*header).freeze
107
125
  end
108
126
 
109
127
  # Compare the tuple with other tuple for equivalency
@@ -118,10 +136,8 @@ module Veritas
118
136
  #
119
137
  # @api public
120
138
  def ==(other)
121
- header = self.header
122
- other = self.class.coerce(header, other)
123
- header == other.header &&
124
- to_ary == other.project(header).to_ary
139
+ other = self.class.coerce(header, other)
140
+ data == other.data
125
141
  end
126
142
 
127
143
  # Compare the tuple with other tuple for equality
@@ -136,10 +152,8 @@ module Veritas
136
152
  #
137
153
  # @api public
138
154
  def eql?(other)
139
- header = self.header
140
155
  instance_of?(other.class) &&
141
- header.eql?(other.header) &&
142
- to_ary.eql?(other.project(header).to_ary)
156
+ data.eql?(other.data)
143
157
  end
144
158
 
145
159
  # Return the hash of the tuple
@@ -151,19 +165,19 @@ module Veritas
151
165
  #
152
166
  # @api public
153
167
  def hash
154
- self.class.hash ^ header.hash ^ @data.hash
168
+ self.class.hash ^ data.hash
155
169
  end
156
170
 
157
171
  # Return a string representing the tuple data
158
172
  #
159
173
  # @example
160
- # tuple.inspect # => "[1, 2, 3]"
174
+ # tuple.inspect # => "{<Attribute::Integer name: id>=>1}"
161
175
  #
162
176
  # @return [String]
163
177
  #
164
178
  # @api public
165
179
  def inspect
166
- to_ary.inspect
180
+ data.inspect
167
181
  end
168
182
 
169
183
  # Coerce an Array-like object into a Tuple
@@ -180,7 +194,7 @@ module Veritas
180
194
  object.kind_of?(Tuple) ? object : new(header, object)
181
195
  end
182
196
 
183
- memoize :hash, :to_ary
197
+ memoize :hash, :predicate, :to_ary
184
198
 
185
199
  end # class Tuple
186
200
  end # module Veritas
@@ -1,5 +1,5 @@
1
1
  # encoding: utf-8
2
2
 
3
3
  module Veritas
4
- VERSION = '0.0.4'
4
+ VERSION = '0.0.5'
5
5
  end # module Veritas
data/lib/veritas.rb CHANGED
@@ -125,9 +125,6 @@ require 'veritas/version'
125
125
 
126
126
  module Veritas
127
127
 
128
- # Represent an undefined argument
129
- module Undefined; end
130
-
131
128
  # Raised when the headers are invalid for Join and Product
132
129
  class InvalidHeaderError < ArgumentError; end
133
130
 
@@ -152,6 +149,12 @@ module Veritas
152
149
  # Raised when an attribute is a duplicate of another in the header
153
150
  class DuplicateAttributeError < StandardError; end
154
151
 
152
+ # Represent an undefined argument
153
+ Undefined = Object.new.freeze
154
+
155
+ # Represent a relation with an empty header and no tuples
155
156
  TABLE_DUM = Relation::Empty.new([])
157
+
158
+ # Represent a relation with an empty header and a single tuple
156
159
  TABLE_DEE = Relation.new([], [ [] ])
157
160
  end
@@ -6,10 +6,10 @@ describe Algebra::Projection do
6
6
  context 'remove attributes in predicate' do
7
7
  subject { restriction.project([ :name ]) }
8
8
 
9
- let(:left) { Relation.new([ [ :id, Integer ] ], (1..100).map { |n| [ n ] }) }
10
- let(:right) { Relation.new([ [ :name, String ] ], [ [ 'Dan Kubb' ], [ 'John Doe' ], [ 'Jane Doe' ] ]) }
11
- let(:relation) { left * right }
12
- let(:restriction) { relation.restrict { |r| r[:id].gte(1).and(r[:id].lte(10)).and(r[:name].eq('Dan Kubb')) } }
9
+ let(:left) { Relation.new([ [ :id, Integer ] ], (1..100).map { |n| [ n ] }) }
10
+ let(:right) { Relation.new([ [ :name, String ] ], [ [ 'Dan Kubb' ], [ 'John Doe' ], [ 'Jane Doe' ] ]) }
11
+ let(:relation) { left * right }
12
+ let(:restriction) { relation.restrict { |r| r.id.gte(1).and(r.id.lte(10)).and(r.name.eq('Dan Kubb')) } }
13
13
 
14
14
  it 'returns a relation with a single tuple' do
15
15
  should == [ [ 'Dan Kubb' ] ]
@@ -31,7 +31,7 @@ describe Relation do
31
31
  end
32
32
 
33
33
  it '#restrict should be efficient' do
34
- restricted = relation.restrict{ |r| r[:id].gt(5) }
34
+ restricted = relation.restrict{ |r| r.id.gt(5) }
35
35
  sample(restricted).should == [ [ 6 ], [ 7 ], [ 8 ], [ 9 ], [ 10 ] ]
36
36
  end
37
37
 
@@ -6,10 +6,10 @@ shared_examples_for 'an #each method' do
6
6
  context 'with no block' do
7
7
  subject { object.each }
8
8
 
9
- it { should be_kind_of(to_enum.class) }
9
+ it { should be_instance_of(to_enum.class) }
10
10
 
11
11
  it 'yields the expected values' do
12
- subject.to_a.should == object.to_a
12
+ subject.to_a.should eql(object.to_a)
13
13
  end
14
14
  end
15
15
  end
@@ -3,9 +3,9 @@
3
3
  shared_examples_for 'a hash method' do
4
4
  it_should_behave_like 'an idempotent method'
5
5
 
6
- it { should be_kind_of(Fixnum) }
6
+ it { should be_instance_of(Fixnum) }
7
7
 
8
8
  it 'memoizes the hash code' do
9
- should == object.memoized('hash')
9
+ subject.should eql(object.memoized('hash'))
10
10
  end
11
11
  end
data/spec/spec_helper.rb CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  require 'rubygems'
4
4
  require 'backports'
5
+ require 'backports/basic_object'
5
6
  require 'veritas'
6
7
  require 'spec'
7
8
  require 'spec/autorun'
@@ -7,13 +7,13 @@ describe Date, '#pred' do
7
7
 
8
8
  let(:object) { described_class.today }
9
9
 
10
- it { should be_kind_of(described_class) }
10
+ it { should be_instance_of(described_class) }
11
11
 
12
12
  it 'returns the date 1 day ago' do
13
- should == (object - 1)
13
+ should eql(object - 1)
14
14
  end
15
15
 
16
16
  it 'is the inverse of #succ' do
17
- subject.succ.should == object
17
+ subject.succ.should eql(object)
18
18
  end
19
19
  end
@@ -17,7 +17,7 @@ describe Range, '#overlaps?' do
17
17
  it { should be(false) }
18
18
 
19
19
  it 'is symmetric' do
20
- should == other.overlaps?(object)
20
+ should eql(other.overlaps?(object))
21
21
  end
22
22
  end
23
23
 
@@ -30,7 +30,7 @@ describe Range, '#overlaps?' do
30
30
  it { should be(false) }
31
31
 
32
32
  it 'is symmetric' do
33
- should == other.overlaps?(object)
33
+ should eql(other.overlaps?(object))
34
34
  end
35
35
  end
36
36
 
@@ -43,7 +43,7 @@ describe Range, '#overlaps?' do
43
43
  it { should be(true) }
44
44
 
45
45
  it 'is symmetric' do
46
- should == other.overlaps?(object)
46
+ should eql(other.overlaps?(object))
47
47
  end
48
48
  end
49
49
 
@@ -56,7 +56,7 @@ describe Range, '#overlaps?' do
56
56
  it { should be(true) }
57
57
 
58
58
  it 'is symmetric' do
59
- should == other.overlaps?(object)
59
+ should eql(other.overlaps?(object))
60
60
  end
61
61
  end
62
62
 
@@ -69,7 +69,7 @@ describe Range, '#overlaps?' do
69
69
  it { should be(true) }
70
70
 
71
71
  it 'is symmetric' do
72
- should == other.overlaps?(object)
72
+ should eql(other.overlaps?(object))
73
73
  end
74
74
  end
75
75
 
@@ -82,7 +82,7 @@ describe Range, '#overlaps?' do
82
82
  it { should be(true) }
83
83
 
84
84
  it 'is symmetric' do
85
- should == other.overlaps?(object)
85
+ should eql(other.overlaps?(object))
86
86
  end
87
87
  end
88
88
 
@@ -95,7 +95,7 @@ describe Range, '#overlaps?' do
95
95
  it { should be(true) }
96
96
 
97
97
  it 'is symmetric' do
98
- should == other.overlaps?(object)
98
+ should eql(other.overlaps?(object))
99
99
  end
100
100
  end
101
101
 
@@ -108,7 +108,7 @@ describe Range, '#overlaps?' do
108
108
  it { should be(true) }
109
109
 
110
110
  it 'is symmetric' do
111
- should == other.overlaps?(object)
111
+ should eql(other.overlaps?(object))
112
112
  end
113
113
  end
114
114
 
@@ -121,7 +121,7 @@ describe Range, '#overlaps?' do
121
121
  it { should be(true) }
122
122
 
123
123
  it 'is symmetric' do
124
- should == other.overlaps?(object)
124
+ should eql(other.overlaps?(object))
125
125
  end
126
126
  end
127
127
 
@@ -134,7 +134,7 @@ describe Range, '#overlaps?' do
134
134
  it { should be(true) }
135
135
 
136
136
  it 'is symmetric' do
137
- should == other.overlaps?(object)
137
+ should eql(other.overlaps?(object))
138
138
  end
139
139
  end
140
140
 
@@ -147,7 +147,7 @@ describe Range, '#overlaps?' do
147
147
  it { should be(true) }
148
148
 
149
149
  it 'is symmetric' do
150
- should == other.overlaps?(object)
150
+ should eql(other.overlaps?(object))
151
151
  end
152
152
  end
153
153
 
@@ -160,7 +160,7 @@ describe Range, '#overlaps?' do
160
160
  it { should be(true) }
161
161
 
162
162
  it 'is symmetric' do
163
- should == other.overlaps?(object)
163
+ should eql(other.overlaps?(object))
164
164
  end
165
165
  end
166
166
 
@@ -173,7 +173,7 @@ describe Range, '#overlaps?' do
173
173
  it { should be(true) }
174
174
 
175
175
  it 'is symmetric' do
176
- should == other.overlaps?(object)
176
+ should eql(other.overlaps?(object))
177
177
  end
178
178
  end
179
179
 
@@ -186,7 +186,7 @@ describe Range, '#overlaps?' do
186
186
  it { should be(false) }
187
187
 
188
188
  it 'is symmetric' do
189
- should == other.overlaps?(object)
189
+ should eql(other.overlaps?(object))
190
190
  end
191
191
  end
192
192
  end
@@ -14,10 +14,10 @@ describe Range, '#to_inclusive' do
14
14
  let(:range_start) { 1 }
15
15
  let(:range_end) { 3 }
16
16
 
17
- it { should be_kind_of(described_class) }
17
+ it { should be_instance_of(described_class) }
18
18
 
19
19
  it 'returns an inclusive Range' do
20
- should == described_class.new(1, 2)
20
+ should eql(described_class.new(1, 2))
21
21
  end
22
22
  end
23
23
 
@@ -7,13 +7,13 @@ describe Time, '#pred' do
7
7
 
8
8
  let(:object) { described_class.now }
9
9
 
10
- it { should be_kind_of(described_class) }
10
+ it { should be_instance_of(described_class) }
11
11
 
12
12
  it 'returns the time 1 second ago' do
13
- should == (object - 1)
13
+ should eql(object - 1)
14
14
  end
15
15
 
16
16
  it 'is the inverse of #succ' do
17
- subject.succ.should == object
17
+ subject.succ.should eql(object)
18
18
  end
19
19
  end
@@ -10,7 +10,7 @@ describe AbstractClass::ClassMethods, '#new' do
10
10
  context 'called on a subclass' do
11
11
  let(:object) { Class.new(abstract_class) }
12
12
 
13
- it { should be_kind_of(object) }
13
+ it { should be_instance_of(object) }
14
14
  end
15
15
 
16
16
  context 'called on the class' do