totally_lazy 0.0.20 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. data/.idea/.name +1 -0
  3. data/.idea/.rakeTasks +7 -0
  4. data/.idea/compiler.xml +22 -0
  5. data/.idea/encodings.xml +6 -0
  6. data/.idea/misc.xml +19 -0
  7. data/.idea/modules.xml +8 -0
  8. data/.idea/vcs.xml +6 -0
  9. data/.travis.yml +2 -5
  10. data/Gemfile +6 -8
  11. data/Guardfile +2 -17
  12. data/LICENSE +202 -0
  13. data/Rakefile +18 -33
  14. data/VERSION +1 -1
  15. data/contributors.txt +1 -0
  16. data/lib/comparators.rb +9 -0
  17. data/lib/enumerators.rb +74 -0
  18. data/lib/functions.rb +66 -0
  19. data/lib/numbers.rb +38 -0
  20. data/lib/option.rb +38 -268
  21. data/lib/pair.rb +13 -51
  22. data/lib/predicates.rb +5 -0
  23. data/lib/sequence.rb +171 -526
  24. data/lib/strings.rb +13 -0
  25. data/lib/totally_lazy.rb +14 -165
  26. data/readme.md +2 -0
  27. data/spec/option_spec.rb +6 -182
  28. data/spec/sequence_spec.rb +202 -132
  29. data/spec/spec_helper.rb +0 -13
  30. data/totally_lazy.iml +74 -0
  31. metadata +58 -71
  32. data/.document +0 -5
  33. data/.rspec +0 -1
  34. data/LICENSE.txt +0 -20
  35. data/README.md +0 -173
  36. data/lib/any.rb +0 -13
  37. data/lib/functor.rb +0 -92
  38. data/lib/generators.rb +0 -161
  39. data/lib/parallel/parallel.rb +0 -442
  40. data/lib/parallel/processor_count.rb +0 -85
  41. data/lib/predicates/compare.rb +0 -25
  42. data/lib/predicates/conversions.rb +0 -22
  43. data/lib/predicates/numbers.rb +0 -21
  44. data/lib/predicates/predicates.rb +0 -141
  45. data/lib/predicates/where.rb +0 -34
  46. data/lib/predicates/where_processor.rb +0 -13
  47. data/lib/type_check.rb +0 -19
  48. data/lib/utils.rb +0 -9
  49. data/spec/functor_spec.rb +0 -35
  50. data/spec/generators_spec.rb +0 -37
  51. data/spec/pair_spec.rb +0 -44
  52. data/spec/predicate_spec.rb +0 -77
  53. data/spec/serialization_spec.rb +0 -56
  54. data/spec/type_check_spec.rb +0 -20
  55. data/spec/util_spec.rb +0 -10
  56. data/totally_lazy.gemspec +0 -101
data/lib/sequence.rb CHANGED
@@ -1,642 +1,287 @@
1
1
  class NoSuchElementException < RuntimeError
2
2
  end
3
3
 
4
- class UnsupportedTypeException < RuntimeError
5
- end
6
-
7
- class UnsupportedMethodException < RuntimeError
8
- end
9
-
10
- # Array pimps
11
- class Array
12
- def to_seq
13
- sequence(self).flatten
14
- end
15
- end
16
-
17
4
  module Sequences
