totally_lazy 0.0.8 → 0.0.9

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