totally_lazy 0.0.8 → 0.0.9

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: eaad07a76c011ba5573c34c69bf011a0a6c83dcf
4
- data.tar.gz: 0d6623c562462a5e936b60bcee8d43ea919fa4bf
3
+ metadata.gz: 01903b7c27ad47c879061f9c243f2d9584f677b4
4
+ data.tar.gz: aedadff3f94da81d7360577b81a038bc2e59406e
5
5
  SHA512:
6
- metadata.gz: 9000dde503c5754b186847d11e300de5cc53ea8c48f5a0806ecd3847b3f565870cce50e3f7a330df184a0e2af4fd534bc06dfce1abbcfc5d38571128b87e122d
7
- data.tar.gz: 8dc151abd744dbb82190bc7774d431f868cabd9b856a62e275475601e7416cefe053f9e4fb71e50c4f7f6a87c32587a5091481632d244a038b63da84cfea97a4
6
+ metadata.gz: 3cf69966f72d69ec77ad6fde9de8829b83e5fcd40a73c1daf055e4aff7721db506b6cfb85b966eed8eff1b4b04bce55686ea8f2d30c0989a16671c27567ad045
7
+ data.tar.gz: e36f76e5bc0999828dd11b5dd622c4af0ce1e04c071df9b9e31eeadac35ccf3231cc298829532b2e82a05508b903cccdc424aa290ccb6f440141bfa1c971ad71
data/README.md CHANGED
@@ -73,8 +73,87 @@ Iter.range(1,4) # example with Iter: lazily returns 1,2,3,4 with a regular ruby
73
73
  Naturally you can combine these operations together:
74
74
 
