dm-core 0.10.2 → 1.0.0.rc1

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 (183) hide show
  1. data/.gitignore +10 -1
  2. data/Gemfile +143 -0
  3. data/Rakefile +9 -5
  4. data/VERSION +1 -1
  5. data/dm-core.gemspec +160 -57
  6. data/lib/dm-core.rb +131 -56
  7. data/lib/dm-core/adapters.rb +98 -14
  8. data/lib/dm-core/adapters/abstract_adapter.rb +24 -4
  9. data/lib/dm-core/adapters/in_memory_adapter.rb +7 -2
  10. data/lib/dm-core/associations/many_to_many.rb +19 -30
  11. data/lib/dm-core/associations/many_to_one.rb +58 -42
  12. data/lib/dm-core/associations/one_to_many.rb +33 -23
  13. data/lib/dm-core/associations/one_to_one.rb +27 -11
  14. data/lib/dm-core/associations/relationship.rb +4 -4
  15. data/lib/dm-core/collection.rb +23 -16
  16. data/lib/dm-core/core_ext/array.rb +36 -0
  17. data/lib/dm-core/core_ext/hash.rb +30 -0
  18. data/lib/dm-core/core_ext/module.rb +46 -0
  19. data/lib/dm-core/core_ext/object.rb +31 -0
  20. data/lib/dm-core/core_ext/pathname.rb +20 -0
  21. data/lib/dm-core/core_ext/string.rb +22 -0
  22. data/lib/dm-core/core_ext/try_dup.rb +44 -0
  23. data/lib/dm-core/model.rb +88 -27
  24. data/lib/dm-core/model/hook.rb +75 -18
  25. data/lib/dm-core/model/property.rb +50 -9
  26. data/lib/dm-core/model/relationship.rb +31 -31
  27. data/lib/dm-core/model/scope.rb +3 -3
  28. data/lib/dm-core/property.rb +196 -516
  29. data/lib/dm-core/property/binary.rb +7 -0
  30. data/lib/dm-core/property/boolean.rb +35 -0
  31. data/lib/dm-core/property/class.rb +24 -0
  32. data/lib/dm-core/property/date.rb +47 -0
  33. data/lib/dm-core/property/date_time.rb +48 -0
  34. data/lib/dm-core/property/decimal.rb +43 -0
  35. data/lib/dm-core/property/discriminator.rb +48 -0
  36. data/lib/dm-core/property/float.rb +24 -0
  37. data/lib/dm-core/property/integer.rb +32 -0
  38. data/lib/dm-core/property/numeric.rb +43 -0
  39. data/lib/dm-core/property/object.rb +32 -0
  40. data/lib/dm-core/property/serial.rb +8 -0
  41. data/lib/dm-core/property/string.rb +49 -0
  42. data/lib/dm-core/property/text.rb +12 -0
  43. data/lib/dm-core/property/time.rb +48 -0
  44. data/lib/dm-core/property/typecast/numeric.rb +32 -0
  45. data/lib/dm-core/property/typecast/time.rb +28 -0
  46. data/lib/dm-core/property_set.rb +10 -4
  47. data/lib/dm-core/query.rb +14 -37
  48. data/lib/dm-core/query/conditions/comparison.rb +8 -6
  49. data/lib/dm-core/query/conditions/operation.rb +33 -2
  50. data/lib/dm-core/query/operator.rb +2 -5
  51. data/lib/dm-core/query/path.rb +4 -6
  52. data/lib/dm-core/repository.rb +21 -6
  53. data/lib/dm-core/resource.rb +316 -133
  54. data/lib/dm-core/resource/state.rb +79 -0
  55. data/lib/dm-core/resource/state/clean.rb +40 -0
  56. data/lib/dm-core/resource/state/deleted.rb +30 -0
  57. data/lib/dm-core/resource/state/dirty.rb +86 -0
  58. data/lib/dm-core/resource/state/immutable.rb +34 -0
  59. data/lib/dm-core/resource/state/persisted.rb +29 -0
  60. data/lib/dm-core/resource/state/transient.rb +70 -0
  61. data/lib/dm-core/spec/lib/adapter_helpers.rb +52 -0
  62. data/lib/dm-core/spec/lib/collection_helpers.rb +20 -0
  63. data/{spec → lib/dm-core/spec}/lib/counter_adapter.rb +5 -1
  64. data/lib/dm-core/spec/lib/pending_helpers.rb +50 -0
  65. data/lib/dm-core/spec/lib/spec_helper.rb +68 -0
  66. data/lib/dm-core/spec/setup.rb +165 -0
  67. data/lib/dm-core/spec/{adapter_shared_spec.rb → shared/adapter_spec.rb} +21 -7
  68. data/{spec/public/shared/resource_shared_spec.rb → lib/dm-core/spec/shared/resource_spec.rb} +120 -83
  69. data/{spec/public/shared/sel_shared_spec.rb → lib/dm-core/spec/shared/sel_spec.rb} +5 -6
  70. data/lib/dm-core/support/assertions.rb +8 -0
  71. data/lib/dm-core/support/equalizer.rb +1 -0
  72. data/lib/dm-core/support/hook.rb +420 -0
  73. data/lib/dm-core/support/lazy_array.rb +453 -0
  74. data/lib/dm-core/support/local_object_space.rb +12 -0
  75. data/lib/dm-core/support/logger.rb +193 -6
  76. data/lib/dm-core/support/naming_conventions.rb +8 -8
  77. data/lib/dm-core/support/subject.rb +33 -0
  78. data/lib/dm-core/type.rb +4 -0
  79. data/lib/dm-core/types/boolean.rb +2 -0
  80. data/lib/dm-core/types/decimal.rb +9 -0
  81. data/lib/dm-core/types/discriminator.rb +2 -0
  82. data/lib/dm-core/types/object.rb +3 -0
  83. data/lib/dm-core/types/serial.rb +2 -0
  84. data/lib/dm-core/types/text.rb +2 -0
  85. data/lib/dm-core/version.rb +1 -1
  86. data/spec/public/associations/many_to_many/read_multiple_join_spec.rb +67 -0
  87. data/spec/public/model/hook_spec.rb +209 -0
  88. data/spec/public/model/property_spec.rb +35 -0
  89. data/spec/public/model/relationship_spec.rb +33 -20
  90. data/spec/public/model_spec.rb +142 -10
  91. data/spec/public/property/binary_spec.rb +14 -0
  92. data/spec/public/property/boolean_spec.rb +14 -0
  93. data/spec/public/property/class_spec.rb +20 -0
  94. data/spec/public/property/date_spec.rb +14 -0
  95. data/spec/public/property/date_time_spec.rb +14 -0
  96. data/spec/public/property/decimal_spec.rb +14 -0
  97. data/spec/public/{types → property}/discriminator_spec.rb +2 -12
  98. data/spec/public/property/float_spec.rb +14 -0
  99. data/spec/public/property/integer_spec.rb +14 -0
  100. data/spec/public/property/object_spec.rb +9 -17
  101. data/spec/public/property/serial_spec.rb +14 -0
  102. data/spec/public/property/string_spec.rb +14 -0
  103. data/spec/public/property/text_spec.rb +52 -0
  104. data/spec/public/property/time_spec.rb +14 -0
  105. data/spec/public/property_spec.rb +28 -87
  106. data/spec/public/resource_spec.rb +101 -0
  107. data/spec/public/sel_spec.rb +5 -15
  108. data/spec/public/shared/collection_shared_spec.rb +16 -30
  109. data/spec/public/shared/finder_shared_spec.rb +2 -4
  110. data/spec/public/shared/property_shared_spec.rb +176 -0
  111. data/spec/semipublic/adapters/abstract_adapter_spec.rb +1 -1
  112. data/spec/semipublic/adapters/in_memory_adapter_spec.rb +2 -2
  113. data/spec/semipublic/associations/many_to_many_spec.rb +89 -0
  114. data/spec/semipublic/associations/many_to_one_spec.rb +24 -1
  115. data/spec/semipublic/associations/one_to_many_spec.rb +51 -0
  116. data/spec/semipublic/associations/one_to_one_spec.rb +49 -0
  117. data/spec/semipublic/associations/relationship_spec.rb +3 -3
  118. data/spec/semipublic/associations_spec.rb +1 -1
  119. data/spec/semipublic/property/binary_spec.rb +13 -0
  120. data/spec/semipublic/property/boolean_spec.rb +65 -0
  121. data/spec/semipublic/property/class_spec.rb +33 -0
  122. data/spec/semipublic/property/date_spec.rb +43 -0
  123. data/spec/semipublic/property/date_time_spec.rb +46 -0
  124. data/spec/semipublic/property/decimal_spec.rb +82 -0
  125. data/spec/semipublic/property/discriminator_spec.rb +19 -0
  126. data/spec/semipublic/property/float_spec.rb +82 -0
  127. data/spec/semipublic/property/integer_spec.rb +82 -0
  128. data/spec/semipublic/property/serial_spec.rb +13 -0
  129. data/spec/semipublic/property/string_spec.rb +13 -0
  130. data/spec/semipublic/property/text_spec.rb +31 -0
  131. data/spec/semipublic/property/time_spec.rb +50 -0
  132. data/spec/semipublic/property_spec.rb +2 -532
  133. data/spec/semipublic/query/conditions/comparison_spec.rb +171 -169
  134. data/spec/semipublic/query/conditions/operation_spec.rb +53 -51
  135. data/spec/semipublic/query/path_spec.rb +17 -17
  136. data/spec/semipublic/query_spec.rb +47 -78
  137. data/spec/semipublic/resource/state/clean_spec.rb +88 -0
  138. data/spec/semipublic/resource/state/deleted_spec.rb +78 -0
  139. data/spec/semipublic/resource/state/dirty_spec.rb +133 -0
  140. data/spec/semipublic/resource/state/immutable_spec.rb +99 -0
  141. data/spec/semipublic/resource/state/transient_spec.rb +128 -0
  142. data/spec/semipublic/resource/state_spec.rb +226 -0
  143. data/spec/semipublic/shared/property_shared_spec.rb +143 -0
  144. data/spec/semipublic/shared/resource_shared_spec.rb +16 -15
  145. data/spec/semipublic/shared/resource_state_shared_spec.rb +78 -0
  146. data/spec/semipublic/shared/subject_shared_spec.rb +79 -0
  147. data/spec/spec_helper.rb +21 -97
  148. data/spec/support/types/huge_integer.rb +17 -0
  149. data/spec/unit/array_spec.rb +48 -0
  150. data/spec/unit/hash_spec.rb +35 -0
  151. data/spec/unit/hook_spec.rb +1234 -0
  152. data/spec/unit/lazy_array_spec.rb +1959 -0
  153. data/spec/unit/module_spec.rb +70 -0
  154. data/spec/unit/object_spec.rb +37 -0
  155. data/spec/unit/try_dup_spec.rb +45 -0
  156. data/tasks/local_gemfile.rake +18 -0
  157. data/tasks/spec.rake +0 -3
  158. metadata +197 -71
  159. data/deps.rip +0 -2
  160. data/lib/dm-core/adapters/data_objects_adapter.rb +0 -712
  161. data/lib/dm-core/adapters/mysql_adapter.rb +0 -42
  162. data/lib/dm-core/adapters/oracle_adapter.rb +0 -229
  163. data/lib/dm-core/adapters/postgres_adapter.rb +0 -22
  164. data/lib/dm-core/adapters/sqlite3_adapter.rb +0 -17
  165. data/lib/dm-core/adapters/sqlserver_adapter.rb +0 -114
  166. data/lib/dm-core/adapters/yaml_adapter.rb +0 -111
  167. data/lib/dm-core/core_ext/enumerable.rb +0 -28
  168. data/lib/dm-core/migrations.rb +0 -1427
  169. data/lib/dm-core/spec/data_objects_adapter_shared_spec.rb +0 -366
  170. data/lib/dm-core/transaction.rb +0 -508
  171. data/lib/dm-core/types/paranoid_boolean.rb +0 -42
  172. data/lib/dm-core/types/paranoid_datetime.rb +0 -41
  173. data/spec/lib/adapter_helpers.rb +0 -105
  174. data/spec/lib/collection_helpers.rb +0 -18
  175. data/spec/lib/pending_helpers.rb +0 -46
  176. data/spec/public/migrations_spec.rb +0 -503
  177. data/spec/public/transaction_spec.rb +0 -153
  178. data/spec/semipublic/adapters/mysql_adapter_spec.rb +0 -17
  179. data/spec/semipublic/adapters/oracle_adapter_spec.rb +0 -194
  180. data/spec/semipublic/adapters/postgres_adapter_spec.rb +0 -17
  181. data/spec/semipublic/adapters/sqlite3_adapter_spec.rb +0 -17
  182. data/spec/semipublic/adapters/sqlserver_adapter_spec.rb +0 -17
  183. data/spec/semipublic/adapters/yaml_adapter_spec.rb +0 -12
