totally_lazy 0.0.4 → 0.0.5
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 +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
|
+
[](https://travis-ci.org/kingsleyh/totally_lazy)
|
8
|
+
[](http://badge.fury.io/rb/totally_lazy)
|
9
|
+
[](http://waffle.io/kingsleyh/totally_lazy)
|
10
|
+
[](https://coveralls.io/r/kingsleyh/totally_lazy?branch=master)
|
11
|
+
[](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
|