totally_lazy 0.0.4 → 0.0.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +3 -0
- data/Gemfile +3 -0
- data/Guardfile +24 -0
- data/README.md +31 -0
- data/Rakefile +12 -0
- data/VERSION +1 -1
- data/lib/any.rb +13 -0
- data/lib/generators.rb +161 -0
- data/lib/option.rb +75 -10
- data/lib/pair.rb +6 -0
- data/lib/parallel/parallel.rb +442 -0
- data/lib/parallel/processor_count.rb +85 -0
- data/lib/predicates/compare.rb +32 -0
- data/lib/{predicates.rb → predicates/conversions.rb} +0 -13
- data/lib/predicates/numbers.rb +25 -0
- data/lib/predicates/predicates.rb +57 -0
- data/lib/predicates/where.rb +34 -0
- data/lib/predicates/where_processor.rb +13 -0
- data/lib/sequence.rb +217 -21
- data/lib/totally_lazy.rb +124 -1
- data/spec/functor_spec.rb +35 -0
- data/spec/generators_spec.rb +37 -0
- data/spec/option_spec.rb +73 -2
- data/spec/pair_spec.rb +5 -2
- data/spec/predicate_spec.rb +37 -5
- data/spec/sequence_spec.rb +144 -4
- data/spec/serialization_spec.rb +56 -0
- data/spec/spec_helper.rb +27 -0
- data/spec/type_check_spec.rb +1 -2
- data/totally_lazy.gemspec +28 -4
- metadata +60 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ef27c17e829a30f3c3efd0bacdb6023066e85326
|
4
|
+
data.tar.gz: d583a528661e3c190245c64ffce9cf9b8093d55a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 32ed21dfa78360ba8dec458c2f6646a4af09a448957b84e51c0ee686aa1fb6e031334f676e7bb5a51e759bceb9c8e88a942f022b39c80189e64877949f121aa2
|
7
|
+
data.tar.gz: 9e903a0e2716f72c524753d35de1a5ecfdb0f71228b6aa4aef1f0f55e92c3bdf9a6cb38c9fdfad99acc49a19f2501992d4175180daa1b7805cde33b84f5bb305
|
data/.travis.yml
ADDED
data/Gemfile
CHANGED
data/Guardfile
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# A sample Guardfile
|
2
|
+
# More info at https://github.com/guard/guard#readme
|
3
|
+
|
4
|
+
guard :rspec do
|
5
|
+
watch(%r{^spec/.+_spec\.rb$})
|
6
|
+
watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
|
7
|
+
watch('spec/spec_helper.rb') { "spec" }
|
8
|
+
|
9
|
+
# # Rails example
|
10
|
+
# watch(%r{^app/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
|
11
|
+
# watch(%r{^app/(.*)(\.erb|\.haml|\.slim)$}) { |m| "spec/#{m[1]}#{m[2]}_spec.rb" }
|
12
|
+
# watch(%r{^app/controllers/(.+)_(controller)\.rb$}) { |m| ["spec/routing/#{m[1]}_routing_spec.rb", "spec/#{m[2]}s/#{m[1]}_#{m[2]}_spec.rb", "spec/acceptance/#{m[1]}_spec.rb"] }
|
13
|
+
# watch(%r{^spec/support/(.+)\.rb$}) { "spec" }
|
14
|
+
# watch('config/routes.rb') { "spec/routing" }
|
15
|
+
# watch('app/controllers/application_controller.rb') { "spec/controllers" }
|
16
|
+
#
|
17
|
+
# # Capybara features specs
|
18
|
+
# watch(%r{^app/views/(.+)/.*\.(erb|haml|slim)$}) { |m| "spec/features/#{m[1]}_spec.rb" }
|
19
|
+
#
|
20
|
+
# # Turnip features and steps
|
21
|
+
# watch(%r{^spec/acceptance/(.+)\.feature$})
|
22
|
+
# watch(%r{^spec/acceptance/steps/(.+)_steps\.rb$}) { |m| Dir[File.join("**/#{m[1]}.feature")][0] || 'spec/acceptance' }
|
23
|
+
end
|
24
|
+
|
data/README.md
CHANGED
@@ -2,6 +2,13 @@
|
|
2
2
|
|
3
3
|
This is a port of the java functional library [Totally Lazy](https://code.google.com/p/totallylazy/) to the ruby language. I've tried to get it as close as I can to the original concepts behind the java version of Totally Lazy but I'm still pretty far away from being happy with it.
|
4
4
|
|
5
|
+
### Status
|
6
|
+
|
7
|
+
[![Build Status](https://travis-ci.org/kingsleyh/totally_lazy.svg?branch=master)](https://travis-ci.org/kingsleyh/totally_lazy)
|
8
|
+
[![Gem Version](https://badge.fury.io/rb/totally_lazy.svg)](http://badge.fury.io/rb/totally_lazy)
|
9
|
+
[![Stories in Ready](https://badge.waffle.io/kingsleyh/totally_lazy.svg?label=ready&title=Ready)](http://waffle.io/kingsleyh/totally_lazy)
|
10
|
+
[![Coverage Status](https://coveralls.io/repos/kingsleyh/totally_lazy/badge.png?branch=master)](https://coveralls.io/r/kingsleyh/totally_lazy?branch=master)
|
11
|
+
[![Inline docs](http://inch-ci.org/github/kingsleyh/totally_lazy.png?branch=master)](http://inch-ci.org/github/kingsleyh/totally_lazy)
|
5
12
|
### Summary
|
6
13
|
|
7
14
|
* Tries to be as lazy as possible
|
@@ -31,12 +38,34 @@ require 'totally_lazy'
|
|
31
38
|
|
32
39
|
sequence(1,2,3,4).filter(even) # lazily returns 2,4
|
33
40
|
sequence(1,2).map(as_string) # lazily returns "1","2"
|
41
|
+
sequence(1, 2).map_concurrently(to_string) # lazily distributes the work to background threads
|
34
42
|
sequence(1,2,3).take(2) # lazily returns 1,2
|
35
43
|
sequence(1,2,3).drop(2) # lazily returns 3
|
36
44
|
sequence(1,2,3).tail # lazily returns 2,3
|
37
45
|
sequence(1,2,3).head # eagerly returns 1
|
38
46
|
sequence(1,2,3).head_option # eagerly returns an option
|
39
47
|
some(sequence(1,2,3)).get_or_else(empty) # eagerly returns value or else empty sequence
|
48
|
+
sequence(1, 2, 3, 4, 5).filter(where(is greater_than 2).and(is odd)) # lazily returns 3,5
|
49
|
+
sequence(pair(1, 2), pair(3, 4)).filter(where(key:odd)) # lazily returns 1,3
|
50
|
+
```
|
51
|
+
|
52
|
+
#### Generators
|
53
|
+
|
54
|
+
There are 2 types of generators:
|
55
|
+
|
56
|
+
* Seq - returns a sequence
|
57
|
+
* Iter - returns a regular ruby enumerator
|
58
|
+
|
59
|
+
```ruby
|
60
|
+
Seq.range(1, 4) # lazily returns 1,2,3,4
|
61
|
+
Seq.repeat("car") # lazily returns an infinite sequence of "car"s
|
62
|
+
Seq.iterate(:+, 1) # lazily returns 1,2,3 ... to infinity
|
63
|
+
Seq.range(1, 4).cycle # lazily returns 1,2,3,4,1,2,3,4,1,2,3,4 infinitely
|
64
|
+
Seq.primes # lazily returns every prime number
|
65
|
+
Seq.fibonacci # lazily returns the fibonacci sequence
|
66
|
+
Seq.powers_of(3) # lazily returns the powers of 3 (i.e 1,3,9,27 ...)
|
67
|
+
|
68
|
+
Iter.range(1,4) # example with Iter: lazily returns 1,2,3,4 with a regular ruby enumerator
|
40
69
|
```
|
41
70
|
|
42
71
|
Naturally you can combine these operations together:
|
@@ -44,4 +73,6 @@ Naturally you can combine these operations together:
|
|
44
73
|
```ruby
|
45
74
|
option(1).join(sequence(2,3,4)).join(sequence(5,6)).filter(odd).take(2)
|
46
75
|
# lazily returns 1,3
|
76
|
+
|
77
|
+
Seq.iterate(:+, 1).filter(even).take(2).reduce(:+) # returns 6
|
47
78
|
```
|
data/Rakefile
CHANGED
@@ -48,3 +48,15 @@ Rake::RDocTask.new do |rdoc|
|
|
48
48
|
rdoc.rdoc_files.include('README*')
|
49
49
|
rdoc.rdoc_files.include('lib/**/*.rb')
|
50
50
|
end
|
51
|
+
|
52
|
+
desc 'run rspec guard'
|
53
|
+
task :guard do
|
54
|
+
system('bundle exec guard')
|
55
|
+
end
|
56
|
+
|
57
|
+
desc 'rebuild gem'
|
58
|
+
task :re do
|
59
|
+
system('gem uninstall totally_lazy && rake build && gem install -l pkg/totally_lazy-' + File.read('VERSION') + '.gem')
|
60
|
+
end
|
61
|
+
|
62
|
+
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0.
|
1
|
+
0.0.5
|
data/lib/any.rb
ADDED
data/lib/generators.rb
ADDED
@@ -0,0 +1,161 @@
|
|
1
|
+
module Generators
|
2
|
+
|
3
|
+
module Seq
|
4
|
+
|
5
|
+
module_function
|
6
|
+
|
7
|
+
def repeat(item)
|
8
|
+
Sequence.new(Sequence::Generator.new do |g|
|
9
|
+
loop { g.yield item.respond_to?(:call) ? item.call : item }
|
10
|
+
end)
|
11
|
+
end
|
12
|
+
|
13
|
+
def range(lower, higher)
|
14
|
+
Sequence.new(Sequence::Generator.new do |g|
|
15
|
+
(lower..higher).each { |item| g.yield item }
|
16
|
+
end)
|
17
|
+
end
|
18
|
+
|
19
|
+
def iterate(operator, item, start=1)
|
20
|
+
Sequence.new(Sequence::Generator.new do |g|
|
21
|
+
value = start
|
22
|
+
loop do
|
23
|
+
g.yield value
|
24
|
+
value = value.send(operator, item)
|
25
|
+
end
|
26
|
+
end)
|
27
|
+
end
|
28
|
+
|
29
|
+
def primes
|
30
|
+
Sequence.new(Sequence::Generator.new do |g|
|
31
|
+
Prime.each { |n| g.yield n }
|
32
|
+
end)
|
33
|
+
end
|
34
|
+
|
35
|
+
def fibonacci
|
36
|
+
Sequence.new(Sequence::Generator.new do |g|
|
37
|
+
i, j = 1, 1
|
38
|
+
loop do
|
39
|
+
g.yield i
|
40
|
+
i, j = j, i + j
|
41
|
+
end
|
42
|
+
end)
|
43
|
+
end
|
44
|
+
|
45
|
+
def powers_of(v)
|
46
|
+
Sequence.new(Sequence::Generator.new do |g|
|
47
|
+
Seq.iterate(:+,1,0).each {|n| g.yield v**n}
|
48
|
+
end)
|
49
|
+
end
|
50
|
+
|
51
|
+
|
52
|
+
end
|
53
|
+
|
54
|
+
module Iter
|
55
|
+
|
56
|
+
module_function
|
57
|
+
|
58
|
+
def repeat(item)
|
59
|
+
Repeater.new(item)
|
60
|
+
end
|
61
|
+
|
62
|
+
def range(lower, higher)
|
63
|
+
Ranger.new(lower, higher)
|
64
|
+
end
|
65
|
+
|
66
|
+
def iterate(operator, item, start=1)
|
67
|
+
Iterate.new(operator, item, start)
|
68
|
+
end
|
69
|
+
|
70
|
+
def primes
|
71
|
+
Primes.new
|
72
|
+
end
|
73
|
+
|
74
|
+
def fibonacci
|
75
|
+
Fibonacci.new
|
76
|
+
end
|
77
|
+
|
78
|
+
def powers_of(v)
|
79
|
+
PowerOf.new(v)
|
80
|
+
end
|
81
|
+
|
82
|
+
class Repeater
|
83
|
+
include Enumerable
|
84
|
+
|
85
|
+
def initialize(item)
|
86
|
+
@item = item
|
87
|
+
end
|
88
|
+
|
89
|
+
def each
|
90
|
+
loop { yield(@item) }
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
class Ranger
|
95
|
+
include Enumerable
|
96
|
+
|
97
|
+
def initialize(lower, higher)
|
98
|
+
@lower = lower
|
99
|
+
@higher = higher
|
100
|
+
end
|
101
|
+
|
102
|
+
def each
|
103
|
+
(@lower..@higher).each { |i| yield i }
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
class Iterate
|
108
|
+
|
109
|
+
include Enumerable
|
110
|
+
|
111
|
+
def initialize(operator, item, start)
|
112
|
+
@operator = operator
|
113
|
+
@item = item
|
114
|
+
@start = start
|
115
|
+
end
|
116
|
+
|
117
|
+
def each
|
118
|
+
value = @start
|
119
|
+
loop do
|
120
|
+
yield value
|
121
|
+
value = value.send(@operator, @item)
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
end
|
126
|
+
|
127
|
+
class Primes
|
128
|
+
include Enumerable
|
129
|
+
|
130
|
+
def each
|
131
|
+
Prime.each { |p| yield p }
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
class Fibonacci
|
136
|
+
include Enumerable
|
137
|
+
|
138
|
+
def each
|
139
|
+
i, j = 1, 1
|
140
|
+
loop do
|
141
|
+
yield i
|
142
|
+
i, j = j, i + j
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
class PowerOf
|
148
|
+
include Enumerable
|
149
|
+
|
150
|
+
def initialize(v)
|
151
|
+
@v = v
|
152
|
+
end
|
153
|
+
|
154
|
+
def each
|
155
|
+
Iter.iterate(:+,1,0).each {|n| yield @v**n}
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
end
|
160
|
+
|
161
|
+
end
|
data/lib/option.rb
CHANGED
@@ -1,7 +1,8 @@
|
|
1
1
|
module Option
|
2
2
|
|
3
3
|
def option(thing)
|
4
|
-
thing.
|
4
|
+
validate = thing.respond_to?(:empty?) ? thing.empty? : !thing
|
5
|
+
validate ? none : some(thing)
|
5
6
|
end
|
6
7
|
|
7
8
|
def some(thing)
|
@@ -18,13 +19,21 @@ module Option
|
|
18
19
|
|
19
20
|
def initialize(content)
|
20
21
|
@content = content
|
21
|
-
raise(Exception,'some cannot be nil') if @content.nil?
|
22
|
+
raise(Exception, 'some cannot be nil') if @content.nil?
|
22
23
|
end
|
23
24
|
|
24
25
|
def <=>(object)
|
25
26
|
self.state <=> object.state
|
26
27
|
end
|
27
28
|
|
29
|
+
def is_none?
|
30
|
+
self.is_a?(None)
|
31
|
+
end
|
32
|
+
|
33
|
+
def is_some?
|
34
|
+
self.is_a?(Some)
|
35
|
+
end
|
36
|
+
|
28
37
|
def get
|
29
38
|
@content
|
30
39
|
end
|
@@ -34,11 +43,11 @@ module Option
|
|
34
43
|
end
|
35
44
|
|
36
45
|
def empty?
|
37
|
-
|
46
|
+
blank?
|
38
47
|
end
|
39
48
|
|
40
49
|
def defined?
|
41
|
-
!
|
50
|
+
!blank?
|
42
51
|
end
|
43
52
|
|
44
53
|
def get_or_else(item)
|
@@ -49,8 +58,8 @@ module Option
|
|
49
58
|
blank? ? nil : @content
|
50
59
|
end
|
51
60
|
|
52
|
-
def get_or_throw(exception)
|
53
|
-
blank? ? raise(exception) : @content
|
61
|
+
def get_or_throw(exception,message='')
|
62
|
+
blank? ? raise(exception,message) : @content
|
54
63
|
end
|
55
64
|
|
56
65
|
def to_seq
|
@@ -58,16 +67,17 @@ module Option
|
|
58
67
|
end
|
59
68
|
|
60
69
|
def contains(item)
|
61
|
-
|
70
|
+
value == item
|
62
71
|
end
|
63
72
|
|
64
73
|
def exists?(predicate)
|
65
|
-
|
74
|
+
value
|
66
75
|
end
|
67
76
|
|
68
77
|
def join(target_sequence)
|
69
|
-
|
78
|
+
sequence(value) << target_sequence
|
70
79
|
end
|
80
|
+
|
71
81
|
alias + join
|
72
82
|
alias << join
|
73
83
|
|
@@ -79,7 +89,7 @@ module Option
|
|
79
89
|
private
|
80
90
|
|
81
91
|
def blank?
|
82
|
-
@content.respond_to?(:empty?) ? empty? :
|
92
|
+
@content.respond_to?(:empty?) ? @content.empty? : !@content
|
83
93
|
end
|
84
94
|
|
85
95
|
end
|
@@ -96,6 +106,61 @@ module Option
|
|
96
106
|
self.state <=> object.state
|
97
107
|
end
|
98
108
|
|
109
|
+
def is_none?
|
110
|
+
self.is_a?(None)
|
111
|
+
end
|
112
|
+
|
113
|
+
def is_some?
|
114
|
+
self.is_a?(Some)
|
115
|
+
end
|
116
|
+
|
117
|
+
def get
|
118
|
+
raise NoSuchElementException.new, 'The option was empty'
|
119
|
+
end
|
120
|
+
|
121
|
+
def value
|
122
|
+
raise NoSuchElementException.new, 'The option was empty'
|
123
|
+
end
|
124
|
+
|
125
|
+
def empty?
|
126
|
+
true
|
127
|
+
end
|
128
|
+
|
129
|
+
def defined?
|
130
|
+
false
|
131
|
+
end
|
132
|
+
|
133
|
+
def get_or_else(item)
|
134
|
+
item
|
135
|
+
end
|
136
|
+
|
137
|
+
def get_or_nil
|
138
|
+
nil
|
139
|
+
end
|
140
|
+
|
141
|
+
def get_or_throw(exception,message='')
|
142
|
+
raise(exception,message)
|
143
|
+
end
|
144
|
+
|
145
|
+
def to_seq
|
146
|
+
sequence(self)
|
147
|
+
end
|
148
|
+
|
149
|
+
def contains(item)
|
150
|
+
false
|
151
|
+
end
|
152
|
+
|
153
|
+
def exists?(predicate)
|
154
|
+
false
|
155
|
+
end
|
156
|
+
|
157
|
+
def join(target_sequence)
|
158
|
+
target_sequence.is_a?(Sequences::Sequence) ? target_sequence : sequence(target_sequence)
|
159
|
+
end
|
160
|
+
|
161
|
+
alias + join
|
162
|
+
alias << join
|
163
|
+
|
99
164
|
protected
|
100
165
|
|
101
166
|
def state
|