@@ -0,0 +1,453 @@
1
+ require 'dm-core/core_ext/try_dup'
2
+
3
+ class LazyArray # borrowed partially from StrokeDB
4
+ include Enumerable
5
+
6
+ attr_reader :head, :tail
7
+
8
+ def first(*args)
9
+ if lazy_possible?(@head, *args)
10
+ @head.first(*args)
11
+ else
12
+ lazy_load
13
+ @array.first(*args)
14
+ end
15
+ end
16
+
17
+ def last(*args)
18
+ if lazy_possible?(@tail, *args)
19
+ @tail.last(*args)
20
+ else
21
+ lazy_load
22
+ @array.last(*args)
23
+ end
24
+ end
25
+
26
+ def at(index)
27
+ if index >= 0 && lazy_possible?(@head, index + 1)
28
+ @head.at(index)
29
+ elsif index < 0 && lazy_possible?(@tail, index.abs)
30
+ @tail.at(index)
31
+ else
32
+ lazy_load
33
+ @array.at(index)
34
+ end
35
+ end
36
+
37
+ def fetch(*args, &block)
38
+ index = args.first
39
+
40
+ if index >= 0 && lazy_possible?(@head, index + 1)
41
+ @head.fetch(*args, &block)
42
+ elsif index < 0 && lazy_possible?(@tail, index.abs)
43
+ @tail.fetch(*args, &block)
44
+ else
45
+ lazy_load
46
+ @array.fetch(*args, &block)
47
+ end
48
+ end
49
+
50
+ def values_at(*args)
51
+ accumulator = []
52
+
53
+ lazy_possible = args.all? do |arg|
54
+ index, length = extract_slice_arguments(arg)
55
+
56
+ if index >= 0 && lazy_possible?(@head, index + length)
57
+ accumulator.concat(head.values_at(*arg))
58
+ elsif index < 0 && lazy_possible?(@tail, index.abs)
59
+ accumulator.concat(tail.values_at(*arg))
60
+ end
61
+ end
62
+
63
+ if lazy_possible
64
+ accumulator
65
+ else
66
+ lazy_load
67
+ @array.values_at(*args)
68
+ end
69
+ end
70
+
71
+ def index(entry)
72
+ (lazy_possible?(@head) && @head.index(entry)) || begin
73
+ lazy_load
74
+ @array.index(entry)
75
+ end
76
+ end
77
+
78
+ def include?(entry)
79
+ (lazy_possible?(@tail) && @tail.include?(entry)) ||
80
+ (lazy_possible?(@head) && @head.include?(entry)) || begin
81
+ lazy_load
82
+ @array.include?(entry)
83
+ end
84
+ end
85
+
86
+ def empty?
87
+ (@tail.nil? || @tail.empty?) &&
88
+ (@head.nil? || @head.empty?) && begin
89
+ lazy_load
90
+ @array.empty?
91
+ end
92
+ end
93
+
94
+ def any?(&block)
95
+ (lazy_possible?(@tail) && @tail.any?(&block)) ||
96
+ (lazy_possible?(@head) && @head.any?(&block)) || begin
97
+ lazy_load
98
+ @array.any?(&block)
99
+ end
100
+ end
101
+
102
+ def [](*args)
103
+ index, length = extract_slice_arguments(*args)
104
+
105
+ if length == 1 && args.size == 1 && args.first.kind_of?(Integer)
106
+ return at(index)
107
+ end
108
+
109
+ if index >= 0 && lazy_possible?(@head, index + length)
110
+ @head[*args]
111
+ elsif index < 0 && lazy_possible?(@tail, index.abs - 1 + length)
112
+ @tail[*args]
113
+ else
114
+ lazy_load
115
+ @array[*args]
116
+ end
117
+ end
118
+
119
+ alias slice []
120
+
121
+ def slice!(*args)
122
+ index, length = extract_slice_arguments(*args)
123
+
124
+ if index >= 0 && lazy_possible?(@head, index + length)
125
+ @head.slice!(*args)
126
+ elsif index < 0 && lazy_possible?(@tail, index.abs - 1 + length)
127
+ @tail.slice!(*args)
128
+ else
129
+ lazy_load
130
+ @array.slice!(*args)
131
+ end
132
+ end
133
+
134
+ def []=(*args)
135
+ index, length = extract_slice_arguments(*args[0..-2])
136
+
137
+ if index >= 0 && lazy_possible?(@head, index + length)
138
+ @head.[]=(*args)
139
+ elsif index < 0 && lazy_possible?(@tail, index.abs - 1 + length)
140
+ @tail.[]=(*args)
141
+ else
142
+ lazy_load
143
+ @array.[]=(*args)
144
+ end
145
+ end
146
+
147
+ alias splice []=
148
+
149
+ def reverse
150
+ dup.reverse!
151
+ end
152
+
153
+ def reverse!
154
+ # reverse without kicking if possible
155
+ if loaded?
156
+ @array = @array.reverse
157
+ else
158
+ @head, @tail = @tail.reverse, @head.reverse
159
+
160
+ proc = @load_with_proc
161
+
162
+ @load_with_proc = lambda do |v|
163
+ proc.call(v)
164
+ v.instance_variable_get(:@array).reverse!
165
+ end
166
+ end
167
+
168
+ self
169
+ end
170
+
171
+ def <<(entry)
172
+ if loaded?
173
+ lazy_load
174
+ @array << entry
175
+ else
176
+ @tail << entry
177
+ end
178
+ self
179
+ end
180
+
181
+ def concat(other)
182
+ if loaded?
183
+ lazy_load
184
+ @array.concat(other)
185
+ else
186
+ @tail.concat(other)
187
+ end
188
+ self
189
+ end
190
+
191
+ def push(*entries)
192
+ if loaded?
193
+ lazy_load
194
+ @array.push(*entries)
195
+ else
196
+ @tail.push(*entries)
197
+ end
198
+ self
199
+ end
200
+
201
+ def unshift(*entries)
202
+ if loaded?
203
+ lazy_load
204
+ @array.unshift(*entries)
205
+ else
206
+ @head.unshift(*entries)
207
+ end
208
+ self
209
+ end
210
+
211
+ def insert(index, *entries)
212
+ if index >= 0 && lazy_possible?(@head, index)
213
+ @head.insert(index, *entries)
214
+ elsif index < 0 && lazy_possible?(@tail, index.abs - 1)
215
+ @tail.insert(index, *entries)
216
+ else
217
+ lazy_load
218
+ @array.insert(index, *entries)
219
+ end
220
+ self
221
+ end
222
+
223
+ def pop(*args)
224
+ if lazy_possible?(@tail, *args)
225
+ @tail.pop(*args)
226
+ else
227
+ lazy_load
228
+ @array.pop(*args)
229
+ end
230
+ end
231
+
232
+ def shift(*args)
233
+ if lazy_possible?(@head, *args)
234
+ @head.shift(*args)
235
+ else
236
+ lazy_load
237
+ @array.shift(*args)
238
+ end
239
+ end
240
+
241
+ def delete_at(index)
242
+ if index >= 0 && lazy_possible?(@head, index + 1)
243
+ @head.delete_at(index)
244
+ elsif index < 0 && lazy_possible?(@tail, index.abs)
245
+ @tail.delete_at(index)
246
+ else
247
+ lazy_load
248
+ @array.delete_at(index)
249
+ end
250
+ end
251
+
252
+ def delete_if(&block)
253
+ if loaded?
254
+ lazy_load
255
+ @array.delete_if(&block)
256
+ else
257
+ @reapers << block
258
+ @head.delete_if(&block)
259
+ @tail.delete_if(&block)
260
+ end
261
+ self
262
+ end
263
+
264
+ def replace(other)
265
+ mark_loaded
266
+ @array.replace(other)
267
+ self
268
+ end
269
+
270
+ def clear
271
+ mark_loaded
272
+ @array.clear
273
+ self
274
+ end
275
+
276
+ def to_a
277
+ lazy_load
278
+ @array.to_a
279
+ end
280
+
281
+ alias to_ary to_a
282
+
283
+ def load_with(&block)
284
+ @load_with_proc = block
285
+ self
286
+ end
287
+
288
+ def loaded?
289
+ @loaded == true
290
+ end
291
+
292
+ def kind_of?(klass)
293
+ super || @array.kind_of?(klass)
294
+ end
295
+
296
+ alias is_a? kind_of?
297
+
298
+ def respond_to?(method, include_private = false)
299
+ super || @array.respond_to?(method)
300
+ end
301
+
302
+ def freeze
303
+ if loaded?
304
+ @array.freeze
305
+ else
306
+ @head.freeze
307
+ @tail.freeze
308
+ end
309
+ @frozen = true
310
+ self
311
+ end
312
+
313
+ def frozen?
314
+ @frozen == true
315
+ end
316
+
317
+ def ==(other)
318
+ if equal?(other)
319
+ return true
320
+ end
321
+
322
+ unless other.respond_to?(:to_ary)
323
+ return false
324
+ end
325
+
326
+ # if necessary, convert to something that can be compared
327
+ other = other.to_ary unless other.respond_to?(:[])
328
+
329
+ cmp?(other, :==)
330
+ end
331
+
332
+ def eql?(other)
333
+ if equal?(other)
334
+ return true
335
+ end
336
+
337
+ unless other.class.equal?(self.class)
338
+ return false
339
+ end
340
+
341
+ cmp?(other, :eql?)
342
+ end
343
+
344
+ def lazy_possible?(list, need_length = 1)
345
+ !loaded? && need_length <= list.size
346
+ end
347
+
348
+ private
349
+
350
+ def initialize
351
+ @frozen = false
352
+ @loaded = false
353
+ @load_with_proc = lambda { |v| v }
354
+ @head = []
355
+ @tail = []
356
+ @array = []
357
+ @reapers = []
358
+ end
359
+
360
+ def initialize_copy(original)
361
+ @head = @head.try_dup
362
+ @tail = @tail.try_dup
363
+ @array = @array.try_dup
364
+ end
365
+
366
+ def lazy_load
367
+ return if loaded?
368
+ mark_loaded
369
+ @load_with_proc[self]
370
+ @array.unshift(*@head)
371
+ @array.concat(@tail)
372
+ @head = @tail = nil
373
+ @reapers.each { |r| @array.delete_if(&r) } if @reapers
374
+ @array.freeze if frozen?
375
+ end
376
+
377
+ def mark_loaded
378
+ @loaded = true
379
+ end
380
+
381
+ ##
382
+ # Extract arguments for #slice an #slice! and return index and length
383
+ #
384
+ # @param [Integer, Array(Integer), Range] *args the index,
385
+ # index and length, or range indicating first and last position
386
+ #
387
+ # @return [Integer] the index
388
+ # @return [Integer,NilClass] the length, if any
389
+ #
390
+ # @api private
391
+ def extract_slice_arguments(*args)
392
+ first_arg, second_arg = args
393
+
394
+ if args.size == 2 && first_arg.kind_of?(Integer) && second_arg.kind_of?(Integer)
395
+ return first_arg, second_arg
396
+ elsif args.size == 1
397
+ if first_arg.kind_of?(Integer)
398
+ return first_arg, 1
399
+ elsif first_arg.kind_of?(Range)
400
+ index = first_arg.first
401
+ length = first_arg.last - index
402
+ length += 1 unless first_arg.exclude_end?
403
+ return index, length
404
+ end
405
+ end
406
+
407
+ raise ArgumentError, "arguments may be 1 or 2 Integers, or 1 Range object, was: #{args.inspect}", caller(1)
408
+ end
409
+
410
+ def each
411
+ lazy_load
412
+ if block_given?
413
+ @array.each { |entry| yield entry }
414
+ self
415
+ else
416
+ @array.each
417
+ end
418
+ end
419
+
420
+ # delegate any not-explicitly-handled methods to @array, if possible.
421
+ # this is handy for handling methods mixed-into Array like group_by
422
+ def method_missing(method, *args, &block)
423
+ if @array.respond_to?(method)
424
+ lazy_load
425
+ results = @array.send(method, *args, &block)
426
+ results.equal?(@array) ? self : results
427
+ else
428
+ super
429
+ end
430
+ end
431
+
432
+ def cmp?(other, operator)
433
+ unless loaded?
434
+ # compare the head against the beginning of other. start at index
435
+ # 0 and incrementally compare each entry. if other is a LazyArray
436
+ # this has a lesser likelyhood of triggering a lazy load
437
+ 0.upto(@head.size - 1) do |i|
438
+ return false unless @head[i].__send__(operator, other[i])
439
+ end
440
+
441
+ # compare the tail against the end of other. start at index
442
+ # -1 and decrementally compare each entry. if other is a LazyArray
443
+ # this has a lesser likelyhood of triggering a lazy load
444
+ -1.downto(@tail.size * -1) do |i|
445
+ return false unless @tail[i].__send__(operator, other[i])
446
+ end
447
+
448
+ lazy_load
449
+ end
450
+
451
+ @array.send(operator, other.to_ary)
452
+ end
453
+ end