ruby-maybe 0.1.1 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +5 -0
- data/LICENSE.md +7 -0
- data/README.md +38 -2
- data/lib/ruby-maybe.rb +18 -11
- data/ruby-maybe.gemspec +3 -2
- data/spec/ruby-maybe_spec.rb +11 -17
- metadata +7 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c9211030f655e23153727e36d2a68d930b54593e
|
4
|
+
data.tar.gz: 5c6cd1eb7a99765baa024d45de70d928f9ba88c8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 31eafb9088606234257ed2d151cb3f78712f57ddee187b74f58d1a02a8f185a6ea40efd5e37cf07586a51f57e9dcea5fe8c4023af4b297956500ed3f50d950a1
|
7
|
+
data.tar.gz: fbc6e39d5d9cef5c25a515c1a99948b4d1cec192192670ddd60d96a479d0db77dbef4f4dfeb8487b2ce681a88152f2aeb31f522998828026533677e5b11147d0
|
data/.travis.yml
ADDED
data/LICENSE.md
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
The MIT License (MIT) Copyright (c) Callum Stott, http://www.seadowg.com
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
4
|
+
|
5
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
6
|
+
|
7
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
CHANGED
@@ -1,11 +1,13 @@
|
|
1
1
|
# ruby-maybe
|
2
2
|
|
3
|
-
[![Build Status](https://travis-ci.org/
|
3
|
+
[![Build Status](https://travis-ci.org/seadowg/ruby-maybe.png?branch=master)](https://travis-ci.org/seadowg/ruby-maybe)
|
4
4
|
|
5
5
|
![](http://f.cl.ly/items/2o2A3k1N2d3a1b0V3V0T/maybe.png)
|
6
6
|
|
7
7
|
## Description
|
8
8
|
|
9
|
+
### The Basics
|
10
|
+
|
9
11
|
'Maybe' not 'Maeby'. This is an implementation of the 'Maybe' or 'Option' monad similar to that used
|
10
12
|
[Haskell](http://www.haskell.org/haskellwiki/Maybe). Monads provide a
|
11
13
|
safe way to create non deterministic programs (for example, when not all
|
@@ -53,7 +55,41 @@ without having them throw exceptions or simply return `nil`.
|
|
53
55
|
|
54
56
|
`Maybe` is a very basic monad and at first might not seem that powerful
|
55
57
|
but after using it instead of the more verbose control flow it replaces
|
56
|
-
|
58
|
+
you might just learn to love it.
|
59
|
+
|
60
|
+
### Method Lifting
|
61
|
+
|
62
|
+
Ok so using `bind` to operate on Maybe is all well and good, but what if
|
63
|
+
you want to add three Maybe's together:
|
64
|
+
|
65
|
+
x.bind { |x_val|
|
66
|
+
y.bind { |y_val|
|
67
|
+
z.bind { |z_val|
|
68
|
+
Just.new(x + y + z)
|
69
|
+
}
|
70
|
+
}
|
71
|
+
}
|
72
|
+
|
73
|
+
Yeah... I don't think so. In languages like Haskell we can use [Applicative Functors](http://learnyouahaskell.com/functors-applicative-functors-and-monoids)
|
74
|
+
to deal with making expressions like the above less verbose. You can go read about them but that's not really important.
|
75
|
+
With ruby-maybe methods on the contained object in a Maybe can be lifted to operate on the Maybe:
|
76
|
+
|
77
|
+
Just.new(5) + Just.new(6) # => Just.new(11)
|
78
|
+
Just.new("OMG").downcase # => Just.new("omg")
|
79
|
+
Just.new([1,2]).inject(Just.new(0), :+) # => Just.new(3)
|
80
|
+
|
81
|
+
All operations can be lifted like this and you can mix and match actual values and Maybes in the arguments. This also
|
82
|
+
works for Nothing:
|
83
|
+
|
84
|
+
Nothing.new + Just.new(5) # => Nothing.new
|
85
|
+
Just.new(0) * Nothing.new / Just.new(1) # => Nothing.new
|
86
|
+
|
87
|
+
### Extracting Values from a Maybe
|
88
|
+
|
89
|
+
Try not to do this. Please. Monads are best used when we play nice and let the Monad look after our values. Of course,
|
90
|
+
you're thinking "well at some point I have to take it out to write it out or stick it in a web response on something
|
91
|
+
right?". Yes, of course. But its best if these cases have abstractions that can receive monads or are structured as
|
92
|
+
Monads themselves (some languages like Haskell include Monads for IO, Web request processing [etc](http://learnyouahaskell.com/a-fistful-of-monads)).
|
57
93
|
|
58
94
|
## Installation
|
59
95
|
|
data/lib/ruby-maybe.rb
CHANGED
@@ -1,17 +1,10 @@
|
|
1
1
|
class Maybe
|
2
|
-
def method_missing(method_name, *args, &block)
|
3
|
-
Maybe.new
|
4
|
-
end
|
5
|
-
|
6
|
-
def bind(&block)
|
7
|
-
Maybe.new
|
8
|
-
end
|
9
2
|
end
|
10
3
|
|
11
4
|
class Just < Maybe
|
12
5
|
def method_missing(method_name, *args, &block)
|
13
6
|
values = args.map { |arg|
|
14
|
-
|
7
|
+
return Nothing.new if arg == Nothing.new
|
15
8
|
arg.kind_of?(Just) ? arg.value : arg
|
16
9
|
}
|
17
10
|
|
@@ -23,9 +16,9 @@ class Just < Maybe
|
|
23
16
|
end
|
24
17
|
|
25
18
|
def bind(&block)
|
26
|
-
|
27
|
-
warn("Not returning a Maybe from #bind is really bad form...") unless
|
28
|
-
|
19
|
+
computed = block.call(@value)
|
20
|
+
warn("Not returning a Maybe from #bind is really bad form...") unless computed.kind_of?(Maybe)
|
21
|
+
computed
|
29
22
|
end
|
30
23
|
|
31
24
|
def ==(object)
|
@@ -36,6 +29,10 @@ class Just < Maybe
|
|
36
29
|
end
|
37
30
|
end
|
38
31
|
|
32
|
+
def _extract!
|
33
|
+
value
|
34
|
+
end
|
35
|
+
|
39
36
|
protected
|
40
37
|
|
41
38
|
def value
|
@@ -59,4 +56,14 @@ class Nothing < Maybe
|
|
59
56
|
false
|
60
57
|
end
|
61
58
|
end
|
59
|
+
|
60
|
+
def _extract!
|
61
|
+
raise AttemptedExtract.new
|
62
|
+
end
|
63
|
+
|
64
|
+
class AttemptedExtract < Exception
|
65
|
+
def initialize
|
66
|
+
super("Attempted to extract value from Nothing")
|
67
|
+
end
|
68
|
+
end
|
62
69
|
end
|
data/ruby-maybe.gemspec
CHANGED
@@ -3,11 +3,12 @@ $:.unshift lib unless $:.include?(lib)
|
|
3
3
|
|
4
4
|
Gem::Specification.new do |s|
|
5
5
|
s.name = "ruby-maybe"
|
6
|
-
s.version = "0.
|
6
|
+
s.version = "0.2.0"
|
7
7
|
s.platform = Gem::Platform::RUBY
|
8
8
|
s.authors = ["Callum Stott"]
|
9
|
-
s.email = ["callum
|
9
|
+
s.email = ["callum@seadowg"]
|
10
10
|
s.summary = "Maybe monad implementation for Ruby"
|
11
|
+
s.license = 'MIT'
|
11
12
|
|
12
13
|
s.require_paths = ['lib']
|
13
14
|
s.files = `git ls-files`.split("\n")
|
data/spec/ruby-maybe_spec.rb
CHANGED
@@ -41,6 +41,12 @@ describe "Just" do
|
|
41
41
|
count.must_equal(10)
|
42
42
|
end
|
43
43
|
end
|
44
|
+
|
45
|
+
describe "#_extract!" do
|
46
|
+
it "returns the contained value" do
|
47
|
+
Just.new(5)._extract!.must_equal(5)
|
48
|
+
end
|
49
|
+
end
|
44
50
|
end
|
45
51
|
|
46
52
|
describe "Nothing" do
|
@@ -71,24 +77,12 @@ describe "Nothing" do
|
|
71
77
|
Nothing.new.missing.must_equal(Nothing.new)
|
72
78
|
end
|
73
79
|
end
|
74
|
-
end
|
75
|
-
|
76
|
-
describe "Maybe" do
|
77
|
-
describe "#bind" do
|
78
|
-
it "does not execute the passed block" do
|
79
|
-
executed = false
|
80
|
-
Maybe.new.bind { |val| executed = true }
|
81
|
-
executed.must_equal false
|
82
|
-
end
|
83
|
-
|
84
|
-
it "returns a Maybe" do
|
85
|
-
Maybe.new.bind { |val| val }.kind_of?(Maybe).must_equal true
|
86
|
-
end
|
87
|
-
end
|
88
80
|
|
89
|
-
describe "
|
90
|
-
it "
|
91
|
-
|
81
|
+
describe "#_extract!" do
|
82
|
+
it "raises an exception" do
|
83
|
+
assert_raises(Nothing::AttemptedExtract) {
|
84
|
+
Nothing.new._extract!
|
85
|
+
}
|
92
86
|
end
|
93
87
|
end
|
94
88
|
end
|
metadata
CHANGED
@@ -1,32 +1,35 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ruby-maybe
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Callum Stott
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-
|
11
|
+
date: 2013-05-31 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description:
|
14
14
|
email:
|
15
|
-
- callum
|
15
|
+
- callum@seadowg
|
16
16
|
executables: []
|
17
17
|
extensions: []
|
18
18
|
extra_rdoc_files: []
|
19
19
|
files:
|
20
20
|
- .gitignore
|
21
|
+
- .travis.yml
|
21
22
|
- Gemfile
|
22
23
|
- Gemfile.lock
|
24
|
+
- LICENSE.md
|
23
25
|
- README.md
|
24
26
|
- Rakefile
|
25
27
|
- lib/ruby-maybe.rb
|
26
28
|
- ruby-maybe.gemspec
|
27
29
|
- spec/ruby-maybe_spec.rb
|
28
30
|
homepage:
|
29
|
-
licenses:
|
31
|
+
licenses:
|
32
|
+
- MIT
|
30
33
|
metadata: {}
|
31
34
|
post_install_message:
|
32
35
|
rdoc_options: []
|