totally_lazy 0.0.1
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 +7 -0
- data/.document +5 -0
- data/.rspec +1 -0
- data/Gemfile +9 -0
- data/LICENSE.txt +20 -0
- data/README.md +43 -0
- data/Rakefile +50 -0
- data/VERSION +1 -0
- data/lib/option.rb +108 -0
- data/lib/pair.rb +47 -0
- data/lib/sequence.rb +248 -0
- data/lib/totally_lazy.rb +8 -0
- data/lib/tuple.rb +5 -0
- data/spec/option_spec.rb +45 -0
- data/spec/pair_spec.rb +32 -0
- data/spec/sequence_spec.rb +50 -0
- data/spec/tuple_spec.rb +0 -0
- metadata +131 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: b2a0d97dd8aedb8afc89adef7c596aa2a547a24d
|
4
|
+
data.tar.gz: 7a6b85c74b930787327b38eea1557ca615f397f5
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 97d6df56b8e0a9f295117f7e3f52e6f5bdf11c280c8df69b7fffb49c02fca403ce36e76a0875b5bb9d71ff20dc63bdc510b1ede0782ac02780f2defc2afb8251
|
7
|
+
data.tar.gz: f2e0cb93b2217ae84954a03d876a77a29b17f11e36b7e1624a1262abdd19e57a9e9f1bf09b112983ea3d67dc61b69632b08b8ac371ee25e05e780f1fa905a2cd
|
data/.document
ADDED
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2014 Kingsley Hendrickse
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
# Totally Lazy for Ruby
|
2
|
+
|
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
|
+
|
5
|
+
### Summary
|
6
|
+
|
7
|
+
* Tries to be as lazy as possible
|
8
|
+
* Supports method chaining
|
9
|
+
* Is primarily based on ruby Enumerators
|
10
|
+
|
11
|
+
### Install
|
12
|
+
|
13
|
+
In your bundler Gemfile
|
14
|
+
|
15
|
+
```ruby
|
16
|
+
gem totally_lazy, '~>0.0.1'
|
17
|
+
```
|
18
|
+
|
19
|
+
Or with rubygems
|
20
|
+
|
21
|
+
```
|
22
|
+
gem install totall_lazy
|
23
|
+
```
|
24
|
+
|
25
|
+
### Examples
|
26
|
+
|
27
|
+
The following are some simple examples of the currently implemented functionality.
|
28
|
+
|
29
|
+
```ruby
|
30
|
+
sequence(1,2,3,4).filter{|i| i.even? } # lazily returns 2,4
|
31
|
+
sequence(1,2).map{|i| i.to_s} # lazily returns "1","2"
|
32
|
+
sequence(1,2,3).take(2) # lazily returns 1,2
|
33
|
+
sequence(1,2,3).drop(2) # lazily returns 3
|
34
|
+
sequence(1,2,3).tail # lazily returns 2,3
|
35
|
+
sequence(1,2,3).head # eagerly returns 1
|
36
|
+
```
|
37
|
+
|
38
|
+
Naturally you can combine these operations together:
|
39
|
+
|
40
|
+
```ruby
|
41
|
+
option(1).join(sequence(2,3,4)).join(sequence(5,6)).filter{|i| i.odd?}.take(2)
|
42
|
+
# lazily returns 1,3
|
43
|
+
```
|
data/Rakefile
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'bundler'
|
5
|
+
begin
|
6
|
+
Bundler.setup(:default, :development)
|
7
|
+
rescue Bundler::BundlerError => e
|
8
|
+
$stderr.puts e.message
|
9
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
10
|
+
exit e.status_code
|
11
|
+
end
|
12
|
+
require 'rake'
|
13
|
+
|
14
|
+
require 'jeweler'
|
15
|
+
Jeweler::Tasks.new do |gem|
|
16
|
+
# gem is a Gem::Specification... see http://guides.rubygems.org/specification-reference/ for more options
|
17
|
+
gem.name = "totally_lazy"
|
18
|
+
gem.homepage = "http://github.com/kingsleyh/totally_lazy"
|
19
|
+
gem.license = "MIT"
|
20
|
+
gem.summary = %Q{Port of java functional library totally lazy to ruby}
|
21
|
+
gem.description = %Q{Port of java functional library totally lazy to ruby}
|
22
|
+
gem.email = "kingsleyhendrickse@me.com"
|
23
|
+
gem.authors = ["Kingsley Hendrickse"]
|
24
|
+
# dependencies defined in Gemfile
|
25
|
+
end
|
26
|
+
Jeweler::RubygemsDotOrgTasks.new
|
27
|
+
|
28
|
+
require 'rspec/core'
|
29
|
+
require 'rspec/core/rake_task'
|
30
|
+
RSpec::Core::RakeTask.new(:spec) do |spec|
|
31
|
+
spec.pattern = FileList['spec/**/*_spec.rb']
|
32
|
+
end
|
33
|
+
|
34
|
+
desc "Code coverage detail"
|
35
|
+
task :simplecov do
|
36
|
+
ENV['COVERAGE'] = "true"
|
37
|
+
Rake::Task['spec'].execute
|
38
|
+
end
|
39
|
+
|
40
|
+
task :default => :spec
|
41
|
+
|
42
|
+
require 'rdoc/task'
|
43
|
+
Rake::RDocTask.new do |rdoc|
|
44
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
45
|
+
|
46
|
+
rdoc.rdoc_dir = 'rdoc'
|
47
|
+
rdoc.title = "totally_lazy #{version}"
|
48
|
+
rdoc.rdoc_files.include('README*')
|
49
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
50
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.0.1
|
data/lib/option.rb
ADDED
@@ -0,0 +1,108 @@
|
|
1
|
+
module Option
|
2
|
+
|
3
|
+
def option(thing)
|
4
|
+
thing.nil? ? none : some(thing)
|
5
|
+
end
|
6
|
+
|
7
|
+
def some(thing)
|
8
|
+
Some.new(thing)
|
9
|
+
end
|
10
|
+
|
11
|
+
def none(thing=nil)
|
12
|
+
None.new(thing)
|
13
|
+
end
|
14
|
+
|
15
|
+
class Some
|
16
|
+
|
17
|
+
include Comparable
|
18
|
+
|
19
|
+
def initialize(content)
|
20
|
+
@content = content
|
21
|
+
raise(Exception,'some cannot be nil') if @content.nil?
|
22
|
+
end
|
23
|
+
|
24
|
+
def <=>(object)
|
25
|
+
self.state <=> object.state
|
26
|
+
end
|
27
|
+
|
28
|
+
def get
|
29
|
+
@content
|
30
|
+
end
|
31
|
+
|
32
|
+
def value
|
33
|
+
get
|
34
|
+
end
|
35
|
+
|
36
|
+
def empty?
|
37
|
+
@content.empty?
|
38
|
+
end
|
39
|
+
|
40
|
+
def defined?
|
41
|
+
!empty?
|
42
|
+
end
|
43
|
+
|
44
|
+
def get_or_else(item)
|
45
|
+
blank? ? item : @content
|
46
|
+
end
|
47
|
+
|
48
|
+
def get_or_nil
|
49
|
+
@content
|
50
|
+
end
|
51
|
+
|
52
|
+
def get_or_throw(exception)
|
53
|
+
blank? ? @content : exception.call
|
54
|
+
end
|
55
|
+
|
56
|
+
def to_seq
|
57
|
+
sequence(self)
|
58
|
+
end
|
59
|
+
|
60
|
+
def contains(item)
|
61
|
+
value == item
|
62
|
+
end
|
63
|
+
|
64
|
+
def exists?(predicate)
|
65
|
+
|
66
|
+
end
|
67
|
+
|
68
|
+
def join(target_sequence)
|
69
|
+
sequence(value) << target_sequence
|
70
|
+
end
|
71
|
+
alias + join
|
72
|
+
alias << join
|
73
|
+
|
74
|
+
protected
|
75
|
+
def state
|
76
|
+
@content
|
77
|
+
end
|
78
|
+
|
79
|
+
private
|
80
|
+
|
81
|
+
def blank?
|
82
|
+
@content.nil? || @content.empty?
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
86
|
+
|
87
|
+
class None
|
88
|
+
|
89
|
+
include Comparable
|
90
|
+
|
91
|
+
def initialize(content)
|
92
|
+
@content = content
|
93
|
+
end
|
94
|
+
|
95
|
+
def <=>(object)
|
96
|
+
self.state <=> object.state
|
97
|
+
end
|
98
|
+
|
99
|
+
protected
|
100
|
+
|
101
|
+
def state
|
102
|
+
@content
|
103
|
+
end
|
104
|
+
|
105
|
+
end
|
106
|
+
|
107
|
+
|
108
|
+
end
|
data/lib/pair.rb
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
module Pair
|
2
|
+
|
3
|
+
def pair(first, second)
|
4
|
+
Pair.new(first, second)
|
5
|
+
end
|
6
|
+
|
7
|
+
def from_map(a_map)
|
8
|
+
Pair.from_map(a_map)
|
9
|
+
end
|
10
|
+
|
11
|
+
class Pair
|
12
|
+
|
13
|
+
def initialize(first, second)
|
14
|
+
@first = -> { first }
|
15
|
+
@second = -> { second }
|
16
|
+
end
|
17
|
+
|
18
|
+
def first
|
19
|
+
@first.call
|
20
|
+
end
|
21
|
+
alias key first
|
22
|
+
|
23
|
+
def second
|
24
|
+
@second.call
|
25
|
+
end
|
26
|
+
alias value second
|
27
|
+
|
28
|
+
def to_map
|
29
|
+
{first => second}
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.from_map(a_map)
|
33
|
+
sequence(a_map).map{|k,v| Pair.new(k,v)}
|
34
|
+
end
|
35
|
+
|
36
|
+
def to_s
|
37
|
+
to_map.inspect
|
38
|
+
end
|
39
|
+
|
40
|
+
def values
|
41
|
+
sequence(first, second)
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
|
46
|
+
|
47
|
+
end
|
data/lib/sequence.rb
ADDED
@@ -0,0 +1,248 @@
|
|
1
|
+
class NoSuchElementException < RuntimeError
|
2
|
+
end
|
3
|
+
|
4
|
+
class Empty
|
5
|
+
|
6
|
+
def each
|
7
|
+
yield self
|
8
|
+
end
|
9
|
+
|
10
|
+
end
|
11
|
+
|
12
|
+
module Sequences
|
13
|
+
|
14
|
+
def sequence(*items)
|
15
|
+
if items.size == 1
|
16
|
+
if items.first.kind_of?(Range)
|
17
|
+
Sequence.new(items.first)
|
18
|
+
elsif items.first.kind_of?(Hash)
|
19
|
+
Sequence.new(items.first)
|
20
|
+
else
|
21
|
+
Sequence.new(items)
|
22
|
+
end
|
23
|
+
else
|
24
|
+
Sequence.new(items)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def empty
|
29
|
+
sequence(Empty.new)
|
30
|
+
end
|
31
|
+
|
32
|
+
class Sequence < Enumerator
|
33
|
+
|
34
|
+
include Comparable
|
35
|
+
|
36
|
+
def initialize(obj, &block)
|
37
|
+
super() { |yielder|
|
38
|
+
begin
|
39
|
+
obj.each { |x|
|
40
|
+
if block
|
41
|
+
block.call(yielder, x)
|
42
|
+
else
|
43
|
+
yielder << x
|
44
|
+
end
|
45
|
+
}
|
46
|
+
rescue StopIteration
|
47
|
+
end
|
48
|
+
}
|
49
|
+
end
|
50
|
+
|
51
|
+
def <=>(object)
|
52
|
+
self.class <=> object.class
|
53
|
+
end
|
54
|
+
|
55
|
+
def map(&block)
|
56
|
+
Sequence.new(self) { |yielder, val|
|
57
|
+
yielder << block.call(val)
|
58
|
+
}
|
59
|
+
end
|
60
|
+
|
61
|
+
alias collect map
|
62
|
+
|
63
|
+
def select(&block)
|
64
|
+
Sequence.new(self) { |yielder, val|
|
65
|
+
if block.call(val)
|
66
|
+
yielder << val
|
67
|
+
end
|
68
|
+
}
|
69
|
+
end
|
70
|
+
|
71
|
+
alias find_all select
|
72
|
+
alias filter select
|
73
|
+
|
74
|
+
def reject(&block)
|
75
|
+
Sequence.new(self) { |yielder, val|
|
76
|
+
if not block.call(val)
|
77
|
+
yielder << val
|
78
|
+
end
|
79
|
+
}
|
80
|
+
end
|
81
|
+
|
82
|
+
def grep(pattern)
|
83
|
+
Sequence.new(self) { |yielder, val|
|
84
|
+
if pattern === val
|
85
|
+
yielder << val
|
86
|
+
end
|
87
|
+
}
|
88
|
+
end
|
89
|
+
|
90
|
+
def drop(n)
|
91
|
+
dropped = 0
|
92
|
+
Sequence.new(self) { |yielder, val|
|
93
|
+
if dropped < n
|
94
|
+
dropped += 1
|
95
|
+
else
|
96
|
+
yielder << val
|
97
|
+
end
|
98
|
+
}
|
99
|
+
end
|
100
|
+
|
101
|
+
def drop_while(&block)
|
102
|
+
dropping = true
|
103
|
+
Sequence.new(self) { |yielder, val|
|
104
|
+
if dropping
|
105
|
+
if not block.call(val)
|
106
|
+
yielder << val
|
107
|
+
dropping = false
|
108
|
+
end
|
109
|
+
else
|
110
|
+
yielder << val
|
111
|
+
end
|
112
|
+
}
|
113
|
+
end
|
114
|
+
|
115
|
+
def take(n)
|
116
|
+
taken = 0
|
117
|
+
Sequence.new(self) { |yielder, val|
|
118
|
+
if taken < n
|
119
|
+
yielder << val
|
120
|
+
taken += 1
|
121
|
+
else
|
122
|
+
raise StopIteration
|
123
|
+
end
|
124
|
+
}
|
125
|
+
end
|
126
|
+
|
127
|
+
def take_while(&block)
|
128
|
+
Sequence.new(self) { |yielder, val|
|
129
|
+
if block.call(val)
|
130
|
+
yielder << val
|
131
|
+
else
|
132
|
+
raise StopIteration
|
133
|
+
end
|
134
|
+
}
|
135
|
+
end
|
136
|
+
|
137
|
+
def flat_map(&block)
|
138
|
+
Sequence.new(self) { |yielder, val|
|
139
|
+
ary = block.call(val)
|
140
|
+
# TODO: check ary is an Array
|
141
|
+
ary.each { |x|
|
142
|
+
yielder << x
|
143
|
+
}
|
144
|
+
}
|
145
|
+
end
|
146
|
+
|
147
|
+
alias collect_concat flat_map
|
148
|
+
|
149
|
+
def zip(*args, &block)
|
150
|
+
enums = [self] + args
|
151
|
+
Sequence.new(self) { |yielder, val|
|
152
|
+
ary = enums.map { |e| e.next }
|
153
|
+
if block
|
154
|
+
yielder << block.call(ary)
|
155
|
+
else
|
156
|
+
yielder << ary
|
157
|
+
end
|
158
|
+
}
|
159
|
+
end
|
160
|
+
|
161
|
+
def [](n)
|
162
|
+
Sequence.new(self).entries[n]
|
163
|
+
end
|
164
|
+
|
165
|
+
alias get []
|
166
|
+
|
167
|
+
def empty?
|
168
|
+
sequence.next.kind_of?(Empty)
|
169
|
+
end
|
170
|
+
|
171
|
+
def head
|
172
|
+
sequence.empty? ? raise(NoSuchElementException.new, 'The sequence was empty') : sequence.first
|
173
|
+
end
|
174
|
+
|
175
|
+
def head_option
|
176
|
+
sequence.empty? ? none : some(sequence.first)
|
177
|
+
end
|
178
|
+
|
179
|
+
def last
|
180
|
+
sequence.empty? ? raise(NoSuchElementException.new, 'The sequence was empty') : sequence.entries.last
|
181
|
+
end
|
182
|
+
|
183
|
+
def last_option
|
184
|
+
sequence.empty? ? none : some(sequence.entries.last)
|
185
|
+
end
|
186
|
+
|
187
|
+
def tail
|
188
|
+
Sequence.new(Sequence::Generator.new do |g|
|
189
|
+
self.empty? ? raise(NoSuchElementException.new, 'The sequence was empty') : self.drop(1).each { |i| g.yield i }
|
190
|
+
end)
|
191
|
+
end
|
192
|
+
|
193
|
+
def init
|
194
|
+
Sequence.new(Sequence::Generator.new do |g|
|
195
|
+
size = self.count
|
196
|
+
self.empty? ? raise(NoSuchElementException.new, 'The sequence was empty') : self.first(size-1).each { |i| g.yield i }
|
197
|
+
end)
|
198
|
+
end
|
199
|
+
|
200
|
+
def shuffle
|
201
|
+
Sequence.new(Sequence::Generator.new do |g|
|
202
|
+
self.empty? ? raise(NoSuchElementException.new, 'The sequence was empty') : self.entries.shuffle.each { |i| g.yield i }
|
203
|
+
end)
|
204
|
+
end
|
205
|
+
|
206
|
+
def transpose
|
207
|
+
Sequence.new(Sequence::Generator.new do |g|
|
208
|
+
result = []
|
209
|
+
max_size = self.entries.max { |a, b| a.size <=> b.size }.size
|
210
|
+
max_size.times do |i|
|
211
|
+
result[i] = [self.entries.first.size]
|
212
|
+
self.entries.each_with_index { |r, j| result[i][j] = r[i] }
|
213
|
+
end
|
214
|
+
result
|
215
|
+
self.empty? ? raise(NoSuchElementException.new, 'The sequence was empty') : result.each { |i| g.yield i }
|
216
|
+
end)
|
217
|
+
end
|
218
|
+
|
219
|
+
def join(target_sequence)
|
220
|
+
Sequence.new(Sequence::Generator.new do |g|
|
221
|
+
raise(Exception.new, 'The target (right side) must be a sequence') unless target_sequence.kind_of?(Sequences::Sequence)
|
222
|
+
(self.entries << target_sequence.entries).flatten.each{|i| g.yield i}
|
223
|
+
end)
|
224
|
+
end
|
225
|
+
alias + join
|
226
|
+
alias << join
|
227
|
+
|
228
|
+
private
|
229
|
+
def sequence
|
230
|
+
Sequence.new(self)
|
231
|
+
end
|
232
|
+
|
233
|
+
end
|
234
|
+
|
235
|
+
end
|
236
|
+
|
237
|
+
|
238
|
+
|
239
|
+
|
240
|
+
|
241
|
+
|
242
|
+
|
243
|
+
|
244
|
+
|
245
|
+
|
246
|
+
|
247
|
+
|
248
|
+
|
data/lib/totally_lazy.rb
ADDED
data/spec/option_spec.rb
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'rspec'
|
2
|
+
require_relative '../lib/totally_lazy'
|
3
|
+
|
4
|
+
describe 'Option' do
|
5
|
+
|
6
|
+
it 'should support contains' do
|
7
|
+
expect(option(1).contains(1)).to be(true)
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'should support is alias' do
|
11
|
+
pending('support is alias')
|
12
|
+
pass
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'should support exists' do
|
16
|
+
pending('exists')
|
17
|
+
pass
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'should support join' do
|
21
|
+
expect(option(1).join(sequence(2,3))).to eq(sequence(1,2,3))
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'should get value of some' do
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'should not get value of none' do
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'should get or else' do
|
33
|
+
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'should get or nil' do
|
37
|
+
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'should get or raise exception' do
|
41
|
+
|
42
|
+
end
|
43
|
+
|
44
|
+
|
45
|
+
end
|
data/spec/pair_spec.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'rspec'
|
2
|
+
require_relative '../lib/totally_lazy'
|
3
|
+
|
4
|
+
describe 'Pair' do
|
5
|
+
|
6
|
+
it 'should return the first item: first/key' do
|
7
|
+
expect(pair(1, 2).first).to eq(1)
|
8
|
+
expect(pair(1, 2).key).to eq(1)
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'should return the second item: second/value' do
|
12
|
+
expect(pair(1, 2).second).to eq(2)
|
13
|
+
expect(pair(1, 2).value).to eq(2)
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'should return sequence of values' do
|
17
|
+
expect(pair(1,2).values).to eq(sequence(1,2))
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'should convert to string' do
|
21
|
+
expect(pair('apples',2).to_s).to eq('{"apples"=>2}')
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'should convert to a sequence of pairs from a map' do
|
25
|
+
expect(Pair.from_map({apples:'10'})).to eq(sequence(pair(:apples,'10')))
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'should convert a pair to a map' do
|
29
|
+
expect(pair(1,2).to_map).to eq({1=>2})
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'rspec'
|
2
|
+
require_relative '../lib/totally_lazy'
|
3
|
+
|
4
|
+
describe 'Sequence' do
|
5
|
+
|
6
|
+
it 'should create empty sequence when iterable is nil' do
|
7
|
+
expect(sequence(nil)).to eq(empty)
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'should support transpose' do
|
11
|
+
expect(sequence(sequence(1, 2), sequence(3, 4), sequence(5, 6))).to include(sequence(1, 3, 5), sequence(2, 4, 6))
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'should eagerly return the first element of a sequence, returns NoSuchElementException if empty' do
|
15
|
+
expect(sequence(1, 2).head).to eq(1)
|
16
|
+
expect { empty.head }.to raise_error(NoSuchElementException)
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'should eagerly return the first element of a sequence wrapped in a some, returns none if empty' do
|
20
|
+
expect(sequence(1, 2).head_option).to eq(some(1))
|
21
|
+
expect(empty.head_option).to eq(none)
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'should eagerly return the last element of a finite sequence, throws NoSuchElementException if empty' do
|
25
|
+
expect(sequence(1, 2).last).to eq(2)
|
26
|
+
expect { empty.last }.to raise_error(NoSuchElementException)
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'should eagerly return the last element of a finite sequence wrapped in a some, returns none if empty' do
|
30
|
+
expect(sequence(1, 2).last_option).to eq(some(2))
|
31
|
+
expect(empty.last_option).to eq(none)
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'should lazily return the elements except the last one - throws NoSuchElementException if empty. Works with infinite sequences' do
|
35
|
+
expect(sequence(1, 2, 3).tail).to eq(sequence(2, 3))
|
36
|
+
expect { empty.tail.first }.to raise_error(NoSuchElementException)
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'should lazily return the elements except the first one - throws NoSuchElementException if empty' do
|
40
|
+
expect(sequence(1, 2, 3).init).to eq(sequence(1, 2))
|
41
|
+
expect { empty.init.first }.to raise_error(NoSuchElementException)
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'should lazily shuffle the elements - throws NoSuchElementException if empty' do
|
45
|
+
expect(sequence(1..50).shuffle.entries).not_to eq(sequence(1..50).entries)
|
46
|
+
expect { empty.shuffle.first }.to raise_error(NoSuchElementException)
|
47
|
+
end
|
48
|
+
|
49
|
+
|
50
|
+
end
|
data/spec/tuple_spec.rb
ADDED
File without changes
|
metadata
ADDED
@@ -0,0 +1,131 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: totally_lazy
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Kingsley Hendrickse
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-08-15 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rspec
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 3.0.0
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 3.0.0
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rdoc
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '3.12'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '3.12'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: bundler
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '1.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '1.0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: jeweler
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 2.0.1
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 2.0.1
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rspec_html_formatter
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 0.3.0
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 0.3.0
|
83
|
+
description: Port of java functional library totally lazy to ruby
|
84
|
+
email: kingsleyhendrickse@me.com
|
85
|
+
executables: []
|
86
|
+
extensions: []
|
87
|
+
extra_rdoc_files:
|
88
|
+
- LICENSE.txt
|
89
|
+
- README.md
|
90
|
+
files:
|
91
|
+
- ".document"
|
92
|
+
- ".rspec"
|
93
|
+
- Gemfile
|
94
|
+
- LICENSE.txt
|
95
|
+
- README.md
|
96
|
+
- Rakefile
|
97
|
+
- VERSION
|
98
|
+
- lib/option.rb
|
99
|
+
- lib/pair.rb
|
100
|
+
- lib/sequence.rb
|
101
|
+
- lib/totally_lazy.rb
|
102
|
+
- lib/tuple.rb
|
103
|
+
- spec/option_spec.rb
|
104
|
+
- spec/pair_spec.rb
|
105
|
+
- spec/sequence_spec.rb
|
106
|
+
- spec/tuple_spec.rb
|
107
|
+
homepage: http://github.com/kingsleyh/totally_lazy
|
108
|
+
licenses:
|
109
|
+
- MIT
|
110
|
+
metadata: {}
|
111
|
+
post_install_message:
|
112
|
+
rdoc_options: []
|
113
|
+
require_paths:
|
114
|
+
- lib
|
115
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
116
|
+
requirements:
|
117
|
+
- - ">="
|
118
|
+
- !ruby/object:Gem::Version
|
119
|
+
version: '0'
|
120
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
requirements: []
|
126
|
+
rubyforge_project:
|
127
|
+
rubygems_version: 2.2.2
|
128
|
+
signing_key:
|
129
|
+
specification_version: 4
|
130
|
+
summary: Port of java functional library totally lazy to ruby
|
131
|
+
test_files: []
|