18
-
19
- # Creates a sequence
20
- #
21
- # == Parameters:
22
- # items::
23
- # Varargs - any valid ruby objects can be supplied
24
- #
25
- # == Returns:
26
- # A sequence
27
- #
28
- # == Examples
29
- #
30
- # sequence(1,2,3,4).filter(even) # lazily returns 2,4
31
- # sequence(1,2).map(as_string) # lazily returns "1","2"
32
- # sequence(1, 2).map_concurrently(to_string) # lazily distributes the work to background threads
33
- # sequence(1,2,3).take(2) # lazily returns 1,2
34
- # sequence(1,2,3).drop(2) # lazily returns 3
35
- # sequence(1,2,3).tail # lazily returns 2,3
36
- # sequence(1,2,3).head # eagerly returns 1
37
- # sequence(1,2,3).head_option # eagerly returns an option
38
- # some(sequence(1,2,3)).get_or_else(empty) # eagerly returns value or else empty sequence
39
- # sequence(1, 2, 3, 4, 5).filter(where(is greater_than 2).and(is odd)) # lazily returns 3,5
40
- # def sequence(*items)
41
- # if items.size == 1
42
- # if [Range, Hash, Array, Set].include?(items.first.class)
43
- # Sequence.new(items.first)
44
- # elsif items.first.nil?
45
- # empty
46
- # else
47
- # Sequence.new(items)
48
- # end
49
- # else
50
- # Sequence.new(items)
51
- # end
52
- # end
5
+ def empty
6
+ EMPTY
7
+ end
53
8
 
54
9
  def sequence(*items)
55
10
  if items.first.nil?
56
11
  empty
57
12
  else
58
- Sequence.new(items)
13
+ Sequence.new(items.lazy)
59
14
  end
60
15
  end
61
16
 
62
- def flatten
63
- Sequence.new(entries.map do |entry|
64
- if entry.respond_to?(:flatten)
65
- entry.flatten
66
- else
67
- raise UnsupportedMethodException.new, "flatten is not supported by: #{self.entries.class}"
68
- end
69
- end.flatten)
17
+ def zip(left, right)
18
+ left.zip(right)
70
19
  end
71
20
 
72
- # Creates an empty sequence
73
- #
74
- # == Returns:
75
- # An empty sequence
76
- #
77
- # == Examples
78
- #
79
- # empty
80
- # some(sequence(1,2,3)).get_or_else(empty) # eagerly returns value or else empty sequence
81
- def empty
82
- Empty.new
21
+ def take(sequence, count)
22
+ Sequence.new(sequence.enumerator.take(count))
83
23
  end
84
24
 
85
- def deserialize(data)
86
- sequence(data).deserialize
25
+ def drop(sequence, count)
26
+ Sequence.new(sequence.enumerator.drop(count))
87
27
  end
88
28
 
89
- class Sequence < Enumerator
90
-
91
- include Comparable
92
-
93
- def initialize(obj, &block)
94
- super() { |yielder|
95
- begin
96
- obj.each { |x|
97
- if block
98
- block.call(yielder, x)
99
- else
100
- yielder << x
101
- end
102
- }
103
- rescue StopIteration
104
- end
105
- }
106
- end
107
-
108
- def <=>(object)
109
- self.entries <=> object.entries
110
- end
111
-
112
- def flat_map(predicate=nil, &block)
113
- if predicate
114
- Sequence.new(self) { |yielder, val|
115
- val.each {|x|
116
- v = predicate.is_a?(WherePredicate) ? WhereProcessor.new(x).apply(predicate.predicates) : predicate.exec.call(x)
117
- yielder << v unless v.nil?
118
- }
119
- }
120
- else
121
- Sequence.new(self) { |yielder, val|
122
- val.each {|e|
123
- yielder << block.call(e)
124
- }
125
- }
126
- end
127
- end
128
- alias collect_concat flat_map
129
-
130
- def map(predicate=nil, &block)
131
- if predicate
132
- Sequence.new(self) { |yielder, val|
133
- v = predicate.is_a?(WherePredicate) ? WhereProcessor.new(val).apply(predicate.predicates) : predicate.exec.call(val)
134
- yielder << v unless v.nil?
135
- }
136
- else
137
- Sequence.new(self) { |yielder, val|
138
- yielder << block.call(val)
139
- }
140
- end
141
- end
29
+ def repeat(item)
30
+ Sequence.new(repeat_enumerator(item))
31
+ end
142
32
 
