wrapped 0.0.3 → 0.1.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.
- checksums.yaml +4 -4
- data/README.md +104 -76
- data/lib/wrapped/blank.rb +28 -4
- data/lib/wrapped/present.rb +29 -10
- data/lib/wrapped/version.rb +1 -1
- data/spec/spec_helper.rb +8 -0
- data/spec/wrapped_spec.rb +124 -44
- data/wrapped.gemspec +2 -2
- metadata +8 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ef031daae3bfd8056b4b709aa3a500ac7197e541
|
4
|
+
data.tar.gz: 70978101ccd2d40c521e4dffd6d9f6420a9edb71
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d601312592eedffda77e3fa31e8efebfdf226ae06bd4a428213b6acda443cabc414e1af1d7fe4cd239d8abbbd7336d91c25079c0c62fdd83b7eb33b3a11a5c79
|
7
|
+
data.tar.gz: 1a8d7a800f1c17a4a1fb0f546864cace441c86c8dbb04e6ab315e9afcf38e02884831487841d8f8c7e415322e8f0ce5b9554cf5b2108820a1cecfde93b3f39c5
|
data/README.md
CHANGED
@@ -6,6 +6,13 @@ your code to find bugs earlier and faster. It works like this: any time you
|
|
6
6
|
write a method that could produce nil, you instead write a method that produces
|
7
7
|
a wrapped value.
|
8
8
|
|
9
|
+
Warning: Experimental
|
10
|
+
---------------------
|
11
|
+
|
12
|
+
This library is in an early, experimental phase and may change suddenly and
|
13
|
+
drastically. Backwards-compatibility should not be expected between releases,
|
14
|
+
and the project may be cancelled at any time.
|
15
|
+
|
9
16
|
Example
|
10
17
|
-------
|
11
18
|
|
@@ -14,33 +21,39 @@ Here's an example along with how it can help with errors:
|
|
14
21
|
Say you have a collection of users along with a method for accessing the first
|
15
22
|
user:
|
16
23
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
24
|
+
```ruby
|
25
|
+
class UserCollection
|
26
|
+
def initialize(users)
|
27
|
+
@users = users
|
28
|
+
end
|
29
|
+
|
30
|
+
def first_user
|
31
|
+
@users.first
|
32
|
+
end
|
33
|
+
end
|
34
|
+
```
|
26
35
|
|
27
36
|
Now your friend uses your awesome UserCollection code:
|
28
37
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
38
|
+
```ruby
|
39
|
+
class FriendGroups
|
40
|
+
def initialize(user_collections)
|
41
|
+
@user_collections = user_collections
|
42
|
+
end
|
33
43
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
end
|
38
|
-
end
|
44
|
+
def first_names
|
45
|
+
@user_collections.map do |user_collection|
|
46
|
+
user_collection.first_user.first_name
|
39
47
|
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
```
|
40
51
|
|
41
52
|
And then she tries it:
|
42
53
|
|
43
|
-
|
54
|
+
```ruby
|
55
|
+
FriendGroups.new([UserCollection.new([])]).first_names
|
56
|
+
```
|
44
57
|
|
45
58
|
... and it promptly blows up:
|
46
59
|
|
@@ -59,15 +72,17 @@ Right.
|
|
59
72
|
Instead what you want to do is wrap it. Wrap that nil. Make the user know that
|
60
73
|
they have to consider the result.
|
61
74
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
75
|
+
```ruby
|
76
|
+
class UserCollection
|
77
|
+
def initialize(users)
|
78
|
+
@users = users
|
79
|
+
end
|
80
|
+
|
81
|
+
def first_user
|
82
|
+
@users.first.wrapped
|
83
|
+
end
|
84
|
+
end
|
85
|
+
```
|
71
86
|
|
72
87
|
Now in your documentation you explain that it produces a wrapped value. And
|
73
88
|
people who skip documentation and instead read source code will see that it is
|
@@ -76,17 +91,19 @@ wrapped.
|
|
76
91
|
So they unwrap it, because they must. They can't even get a happy path without
|
77
92
|
unwrapping it.
|
78
93
|
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
94
|
+
```ruby
|
95
|
+
class FriendGroups
|
96
|
+
def initialize(user_collections)
|
97
|
+
@user_collections = user_collections
|
98
|
+
end
|
83
99
|
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
end
|
88
|
-
end
|
100
|
+
def first_names
|
101
|
+
@user_collections.map do |user_collection|
|
102
|
+
user_collection.first_user.unwrap_or('') {|user| user.first_name }
|
89
103
|
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
```
|
90
107
|
|
91
108
|
Cool Stuff
|
92
109
|
----------
|
@@ -99,15 +116,19 @@ wrapped value. By wrapping it you've just made it more powerful!
|
|
99
116
|
|
100
117
|
For example:
|
101
118
|
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
119
|
+
```ruby
|
120
|
+
irb(main):054:0> 1.wrapped.inject(0) {|_, n| n+1}
|
121
|
+
=> 2
|
122
|
+
irb(main):055:0> nil.wrapped.inject(0) {|_, n| n+1}
|
123
|
+
=> 0
|
124
|
+
```
|
106
125
|
|
107
126
|
And then we have `flat_map`, which you can use to produce another wrapped object:
|
108
127
|
|
109
|
-
|
110
|
-
|
128
|
+
```ruby
|
129
|
+
irb> 1.wrapped.flat_map {|n| (n + 1).wrapped}.flat_map {|n| (n*2).wrapped}.unwrap
|
130
|
+
=> 4
|
131
|
+
```
|
111
132
|
|
112
133
|
Those same people who will exclaim things about functors will, at this point,
|
113
134
|
get giddy about monads. I mean, they're right, but they can relax. It's just a
|
@@ -116,44 +137,51 @@ monad.
|
|
116
137
|
Those people ("what do you mean, 'those people'?!") may prefer the `fmap`
|
117
138
|
method:
|
118
139
|
|
119
|
-
|
120
|
-
|
140
|
+
```ruby
|
141
|
+
irb> 1.wrapped.fmap {|n| n+1}.unwrap_or(0) {|n| n+4}
|
142
|
+
=> 6
|
143
|
+
```
|
121
144
|
|
122
145
|
Other Methods
|
123
146
|
-------------
|
124
147
|
|
125
148
|
Then we added some convenience methods to all of this. Here's a tour:
|
126
149
|
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
150
|
+
```ruby
|
151
|
+
irb> require 'wrapped'
|
152
|
+
=> true
|
153
|
+
irb> 1.wrapped.unwrap_or(-1)
|
154
|
+
=> 1
|
155
|
+
irb> nil.wrapped.unwrap_or(-1)
|
156
|
+
=> -1
|
157
|
+
irb> 1.wrapped.present {|n| p n }.blank { puts "nothing!" }
|
158
|
+
1
|
159
|
+
=> #<Present:0x7fc570aed0e8 @value=1>
|
160
|
+
irb> nil.wrapped.present {|n| p n }.blank { puts "nothing!" }
|
161
|
+
nothing!
|
162
|
+
=> #<Blank:0x7fc570ae21c0>
|
163
|
+
irb> 1.wrapped.unwrap
|
164
|
+
=> 1
|
165
|
+
irb> nil.wrapped.unwrap
|
166
|
+
IndexError: Blank has no value
|
167
|
+
from /home/mike/wrapped/lib/wrapped/types.rb:43:in `unwrap'
|
168
|
+
from (irb):7
|
169
|
+
```
|
170
|
+
|
171
|
+
```ruby
|
172
|
+
irb> 1.wrapped.present?
|
173
|
+
=> true
|
174
|
+
irb> nil.wrapped.present?
|
175
|
+
=> false
|
176
|
+
irb> nil.wrapped.blank?
|
177
|
+
=> true
|
178
|
+
irb> 1.wrapped.blank?
|
179
|
+
=> false
|
180
|
+
irb> 1.wrapped.unwrap_or(0) {|n| n * 100}
|
181
|
+
=> 100
|
182
|
+
irb> nil.wrapped.unwrap_or(0) {|n| n * 100}
|
183
|
+
=> 0
|
184
|
+
```
|
157
185
|
|
158
186
|
Inspiration
|
159
187
|
-----------
|
@@ -166,4 +194,4 @@ functor or the option class for more.
|
|
166
194
|
|
167
195
|
Copyright
|
168
196
|
---------
|
169
|
-
Copyright 2011
|
197
|
+
Copyright 2011 Mike Burns. Copyright 2014 thoughtbot.
|
data/lib/wrapped/blank.rb
CHANGED
@@ -10,8 +10,12 @@ class Blank
|
|
10
10
|
# Produce the value that is passed in.
|
11
11
|
#
|
12
12
|
# > w.unwrap_or(0)
|
13
|
-
def unwrap_or(default)
|
14
|
-
|
13
|
+
def unwrap_or(default = nil)
|
14
|
+
if block_given?
|
15
|
+
yield
|
16
|
+
else
|
17
|
+
default
|
18
|
+
end
|
15
19
|
end
|
16
20
|
|
17
21
|
# Does nothing, returning itself. This is chainable. See blank for its
|
@@ -37,7 +41,24 @@ class Blank
|
|
37
41
|
#
|
38
42
|
# > w.each {|n| puts n }
|
39
43
|
def each
|
40
|
-
|
44
|
+
self
|
45
|
+
end
|
46
|
+
|
47
|
+
# Produces itself.
|
48
|
+
def select
|
49
|
+
self
|
50
|
+
end
|
51
|
+
|
52
|
+
alias_method :find_all, :select
|
53
|
+
|
54
|
+
# Produces itself.
|
55
|
+
def reject
|
56
|
+
self
|
57
|
+
end
|
58
|
+
|
59
|
+
# Produces itself.
|
60
|
+
def grep(*)
|
61
|
+
self
|
41
62
|
end
|
42
63
|
|
43
64
|
# False; this is not an instance of a wrapped value.
|
@@ -64,12 +85,15 @@ class Blank
|
|
64
85
|
self
|
65
86
|
end
|
66
87
|
|
88
|
+
alias_method :collect, :fmap
|
89
|
+
alias_method :map, :fmap
|
90
|
+
|
67
91
|
# Is this wrapped value equal to the given wrapped value? All blank values
|
68
92
|
# are equal to each other.
|
69
93
|
#
|
70
94
|
# > nil.wrapped == nil.wrapped
|
71
95
|
# > 1.wrapped == nil.wrapped
|
72
96
|
def ==(other)
|
73
|
-
other.
|
97
|
+
other.is_a?(Blank)
|
74
98
|
end
|
75
99
|
end
|
data/lib/wrapped/present.rb
CHANGED
@@ -14,12 +14,8 @@ class Present
|
|
14
14
|
#
|
15
15
|
# > w.unwrap_or(0)
|
16
16
|
# > w.unwrap_or("hello") {|s| "Hi, #{s}" }
|
17
|
-
def unwrap_or(
|
18
|
-
|
19
|
-
yield unwrap
|
20
|
-
else
|
21
|
-
unwrap
|
22
|
-
end
|
17
|
+
def unwrap_or(_default = nil)
|
18
|
+
unwrap
|
23
19
|
end
|
24
20
|
|
25
21
|
# Invoke the block on the value, unwrapped. This method produces the wrapped
|
@@ -39,7 +35,7 @@ class Present
|
|
39
35
|
self
|
40
36
|
end
|
41
37
|
|
42
|
-
#
|
38
|
+
# Produces itself.
|
43
39
|
#
|
44
40
|
# If a block is passed, it is run against the unwrapped value.
|
45
41
|
#
|
@@ -48,7 +44,27 @@ class Present
|
|
48
44
|
# > w.each {|n| puts "Found #{n}" }
|
49
45
|
def each
|
50
46
|
yield unwrap if block_given?
|
51
|
-
|
47
|
+
self
|
48
|
+
end
|
49
|
+
|
50
|
+
# Produces itself if the block evaluates to true. Produces Blank if the block
|
51
|
+
# evaluates to false.
|
52
|
+
def select
|
53
|
+
super.first.wrapped
|
54
|
+
end
|
55
|
+
|
56
|
+
alias_method :find_all, :select
|
57
|
+
|
58
|
+
# Produces itself if the block evaluates to false. Produces Blank if the block
|
59
|
+
# evaluates to true.
|
60
|
+
def reject
|
61
|
+
super.first.wrapped
|
62
|
+
end
|
63
|
+
|
64
|
+
# Produces itself if the unwrapped value matches the given expression.
|
65
|
+
# Produces Blank otherwise.
|
66
|
+
def grep(*)
|
67
|
+
super.first.wrapped
|
52
68
|
end
|
53
69
|
|
54
70
|
# The raw value. I doubt you need this method.
|
@@ -84,14 +100,17 @@ class Present
|
|
84
100
|
#
|
85
101
|
# This makes it a functor.
|
86
102
|
def fmap
|
87
|
-
(yield unwrap)
|
103
|
+
Present.new(yield unwrap)
|
88
104
|
end
|
89
105
|
|
106
|
+
alias_method :collect, :fmap
|
107
|
+
alias_method :map, :fmap
|
108
|
+
|
90
109
|
# Is this wrapped value equal to the given wrapped value?
|
91
110
|
#
|
92
111
|
# > 1.wrapped == 1.wrapped
|
93
112
|
# > nil.wrapped == 2.wrapped
|
94
113
|
def ==(other)
|
95
|
-
unwrap == other.unwrap_or(nil)
|
114
|
+
other.is_a?(Present) && unwrap == other.unwrap_or(nil)
|
96
115
|
end
|
97
116
|
end
|
data/lib/wrapped/version.rb
CHANGED
data/spec/spec_helper.rb
CHANGED
data/spec/wrapped_spec.rb
CHANGED
@@ -8,16 +8,16 @@ describe Wrapped, 'conversion' do
|
|
8
8
|
let(:delegator) { SimpleDelegator.new(value).wrapped }
|
9
9
|
|
10
10
|
it "converts the value to a Present" do
|
11
|
-
just.
|
11
|
+
expect(just).to be_instance_of(Present)
|
12
12
|
end
|
13
13
|
|
14
14
|
it "converts the nil to a Blank" do
|
15
|
-
nothing.
|
15
|
+
expect(nothing).to be_instance_of(Blank)
|
16
16
|
end
|
17
17
|
|
18
18
|
it "converts a simple delegator to a Present" do
|
19
|
-
delegator.
|
20
|
-
delegator.unwrap.
|
19
|
+
expect(delegator).to be_instance_of(Present)
|
20
|
+
expect(delegator.unwrap).to be_instance_of(SimpleDelegator)
|
21
21
|
end
|
22
22
|
end
|
23
23
|
|
@@ -27,7 +27,7 @@ describe Wrapped, 'accessing' do
|
|
27
27
|
let(:nothing) { nil.wrapped }
|
28
28
|
|
29
29
|
it 'produces the value of the wrapped object' do
|
30
|
-
just.unwrap.
|
30
|
+
expect(just.unwrap).to eq(value)
|
31
31
|
end
|
32
32
|
|
33
33
|
it 'raises an exception when called on the wrapped nil' do
|
@@ -43,44 +43,41 @@ describe Wrapped, 'callbacks' do
|
|
43
43
|
it 'calls the proper callback for a wrapped value' do
|
44
44
|
result = false
|
45
45
|
just.present {|v| result = v}
|
46
|
-
result.
|
46
|
+
expect(result).to be_truthy
|
47
47
|
end
|
48
48
|
|
49
49
|
it 'calls the proper callback for a wrapped nil' do
|
50
50
|
result = false
|
51
51
|
nothing.blank {result = true}
|
52
|
-
result.
|
52
|
+
expect(result).to be_truthy
|
53
53
|
end
|
54
54
|
|
55
55
|
it 'ignores the other callback for a wrapped value' do
|
56
56
|
result = true
|
57
57
|
just.blank { result = false }
|
58
|
-
result.
|
58
|
+
expect(result).to be_truthy
|
59
59
|
end
|
60
60
|
|
61
61
|
|
62
62
|
it 'ignores the other callback for a wrapped nil' do
|
63
63
|
result = true
|
64
64
|
nothing.present { result = false }
|
65
|
-
result.
|
65
|
+
expect(result).to be_truthy
|
66
66
|
end
|
67
67
|
|
68
68
|
it 'chains for wrapped values' do
|
69
69
|
result = false
|
70
70
|
just.present { result = true }.blank { result = false }
|
71
|
-
result.
|
71
|
+
expect(result).to be_truthy
|
72
72
|
end
|
73
73
|
|
74
74
|
it 'chains for wrapped nils' do
|
75
75
|
result = false
|
76
76
|
nothing.present { result = false }.blank { result = true }
|
77
|
-
result.
|
77
|
+
expect(result).to be_truthy
|
78
78
|
end
|
79
79
|
end
|
80
80
|
|
81
|
-
# This behavior is different from Haskell and Scala.
|
82
|
-
# It is done this way for consistency with Ruby.
|
83
|
-
# See the functor description later for `fmap'.
|
84
81
|
describe Wrapped, 'enumerable' do
|
85
82
|
let(:value) { 1 }
|
86
83
|
let(:just) { 1.wrapped }
|
@@ -89,29 +86,75 @@ describe Wrapped, 'enumerable' do
|
|
89
86
|
it 'acts over the value for #each on a wrapped value' do
|
90
87
|
result = -1
|
91
88
|
just.each {|v| result = v }
|
92
|
-
result.
|
89
|
+
expect(result).to eq(value)
|
93
90
|
end
|
94
91
|
|
95
|
-
it 'produces
|
96
|
-
just.each.
|
92
|
+
it 'produces itself for #each' do
|
93
|
+
expect(just.each).to eq(just)
|
97
94
|
end
|
98
95
|
|
99
96
|
it 'skips the block for #each on a wrapped nil' do
|
100
97
|
result = -1
|
101
98
|
nothing.each {|v| result = v }
|
102
|
-
result.
|
99
|
+
expect(result).to eq(-1)
|
103
100
|
end
|
104
101
|
|
105
|
-
it 'produces
|
106
|
-
nothing.each.
|
102
|
+
it 'produces blank for a wrapped nil on #each' do
|
103
|
+
expect(nothing.each).to eq(nothing)
|
107
104
|
end
|
108
105
|
|
109
106
|
it 'maps over the value for a wrapped value' do
|
110
|
-
just.map {|n| n + 1}.
|
107
|
+
expect(just.map {|n| n + 1}).to eq((value+1).wrapped)
|
111
108
|
end
|
112
109
|
|
113
|
-
it 'map produces
|
114
|
-
nothing.map {|n| n + 1}.
|
110
|
+
it 'map produces blank' do
|
111
|
+
expect(nothing.map {|n| n + 1}).to be_instance_of(Blank)
|
112
|
+
end
|
113
|
+
|
114
|
+
it 'aliases map to collect' do
|
115
|
+
expect(just.method(:collect)).to be_alias_of(just.method(:map))
|
116
|
+
expect(nothing.method(:collect)).to be_alias_of(nothing.method(:map))
|
117
|
+
end
|
118
|
+
|
119
|
+
it 'select produces present for a value matching the block' do
|
120
|
+
expect(just.select { |n| n == value }).to eq(just)
|
121
|
+
end
|
122
|
+
|
123
|
+
it 'select produces blank for a value that does not match the block' do
|
124
|
+
expect(just.select { |n| n != value }).to be_instance_of(Blank)
|
125
|
+
end
|
126
|
+
|
127
|
+
it 'select products blank for a blank' do
|
128
|
+
expect(nothing.select { true }).to be_instance_of(Blank)
|
129
|
+
end
|
130
|
+
|
131
|
+
it 'aliases select to find_all' do
|
132
|
+
expect(just.method(:find_all)).to be_alias_of(just.method(:select))
|
133
|
+
expect(nothing.method(:find_all)).to be_alias_of(nothing.method(:select))
|
134
|
+
end
|
135
|
+
|
136
|
+
it 'reject produces present for a value matching the block' do
|
137
|
+
expect(just.reject { |n| n != value }).to eq(just)
|
138
|
+
end
|
139
|
+
|
140
|
+
it 'reject produces blank for a value that does not match the block' do
|
141
|
+
expect(just.reject { |n| n == value }).to be_instance_of(Blank)
|
142
|
+
end
|
143
|
+
|
144
|
+
it 'reject products blank for a blank' do
|
145
|
+
expect(nothing.reject { true }).to be_instance_of(Blank)
|
146
|
+
end
|
147
|
+
|
148
|
+
it 'grep produces present for a value matching the pattern' do
|
149
|
+
expect("hello".wrapped.grep(/ello$/)).to eq("hello".wrapped)
|
150
|
+
end
|
151
|
+
|
152
|
+
it 'grep produces blank for a value that does not match the pattern' do
|
153
|
+
expect("hello".wrapped.grep(/^ello/)).to be_instance_of(Blank)
|
154
|
+
end
|
155
|
+
|
156
|
+
it 'grep products blank for a blank' do
|
157
|
+
expect(nothing.grep(/.*/)).to be_instance_of(Blank)
|
115
158
|
end
|
116
159
|
end
|
117
160
|
|
@@ -121,13 +164,13 @@ describe Wrapped, 'queries' do
|
|
121
164
|
let(:nothing) { nil.wrapped }
|
122
165
|
|
123
166
|
it 'knows whether it is present' do
|
124
|
-
just.
|
125
|
-
nothing.
|
167
|
+
expect(just).to be_present
|
168
|
+
expect(nothing).not_to be_present
|
126
169
|
end
|
127
170
|
|
128
171
|
it 'knows whether it is blank' do
|
129
|
-
just.
|
130
|
-
nothing.
|
172
|
+
expect(just).not_to be_blank
|
173
|
+
expect(nothing).to be_blank
|
131
174
|
end
|
132
175
|
end
|
133
176
|
|
@@ -136,20 +179,20 @@ describe Wrapped, 'unwrap_or' do
|
|
136
179
|
let(:just) { 1.wrapped }
|
137
180
|
let(:nothing) { nil.wrapped }
|
138
181
|
|
139
|
-
it 'produces the value for a wrapped value' do
|
140
|
-
just.unwrap_or(-1).
|
182
|
+
it 'produces the value for a wrapped value with an argument' do
|
183
|
+
expect(just.unwrap_or(-1)).to eq(value)
|
141
184
|
end
|
142
185
|
|
143
|
-
it 'produces the
|
144
|
-
nothing.unwrap_or(-1).
|
186
|
+
it 'produces the argument for a wrapped nil with an argument' do
|
187
|
+
expect(nothing.unwrap_or(-1)).to eq(-1)
|
145
188
|
end
|
146
189
|
|
147
|
-
it 'produces the value
|
148
|
-
just.unwrap_or
|
190
|
+
it 'produces the value for a wrapped value with a block' do
|
191
|
+
expect(just.unwrap_or { value + 1 }).to eq(value)
|
149
192
|
end
|
150
193
|
|
151
|
-
it 'produces the
|
152
|
-
nothing.unwrap_or
|
194
|
+
it 'produces the block result for a wrapped nil with a block' do
|
195
|
+
expect(nothing.unwrap_or { 2 }).to eq(2)
|
153
196
|
end
|
154
197
|
end
|
155
198
|
|
@@ -159,11 +202,11 @@ describe Wrapped, 'monadic' do
|
|
159
202
|
let(:nothing) { nil.wrapped }
|
160
203
|
|
161
204
|
it 'produces the value from #flat_map for a wrapped value' do
|
162
|
-
just.flat_map {|n| (n+1).wrapped }.unwrap.
|
205
|
+
expect(just.flat_map {|n| (n+1).wrapped }.unwrap).to eq(value+1)
|
163
206
|
end
|
164
207
|
|
165
208
|
it 'produces blank from #flat_map for a wrapped nil' do
|
166
|
-
nothing.flat_map {|n| (n+1).wrapped}.
|
209
|
+
expect(nothing.flat_map {|n| (n+1).wrapped}).to be_blank
|
167
210
|
end
|
168
211
|
end
|
169
212
|
|
@@ -173,32 +216,69 @@ describe Wrapped, 'functor' do
|
|
173
216
|
let(:nothing) { nil.wrapped }
|
174
217
|
|
175
218
|
it 'unwraps, applies the block, then re-wraps for a wrapped value' do
|
176
|
-
just.fmap {|n| n+1}.unwrap.
|
219
|
+
expect(just.fmap {|n| n+1}.unwrap).to eq(value+1)
|
177
220
|
end
|
178
221
|
|
179
222
|
it 'produces the blank for a wrapped nil' do
|
180
|
-
nothing.fmap {|n| n+1}.
|
223
|
+
expect(nothing.fmap {|n| n+1}).to be_blank
|
224
|
+
end
|
225
|
+
|
226
|
+
it 'obeys the functor law: fmap id == id' do
|
227
|
+
expect(fmap(id).(just)).to eq(id.(just))
|
228
|
+
end
|
229
|
+
|
230
|
+
it 'obeys the functor law: fmap (f . g) == fmap f . fmap g' do
|
231
|
+
expect(fmap(compose(null, const(nil))).(just)).
|
232
|
+
to eq(compose(fmap(null), fmap(const(nil))).(just))
|
233
|
+
end
|
234
|
+
|
235
|
+
def fmap(f)
|
236
|
+
lambda { |x| x.fmap(&f) }
|
237
|
+
end
|
238
|
+
|
239
|
+
def const(x)
|
240
|
+
lambda { |_| x }
|
241
|
+
end
|
242
|
+
|
243
|
+
def id
|
244
|
+
lambda { |x| x }
|
245
|
+
end
|
246
|
+
|
247
|
+
def compose(f, g)
|
248
|
+
lambda { |x| f.call(g.call(x)) }
|
249
|
+
end
|
250
|
+
|
251
|
+
def null
|
252
|
+
lambda {|x| x.nil? }
|
181
253
|
end
|
182
254
|
end
|
183
255
|
|
184
256
|
describe Wrapped, 'equality' do
|
185
257
|
it 'is equal with the same wrapped value' do
|
186
|
-
1.wrapped.
|
258
|
+
expect(1.wrapped).to eq(1.wrapped)
|
187
259
|
end
|
188
260
|
|
189
261
|
it 'is not equal with a different wrapped value' do
|
190
|
-
1.wrapped.
|
262
|
+
expect(1.wrapped).not_to eq(2.wrapped)
|
191
263
|
end
|
192
264
|
|
193
265
|
it 'is equal with two wrapped nils' do
|
194
|
-
nil.wrapped.
|
266
|
+
expect(nil.wrapped).to eq(nil.wrapped)
|
195
267
|
end
|
196
268
|
|
197
269
|
it 'is not equal with a wrapped nil and a wrapped value' do
|
198
|
-
nil.wrapped.
|
270
|
+
expect(nil.wrapped).not_to eq(1.wrapped)
|
199
271
|
end
|
200
272
|
|
201
273
|
it 'is not equal with a wrapped value and a wrapped nil' do
|
202
|
-
1.wrapped.
|
274
|
+
expect(1.wrapped).not_to eq(nil.wrapped)
|
275
|
+
end
|
276
|
+
|
277
|
+
it 'is not equal with a present value and un unwrapped value' do
|
278
|
+
expect(1.wrapped).not_to eq(1)
|
279
|
+
end
|
280
|
+
|
281
|
+
it 'is not equal with a blank value and an unwrapped value' do
|
282
|
+
expect(nil.wrapped).not_to eq(1)
|
203
283
|
end
|
204
284
|
end
|
data/wrapped.gemspec
CHANGED
@@ -16,6 +16,6 @@ Gem::Specification.new do |s|
|
|
16
16
|
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
17
17
|
s.require_paths = ["lib"]
|
18
18
|
|
19
|
-
s.add_development_dependency(
|
20
|
-
s.add_development_dependency(
|
19
|
+
s.add_development_dependency("rspec", "~> 3.1.0")
|
20
|
+
s.add_development_dependency("rake")
|
21
21
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: wrapped
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mike Burns
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-11-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rspec
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version:
|
19
|
+
version: 3.1.0
|
20
20
|
type: :development
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version:
|
26
|
+
version: 3.1.0
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: rake
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -83,8 +83,10 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
83
83
|
version: '0'
|
84
84
|
requirements: []
|
85
85
|
rubyforge_project:
|
86
|
-
rubygems_version: 2.
|
86
|
+
rubygems_version: 2.4.2
|
87
87
|
signing_key:
|
88
88
|
specification_version: 4
|
89
89
|
summary: The maybe functor for Ruby
|
90
|
-
test_files:
|
90
|
+
test_files:
|
91
|
+
- spec/spec_helper.rb
|
92
|
+
- spec/wrapped_spec.rb
|