totally_lazy 0.0.20 → 0.1.0

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