143
- alias collect map
144
-
145
- # def reduce(operation_or_value=nil)
146
- # case operation_or_value
147
- # when Symbol
148
- # # convert things like reduce(:+) into reduce { |s,e| s + e }
149
- # return reduce { |s,e| s.send(operation_or_value, e) }
150
- # when nil
151
- # acc = nil
152
- # else
153
- # acc = operation_or_value
154
- # end
155
- #
156
- # each do |a|
157
- # if acc.nil?
158
- # acc = a
159
- # else
160
- # acc = yield(acc, a)
161
- # end
162
- # end
163
- #
164
- # return acc
165
- # end
166
-
167
- def select(predicate=nil, &block)
168
- if predicate
169
- Sequence.new(self) { |yielder, val|
170
- v = predicate.is_a?(WherePredicate) ? WhereProcessor.new(val).apply(predicate.predicates) : predicate.exec.call(val)
171
- yielder << v unless v.nil?
172
- }
173
- else
174
- Sequence.new(self) { |yielder, val|
175
- if block.call(val)
176
- yielder << val
177
- end
178
- }
179
- end
180
- end
33
+ def repeat_fn(item)
34
+ Sequence.new(repeat_fn_enumerator(item))
35
+ end
181
36
 
182
- alias find_all select
183
- alias filter select
184
-
185
- def reject(predicate=nil, &block)
186
- if predicate
187
- Sequence.new(self) { |yielder, val|
188
- v = predicate.is_a?(WherePredicate) ? WhereProcessor.new(val).apply(predicate.predicates, true) : predicate.exec.call(val, :self, true)
189
- yielder << v unless v.nil?
190
- }
191
- else
192
- Sequence.new(self) { |yielder, val|
193
- unless block.call(val)
194
- yielder << val
195
- end
196
- }
197
- end
198
- end
37
+ def sort(sequence, comparator=ascending)
38
+ Sequence.new(sequence.enumerator.sort { |a, b| comparator.(a, b) }.lazy)
39
+ end
199
40
 
200
- alias unfilter reject
41
+ def map_concurrently(sequence, fn=nil, &block)
42
+ call_concurrently(sequence.map(defer_return(block_given? ? ->(value) { block.call(value) } : fn)))
43
+ end
201
44
 
202
- def grep(pattern)
203
- Sequence.new(self) { |yielder, val|
204
- if pattern === val
205
- yielder << val
206
- end
207
- }
208
- end
45
+ # noinspection RubyTooManyMethodsInspection
46
+ class Sequence
47
+ include Comparable
48
+ attr_reader :enumerator
209
49
 
210
- def drop(n)
211
- Sequence.new(Sequence::Generator.new do |g|
212
- self.each_with_index do |v, i|
213
- unless i < n
214
- g.yield v
215
- end
216
- end
217
- end)
218
- end
219
-
220
- def drop_while(&block)
221
- dropping = true
222
- Sequence.new(self) { |yielder, val|
223
- if dropping
224
- if not block.call(val)
225
- yielder << val
226
- dropping = false
227
- end
228
- else
229
- yielder << val
230
- end
231
- }
50
+ def initialize(enumerator)
51
+ raise "Sequence only accepts Enumerator::Lazy, not #{enumerator.class}" unless (enumerator.class == Enumerator::Lazy)
52
+ @enumerator = enumerator
232
53
  end
233
54
 
234
- def take(n)
235
- Sequence.new(Sequence::Generator.new do |g|
236
- self.each_with_index do |v, i|
237
- if i < n
238
- g.yield v
239
- else
240
- raise StopIteration
241
- end
242
- end
243
- end)
244
- end
245
-
246
- def take_while(&block)
247
- Sequence.new(self) { |yielder, val|
248
- if block.call(val)
249
- yielder << val
250
- else
251
- raise StopIteration
252
- end
253
- }
55
+ def is_empty?
56
+ @enumerator.rewind
57
+ begin
58
+ @enumerator.peek
59
+ false
60
+ rescue
61
+ true
62
+ end
254
63
  end
