option 0.3.1 → 0.4.0
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.
- data/.travis.yml +0 -1
- data/README.md +11 -3
- data/lib/option.rb +18 -5
- data/lib/option/version.rb +1 -1
- data/spec/option_spec.rb +39 -12
- metadata +6 -6
data/.travis.yml
CHANGED
data/README.md
CHANGED
@@ -1,7 +1,9 @@
|
|
1
1
|
# Option
|
2
2
|
|
3
|
-
A Ruby port
|
4
|
-
but also pragmatic in RE: to
|
3
|
+
A Ruby port of Scala's Option monad. Tries to be faithful
|
4
|
+
but also pragmatic in RE: to duck typing.
|
5
|
+
|
6
|
+
Blog post: http://robares.com/2012/09/16/ruby-port-of-scala-option/
|
5
7
|
|
6
8
|
## Installation
|
7
9
|
|
@@ -54,10 +56,16 @@ None.fold(-> { "missing" }) { |v| v.upcase } #=> missing
|
|
54
56
|
|
55
57
|
# filter values returning an option
|
56
58
|
foo.filter { |v| v == "baz" } #=> None
|
59
|
+
|
60
|
+
# mutation
|
61
|
+
foo.inside { |v| v.upcase! } #=> Some("BAR")
|
57
62
|
```
|
58
63
|
|
59
64
|
## Build Status
|
60
|
-
|
65
|
+
[](http://travis-ci.org/rares/option)
|
66
|
+
|
67
|
+
## Code Climate
|
68
|
+
[](https://codeclimate.com/github/rares/option)
|
61
69
|
|
62
70
|
## Contributing
|
63
71
|
|
data/lib/option.rb
CHANGED
@@ -9,6 +9,15 @@ class OptionClass
|
|
9
9
|
else or_nil == that
|
10
10
|
end
|
11
11
|
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def assert_option(result)
|
16
|
+
case result
|
17
|
+
when OptionClass then return result
|
18
|
+
else raise TypeError, "Must be an Option"
|
19
|
+
end
|
20
|
+
end
|
12
21
|
end
|
13
22
|
|
14
23
|
class SomeClass < OptionClass
|
@@ -52,11 +61,7 @@ class SomeClass < OptionClass
|
|
52
61
|
end
|
53
62
|
|
54
63
|
def flat_map(&blk)
|
55
|
-
|
56
|
-
case result
|
57
|
-
when OptionClass then return result
|
58
|
-
else raise TypeError, "Must be an Option"
|
59
|
-
end
|
64
|
+
assert_option(blk.call(get))
|
60
65
|
end
|
61
66
|
|
62
67
|
def fold(if_empty, &blk)
|
@@ -75,6 +80,10 @@ class SomeClass < OptionClass
|
|
75
80
|
blk.call(get)
|
76
81
|
self
|
77
82
|
end
|
83
|
+
|
84
|
+
def or_else(&blk)
|
85
|
+
self
|
86
|
+
end
|
78
87
|
end
|
79
88
|
|
80
89
|
class NoneClass < OptionClass
|
@@ -130,6 +139,10 @@ class NoneClass < OptionClass
|
|
130
139
|
def inside(&blk)
|
131
140
|
self
|
132
141
|
end
|
142
|
+
|
143
|
+
def or_else(&blk)
|
144
|
+
assert_option(blk.call)
|
145
|
+
end
|
133
146
|
end
|
134
147
|
|
135
148
|
None = NoneClass.new
|
data/lib/option/version.rb
CHANGED
data/spec/option_spec.rb
CHANGED
@@ -1,8 +1,23 @@
|
|
1
1
|
require "minitest/autorun"
|
2
|
+
require "minitest/pride"
|
2
3
|
require "minitest/spec"
|
3
4
|
|
4
5
|
require "option"
|
5
6
|
|
7
|
+
module MiniTest::Assertions
|
8
|
+
|
9
|
+
def assert_some(value, option, msg = nil)
|
10
|
+
assert (option.is_a?(Some) && option.or_nil == value), "Expected Some(#{value})"
|
11
|
+
end
|
12
|
+
|
13
|
+
def assert_none(value, option, msg = nil)
|
14
|
+
assert option == None, "Expected None"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
OptionClass.infect_an_assertion :assert_some, :must_be_some
|
19
|
+
OptionClass.infect_an_assertion :assert_none, :must_be_none
|
20
|
+
|
6
21
|
def value
|
7
22
|
12
|
8
23
|
end
|
@@ -41,11 +56,11 @@ describe NoneClass do
|
|
41
56
|
end
|
42
57
|
|
43
58
|
it "#map should return itself" do
|
44
|
-
None.map {}.
|
59
|
+
None.map {}.must_be_none
|
45
60
|
end
|
46
61
|
|
47
62
|
it "#flat_map should return itself" do
|
48
|
-
None.flat_map {}.
|
63
|
+
None.flat_map {}.must_be_none
|
49
64
|
end
|
50
65
|
|
51
66
|
it "#exists? should return false" do
|
@@ -57,11 +72,11 @@ describe NoneClass do
|
|
57
72
|
end
|
58
73
|
|
59
74
|
it "#filter with a true predicate returns itself" do
|
60
|
-
Option(value).filter { |i| i == 12 }.
|
75
|
+
Option(value).filter { |i| i == 12 }.must_be_some(value)
|
61
76
|
end
|
62
77
|
|
63
78
|
it "#filter with a false predicate returns None" do
|
64
|
-
Option(value).filter { |i| i == 1 }.
|
79
|
+
Option(value).filter { |i| i == 1 }.must_be_none
|
65
80
|
end
|
66
81
|
|
67
82
|
it "should be aliased to None" do
|
@@ -73,6 +88,14 @@ describe NoneClass do
|
|
73
88
|
None.inside { |v| expected = value }
|
74
89
|
expected.must_be_nil
|
75
90
|
end
|
91
|
+
|
92
|
+
it "#or_else should invoke the block and return an Option" do
|
93
|
+
None.or_else { Some(value) }.must_be_some(value)
|
94
|
+
end
|
95
|
+
|
96
|
+
it "#or_else should raise a TypeError if an Option is not returned" do
|
97
|
+
lambda { None.or_else { value } }.must_raise TypeError
|
98
|
+
end
|
76
99
|
end
|
77
100
|
|
78
101
|
describe SomeClass do
|
@@ -116,7 +139,7 @@ describe SomeClass do
|
|
116
139
|
end
|
117
140
|
|
118
141
|
it "#map should return the result of the proc over the value in an Option" do
|
119
|
-
Some(value).map { |v| v * 2 }.
|
142
|
+
Some(value).map { |v| v * 2 }.must_be_some(24)
|
120
143
|
end
|
121
144
|
|
122
145
|
it "#flat_map should raise TypeError if the returned value is not an Option" do
|
@@ -124,11 +147,11 @@ describe SomeClass do
|
|
124
147
|
end
|
125
148
|
|
126
149
|
it "#flat_map should return an Option value from the block" do
|
127
|
-
Some(value).flat_map { |v| Option(v * 2) }.
|
150
|
+
Some(value).flat_map { |v| Option(v * 2) }.must_be_some(24)
|
128
151
|
end
|
129
152
|
|
130
153
|
it "#flat_map can return None from the block" do
|
131
|
-
Some(value).flat_map { |_| None }.
|
154
|
+
Some(value).flat_map { |_| None }.must_be_none
|
132
155
|
end
|
133
156
|
|
134
157
|
it "#exists? should return true when the block evaluates true" do
|
@@ -144,32 +167,36 @@ describe SomeClass do
|
|
144
167
|
end
|
145
168
|
|
146
169
|
it "#filter should return itself" do
|
147
|
-
None.filter { |i| i == 0 }.
|
170
|
+
None.filter { |i| i == 0 }.must_be_none
|
148
171
|
end
|
149
172
|
|
150
173
|
it "#inside should invoke the proc and return itself" do
|
151
174
|
expected = nil
|
152
|
-
Some(value).inside { |v| expected = v }.
|
175
|
+
Some(value).inside { |v| expected = v }.must_be_some(value)
|
153
176
|
expected.must_equal(value)
|
154
177
|
end
|
155
178
|
|
179
|
+
it "#or_else should return itself" do
|
180
|
+
Some(value).or_else { None }.must_be_some(value)
|
181
|
+
end
|
182
|
+
|
156
183
|
it "should wrap the creation of a Some" do
|
157
184
|
Some(value).must_be_instance_of(SomeClass)
|
158
185
|
end
|
159
186
|
|
160
187
|
it "should be aliased to Some" do
|
161
|
-
Some.new(value).
|
188
|
+
Some.new(value).must_be_some(value)
|
162
189
|
end
|
163
190
|
end
|
164
191
|
|
165
192
|
describe OptionClass do
|
166
193
|
|
167
194
|
it "must return a some if the passed value is not nil" do
|
168
|
-
Option(value).
|
195
|
+
Option(value).must_be_some(value)
|
169
196
|
end
|
170
197
|
|
171
198
|
it "must return a None if the passed value is nil" do
|
172
|
-
Option(nil).
|
199
|
+
Option(nil).must_be_none
|
173
200
|
end
|
174
201
|
|
175
202
|
it "should do equality checks against the boxed value" do
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: option
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-10-07 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rake
|
16
|
-
requirement: &
|
16
|
+
requirement: &70193288139160 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - =
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: 0.9.2.2
|
22
22
|
type: :development
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *70193288139160
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: minitest
|
27
|
-
requirement: &
|
27
|
+
requirement: &70193288138600 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - =
|
@@ -32,7 +32,7 @@ dependencies:
|
|
32
32
|
version: 3.4.0
|
33
33
|
type: :development
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *70193288138600
|
36
36
|
description: Ruby port of Scala's Option Monad
|
37
37
|
email:
|
38
38
|
- rob.ares@gmail.com
|