totally_lazy 0.1.22 → 0.1.23
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 +8 -8
- data/Rakefile +1 -1
- data/lib/totally_lazy.rb +11 -11
- data/lib/{comparators.rb → totally_lazy/comparators.rb} +1 -0
- data/lib/{enumerators.rb → totally_lazy/enumerators.rb} +7 -6
- data/lib/{functions.rb → totally_lazy/functions.rb} +3 -12
- data/lib/{lambda_block.rb → totally_lazy/lambda_block.rb} +0 -0
- data/lib/{numbers.rb → totally_lazy/numbers.rb} +2 -1
- data/lib/totally_lazy/option.rb +191 -0
- data/lib/totally_lazy/pair.rb +39 -0
- data/lib/{predicates.rb → totally_lazy/predicates.rb} +2 -1
- data/lib/totally_lazy/sequence.rb +327 -0
- data/lib/{strings.rb → totally_lazy/strings.rb} +1 -0
- data/spec/option_spec.rb +17 -5
- data/spec/sequence_spec.rb +4 -3
- data/spec/spec_helper.rb +1 -1
- metadata +12 -12
- data/lib/option.rb +0 -156
- data/lib/pair.rb +0 -40
- data/lib/sequence.rb +0 -298
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
ZjQ0ZWZiYjdhYjFkODdjOTU3M2IzMTQ0MGY0YmYxMzUwMjI0OWQ0Ng==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
Mzg2NzRhNzgwZDYzODE4M2M4ZmY4OTZlOWRkMjViNDNlY2M2NjA4OQ==
|
7
7
|
SHA512:
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
Y2M0MWVjYTEzOWFmZWI4MWQzNjFiMWI5MjkzNjY0NjkyYzMwYmE3MzM2YjNk
|
10
|
+
ZTgyOGU1MGY5NGQwNzk5ZTViMzFlZjc0NDE4YTIwNDg3ZjgwMjNiNzQwYTU5
|
11
|
+
NTc5NDBiNjM3MTdhZDM2MzQ2ODA4YzdjOWMyZDMwOWJkNTM0MGY=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
ZjE3ZTJmMzg1NzViZjY0ZGNiMmJlNGU2MDIwZjY4MDJlY2NjYjBkM2U4YjNh
|
14
|
+
MDQ2ZWU5YmQ1ZjkwYTEzNDYzYWE0YjQ5MzYxZDdjNGZmMWJmZmU5NzdkMDNl
|
15
|
+
NGI1YjQ5YWIxMDZmYWNlMzFhYjdjZGY4ZGM0MTBjZDQwYzMyNmI=
|
data/Rakefile
CHANGED
@@ -36,7 +36,7 @@ Jeweler::Tasks.new do |gem|
|
|
36
36
|
gem.description = 'Port of java functional library totallylazy to ruby'
|
37
37
|
gem.email = 'rbarlow@raymanoz.com'
|
38
38
|
gem.authors = ['Raymond Barlow', 'Kingsley Hendrickse']
|
39
|
-
gem.required_ruby_version = '2.0.0'
|
39
|
+
gem.required_ruby_version = '>= 2.0.0'
|
40
40
|
end
|
41
41
|
Jeweler::RubygemsDotOrgTasks.new
|
42
42
|
|
data/lib/totally_lazy.rb
CHANGED
@@ -1,19 +1,19 @@
|
|
1
|
-
require_relative 'comparators'
|
2
|
-
require_relative 'enumerators'
|
3
|
-
require_relative 'functions'
|
4
|
-
require_relative 'numbers'
|
5
|
-
require_relative 'option'
|
6
|
-
require_relative 'pair'
|
7
|
-
require_relative 'predicates'
|
8
|
-
require_relative 'sequence'
|
9
|
-
require_relative 'strings'
|
1
|
+
require_relative 'totally_lazy/comparators'
|
2
|
+
require_relative 'totally_lazy/enumerators'
|
3
|
+
require_relative 'totally_lazy/functions'
|
4
|
+
require_relative 'totally_lazy/numbers'
|
5
|
+
require_relative 'totally_lazy/option'
|
6
|
+
require_relative 'totally_lazy/pair'
|
7
|
+
require_relative 'totally_lazy/predicates'
|
8
|
+
require_relative 'totally_lazy/sequence'
|
9
|
+
require_relative 'totally_lazy/strings'
|
10
10
|
|
11
11
|
include Comparators
|
12
12
|
include Enumerators
|
13
13
|
include Functions
|
14
14
|
include Numbers
|
15
|
-
include
|
16
|
-
include
|
15
|
+
include Options
|
16
|
+
include Pairs
|
17
17
|
include Predicates
|
18
18
|
include Sequences
|
19
19
|
include Strings
|
@@ -1,5 +1,6 @@
|
|
1
1
|
module Enumerators
|
2
|
-
|
2
|
+
private
|
3
|
+
def reverse_enumerator(e)
|
3
4
|
e.reverse_each
|
4
5
|
end
|
5
6
|
|
@@ -12,7 +13,7 @@ module Enumerators
|
|
12
13
|
end
|
13
14
|
end
|
14
15
|
|
15
|
-
def
|
16
|
+
def enumerator_of(fn, init)
|
16
17
|
Enumerator.new do |y|
|
17
18
|
value = init
|
18
19
|
y << value
|
@@ -23,10 +24,6 @@ module Enumerators
|
|
23
24
|
end.lazy
|
24
25
|
end
|
25
26
|
|
26
|
-
def repeat_enumerator(value)
|
27
|
-
Enumerators.repeat_fn_enumerator(returns(value))
|
28
|
-
end
|
29
|
-
|
30
27
|
def repeat_fn_enumerator(fn)
|
31
28
|
Enumerator.new do |y|
|
32
29
|
loop do
|
@@ -35,6 +32,10 @@ module Enumerators
|
|
35
32
|
end.lazy
|
36
33
|
end
|
37
34
|
|
35
|
+
def repeat_enumerator(value)
|
36
|
+
repeat_fn_enumerator(returns(value))
|
37
|
+
end
|
38
|
+
|
38
39
|
def character_enumerator(string)
|
39
40
|
Enumerator.new do |y|
|
40
41
|
index = 0
|
@@ -1,19 +1,8 @@
|
|
1
1
|
require 'concurrent/executors'
|
2
2
|
require 'concurrent/promise'
|
3
3
|
|
4
|
-
class Proc
|
5
|
-
def optional
|
6
|
-
->(value) {
|
7
|
-
begin
|
8
|
-
option(self.(value))
|
9
|
-
rescue
|
10
|
-
none
|
11
|
-
end
|
12
|
-
}
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
4
|
module Functions
|
5
|
+
private
|
17
6
|
def monoid(fn, id)
|
18
7
|
fn.define_singleton_method(:identity) do
|
19
8
|
id
|
@@ -45,6 +34,8 @@ module Functions
|
|
45
34
|
-> { raise e }
|
46
35
|
end
|
47
36
|
|
37
|
+
alias call_throws call_raises
|
38
|
+
|
48
39
|
def call
|
49
40
|
->(fn) { fn.() }
|
50
41
|
end
|
File without changes
|
@@ -1,4 +1,5 @@
|
|
1
1
|
module Numbers
|
2
|
+
private
|
2
3
|
def sum
|
3
4
|
monoid(->(a, b) { a + b }, 0)
|
4
5
|
end
|
@@ -28,7 +29,7 @@ module Numbers
|
|
28
29
|
end
|
29
30
|
|
30
31
|
def range_from(start)
|
31
|
-
Sequence.new(
|
32
|
+
Sequence.new(enumerator_of(increment, start))
|
32
33
|
end
|
33
34
|
|
34
35
|
def range(from, to)
|
@@ -0,0 +1,191 @@
|
|
1
|
+
require_relative 'lambda_block'
|
2
|
+
|
3
|
+
class Proc
|
4
|
+
def optional
|
5
|
+
->(value) {
|
6
|
+
begin
|
7
|
+
Option.option(self.(value))
|
8
|
+
rescue
|
9
|
+
Option.none
|
10
|
+
end
|
11
|
+
}
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
module Options
|
16
|
+
private
|
17
|
+
def option(value)
|
18
|
+
Option.option(value)
|
19
|
+
end
|
20
|
+
|
21
|
+
def some(value)
|
22
|
+
Option.some(value)
|
23
|
+
end
|
24
|
+
|
25
|
+
def none
|
26
|
+
Option.none
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
class Option
|
31
|
+
def self.option(value)
|
32
|
+
value.nil? ? none : some(value)
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.some(value)
|
36
|
+
Some.new(value)
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.none
|
40
|
+
NONE
|
41
|
+
end
|
42
|
+
|
43
|
+
def is_defined?
|
44
|
+
!is_empty?
|
45
|
+
end
|
46
|
+
|
47
|
+
def is?(fn_pred=nil, &block_pred)
|
48
|
+
assert_funcs(fn_pred, block_given?)
|
49
|
+
exists?(block_given? ? ->(value) { block_pred.call(value) } : fn_pred)
|
50
|
+
end
|
51
|
+
|
52
|
+
def flatten
|
53
|
+
flat_map(identity)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
class Some < Option
|
58
|
+
include Comparable
|
59
|
+
include LambdaBlock
|
60
|
+
|
61
|
+
attr_reader :value
|
62
|
+
|
63
|
+
def initialize(value)
|
64
|
+
@value = value
|
65
|
+
end
|
66
|
+
|
67
|
+
def contains?(value)
|
68
|
+
@value == value
|
69
|
+
end
|
70
|
+
|
71
|
+
def exists?(fn_pred=nil, &block_pred)
|
72
|
+
assert_funcs(fn_pred, block_given?)
|
73
|
+
block_given? ? block_pred.call(@value) : fn_pred.(@value)
|
74
|
+
end
|
75
|
+
|
76
|
+
def map(fn=nil, &block)
|
77
|
+
assert_funcs(fn, block_given?)
|
78
|
+
option(block_given? ? block.call(@value) : fn.(@value))
|
79
|
+
end
|
80
|
+
|
81
|
+
def flat_map(fn=nil, &block) # function should return an option
|
82
|
+
assert_funcs(fn, block_given?)
|
83
|
+
block_given? ? block.call(@value) : fn.(@value)
|
84
|
+
end
|
85
|
+
|
86
|
+
def fold(seed, fn=nil, &block)
|
87
|
+
assert_funcs(fn, block_given?)
|
88
|
+
block_given? ? block.call(seed, @value) : fn.(seed, @value)
|
89
|
+
end
|
90
|
+
|
91
|
+
alias fold_left fold
|
92
|
+
|
93
|
+
def is_empty?
|
94
|
+
false
|
95
|
+
end
|
96
|
+
|
97
|
+
def size
|
98
|
+
1
|
99
|
+
end
|
100
|
+
|
101
|
+
def get
|
102
|
+
@value
|
103
|
+
end
|
104
|
+
|
105
|
+
def get_or_else(value_or_fn=nil, &block)
|
106
|
+
assert_funcs(value_or_fn, block_given?)
|
107
|
+
get
|
108
|
+
end
|
109
|
+
|
110
|
+
alias or_else get_or_else
|
111
|
+
|
112
|
+
def enumerator
|
113
|
+
Enumerator.new { |y|
|
114
|
+
y << @value
|
115
|
+
raise StopIteration.new
|
116
|
+
}
|
117
|
+
end
|
118
|
+
|
119
|
+
def <=>(other)
|
120
|
+
@value <=> other.value
|
121
|
+
end
|
122
|
+
|
123
|
+
def to_s
|
124
|
+
"Some(#{value})"
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
class None < Option
|
129
|
+
include LambdaBlock
|
130
|
+
|
131
|
+
def is_empty?
|
132
|
+
true
|
133
|
+
end
|
134
|
+
|
135
|
+
def contains?(value)
|
136
|
+
false
|
137
|
+
end
|
138
|
+
|
139
|
+
def exists?(fn_pred=nil, &block_pred)
|
140
|
+
assert_funcs(fn_pred, block_given?)
|
141
|
+
false
|
142
|
+
end
|
143
|
+
|
144
|
+
def map(fn=nil, &block)
|
145
|
+
assert_funcs(fn, block_given?)
|
146
|
+
none
|
147
|
+
end
|
148
|
+
|
149
|
+
def flat_map(fn=nil, &block) # function should return an option
|
150
|
+
assert_funcs(fn, block_given?)
|
151
|
+
none
|
152
|
+
end
|
153
|
+
|
154
|
+
def fold(seed, fn=nil &block)
|
155
|
+
assert_funcs(fn, block_given?)
|
156
|
+
seed
|
157
|
+
end
|
158
|
+
|
159
|
+
alias fold_left fold
|
160
|
+
|
161
|
+
def size
|
162
|
+
0
|
163
|
+
end
|
164
|
+
|
165
|
+
def get
|
166
|
+
raise NoSuchElementException.new
|
167
|
+
end
|
168
|
+
|
169
|
+
def get_or_else(value_or_fn=nil, &block)
|
170
|
+
assert_funcs(value_or_fn, block_given?)
|
171
|
+
if (value_or_fn.respond_to? :call) || block_given?
|
172
|
+
block_given? ? block.call : value_or_fn.()
|
173
|
+
else
|
174
|
+
value_or_fn
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
alias or_else get_or_else
|
179
|
+
|
180
|
+
def enumerator
|
181
|
+
Enumerator.new { |y|
|
182
|
+
raise StopIteration.new
|
183
|
+
}
|
184
|
+
end
|
185
|
+
|
186
|
+
def to_s
|
187
|
+
'None'
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
NONE=None.new
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module Pairs
|
2
|
+
private
|
3
|
+
def pair(first, second)
|
4
|
+
Pair.new(first, second)
|
5
|
+
end
|
6
|
+
end
|
7
|
+
|
8
|
+
class Pair
|
9
|
+
include Comparable
|
10
|
+
|
11
|
+
def initialize(first, second)
|
12
|
+
@first = -> { first }
|
13
|
+
@second = -> { second }
|
14
|
+
end
|
15
|
+
|
16
|
+
def first
|
17
|
+
@first.()
|
18
|
+
end
|
19
|
+
|
20
|
+
def second
|
21
|
+
@second.()
|
22
|
+
end
|
23
|
+
|
24
|
+
def enumerator
|
25
|
+
Enumerator.new { |y|
|
26
|
+
y << first
|
27
|
+
y << second
|
28
|
+
raise StopIteration.new
|
29
|
+
}
|
30
|
+
end
|
31
|
+
|
32
|
+
def <=>(other)
|
33
|
+
(first <=> other.first) <=> (second <=> other.second)
|
34
|
+
end
|
35
|
+
|
36
|
+
def to_s
|
37
|
+
"(#{first}, #{second})"
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,327 @@
|
|
1
|
+
require_relative 'lambda_block'
|
2
|
+
|
3
|
+
class NoSuchElementException < RuntimeError
|
4
|
+
end
|
5
|
+
|
6
|
+
module Sequences
|
7
|
+
def empty
|
8
|
+
Sequence.empty
|
9
|
+
end
|
10
|
+
|
11
|
+
def sequence(*items)
|
12
|
+
Sequence.sequence(*items)
|
13
|
+
end
|
14
|
+
|
15
|
+
def drop(sequence, count)
|
16
|
+
Sequence.drop(sequence, count)
|
17
|
+
end
|
18
|
+
|
19
|
+
def sort(sequence, comparator=ascending)
|
20
|
+
Sequence.sort(sequence, comparator)
|
21
|
+
end
|
22
|
+
|
23
|
+
def map_concurrently(sequence, fn=nil, &block)
|
24
|
+
Sequence.map_concurrently(sequence, block_given? ? ->(value) { block.call(value) } : fn)
|
25
|
+
end
|
26
|
+
|
27
|
+
def group(key, enumerator)
|
28
|
+
Group.new(key, enumerator)
|
29
|
+
end
|
30
|
+
|
31
|
+
def repeat(item)
|
32
|
+
Sequence.new(repeat_enumerator(item))
|
33
|
+
end
|
34
|
+
|
35
|
+
def repeat_fn(item)
|
36
|
+
Sequence.new(repeat_fn_enumerator(item))
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def pair_enumerator(left, right)
|
42
|
+
Enumerator.new do |y|
|
43
|
+
left.rewind
|
44
|
+
right.rewind
|
45
|
+
loop do
|
46
|
+
y << pair(left.next, right.next)
|
47
|
+
end
|
48
|
+
end.lazy
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
class Sequence
|
53
|
+
include Comparable
|
54
|
+
include LambdaBlock
|
55
|
+
|
56
|
+
attr_reader :enumerator
|
57
|
+
|
58
|
+
def self.map_concurrently(sequence, fn=nil, &block)
|
59
|
+
call_concurrently(sequence.map(defer_return(block_given? ? ->(value) { block.call(value) } : fn)))
|
60
|
+
end
|
61
|
+
|
62
|
+
def self.sort(sequence, comparator=ascending)
|
63
|
+
Sequence.new(sequence.enumerator.sort { |a, b| comparator.(a, b) }.lazy)
|
64
|
+
end
|
65
|
+
|
66
|
+
def self.drop(sequence, count)
|
67
|
+
Sequence.new(sequence.enumerator.drop(count))
|
68
|
+
end
|
69
|
+
|
70
|
+
def self.repeat(item)
|
71
|
+
Sequence.new(repeat_enumerator(item))
|
72
|
+
end
|
73
|
+
|
74
|
+
def self.repeat_fn(item)
|
75
|
+
Sequence.new(repeat_fn_enumerator(item))
|
76
|
+
end
|
77
|
+
|
78
|
+
def self.take(sequence, count)
|
79
|
+
Sequence.new(sequence.enumerator.take(count))
|
80
|
+
end
|
81
|
+
|
82
|
+
def self.zip(left, right)
|
83
|
+
left.zip(right)
|
84
|
+
end
|
85
|
+
|
86
|
+
|
87
|
+
def self.sequence(*items)
|
88
|
+
if items.first.nil?
|
89
|
+
empty
|
90
|
+
else
|
91
|
+
Sequence.new(items.lazy)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def self.empty
|
96
|
+
EMPTY
|
97
|
+
end
|
98
|
+
|
99
|
+
def initialize(enumerator)
|
100
|
+
raise "Sequence only accepts Enumerator::Lazy, not #{enumerator.class}" unless (enumerator.class == Enumerator::Lazy)
|
101
|
+
@enumerator = enumerator
|
102
|
+
end
|
103
|
+
|
104
|
+
def is_empty?
|
105
|
+
@enumerator.rewind
|
106
|
+
begin
|
107
|
+
@enumerator.peek
|
108
|
+
false
|
109
|
+
rescue
|
110
|
+
true
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
def size
|
115
|
+
@enumerator.count
|
116
|
+
end
|
117
|
+
|
118
|
+
def head
|
119
|
+
@enumerator.first
|
120
|
+
end
|
121
|
+
|
122
|
+
alias first head
|
123
|
+
|
124
|
+
def second
|
125
|
+
tail.head
|
126
|
+
end
|
127
|
+
|
128
|
+
def head_option
|
129
|
+
option(head)
|
130
|
+
end
|
131
|
+
|
132
|
+
def last
|
133
|
+
reverse.head
|
134
|
+
end
|
135
|
+
|
136
|
+
def last_option
|
137
|
+
reverse.head_option
|
138
|
+
end
|
139
|
+
|
140
|
+
def reverse
|
141
|
+
Sequence.new(reverse_enumerator(@enumerator))
|
142
|
+
end
|
143
|
+
|
144
|
+
def tail
|
145
|
+
unless has_next(@enumerator)
|
146
|
+
raise NoSuchElementException.new
|
147
|
+
end
|
148
|
+
Sequence.new(@enumerator.drop(1))
|
149
|
+
end
|
150
|
+
|
151
|
+
def init
|
152
|
+
reverse.tail.reverse
|
153
|
+
end
|
154
|
+
|
155
|
+
def map(fn=nil, &block)
|
156
|
+
assert_funcs(fn, block_given?)
|
157
|
+
Sequence.new(@enumerator.map { |value|
|
158
|
+
block_given? ? block.call(value) : fn.(value)
|
159
|
+
})
|
160
|
+
end
|
161
|
+
|
162
|
+
def fold(seed, fn=nil, &block)
|
163
|
+
assert_funcs(fn, block_given?)
|
164
|
+
@enumerator.inject(seed) { |accumulator, value|
|
165
|
+
block_given? ? block.call(accumulator, value) : fn.(accumulator, value)
|
166
|
+
}
|
167
|
+
end
|
168
|
+
|
169
|
+
alias fold_left fold
|
170
|
+
|
171
|
+
def fold_right(seed, fn=nil, &block)
|
172
|
+
assert_funcs(fn, block_given?)
|
173
|
+
reverse_enumerator(@enumerator).inject(seed) { |accumulator, value|
|
174
|
+
block_given? ? block.call(value, accumulator) : fn.(value, accumulator)
|
175
|
+
}
|
176
|
+
end
|
177
|
+
|
178
|
+
def reduce(fn=nil, &block)
|
179
|
+
assert_funcs(fn, block_given?)
|
180
|
+
_fn = block_given? ? ->(a, b) { block.call(a, b) } : fn
|
181
|
+
accumulator = seed(@enumerator, fn)
|
182
|
+
while has_next(@enumerator)
|
183
|
+
accumulator = _fn.(accumulator, @enumerator.next)
|
184
|
+
end
|
185
|
+
accumulator
|
186
|
+
end
|
187
|
+
|
188
|
+
alias reduce_left reduce
|
189
|
+
|
190
|
+
def reduce_right(fn=nil, &block)
|
191
|
+
assert_funcs(fn, block_given?)
|
192
|
+
_fn = block_given? ? ->(a, b) { block.call(a, b) } : fn
|
193
|
+
reversed = reverse_enumerator(@enumerator)
|
194
|
+
accumulator = seed(reversed, fn)
|
195
|
+
while has_next(reversed)
|
196
|
+
accumulator = _fn.(reversed.next, accumulator)
|
197
|
+
end
|
198
|
+
accumulator
|
199
|
+
end
|
200
|
+
|
201
|
+
def find(fn_pred=nil, &block_pred)
|
202
|
+
assert_funcs(fn_pred, block_given?)
|
203
|
+
@enumerator.rewind
|
204
|
+
while has_next(@enumerator)
|
205
|
+
item = @enumerator.next
|
206
|
+
result = block_given? ? block_pred.call(item) : fn_pred.(item)
|
207
|
+
if result
|
208
|
+
return(some(item))
|
209
|
+
end
|
210
|
+
end
|
211
|
+
none
|
212
|
+
end
|
213
|
+
|
214
|
+
def zip(other)
|
215
|
+
Sequence.new(pair_enumerator(@enumerator, other.enumerator))
|
216
|
+
end
|
217
|
+
|
218
|
+
def zip_with_index
|
219
|
+
Sequence.zip(range_from(0), self)
|
220
|
+
end
|
221
|
+
|
222
|
+
def find_index_of(fn_pred=nil, &block_pred)
|
223
|
+
assert_funcs(fn_pred, block_given?)
|
224
|
+
zip_with_index.find(->(pair) { block_given? ? block_pred.call(pair.second) : fn_pred.(pair.second) }).map(->(pair) { pair.first })
|
225
|
+
end
|
226
|
+
|
227
|
+
def take(count)
|
228
|
+
Sequence.take(self, count)
|
229
|
+
end
|
230
|
+
|
231
|
+
def take_while(fn_pred=nil, &block_pred)
|
232
|
+
assert_funcs(fn_pred, block_given?)
|
233
|
+
Sequence.new(@enumerator.take_while { |value| block_given? ? block_pred.call(value) : fn_pred.(value) })
|
234
|
+
end
|
235
|
+
|
236
|
+
def drop(count)
|
237
|
+
Sequence.drop(self, count)
|
238
|
+
end
|
239
|
+
|
240
|
+
def drop_while(fn_pred=nil, &block_pred)
|
241
|
+
assert_funcs(fn_pred, block_given?)
|
242
|
+
Sequence.new(@enumerator.drop_while { |value| block_given? ? block_pred.call(value) : fn_pred.(value) })
|
243
|
+
end
|
244
|
+
|
245
|
+
def flat_map(fn=nil, &block)
|
246
|
+
assert_funcs(fn, block_given?)
|
247
|
+
map(block_given? ? ->(value) { block.call(value) } : fn).flatten
|
248
|
+
end
|
249
|
+
|
250
|
+
def flatten
|
251
|
+
Sequence.new(flatten_enumerator(enumerator))
|
252
|
+
end
|
253
|
+
|
254
|
+
def sort_by(comparator)
|
255
|
+
Sequence.sort(self, comparator)
|
256
|
+
end
|
257
|
+
|
258
|
+
def contains?(value)
|
259
|
+
@enumerator.member?(value)
|
260
|
+
end
|
261
|
+
|
262
|
+
def exists?(fn_pred=nil, &block_pred)
|
263
|
+
assert_funcs(fn_pred, block_given?)
|
264
|
+
@enumerator.any? { |value| block_given? ? block_pred.call(value) : fn_pred.(value) }
|
265
|
+
end
|
266
|
+
|
267
|
+
def for_all?(fn_pred=nil, &block_pred)
|
268
|
+
assert_funcs(fn_pred, block_given?)
|
269
|
+
@enumerator.all? { |value| block_given? ? block_pred.call(value) : fn_pred.(value) }
|
270
|
+
end
|
271
|
+
|
272
|
+
def filter(fn_pred=nil, &block_pred)
|
273
|
+
assert_funcs(fn_pred, block_given?)
|
274
|
+
Sequence.new(@enumerator.select { |value| block_given? ? block_pred.call(value) : fn_pred.(value) })
|
275
|
+
end
|
276
|
+
|
277
|
+
def reject(fn_pred=nil, &block_pred)
|
278
|
+
assert_funcs(fn_pred, block_given?)
|
279
|
+
filter(_not(block_given? ? ->(value) { block_pred.call(value) } : fn_pred))
|
280
|
+
end
|
281
|
+
|
282
|
+
def group_by(fn=nil, &block)
|
283
|
+
assert_funcs(fn, block_given?)
|
284
|
+
groups = @enumerator.group_by { |value| block_given? ? block.call(value) : fn.(value) }
|
285
|
+
Sequence.new(groups.to_a.map { |group| Group.new(group[0], group[1].lazy) }.lazy)
|
286
|
+
end
|
287
|
+
|
288
|
+
def each(fn=nil, &block)
|
289
|
+
assert_funcs(fn, block_given?)
|
290
|
+
@enumerator.each { |value| block_given? ? block.call(value) : fn.(value) }
|
291
|
+
end
|
292
|
+
|
293
|
+
def map_concurrently(fn=nil, &block)
|
294
|
+
assert_funcs(fn, block_given?)
|
295
|
+
Sequence.map_concurrently(self, block_given? ? ->(value) { block.call(value) } : fn)
|
296
|
+
end
|
297
|
+
|
298
|
+
def realise
|
299
|
+
Sequence.new(@enumerator.to_a.lazy)
|
300
|
+
end
|
301
|
+
|
302
|
+
def <=>(other)
|
303
|
+
@enumerator.entries <=> other.enumerator.entries
|
304
|
+
end
|
305
|
+
|
306
|
+
private
|
307
|
+
def seed(enumerator, fn)
|
308
|
+
enumerator.rewind
|
309
|
+
!fn.nil? && fn.respond_to?(:identity) ? fn.identity : enumerator.next
|
310
|
+
end
|
311
|
+
end
|
312
|
+
|
313
|
+
class Group < Sequence
|
314
|
+
include Comparable
|
315
|
+
attr_reader :key
|
316
|
+
|
317
|
+
def initialize(key, enumerator)
|
318
|
+
super(enumerator)
|
319
|
+
@key = key
|
320
|
+
end
|
321
|
+
|
322
|
+
def <=>(other)
|
323
|
+
(@key <=> other.key) <=> (enumerator.entries<=>(other.enumerator.entries))
|
324
|
+
end
|
325
|
+
end
|
326
|
+
|
327
|
+
EMPTY=Sequence.new([].lazy)
|
data/spec/option_spec.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require_relative 'spec_helper'
|
2
2
|
|
3
3
|
describe 'Option' do
|
4
|
+
|
4
5
|
it 'should support is_empty? & is_defined?' do
|
5
6
|
expect(some(1).is_empty?).to eq(false)
|
6
7
|
expect(some(1).is_defined?).to eq(true)
|
@@ -46,7 +47,7 @@ describe 'Option' do
|
|
46
47
|
|
47
48
|
it 'should support flat_map' do
|
48
49
|
expect(some(4).flat_map(divide(2).optional)).to eq(some(2))
|
49
|
-
expect(some(4).flat_map{ |v| divide(2).optional.(v) }).to eq(some(2))
|
50
|
+
expect(some(4).flat_map { |v| divide(2).optional.(v) }).to eq(some(2))
|
50
51
|
expect(some(4).flat_map(divide(0).optional)).to eq(none)
|
51
52
|
expect(none.flat_map(constant(none))).to eq(none)
|
52
53
|
expect(none.flat_map(some(4))).to eq(none)
|
@@ -65,16 +66,26 @@ describe 'Option' do
|
|
65
66
|
|
66
67
|
it 'should support get' do
|
67
68
|
expect(some(1).get).to eq(1)
|
68
|
-
expect{none.get}.to raise_error(NoSuchElementException)
|
69
|
+
expect { none.get }.to raise_error(NoSuchElementException)
|
69
70
|
end
|
70
71
|
|
71
|
-
it 'should support get_or_else (aka or_else)' do
|
72
|
-
expect(some(1).get_or_else(2)).to eq(1)
|
72
|
+
it 'should support get_or_else with value (aka or_else)' do
|
73
|
+
expect(Option::some(1).get_or_else(2)).to eq(1)
|
74
|
+
expect(some(1).or_else(2)).to eq(1)
|
73
75
|
expect(none.get_or_else(2)).to eq(2)
|
74
76
|
expect(option(1).get_or_else(2)).to eq(1)
|
75
77
|
expect(option(nil).get_or_else(2)).to eq(2)
|
76
78
|
end
|
77
79
|
|
80
|
+
it 'should support get_or_else with a function' do
|
81
|
+
expect(some(1).get_or_else(returns(2))).to eq(1)
|
82
|
+
expect(some(1).get_or_else { 2 }).to eq(1)
|
83
|
+
expect(none.get_or_else(returns(2))).to eq(2)
|
84
|
+
expect(option(1).get_or_else(returns(2))).to eq(1)
|
85
|
+
expect(option(nil).get_or_else(returns(2))).to eq(2)
|
86
|
+
expect { option(nil).get_or_else(call_raises(RuntimeError.new)) }.to raise_error(RuntimeError)
|
87
|
+
end
|
88
|
+
|
78
89
|
it 'should raise exception if you try to use both lambda and block' do
|
79
90
|
expect { some(1).exists?(->(a) { a == 1 }) { |b| b == 2 } }.to raise_error(RuntimeError)
|
80
91
|
expect { none.exists?(->(a) { a == 1 }) { |b| b == 2 } }.to raise_error(RuntimeError)
|
@@ -86,7 +97,8 @@ describe 'Option' do
|
|
86
97
|
expect { none.fold_left(0, ->(a, b) { a+b }) { |a, b| a+b } }.to raise_error(RuntimeError)
|
87
98
|
expect { some(1).map(->(v) { v.to_s }) { |v| v.to_s } }.to raise_error(RuntimeError)
|
88
99
|
expect { none.map(->(v) { v.to_s }) { |v| v.to_s } }.to raise_error(RuntimeError)
|
89
|
-
expect { some(4).flat_map(divide(2).optional){ |v| divide(2).optional.(v) } }.to raise_error(RuntimeError)
|
100
|
+
expect { some(4).flat_map(divide(2).optional) { |v| divide(2).optional.(v) } }.to raise_error(RuntimeError)
|
101
|
+
expect { some(1).get_or_else(returns(2)) { |value| 3 } }.to raise_error(RuntimeError)
|
90
102
|
end
|
91
103
|
|
92
104
|
end
|
data/spec/sequence_spec.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require_relative 'spec_helper'
|
2
2
|
|
3
3
|
describe 'Sequence' do
|
4
|
+
|
4
5
|
it 'should create empty sequence when iterable is nil' do
|
5
6
|
expect(sequence(nil)).to eq(empty)
|
6
7
|
end
|
@@ -78,7 +79,7 @@ describe 'Sequence' do
|
|
78
79
|
end
|
79
80
|
|
80
81
|
it 'should support composite predicates' do
|
81
|
-
expect(sequence(1, 2, 3, 4).filter(
|
82
|
+
expect(sequence(1, 2, 3, 4).filter(_not(even))).to eq(sequence(1, 3))
|
82
83
|
end
|
83
84
|
|
84
85
|
it 'should support reject' do
|
@@ -187,8 +188,8 @@ describe 'Sequence' do
|
|
187
188
|
end
|
188
189
|
|
189
190
|
it 'should support repeat' do
|
190
|
-
expect(
|
191
|
-
expect(
|
191
|
+
expect(repeat(10).take(5)).to eq(sequence(10, 10, 10, 10, 10))
|
192
|
+
expect(repeat_fn(returns(20)).take(5)).to eq(sequence(20, 20, 20, 20, 20))
|
192
193
|
end
|
193
194
|
|
194
195
|
it 'should support is_empty?' do
|
data/spec/spec_helper.rb
CHANGED
@@ -2,7 +2,7 @@ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
|
2
2
|
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
3
3
|
|
4
4
|
require 'rspec'
|
5
|
-
|
5
|
+
require_relative '../lib/totally_lazy'
|
6
6
|
|
7
7
|
# Requires supporting files with custom matchers and macros, etc,
|
8
8
|
# in ./support/ and its subdirectories.
|
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.1.
|
4
|
+
version: 0.1.23
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Raymond Barlow
|
@@ -154,17 +154,17 @@ files:
|
|
154
154
|
- Rakefile
|
155
155
|
- VERSION
|
156
156
|
- contributors.txt
|
157
|
-
- lib/comparators.rb
|
158
|
-
- lib/enumerators.rb
|
159
|
-
- lib/functions.rb
|
160
|
-
- lib/lambda_block.rb
|
161
|
-
- lib/numbers.rb
|
162
|
-
- lib/option.rb
|
163
|
-
- lib/pair.rb
|
164
|
-
- lib/predicates.rb
|
165
|
-
- lib/sequence.rb
|
166
|
-
- lib/strings.rb
|
167
157
|
- lib/totally_lazy.rb
|
158
|
+
- lib/totally_lazy/comparators.rb
|
159
|
+
- lib/totally_lazy/enumerators.rb
|
160
|
+
- lib/totally_lazy/functions.rb
|
161
|
+
- lib/totally_lazy/lambda_block.rb
|
162
|
+
- lib/totally_lazy/numbers.rb
|
163
|
+
- lib/totally_lazy/option.rb
|
164
|
+
- lib/totally_lazy/pair.rb
|
165
|
+
- lib/totally_lazy/predicates.rb
|
166
|
+
- lib/totally_lazy/sequence.rb
|
167
|
+
- lib/totally_lazy/strings.rb
|
168
168
|
- readme.md
|
169
169
|
- spec/option_spec.rb
|
170
170
|
- spec/sequence_spec.rb
|
@@ -180,7 +180,7 @@ require_paths:
|
|
180
180
|
- lib
|
181
181
|
required_ruby_version: !ruby/object:Gem::Requirement
|
182
182
|
requirements:
|
183
|
-
- - '
|
183
|
+
- - ! '>='
|
184
184
|
- !ruby/object:Gem::Version
|
185
185
|
version: 2.0.0
|
186
186
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
data/lib/option.rb
DELETED
@@ -1,156 +0,0 @@
|
|
1
|
-
require_relative 'lambda_block'
|
2
|
-
|
3
|
-
module Option
|
4
|
-
include LambdaBlock
|
5
|
-
|
6
|
-
def option(value)
|
7
|
-
value.nil? ? none : some(value)
|
8
|
-
end
|
9
|
-
|
10
|
-
def some(value)
|
11
|
-
Some.new(value)
|
12
|
-
end
|
13
|
-
|
14
|
-
def none
|
15
|
-
NONE
|
16
|
-
end
|
17
|
-
|
18
|
-
class Option
|
19
|
-
def is_defined?
|
20
|
-
!is_empty?
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
def is?(fn_pred=nil, &block_pred)
|
25
|
-
assert_funcs(fn_pred, block_given?)
|
26
|
-
exists?(block_given? ? ->(value) { block_pred.call(value) } : fn_pred)
|
27
|
-
end
|
28
|
-
|
29
|
-
def flatten
|
30
|
-
flat_map(identity)
|
31
|
-
end
|
32
|
-
|
33
|
-
class Some < Option
|
34
|
-
include Comparable
|
35
|
-
attr_reader :value
|
36
|
-
|
37
|
-
def initialize(value)
|
38
|
-
@value = value
|
39
|
-
end
|
40
|
-
|
41
|
-
def contains?(value)
|
42
|
-
@value == value
|
43
|
-
end
|
44
|
-
|
45
|
-
def exists?(fn_pred=nil, &block_pred)
|
46
|
-
assert_funcs(fn_pred, block_given?)
|
47
|
-
block_given? ? block_pred.call(@value) : fn_pred.(@value)
|
48
|
-
end
|
49
|
-
|
50
|
-
def map(fn=nil, &block)
|
51
|
-
assert_funcs(fn, block_given?)
|
52
|
-
option(block_given? ? block.call(@value) : fn.(@value))
|
53
|
-
end
|
54
|
-
|
55
|
-
def flat_map(fn=nil, &block) # function should return an option
|
56
|
-
assert_funcs(fn, block_given?)
|
57
|
-
block_given? ? block.call(@value) : fn.(@value)
|
58
|
-
end
|
59
|
-
|
60
|
-
def fold(seed, fn=nil, &block)
|
61
|
-
assert_funcs(fn, block_given?)
|
62
|
-
block_given? ? block.call(seed, @value) : fn.(seed, @value)
|
63
|
-
end
|
64
|
-
|
65
|
-
alias fold_left fold
|
66
|
-
|
67
|
-
def is_empty?
|
68
|
-
false
|
69
|
-
end
|
70
|
-
|
71
|
-
def size
|
72
|
-
1
|
73
|
-
end
|
74
|
-
|
75
|
-
def get
|
76
|
-
@value
|
77
|
-
end
|
78
|
-
|
79
|
-
def get_or_else(value)
|
80
|
-
get
|
81
|
-
end
|
82
|
-
|
83
|
-
def enumerator
|
84
|
-
Enumerator.new { |y|
|
85
|
-
y << @value
|
86
|
-
raise StopIteration.new
|
87
|
-
}
|
88
|
-
end
|
89
|
-
|
90
|
-
def <=>(other)
|
91
|
-
@value <=> other.value
|
92
|
-
end
|
93
|
-
|
94
|
-
def to_s
|
95
|
-
"Some(#{value})"
|
96
|
-
end
|
97
|
-
end
|
98
|
-
|
99
|
-
class None < Option
|
100
|
-
def is_empty?
|
101
|
-
true
|
102
|
-
end
|
103
|
-
|
104
|
-
def contains?(value)
|
105
|
-
false
|
106
|
-
end
|
107
|
-
|
108
|
-
def exists?(fn_pred=nil, &block_pred)
|
109
|
-
assert_funcs(fn_pred, block_given?)
|
110
|
-
false
|
111
|
-
end
|
112
|
-
|
113
|
-
def map(fn=nil, &block)
|
114
|
-
assert_funcs(fn, block_given?)
|
115
|
-
none
|
116
|
-
end
|
117
|
-
|
118
|
-
def flat_map(fn=nil, &block) # function should return an option
|
119
|
-
assert_funcs(fn, block_given?)
|
120
|
-
none
|
121
|
-
end
|
122
|
-
|
123
|
-
def fold(seed, fn=nil &block)
|
124
|
-
assert_funcs(fn, block_given?)
|
125
|
-
seed
|
126
|
-
end
|
127
|
-
|
128
|
-
alias fold_left fold
|
129
|
-
|
130
|
-
def size
|
131
|
-
0
|
132
|
-
end
|
133
|
-
|
134
|
-
def get
|
135
|
-
raise NoSuchElementException.new
|
136
|
-
end
|
137
|
-
|
138
|
-
def get_or_else(value)
|
139
|
-
value
|
140
|
-
end
|
141
|
-
|
142
|
-
alias or_else get_or_else
|
143
|
-
|
144
|
-
def enumerator
|
145
|
-
Enumerator.new { |y|
|
146
|
-
raise StopIteration.new
|
147
|
-
}
|
148
|
-
end
|
149
|
-
|
150
|
-
def to_s
|
151
|
-
'None'
|
152
|
-
end
|
153
|
-
end
|
154
|
-
|
155
|
-
NONE=None.new
|
156
|
-
end
|
data/lib/pair.rb
DELETED
@@ -1,40 +0,0 @@
|
|
1
|
-
module Pair
|
2
|
-
|
3
|
-
def pair(first, second)
|
4
|
-
Pair.new(first, second)
|
5
|
-
end
|
6
|
-
|
7
|
-
class Pair
|
8
|
-
include Comparable
|
9
|
-
|
10
|
-
def initialize(first, second)
|
11
|
-
@first = -> { first }
|
12
|
-
@second = -> { second }
|
13
|
-
end
|
14
|
-
|
15
|
-
def first
|
16
|
-
@first.()
|
17
|
-
end
|
18
|
-
|
19
|
-
def second
|
20
|
-
@second.()
|
21
|
-
end
|
22
|
-
|
23
|
-
def enumerator
|
24
|
-
Enumerator.new { |y|
|
25
|
-
y << first
|
26
|
-
y << second
|
27
|
-
raise StopIteration.new
|
28
|
-
}
|
29
|
-
end
|
30
|
-
|
31
|
-
def <=>(other)
|
32
|
-
(first <=> other.first) <=> (second <=> other.second)
|
33
|
-
end
|
34
|
-
|
35
|
-
def to_s
|
36
|
-
"(#{first}, #{second})"
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
end
|
data/lib/sequence.rb
DELETED
@@ -1,298 +0,0 @@
|
|
1
|
-
require_relative 'lambda_block'
|
2
|
-
|
3
|
-
class NoSuchElementException < RuntimeError
|
4
|
-
end
|
5
|
-
|
6
|
-
module Sequences
|
7
|
-
def empty
|
8
|
-
EMPTY
|
9
|
-
end
|
10
|
-
|
11
|
-
def sequence(*items)
|
12
|
-
if items.first.nil?
|
13
|
-
empty
|
14
|
-
else
|
15
|
-
Sequence.new(items.lazy)
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
def zip(left, right)
|
20
|
-
left.zip(right)
|
21
|
-
end
|
22
|
-
|
23
|
-
def take(sequence, count)
|
24
|
-
Sequence.new(sequence.enumerator.take(count))
|
25
|
-
end
|
26
|
-
|
27
|
-
def drop(sequence, count)
|
28
|
-
Sequence.new(sequence.enumerator.drop(count))
|
29
|
-
end
|
30
|
-
|
31
|
-
def repeat(item)
|
32
|
-
Sequence.new(repeat_enumerator(item))
|
33
|
-
end
|
34
|
-
|
35
|
-
def repeat_fn(item)
|
36
|
-
Sequence.new(repeat_fn_enumerator(item))
|
37
|
-
end
|
38
|
-
|
39
|
-
def sort(sequence, comparator=ascending)
|
40
|
-
Sequence.new(sequence.enumerator.sort { |a, b| comparator.(a, b) }.lazy)
|
41
|
-
end
|
42
|
-
|
43
|
-
def map_concurrently(sequence, fn=nil, &block)
|
44
|
-
call_concurrently(sequence.map(defer_return(block_given? ? ->(value) { block.call(value) } : fn)))
|
45
|
-
end
|
46
|
-
|
47
|
-
# noinspection RubyTooManyMethodsInspection
|
48
|
-
class Sequence
|
49
|
-
include Comparable
|
50
|
-
include LambdaBlock
|
51
|
-
attr_reader :enumerator
|
52
|
-
|
53
|
-
def initialize(enumerator)
|
54
|
-
raise "Sequence only accepts Enumerator::Lazy, not #{enumerator.class}" unless (enumerator.class == Enumerator::Lazy)
|
55
|
-
@enumerator = enumerator
|
56
|
-
end
|
57
|
-
|
58
|
-
def is_empty?
|
59
|
-
@enumerator.rewind
|
60
|
-
begin
|
61
|
-
@enumerator.peek
|
62
|
-
false
|
63
|
-
rescue
|
64
|
-
true
|
65
|
-
end
|
66
|
-
end
|
67
|
-
|
68
|
-
def size
|
69
|
-
@enumerator.count
|
70
|
-
end
|
71
|
-
|
72
|
-
def head
|
73
|
-
@enumerator.first
|
74
|
-
end
|
75
|
-
|
76
|
-
alias first head
|
77
|
-
|
78
|
-
def second
|
79
|
-
tail.head
|
80
|
-
end
|
81
|
-
|
82
|
-
def head_option
|
83
|
-
option(head)
|
84
|
-
end
|
85
|
-
|
86
|
-
def last
|
87
|
-
reverse.head
|
88
|
-
end
|
89
|
-
|
90
|
-
def last_option
|
91
|
-
reverse.head_option
|
92
|
-
end
|
93
|
-
|
94
|
-
def reverse
|
95
|
-
Sequence.new(Enumerators::reverse(@enumerator))
|
96
|
-
end
|
97
|
-
|
98
|
-
def tail
|
99
|
-
unless has_next(@enumerator)
|
100
|
-
raise NoSuchElementException.new
|
101
|
-
end
|
102
|
-
Sequence.new(@enumerator.drop(1))
|
103
|
-
end
|
104
|
-
|
105
|
-
def init
|
106
|
-
reverse.tail.reverse
|
107
|
-
end
|
108
|
-
|
109
|
-
def map(fn=nil, &block)
|
110
|
-
assert_funcs(fn, block_given?)
|
111
|
-
Sequence.new(@enumerator.map { |value|
|
112
|
-
block_given? ? block.call(value) : fn.(value)
|
113
|
-
})
|
114
|
-
end
|
115
|
-
|
116
|
-
def fold(seed, fn=nil, &block)
|
117
|
-
assert_funcs(fn, block_given?)
|
118
|
-
@enumerator.inject(seed) { |accumulator, value|
|
119
|
-
block_given? ? block.call(accumulator, value) : fn.(accumulator, value)
|
120
|
-
}
|
121
|
-
end
|
122
|
-
|
123
|
-
alias fold_left fold
|
124
|
-
|
125
|
-
def fold_right(seed, fn=nil, &block)
|
126
|
-
assert_funcs(fn, block_given?)
|
127
|
-
Enumerators::reverse(@enumerator).inject(seed) { |accumulator, value|
|
128
|
-
block_given? ? block.call(value, accumulator) : fn.(value, accumulator)
|
129
|
-
}
|
130
|
-
end
|
131
|
-
|
132
|
-
def reduce(fn=nil, &block)
|
133
|
-
assert_funcs(fn, block_given?)
|
134
|
-
_fn = block_given? ? ->(a, b) { block.call(a, b) } : fn
|
135
|
-
accumulator = seed(@enumerator, fn)
|
136
|
-
while has_next(@enumerator)
|
137
|
-
accumulator = _fn.(accumulator, @enumerator.next)
|
138
|
-
end
|
139
|
-
accumulator
|
140
|
-
end
|
141
|
-
|
142
|
-
alias reduce_left reduce
|
143
|
-
|
144
|
-
def reduce_right(fn=nil, &block)
|
145
|
-
assert_funcs(fn, block_given?)
|
146
|
-
_fn = block_given? ? ->(a, b) { block.call(a, b) } : fn
|
147
|
-
reversed = Enumerators::reverse(@enumerator)
|
148
|
-
accumulator = seed(reversed, fn)
|
149
|
-
while has_next(reversed)
|
150
|
-
accumulator = _fn.(reversed.next, accumulator)
|
151
|
-
end
|
152
|
-
accumulator
|
153
|
-
end
|
154
|
-
|
155
|
-
def find(fn_pred=nil, &block_pred)
|
156
|
-
assert_funcs(fn_pred, block_given?)
|
157
|
-
@enumerator.rewind
|
158
|
-
while has_next(@enumerator)
|
159
|
-
item = @enumerator.next
|
160
|
-
result = block_given? ? block_pred.call(item) : fn_pred.(item)
|
161
|
-
if result
|
162
|
-
return(some(item))
|
163
|
-
end
|
164
|
-
end
|
165
|
-
none
|
166
|
-
end
|
167
|
-
|
168
|
-
def zip(other)
|
169
|
-
Sequence.new(pair_enumerator(@enumerator, other.enumerator))
|
170
|
-
end
|
171
|
-
|
172
|
-
def zip_with_index
|
173
|
-
Sequences.zip(range_from(0), self)
|
174
|
-
end
|
175
|
-
|
176
|
-
def find_index_of(fn_pred=nil, &block_pred)
|
177
|
-
assert_funcs(fn_pred, block_given?)
|
178
|
-
zip_with_index.find(->(pair) { block_given? ? block_pred.call(pair.second) : fn_pred.(pair.second) }).map(->(pair) { pair.first })
|
179
|
-
end
|
180
|
-
|
181
|
-
def take(count)
|
182
|
-
Sequences::take(self, count)
|
183
|
-
end
|
184
|
-
|
185
|
-
def take_while(fn_pred=nil, &block_pred)
|
186
|
-
assert_funcs(fn_pred, block_given?)
|
187
|
-
Sequence.new(@enumerator.take_while { |value| block_given? ? block_pred.call(value) : fn_pred.(value) })
|
188
|
-
end
|
189
|
-
|
190
|
-
def drop(count)
|
191
|
-
Sequences::drop(self, count)
|
192
|
-
end
|
193
|
-
|
194
|
-
def drop_while(fn_pred=nil, &block_pred)
|
195
|
-
assert_funcs(fn_pred, block_given?)
|
196
|
-
Sequence.new(@enumerator.drop_while { |value| block_given? ? block_pred.call(value) : fn_pred.(value) })
|
197
|
-
end
|
198
|
-
|
199
|
-
def flat_map(fn=nil, &block)
|
200
|
-
assert_funcs(fn, block_given?)
|
201
|
-
map(block_given? ? ->(value) { block.call(value) } : fn).flatten
|
202
|
-
end
|
203
|
-
|
204
|
-
def flatten
|
205
|
-
Sequence.new(flatten_enumerator(enumerator))
|
206
|
-
end
|
207
|
-
|
208
|
-
def sort_by(comparator)
|
209
|
-
Sequences::sort(self, comparator)
|
210
|
-
end
|
211
|
-
|
212
|
-
def contains?(value)
|
213
|
-
@enumerator.member?(value)
|
214
|
-
end
|
215
|
-
|
216
|
-
def exists?(fn_pred=nil, &block_pred)
|
217
|
-
assert_funcs(fn_pred, block_given?)
|
218
|
-
@enumerator.any? { |value| block_given? ? block_pred.call(value) : fn_pred.(value) }
|
219
|
-
end
|
220
|
-
|
221
|
-
def for_all?(fn_pred=nil, &block_pred)
|
222
|
-
assert_funcs(fn_pred, block_given?)
|
223
|
-
@enumerator.all? { |value| block_given? ? block_pred.call(value) : fn_pred.(value) }
|
224
|
-
end
|
225
|
-
|
226
|
-
def filter(fn_pred=nil, &block_pred)
|
227
|
-
assert_funcs(fn_pred, block_given?)
|
228
|
-
Sequence.new(@enumerator.select { |value| block_given? ? block_pred.call(value) : fn_pred.(value) })
|
229
|
-
end
|
230
|
-
|
231
|
-
def reject(fn_pred=nil, &block_pred)
|
232
|
-
assert_funcs(fn_pred, block_given?)
|
233
|
-
filter(Predicates::not(block_given? ? ->(value) { block_pred.call(value) } : fn_pred))
|
234
|
-
end
|
235
|
-
|
236
|
-
def group_by(fn=nil, &block)
|
237
|
-
assert_funcs(fn, block_given?)
|
238
|
-
groups = @enumerator.group_by { |value| block_given? ? block.call(value) : fn.(value) }
|
239
|
-
Sequence.new(groups.to_a.map { |group| Group.new(group[0], group[1].lazy) }.lazy)
|
240
|
-
end
|
241
|
-
|
242
|
-
def each(fn=nil, &block)
|
243
|
-
assert_funcs(fn, block_given?)
|
244
|
-
@enumerator.each { |value| block_given? ? block.call(value) : fn.(value) }
|
245
|
-
end
|
246
|
-
|
247
|
-
def map_concurrently(fn=nil, &block)
|
248
|
-
assert_funcs(fn, block_given?)
|
249
|
-
Sequences::map_concurrently(self, block_given? ? ->(value) { block.call(value) } : fn)
|
250
|
-
end
|
251
|
-
|
252
|
-
def realise
|
253
|
-
Sequence.new(@enumerator.to_a.lazy)
|
254
|
-
end
|
255
|
-
|
256
|
-
def <=>(other)
|
257
|
-
@enumerator.entries <=> other.enumerator.entries
|
258
|
-
end
|
259
|
-
|
260
|
-
private
|
261
|
-
def seed(enumerator, fn)
|
262
|
-
enumerator.rewind
|
263
|
-
!fn.nil? && fn.respond_to?(:identity) ? fn.identity : enumerator.next
|
264
|
-
end
|
265
|
-
end
|
266
|
-
|
267
|
-
def group(key, enumerator)
|
268
|
-
Group.new(key, enumerator)
|
269
|
-
end
|
270
|
-
|
271
|
-
class Group < Sequence
|
272
|
-
include Comparable
|
273
|
-
attr_reader :key
|
274
|
-
|
275
|
-
def initialize(key, enumerator)
|
276
|
-
super(enumerator)
|
277
|
-
@key = key
|
278
|
-
end
|
279
|
-
|
280
|
-
def <=>(other)
|
281
|
-
(@key <=> other.key) <=> (enumerator.entries<=>(other.enumerator.entries))
|
282
|
-
end
|
283
|
-
end
|
284
|
-
|
285
|
-
private
|
286
|
-
|
287
|
-
EMPTY=Sequence.new([].lazy)
|
288
|
-
|
289
|
-
def pair_enumerator(left, right)
|
290
|
-
Enumerator.new do |y|
|
291
|
-
left.rewind
|
292
|
-
right.rewind
|
293
|
-
loop do
|
294
|
-
y << pair(left.next, right.next)
|
295
|
-
end
|
296
|
-
end.lazy
|
297
|
-
end
|
298
|
-
end
|