255
64
 
256
- def zip(*args, &block)
257
- enums = [self] + args
258
- Sequence.new(self) { |yielder, val|
259
- ary = enums.map { |e| e.next }
260
- if block
261
- yielder << block.call(ary)
262
- else
263
- yielder << ary
264
- end
265
- }
65
+ def size
66
+ @enumerator.count
266
67
  end
267
68
 
268
- def [](n)
269
- Sequence.new(self).entries[n]
69
+ def head
70
+ @enumerator.first
270
71
  end
271
72
 
272
- alias get []
73
+ alias first head
273
74
 
274
- def empty?
275
- begin
276
- sequence.peek_values.empty?
277
- rescue StopIteration
278
- true
279
- end
280
- end
281
-
282
- def head
283
- sequence.empty? ? raise(NoSuchElementException.new, 'The sequence was empty') : sequence.entries.first
75
+ def second
76
+ tail.head
284
77
  end
285
78
 
286
79
  def head_option
287
- sequence.empty? ? none : some(sequence.first)
80
+ option(head)
288
81
  end
289
82
 
290
83
  def last
291
- sequence.empty? ? raise(NoSuchElementException.new, 'The sequence was empty') : sequence.entries.last
84
+ reverse.head
292
85
  end
293
86
 
294
87
  def last_option
295
- sequence.empty? ? none : some(sequence.entries.last)
88
+ reverse.head_option
296
89
  end
297
90
 
298
- def contains?(value)
299
- sequence.empty? ? false : sequence.entries.include?(value)
91
+ def reverse
92
+ Sequence.new(Enumerators::reverse(@enumerator))
300
93
  end
301
94
 
302
95
  def tail
303
- Sequence.new(Sequence::Generator.new do |g|
304
- self.empty? ? raise(NoSuchElementException.new, 'The sequence was empty') : self.drop(1).each { |i| g.yield i }
305
- end)
96
+ unless has_next(@enumerator)
97
+ raise NoSuchElementException.new
98
+ end
99
+ Sequence.new(@enumerator.drop(1))
306
100
  end
307
101
 
308
102
  def init
309
- Sequence.new(Sequence::Generator.new do |g|
310
- size = self.count
311
- self.empty? ? raise(NoSuchElementException.new, 'The sequence was empty') : self.first(size-1).each { |i| g.yield i }
312
- end)
103
+ reverse.tail.reverse
313
104
  end
314
105
 
315
- def shuffle
316
- Sequence.new(Sequence::Generator.new do |g|
317
- self.empty? ? raise(NoSuchElementException.new, 'The sequence was empty') : self.entries.shuffle.each { |i| g.yield i }
318
- end)
106
+ def map(fn=nil, &block)
107
+ assert_funcs(fn, block_given?)
108
+ Sequence.new(@enumerator.map { |value|
109
+ block_given? ? block.call(value) : fn.(value)
110
+ })
319
111
  end
320
112
 