75
75
  ```ruby
76
- option(1).join(sequence(2,3,4)).join(sequence(5,6)).filter(odd).take(2)
77
- # lazily returns 1,3
76
+ option(1).join(sequence(2,3,4)).join(sequence(5,6)).filter(odd).take(2) # lazily returns 1,3
78
77
 
79
78
  Seq.iterate(:+, 1).filter(even).take(2).reduce(:+) # returns 6
80
- ```
79
+ ```
80
+
81
+ ### Predicates
82
+
83
+ You can supply basic predicates as follows:
84
+
85
+ ##### numbers
86
+
87
+ sequence(1,2,3).filter(even) # returns 2
88
+
89
+ ##### conversions
90
+
91
+ sequence(1,2,3).map(as_string) # returns ["1","2","3"]
92
+
93
+ ##### comparisons
94
+
95
+ sequence(1,2,3).filter(equals(2) # return 2
96
+
97
+ ##### where - for self or objects
98
+
99
+ **using self**
100
+
101
+ When the predicate applies to an item in the sequence you use the **is** keyword with *where* to indicate the operation is on *self*
102
+
103
+ sequence(1,2,3).filter(where is greater_than 2)
104
+
105
+ **using objects**
106
+
107
+ When the predicate applies to a method on an object in the sequence then you supply hashmap of method_name:predicate (without using *is*)
108
+
109
+ sequence(pair(1,2),pair(3,4)).filter(where key:greater_than(3))
110
+
111
+ (pair has methods key and value)
112
+
113
+ ##### Regex
114
+
115
+ You can use a regex predicate
116
+
117
+ sequence("apple","pear").filter(matches(/app/))
118
+ sequence(pair("apple",1),pair("pear",2)).filter(where(key:matches(/app/)))
119
+
120
+ #### Custom Predicates
121
+
122
+ Writing a custom predicate is very easy and there are 3 built in helpers:
123
+
124
+ * simple_predicate
125
+ * value predicate
126
+ * self predicate
127
+
128
+ ##### simple_predicate
129
+
130
+ For example:
131
+
132
+ def as_uppercase
133
+ simple_predicate(:as_uppercase, -> (v) { v.upcase })
134
+ end
135
+
136
+ sequence("apple","pear").map(as_uppercase) # returns ["APPLE","PEAR"]
137
+
138
+ ##### value_predicate
139
+
140
+ For example:
141
+
142
+ def greater_than_or_equal_to(value)
143
+ value_predicate(:greater_than_or_equal_to,:>=,value)
144
+ end
145
+
146
+ sequence(1,2,3).filter(greater_than_or_equal_to 2)
147
+ sequence(1,2,3).filter(where is greater_than_or_equal_to 2)
148
+
149
+ ##### self_predicate
150
+
151
+ For example:
152
+
153
+ def is_valid
154
+ self_predicate(:is_valid, :is_valid)
155
+ end
156
+
157
+ sequence(OpenStruct.new(is_valid:true,name:'apple'),OpenStruct.new(is_valid:false,name:'pear')).filter(is_valid).to_a
158
+ => [#<OpenStruct is_valid=true, name="apple">]
159
+
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.8
1
+ 0.0.9
data/lib/option.rb CHANGED
@@ -23,7 +23,6 @@ module Option
23
23
  end
24
24
 
25
25
 
26
-
27
26
  def <=>(object)
28
27
  self.state <=> object.state
29
28
  end
@@ -81,46 +80,46 @@ module Option
81
80
  end
82
81
 
83
82
  def map(predicate=nil, &block)
84
- sequence(@content).map(predicate, &block).head_option
83
+ as_option(sequence(@content).map(predicate, &block))
85
84
  end
86
85
 
87
86
  alias collect map
88
87
 
89
88
  def select(predicate=nil, &block)
90
- sequence(@content).select(predicate, &block).head_option
89
+ as_option(sequence(@content).select(predicate, &block))
91
90
  end
92
91
 
93
92
  alias find_all select
94
93
  alias filter select
95
94
 
96
95
  def reject(predicate=nil, &block)
97
- sequence(@content).reject(predicate, &block).head_option
96
+ as_option(sequence(@content).reject(predicate, &block))
98
97
  end
99
98
 
100
99
  alias unfilter reject
101
100
 
102
101
  def grep(pattern)
103
- sequence(@content).grep(pattern).head_option
102
+ as_option(sequence(@content).grep(pattern))
104
103
  end
105
104
 
106
105
  def drop(n)
107
- sequence(@content).drop(n).head_option
106
+ as_option(sequence(@content).drop(n))
108
107
  end
109
108
 
110
109
  def drop_while(&block)
111
- sequence(@content).drop_while(&block).head_option
110
+ as_option(sequence(@content).drop_while(&block))
112
111
  end
113
112
 
114
113
  def take(n)
115
- sequence(@content).take(n).head_option
114
+ as_option(sequence(@content).take(n))
116
115
  end
117
116
 
118
117
  def take_while(&block)
119
- sequence(@content).take_while(&block).head_option
118
+ as_option(sequence(@content).take_while(&block))
120
119
  end
121
120
 
122
121
  def flat_map(&block)
123
- sequence(@content).flat_map(&block).head_option
122
+ as_option(sequence(@content).flat_map(&block))
124
123
  end
125
124
 
126
125
  alias collect_concat flat_map
@@ -144,6 +143,10 @@ module Option
144
143
  @content.respond_to?(:empty?) ? @content.empty? : !@content
145
144
  end
146
145
 
146
+ def as_option(seq)
147
+ seq.count == 1 ? seq.head_option : option(seq.entries)
148
+ end
149
+
147
150
  end
148
151
 
149
152
  class None
@@ -214,49 +217,49 @@ module Option
214
217
  alias << join
215
218
 
216
219
  def map(predicate=nil, &block)
217
- sequence(@content).map(predicate, &block).head_option
218
- end
220
+ none
221
+ end
219
222
 
220
- alias collect map
223
+ alias collect map
221
224
 
222
- def select(predicate=nil, &block)
223
- none
224
- end
225
+ def select(predicate=nil, &block)
226
+ none
227
+ end
225
228
 
226
- alias find_all select
227
- alias filter select
229
+ alias find_all select
230
+ alias filter select
228
231
 
229
- def reject(predicate=nil, &block)
230
- none
231
- end
232
+ def reject(predicate=nil, &block)
233
+ none
234
+ end
232
235
 
233
- alias unfilter reject
236
+ alias unfilter reject
234
237
 
235
- def grep(pattern)
236
- none
237
- end
238
+ def grep(pattern)
239
+ none
240
+ end
238
241
 
239
- def drop(n)
240
- none
241
- end
242
+ def drop(n)
243
+ none
244
+ end
242
245
 
243
- def drop_while(&block)
244
- none
245
- end
246
+ def drop_while(&block)
247
+ none
248
+ end
246
249
 
247
- def take(n)
248
- none
249
- end
250
+ def take(n)
251
+ none
252
+ end
250
253
 
251
- def take_while(&block)
252
- none
253
- end
254
+ def take_while(&block)
255
+ none
256
+ end
254
257
 
255
- def flat_map(&block)
256
- none
257
- end
258
+ def flat_map(&block)
259
+ none
260
+ end
258
261
 
259
- alias collect_concat flat_map
262
+ alias collect_concat flat_map
260
263
 
261
264
  protected
262
265
 
@@ -267,4 +270,4 @@ module Option
267
270
  end
268
271
 
269
272
 
270
- end
273
+ end
data/lib/sequence.rb CHANGED
@@ -44,6 +44,7 @@ module Sequences
44
44
  end
45
45
  end
46
46
 
47
+
47
48
  # Creates an empty sequence
48
49
  #
49
50
  # == Returns:
@@ -165,14 +166,13 @@ module Sequences
165
166
  end
166
167
 
167
168
  def drop(n)
168
- dropped = 0
169
- Sequence.new(self) { |yielder, val|
170
- if dropped < n
171
- dropped += 1
172
- else
173
- yielder << val
174
- end
175
- }
169
+ Sequence.new(Sequence::Generator.new do |g|
170
+ self.each_with_index do |v, i|
171
+ unless i < n
172
+ g.yield v
173
+ end
174
+ end
175
+ end)
176
176
  end
177
177
 
178
178
  def drop_while(&block)
@@ -191,14 +191,14 @@ module Sequences
191
191
 
192
192
  def take(n)
193
193
  Sequence.new(Sequence::Generator.new do |g|
194
- self.each_with_index do |v, i|
195
- if i < n
196
- g.yield v
197
- else
198
- raise StopIteration
199
- end
200
- end
201
- end)
194
+ self.each_with_index do |v, i|
195
+ if i < n
196
+ g.yield v
197
+ else
198
+ raise StopIteration
199
+ end
200
+ end
201
+ end)
202
202
  end
203
203
 
204
204
  def take_while(&block)
@@ -249,7 +249,7 @@ module Sequences
249
249
  end
250
250
 
251
251
  def head
252
- sequence.empty? ? raise(NoSuchElementException.new, 'The sequence was empty') : sequence.first
252
+ sequence.empty? ? raise(NoSuchElementException.new, 'The sequence was empty') : sequence.entries.first
253
253
  end
254
254
 
255
255
  def head_option
@@ -270,83 +270,83 @@ module Sequences
270
270
 
271
271
  def tail
272
272
  Sequence.new(Sequence::Generator.new do |g|
273
- self.empty? ? raise(NoSuchElementException.new, 'The sequence was empty') : self.drop(1).each { |i| g.yield i }
274
- end)
273
+ self.empty? ? raise(NoSuchElementException.new, 'The sequence was empty') : self.drop(1).each { |i| g.yield i }
274
+ end)
275
275
  end
276
276
 
277
277
  def init
278
278
  Sequence.new(Sequence::Generator.new do |g|
279
- size = self.count
280
- self.empty? ? raise(NoSuchElementException.new, 'The sequence was empty') : self.first(size-1).each { |i| g.yield i }
281
- end)
279
+ size = self.count
280
+ self.empty? ? raise(NoSuchElementException.new, 'The sequence was empty') : self.first(size-1).each { |i| g.yield i }
281
+ end)
282
282
  end
283
283
 
284
284
  def shuffle
285
285
  Sequence.new(Sequence::Generator.new do |g|
286
- self.empty? ? raise(NoSuchElementException.new, 'The sequence was empty') : self.entries.shuffle.each { |i| g.yield i }
287
- end)
286
+ self.empty? ? raise(NoSuchElementException.new, 'The sequence was empty') : self.entries.shuffle.each { |i| g.yield i }
287
+ end)
288
288
  end
289
289
 
290
290
  def transpose
291
291
  Sequence.new(Sequence::Generator.new do |g|
292
- if self.empty?
293
- raise(NoSuchElementException.new, 'The sequence was empty')
294
- else
295
- raise(Exception.new, 'The subject of transposition must be multidimensional') unless self.to_a.first.is_a?(Array)
296
- end
297
- result = []
298
- max = option(self.to_a.max { |a, b| a.size <=> b.size })
299
- max_size = max.get_or_throw(NoSuchElementException, 'The option was empty').size
300
- max_size.times do |i|
301
- result[i] = [self.to_a.first.size]
302
- self.to_a.each_with_index { |r, j| result[i][j] = r[i] }
303
- end
304
- result
305
- result.each { |i| g.yield i }
306
- end)
292
+ if self.empty?
293
+ raise(NoSuchElementException.new, 'The sequence was empty')
294
+ else
295
+ raise(Exception.new, 'The subject of transposition must be multidimensional') unless self.to_a.first.is_a?(Array)
296
+ end
297
+ result = []
298
+ max = option(self.to_a.max { |a, b| a.size <=> b.size })
299
+ max_size = max.get_or_throw(NoSuchElementException, 'The option was empty').size
300
+ max_size.times do |i|
301
+ result[i] = [self.to_a.first.size]
302
+ self.to_a.each_with_index { |r, j| result[i][j] = r[i] }
303
+ end
304
+ result
305
+ result.each { |i| g.yield i }
306
+ end)
307
307
  end
308
308
 
309
309
  def join(target_sequence)
310
310
  Sequence.new(Sequence::Generator.new do |g|
311
- raise(Exception.new, 'The target (right side) must be a sequence') unless target_sequence.kind_of?(Sequences::Sequence)
312
- self.entries.push(target_sequence.entries).flatten.each { |i| g.yield i unless i.is_a?(Empty) }
313
- end)
311
+ raise(Exception.new, 'The target (right side) must be a sequence') unless target_sequence.kind_of?(Sequences::Sequence)
312
+ self.entries.push(target_sequence.entries).flatten.each { |i| g.yield i unless i.is_a?(Empty) }
313
+ end)
314
314
  end
315
315
 
316
316
  alias << join
317
317
 
318
318
  def add(target_sequence)
319
319
  Sequence.new(Sequence::Generator.new do |g|
320
- (self.entries + target_sequence.entries).each { |i| g.yield i }
321
- end)
320
+ (self.entries + target_sequence.entries).each { |i| g.yield i }
321
+ end)
322
322
  end
323
323
 
324
324
  alias + add
325
325
 
326
326
  def append(item)
327
327
  Sequence.new(Sequence::Generator.new do |g|
328
- elements = self.entries
329
- elements = elements.reject { |i| i.is_a?(Empty) }
330
- (elements << item).each { |i| g.yield i }
331
- end)
328
+ elements = self.entries
329
+ elements = elements.reject { |i| i.is_a?(Empty) }
330
+ (elements << item).each { |i| g.yield i }
331
+ end)
332
332
  end
333
333
 
334
334
  def to_seq
335
335
  Sequence.new(Sequence::Generator.new do |g|
336
- self.entries.map { |e| Type.responds(e, :entries); e.entries }.flatten.each { |i| g.yield i }
337
- end)
336
+ self.entries.map { |e| Type.responds(e, :entries); e.entries }.flatten.each { |i| g.yield i }
337
+ end)
338
338
  end
339
339
 
340
340
  def to_maps(symbolize=true)
341
341
  Sequence.new(Sequence::Generator.new do |g|
342
- self.each_slice(2) do |k, v|
343
- if symbolize
344
- g.yield k.to_s.to_sym => v
345
- else
346
- g.yield k => v
347
- end
348
- end
349
- end)
342
+ self.each_slice(2) do |k, v|
343
+ if symbolize
344
+ g.yield k.to_s.to_sym => v
345
+ else
346
+ g.yield k => v
347
+ end
348
+ end
349
+ end)
350
350
  end
351
351
 
352
352
  def to_map(symbolize=true)
@@ -355,26 +355,26 @@ module Sequences
355
355
 
356
356
  def from_pairs
357
357
  Sequence.new(Sequence::Generator.new do |g|
358
- self.entries.map { |e| Type.check(e, Pair::Pair); [e.key, e.value] }.flatten.each { |i| g.yield i }
359
- end)
358
+ self.entries.map { |e| Type.check(e, Pair::Pair); [e.key, e.value] }.flatten.each { |i| g.yield i }
359
+ end)
360
360
  end
361
361
 
362
362
  def from_arrays
363
363
  Sequence.new(Sequence::Generator.new do |g|
364
- self.entries.map { |e| Type.check(e, Array); e }.flatten.each { |i| g.yield i }
365
- end)
364
+ self.entries.map { |e| Type.check(e, Array); e }.flatten.each { |i| g.yield i }
365
+ end)
366
366
  end
367
367
 
368
368
  def from_sets
369
369
  Sequence.new(Sequence::Generator.new do |g|
370
- self.entries.map { |e| Type.check(e, Set); e.to_a }.flatten.each { |i| g.yield i }
371
- end)
370
+ self.entries.map { |e| Type.check(e, Set); e.to_a }.flatten.each { |i| g.yield i }
371
+ end)
372
372
  end
373
373
 
374
374
  def in_pairs
375
375
  Sequence.new(Sequence::Generator.new do |g|
376
- self.each_slice(2) { |k, v| g.yield pair(k, v) }
377
- end)
376
+ self.each_slice(2) { |k, v| g.yield pair(k, v) }
377
+ end)
378
378
  end
379
379
 
380
380
  def to_a
@@ -393,21 +393,21 @@ module Sequences
393
393
 
394
394
  def update(item)
395
395
  Sequence.new(Sequence::Generator.new do |g|
396
- if item.is_a?(Hash)
397
- self.map do |e|
398
- item.map { |k, v|
399
- 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}=")
400
- begin
401
- e.send(k, v) if e.respond_to?(k); e
402
- rescue
403
- e.send("#{k}=", v) if e.respond_to?("#{k}="); e
404
- end
405
- }.first
406
- end
407
- else
408
- self.map { item }
409
- end.each { |i| g.yield i }
410
- end)
396
+ if item.is_a?(Hash)
397
+ self.map do |e|
398
+ item.map { |k, v|
399
+ 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}=")
400
+ begin
401
+ e.send(k, v) if e.respond_to?(k); e
402
+ rescue
403
+ e.send("#{k}=", v) if e.respond_to?("#{k}="); e
404
+ end
405
+ }.first
406
+ end
407
+ else
408
+ self.map { item }
409
+ end.each { |i| g.yield i }
410
+ end)
411
411
  end
412
412
 
413
413
  def marshal_dump
@@ -437,19 +437,19 @@ module Sequences
437
437
  def sorting_by(*attr, &block)
438
438
  if attr.empty?
439
439
  Sequence.new(Sequence::Generator.new do |g|
440
- self.sort_by { |e| block.call(e) }.each { |i| g.yield i }
441
- end)
440
+ self.sort_by { |e| block.call(e) }.each { |i| g.yield i }
441
+ end)
442
442
  else
443
443
  Sequence.new(Sequence::Generator.new do |g|
444
- self.sort_by { |e| attr.map{|v| e.send(v)} }.each { |i| g.yield i }
445
- end)
444
+ self.sort_by { |e| attr.map { |v| e.send(v) } }.each { |i| g.yield i }
445
+ end)
446
446
  end
447
447
  end
448
448
 
449
449
  def sorting
450
450
  Sequence.new(Sequence::Generator.new do |g|
451
- self.sort.each { |i| g.yield i }
452
- end)
451
+ self.sort.each { |i| g.yield i }
452
+ end)
453
453
  end
454
454
 
455
455
  def get_or_else(index, or_else)
@@ -466,32 +466,32 @@ module Sequences
466
466
 
467
467
 
468
468
  def get_by(pair_key)
469
- item = self.filter{|e| e.first == pair_key}.head_option
469
+ item = self.filter { |e| e.first == pair_key }.head_option
470
470
  item.is_some? ? item.get.value : none
471
471
  end
472
472
 
473
473
  def into_hash
474
474
  raise(Exception.new, 'The sequence must contain pairs') unless self.head.kind_of?(Pair::Pair)
475
- Maps.merge(self.map{|p| {p.key => p.value}})
475
+ Maps.merge(self.map { |p| {p.key => p.value} })
476
476
  end
477
477
 
478
478
  def drop_nil
479
479
  Sequence.new(Sequence::Generator.new do |g|
480
- self.reject { |e| e.nil? }.each { |i| g.yield i }
481
- end)
480
+ self.reject { |e| e.nil? }.each { |i| g.yield i }
481
+ end)
482
482
  end
483
483
 
484
484
  def map_concurrently(predicate=nil, options={}, &block)
485
485
  if predicate
486
486
  Sequence.new(Sequence::Generator.new do |g|
487
- Parallel.map(self.entries, options) { |val|
488
- predicate.is_a?(WherePredicate) ? WhereProcessor.new(val).apply(predicate.predicates) : predicate.exec.call(val)
489
- }.each { |i| g.yield i unless i.nil? }
490
- end)
487
+ Parallel.map(self.entries, options) { |val|
488
+ predicate.is_a?(WherePredicate) ? WhereProcessor.new(val).apply(predicate.predicates) : predicate.exec.call(val)
489
+ }.each { |i| g.yield i unless i.nil? }
490
+ end)
491
491
  else
492
492
  Sequence.new(Sequence::Generator.new do |g|
493
- Parallel.map(self.entries, options) { |val| block.call(val) }.each { |i| g.yield i }
494
- end)
493
+ Parallel.map(self.entries, options) { |val| block.call(val) }.each { |i| g.yield i }
494
+ end)
495
495
  end
496
496
  end
497
497
 
@@ -501,8 +501,8 @@ module Sequences
501
501
 
502
502
  def cycle
503
503
  Sequence.new(Sequence::Generator.new do |g|
504
- self.entries.cycle.each { |i| g.yield i }
505
- end)
504
+ self.entries.cycle.each { |i| g.yield i }
505
+ end)
506
506
  end
507
507
 
508
508
  protected
data/spec/option_spec.rb CHANGED
@@ -125,6 +125,8 @@ describe 'Option' do
125
125
  end
126
126
 
127
127
  it 'should support map' do
128
+ expect(option([{apple:1,pear:2},{melon:3}]).map{|h| h}).to eq(some([{apple:1,pear:2},{melon:3}]))
129
+ expect(option({apple:1,pear:2})).to eq(some({apple:1,pear:2}))
128
130
  expect(option(1).map(as_string)).to eq(some('1'))
129
131
  expect(option(1).collect(as_string)).to eq(some('1'))
130
132
  expect(option(sequence(1, 2, 3)).map { |s| s.entries }).to eq(some([1, 2, 3]))
@@ -167,4 +169,4 @@ describe 'Option' do
167
169
  expect(option(nil).flat_map{|v| v.first}).to eq(none)
168
170
  end
169
171
 
170
- end
172
+ end
data/totally_lazy.gemspec CHANGED
@@ -6,7 +6,7 @@
6
6
 
7
7
  Gem::Specification.new do |s|
8
8
  s.name = "totally_lazy"
9
- s.version = "0.0.8"
9
+ s.version = "0.0.9"
10
10
 
11
11
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
12
12
  s.require_paths = ["lib"]
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: totally_lazy
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.8
4
+ version: 0.0.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kingsley Hendrickse