321
- def transpose
322
- Sequence.new(Sequence::Generator.new do |g|
323
- if self.empty?
324
- raise(NoSuchElementException.new, 'The sequence was empty')
325
- else
326
- raise(Exception.new, 'The subject of transposition must be multidimensional') unless self.to_a.first.is_a?(Array)
327
- end
328
- result = []
329
- max = option(self.to_a.max { |a, b| a.size <=> b.size })
330
- max_size = max.get_or_throw(NoSuchElementException, 'The option was empty').size
331
- max_size.times do |i|
332
- result[i] = [self.to_a.first.size]
333
- self.to_a.each_with_index { |r, j| result[i][j] = r[i] }
334
- end
335
- result
336
- result.each { |i| g.yield i }
337
- end)
338
- end
339
-
340
- def join(target_sequence)
341
- Sequence.new(Sequence::Generator.new do |g|
342
- raise(Exception.new, 'The target (right side) must be a sequence') unless target_sequence.kind_of?(Sequences::Sequence)
343
- self.entries.push(target_sequence.entries).flatten.each { |i| g.yield i unless i.is_a?(Empty) }
344
- end)
345
- end
346
-
347
- alias << join
348
-
349
- def add(target_sequence)
350
- Sequence.new(Sequence::Generator.new do |g|
351
- (self.entries + target_sequence.entries).each { |i| g.yield i }
352
- end)
353
- end
354
-
355
- alias + add
356
-
357
- def append(item)
358
- Sequence.new(Sequence::Generator.new do |g|
359
- elements = self.entries
360
- elements = elements.reject { |i| i.is_a?(Empty) }
361
- (elements << item).each { |i| g.yield i }
362
- end)
363
- end
364
-
365
- def to_seq
366
- Sequence.new(Sequence::Generator.new do |g|
367
- self.entries.map { |e| Type.responds(e, :entries); e.entries }.flatten.each { |i| g.yield i }
368
- end)
369
- end
370
-
371
- def to_maps(symbolize=true)
372
- Sequence.new(Sequence::Generator.new do |g|
373
- self.each_slice(2) do |k, v|
374
- if symbolize
375
- g.yield k.to_s.to_sym => v
376
- else
377
- g.yield k => v
378
- end
379
- end
380
- end)
381
- end
382
-
383
- def to_map(symbolize=true)
384
- Maps.merge(to_maps(symbolize))
113
+ def fold(seed, fn=nil, &block)
114
+ assert_funcs(fn, block_given?)
115
+ @enumerator.inject(seed) { |accumulator, value|
116
+ block_given? ? block.call(accumulator, value) : fn.(accumulator, value)
117
+ }
385
118
  end
386
119
 
387
- def from_pairs
388
- Sequence.new(Sequence::Generator.new do |g|
389
- self.entries.map { |e| Type.check(e, Pair::Pair); [e.key, e.value] }.flatten.each { |i| g.yield i }
390
- end)
391
- end
120
+ alias fold_left fold
392
121
 
393
- def from_arrays
394
- Sequence.new(Sequence::Generator.new do |g|
395
- self.entries.map { |e| Type.check(e, Array); e }.flatten.each { |i| g.yield i }
396
- end)
122
+ def fold_right(seed, fn=nil, &block)
123
+ assert_funcs(fn, block_given?)
124
+ Enumerators::reverse(@enumerator).inject(seed) { |accumulator, value|
125
+ block_given? ? block.call(value, accumulator) : fn.(value, accumulator)
126
+ }
397
127
  end
398
128
 
399
- def from_sets
400
- Sequence.new(Sequence::Generator.new do |g|
401
- self.entries.map { |e| Type.check(e, Set); e.to_a }.flatten.each { |i| g.yield i }
402
- end)
129
+ def reduce(fn=nil, &block)
130
+ assert_funcs(fn, block_given?)
131
+ @enumerator.inject { |accumulator, value|
132
+ block_given? ? block.call(accumulator, value) : fn.(accumulator, value)
133
+ }
403
134
  end
404
135
 
405
- def in_pairs
406
- Sequence.new(Sequence::Generator.new do |g|
407
- self.each_slice(2) { |k, v| g.yield pair(k, v) }
408
- end)
409
- end
136
+ alias reduce_left reduce
410
137
 
411
- def to_a
412
- execution = {
413
- Sequences::Sequence => -> { self.entries.map { |s| s.entries } },
414
- Pair::Pair => -> { self.entries.map { |pair| pair.to_map } }
138
+ def reduce_right(fn=nil, &block)
139
+ assert_funcs(fn, block_given?)
140
+ Enumerators::reverse(@enumerator).inject { |accumulator, value|
141
+ block_given? ? block.call(value, accumulator) : fn.(value, accumulator)
415
142
  }
416
- if self.empty?
417
- self.entries
418
- else
143
+ end
419
144
 
420
- first_item = self.peek_values.first.class
421
- execution[first_item].nil? ? self.entries : execution[first_item].call
145
+ def find(fn_pred=nil, &block_pred)
146
+ assert_funcs(fn_pred, block_given?)
147
+ @enumerator.rewind
148
+ while has_next(@enumerator)
149
+ item = @enumerator.next
150
+ result = block_given? ? block_pred.call(item) : fn_pred.(item)
151
+ if result
152
+ return(some(item))
153
+ end
422
154
  end
155
+ none
423
156
  end
424
157
 
425
- def update(item)
426
- Sequence.new(Sequence::Generator.new do |g|
427
- if item.is_a?(Hash)
428
- self.map do |e|
429
- item.map { |k, v|
430
- raise(UnsupportedMethodException.new, "Tried to call method: #{k} on #{e.class} but method not supported") unless e.respond_to?(k) or e.respond_to?(":#{k}=")
431
- begin
432
- e.send(k, v) if e.respond_to?(k); e
433
- rescue
434
- e.send("#{k}=", v) if e.respond_to?("#{k}="); e
435
- end
436
- }.first
437
- end
438
- else
439
- self.map { item }
440
- end.each { |i| g.yield i }
441
- end)
158
+ def zip(other)
159
+ Sequence.new(pair_enumerator(@enumerator, other.enumerator))
442
160
  end
443
161
 
444
- def marshal_dump
445
- serialize
162
+ def zip_with_index
163
+ Sequences.zip(range_from(0), self)
446
164
  end
447
165
 
448
- def marshal_load(data)
449
- Sequence.new(data).deserialize
166
+ def find_index_of(fn_pred=nil, &block_pred)
167
+ assert_funcs(fn_pred, block_given?)
168
+ zip_with_index.find(->(pair) { block_given? ? block_pred.call(pair.second) : fn_pred.(pair.second) }).map(->(pair) { pair.first })
450
169
  end
451
170
 
452
- def serialize
453
- c = []
454
- serializer(c, self.entries)
455
- c
171
+ def take(count)
172
+ Sequences::take(self, count)
456
173
  end
457
174
 
458
- def deserialize
459
- c = []
460
- deserializer(c, self.entries)
461
- Sequence.new(c)
175
+ def take_while(fn_pred=nil, &block_pred)
176
+ assert_funcs(fn_pred, block_given?)
177
+ Sequence.new(@enumerator.take_while { |value| block_given? ? block_pred.call(value) : fn_pred.(value) })
462
178
  end
463
179
 
464
- def all
465
- to_a.flatten
180
+ def drop(count)
181
+ Sequences::drop(self, count)
466
182
  end
467
183
 
468
- def sorting_by(*attr, &block)
469
- if attr.empty?
470
- Sequence.new(Sequence::Generator.new do |g|
471
- self.sort_by { |e| block.call(e) }.each { |i| g.yield i }
472
- end)
473
- else
474
- Sequence.new(Sequence::Generator.new do |g|
475
- self.sort_by { |e| attr.map { |v| e.send(v) } }.each { |i| g.yield i }
476
- end)
477
- end
184
+ def drop_while(fn_pred=nil, &block_pred)
185
+ assert_funcs(fn_pred, block_given?)
186
+ Sequence.new(@enumerator.drop_while { |value| block_given? ? block_pred.call(value) : fn_pred.(value) })
478
187
  end
479
188
 
480
- def sorting
481
- Sequence.new(Sequence::Generator.new do |g|
482
- self.sort.each { |i| g.yield i }
483
- end)
189
+ def flat_map(fn=nil, &block)
190
+ assert_funcs(fn, block_given?)
191
+ map(block_given? ? ->(value) { block.call(value) } : fn).flatten
484
192
  end
485
193
 
486
- def get_or_else(index, or_else)
487
- blank?(sequence[index]) ? or_else : sequence[index]
194
+ def flatten
195
+ Sequence.new(flatten_enumerator(enumerator))
488
196
  end
489
197
 
490
- def get_option(index)
491
- blank?(sequence[index]) ? none : some(sequence[index])
198
+ def sort_by(comparator)
199
+ Sequences::sort(self, comparator)
492
200
  end
493
201
 
494
- def get_or_throw(index, exception, message='')
495
- blank?(sequence[index]) ? raise(exception, message) : sequence[index]
202
+ def contains?(value)
203
+ @enumerator.member?(value)
496
204
  end
497
205
 
498
-
499
- def get_by(pair_key)
500
- item = self.filter { |e| e.first == pair_key }.head_option
501
- item.is_some? ? item.get.value : none
206
+ def exists?(fn_pred=nil, &block_pred)
207
+ assert_funcs(fn_pred, block_given?)
208
+ @enumerator.any? { |value| block_given? ? block_pred.call(value) : fn_pred.(value) }
502
209
  end
503
210
 
504
- def into_hash
505
- raise(Exception.new, 'The sequence must contain pairs') unless self.head.kind_of?(Pair::Pair)
506
- Maps.merge(self.map { |p| {p.key => p.value} })
211
+ def for_all?(fn_pred=nil, &block_pred)
212
+ assert_funcs(fn_pred, block_given?)
213
+ @enumerator.all? { |value| block_given? ? block_pred.call(value) : fn_pred.(value) }
507
214
  end
508
215
 
509
- def drop_nil
510
- Sequence.new(Sequence::Generator.new do |g|
511
- self.reject { |e| e.nil? }.each { |i| g.yield i }
512
- end)
216
+ def filter(fn_pred=nil, &block_pred)
217
+ assert_funcs(fn_pred, block_given?)
218
+ Sequence.new(@enumerator.select { |value| block_given? ? block_pred.call(value) : fn_pred.(value) })
513
219
  end
514
220
 
515
- def map_concurrently(predicate=nil, options={}, &block)
516
- if predicate
517
- Sequence.new(Sequence::Generator.new do |g|
518
- Parallel.map(self.entries, options) { |val|
519
- predicate.is_a?(WherePredicate) ? WhereProcessor.new(val).apply(predicate.predicates) : predicate.exec.call(val)
520
- }.each { |i| g.yield i unless i.nil? }
521
- end)
522
- else
523
- Sequence.new(Sequence::Generator.new do |g|
524
- Parallel.map(self.entries, options) { |val| block.call(val) }.each { |i| g.yield i }
525
- end)
526
- end
221
+ def reject(fn_pred=nil, &block_pred)
222
+ assert_funcs(fn_pred, block_given?)
223
+ filter(Predicates::not(block_given? ? ->(value) { block_pred.call(value) } : fn_pred))
527
224
  end
528
225
 
529
- def each_concurrently(options={}, &block)
530
- Parallel.each(self.entries, options) { |val| block.call(val) }
226
+ def group_by(fn=nil, &block)
227
+ assert_funcs(fn, block_given?)
228
+ groups = @enumerator.group_by { |value| block_given? ? block.call(value) : fn.(value) }
229
+ Sequence.new(groups.to_a.map { |group| Group.new(group[0], group[1].lazy) }.lazy)
531
230
  end
532
231
 
533
- def cycle
534
- Sequence.new(Sequence::Generator.new do |g|
535
- self.entries.cycle.each { |i| g.yield i }
536
- end)
232
+ def each(fn=nil, &block)
233
+ assert_funcs(fn, block_given?)
234
+ @enumerator.each { |value| block_given? ? block.call(value) : fn.(value) }
537
235
  end
538
236
 
539
- protected
540
-
541
- def sequence
542
- Sequence.new(self)
237
+ def map_concurrently(fn=nil, &block)
238
+ assert_funcs(fn, block_given?)
239
+ Sequences::map_concurrently(self, block_given? ? ->(value) { block.call(value) } : fn)
543
240
  end
544
241
 
545
- def blank?(item)
546
- item.respond_to?(:empty?) ? item.empty? : !item
242
+ def realise
243
+ Sequence.new(@enumerator.to_a.lazy)
547
244
  end
548
245
 
549
- def serializer(container, entries)
550
- entries.each do |entry|
551
- if entry.is_a?(Sequences::Sequence)
552
- data = []
553
- serializer(data, entry)
554
- container << {type: :sequence, values: data}
555
- elsif entry.is_a?(Pair::Pair)
556
- if entry.second.is_a?(Sequences::Sequence)
557
- data = []
558
- serializer(data, entry)
559
- container << {type: :pair, values: data}
560
- else
561
- container << {type: :pair, values: entry.to_map}
562
- end
563
- elsif entry.is_a?(Option::Some)
564
- container << {type: :some, values: entry.value}
565
- elsif entry.is_a?(Option::None)
566
- container << {type: :none, values: nil}
567
- elsif entry.respond_to?(:each)
568
- data = []
569
- serializer(data, entry)
570
- container << {type: entry.class, values: data}
571
- else
572
- container << entry
573
- end
574
- end
246
+ def <=>(other)
247
+ @enumerator.entries <=> other.enumerator.entries
575
248
  end
576
249
 
577
- def deserializer(container, data)
578
- data.flatten.each do |entry|
579
-
580
- if entry.is_a?(Hash)
581
- if entry[:type] == :sequence
582
- data = []
583
- deserializer(data, entry[:values])
584
- container << Sequence.new(data)
585
- elsif entry[:type] == :pair
586
- if entry[:values].is_a?(Array)
587
- container << pair(entry[:values].first, Sequence.new(entry[:values][1][:values]))
588
- else
589
- container << pair(entry[:values].keys.first, entry[:values].values.first)
590
- end
591
- elsif entry[:type] == :some
592
- container << some(entry[:values])
593
- elsif entry[:type] == :none
594
- container << none
595
- elsif entry[:type] == Hash
596
- container << entry[:values].map{|e| {e[:values].first => e[:values].last } }.reduce({}) { |a, b| a.merge(b) }
597
- else
598
- container << entry[:type].send(:new, entry[:values])
599
- end
600
- else
601
- container << entry
602
- end
603
- end
250
+ private
251
+ def assert_funcs(fn, block_given)
252
+ raise 'Cannot pass both lambda and block expressions' if !fn.nil? && block_given
604
253
  end
605
-
606
254
  end
607
255
 
608
- class Empty < Sequence
609
-
610
- def initialize(obj=[], &block)
611
- super(obj) { |yielder|
612
- begin
613
- obj.each { |x|
614
- if block
615
- block.call(yielder, x)
616
- else
617
- yielder << x
618
- end
619
- }
620
- rescue StopIteration
621
- end
622
- }
623
- end
624
-
256
+ def group(key, enumerator)
257
+ Group.new(key, enumerator)
625
258
  end
626
259
 
627
- end
628
-
629
-
630
-
631
-
632
-
633
-
634
-
635
-
636
-
637
-
260
+ class Group < Sequence
261
+ include Comparable
262
+ attr_reader :key
638
263
 
264
+ def initialize(key, enumerator)
265
+ super(enumerator)
266
+ @key = key
267
+ end
639
268
 
269
+ def <=>(other)
270
+ (@key <=> other.key) <=> (enumerator.entries<=>(other.enumerator.entries))
271
+ end
272
+ end
640
273
 
274
+ private
641
275
 
276
+ EMPTY=Sequence.new([].lazy)
642
277
 
278
+ def pair_enumerator(left, right)
279
+ Enumerator.new do |y|
280
+ left.rewind
281
+ right.rewind
282
+ loop do
283
+ y << pair(left.next, right.next)
284
+ end
285
+ end.lazy
286
+ end
287
+ end