just_maybe 0.2.2 → 1.0.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 +7 -0
- data/README.md +50 -64
- data/just_maybe.gemspec +2 -2
- data/lib/just_maybe/just.rb +25 -0
- data/lib/just_maybe/nothing.rb +27 -0
- data/lib/just_maybe/version.rb +1 -1
- data/lib/just_maybe.rb +11 -1
- data/spec/just_spec.rb +22 -0
- data/spec/nothing_spec.rb +17 -0
- metadata +16 -15
- data/lib/just_maybe/maybe.rb +0 -61
- data/spec/maybe_spec.rb +0 -90
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA1:
|
|
3
|
+
metadata.gz: d2d252ffb42e2b682f5a18422cabec3209753c1a
|
|
4
|
+
data.tar.gz: ab0e342a64665b8964da74aa3dd8fec43dd2507e
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 715a90005076e8bfb1d5f886041bb67763da284ea2a882f6d26bceee852ce9d7cbe9e9ddbd65452cc9b9f9b4ced31627e20d036be0cb41ba9f2c1b92aaeb54cf
|
|
7
|
+
data.tar.gz: a024ad10967d3734eb8029e68d0d216b0c18c2606d7b48b3b6f6d0b5f0c1e50282b53168ecba1f101dd0f91ea1b92723deb8288622db9dae76d79c509fe223c3
|
data/README.md
CHANGED
|
@@ -1,88 +1,74 @@
|
|
|
1
1
|
# JustMaybe
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
An implementation of the "Maybe" pattern.
|
|
4
4
|
|
|
5
|
-
Maybe
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
The philosophy of this particular implementation of the Maybe pattern is that you should use the `Maybe` function to wrap values before returning them from any method that could potentially return nil. This forces the consumer of the returned object to pro-actively acknowledge that it could be nil by forcing them to use the `try` method to access it.
|
|
6
|
+
|
|
7
|
+
This implementation also does no monkey patching and does not rely on method missing or any other Ruby magic for it's implementation.
|
|
8
|
+
|
|
9
|
+
It also has a tiny API. Maybe objects respond to `nothing?`, `something?`, and `try`.
|
|
8
10
|
|
|
9
|
-
Specifically they allow you to safely chain any number of method
|
|
10
|
-
calls on an object before returning it or a default value.
|
|
11
11
|
|
|
12
|
-
```ruby
|
|
13
|
-
Maybe(nil).foo.bar.or_else { 'default' }
|
|
14
|
-
```
|
|
15
12
|
## Installation
|
|
16
13
|
|
|
17
|
-
Add this line to your
|
|
14
|
+
Add this line to your applications Gemfile:
|
|
18
15
|
|
|
19
|
-
|
|
16
|
+
```ruby
|
|
17
|
+
gem 'just_maybe'
|
|
18
|
+
```
|
|
20
19
|
|
|
21
20
|
And then execute:
|
|
22
21
|
|
|
23
|
-
|
|
22
|
+
```console
|
|
23
|
+
bundle
|
|
24
|
+
```
|
|
24
25
|
|
|
25
|
-
|
|
26
|
+
Or install it locally with:
|
|
26
27
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
28
|
+
```console
|
|
29
|
+
gem install just_maybe
|
|
30
|
+
```
|
|
30
31
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
32
|
+
Then load it using:
|
|
33
|
+
|
|
34
|
+
```ruby
|
|
35
|
+
require 'just_maybe'
|
|
36
|
+
```
|
|
35
37
|
|
|
36
|
-
Using Maybe allows me to get the benefit of null objects without having
|
|
37
|
-
to modify the underlying code.
|
|
38
38
|
|
|
39
39
|
## Examples
|
|
40
40
|
|
|
41
41
|
```ruby
|
|
42
42
|
require 'just_maybe'
|
|
43
|
-
# => true
|
|
44
|
-
|
|
45
|
-
# Calling Maybe(object) returns that object wrapped in
|
|
46
|
-
Maybe(
|
|
47
|
-
# =>
|
|
48
|
-
|
|
49
|
-
#
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
#
|
|
55
|
-
#
|
|
56
|
-
Maybe(
|
|
57
|
-
# =>
|
|
58
|
-
|
|
59
|
-
#
|
|
60
|
-
#
|
|
61
|
-
Maybe(
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
# underlying value if it exists or the result of the block if it does not.
|
|
66
|
-
Maybe('FOO').downcase.or_else { 'unknown' }
|
|
67
|
-
# => "foo"
|
|
68
|
-
Maybe(nil).downcase.or_else { 'unknown' }
|
|
69
|
-
# => "unknown"
|
|
70
|
-
|
|
71
|
-
# There are a number of convenience methods that operate like or_else for common null values
|
|
72
|
-
Maybe(nil).foo.bar.or_a # => []
|
|
73
|
-
Maybe(nil).foo.bar.or_f # => 0.0
|
|
74
|
-
Maybe(nil).foo.bar.or_h # => {}
|
|
75
|
-
Maybe(nil).foo.bar.or_nil # => nil
|
|
76
|
-
Maybe(nil).foo.bar.or_s # => ''
|
|
77
|
-
|
|
78
|
-
# Remember if you don't call or_else or one of it's alternatives you will get back
|
|
79
|
-
# an instance of Maybe. It is possible to get the underlying value back by calling
|
|
80
|
-
# __object__ but I'd generally consider using this a code smell.
|
|
81
|
-
Maybe(42).__object__
|
|
82
|
-
# => 42
|
|
83
|
-
Maybe(42).foo.bar.baz.__object__
|
|
84
|
-
# => nil
|
|
43
|
+
# => true
|
|
44
|
+
|
|
45
|
+
# Calling Maybe(object) returns that object wrapped in an instance of Just
|
|
46
|
+
Maybe('anything')
|
|
47
|
+
# => <Just:0x000000020e04f0 @object="anything">
|
|
48
|
+
|
|
49
|
+
# Calling Maybe(nil) returns an instance of Nothing
|
|
50
|
+
Maybe(nothing)
|
|
51
|
+
# => <Nothing:0x000000020b1718>
|
|
52
|
+
|
|
53
|
+
# Instances of Just and Nothing respond to the replicate methods nothing? and something?
|
|
54
|
+
Maybe(42).nothing? # => false
|
|
55
|
+
Maybe(42).something? # => true
|
|
56
|
+
Maybe(nil).nothing? # => true
|
|
57
|
+
Maybe(nil).something? # => false
|
|
58
|
+
|
|
59
|
+
# When try is called on instances of Just it passes the underlying object to the block
|
|
60
|
+
# and returns the result of the block.
|
|
61
|
+
Maybe(40).try{|m| m.succ.succ } # => 42
|
|
62
|
+
|
|
63
|
+
# When try is called on instances of Nothing it returns nil
|
|
64
|
+
Maybe(nil).try{|m| m.succ.succ } # => nil
|
|
85
65
|
```
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
## Notice
|
|
69
|
+
|
|
70
|
+
The public interace of this gem was radically changed with the jump to version 1.0. If you were using version `0.2` or earlier you should pin the version in your Gemfile at "~> 0.2"
|
|
71
|
+
|
|
86
72
|
## Related
|
|
87
73
|
* [Null Objects and Falsiness](http://devblog.avdi.org/2011/05/30/null-objects-and-falsiness/)
|
|
88
74
|
* [If you gaze into nil, nil gazes also into you](http://robots.thoughtbot.com/post/8181879506/if-you-gaze-into-nil-nil-gazes-also-into-you)
|
data/just_maybe.gemspec
CHANGED
|
@@ -4,8 +4,8 @@ require File.expand_path('../lib/just_maybe/version', __FILE__)
|
|
|
4
4
|
Gem::Specification.new do |gem|
|
|
5
5
|
gem.authors = ["Michael Greenly"]
|
|
6
6
|
gem.email = ["mgreenly@gmail.com"]
|
|
7
|
-
gem.description = %q{A simple implmenetation of the Maybe
|
|
8
|
-
gem.summary = %q{A simple implmenetation of the Maybe
|
|
7
|
+
gem.description = %q{A simple implmenetation of the Maybe pattern}
|
|
8
|
+
gem.summary = %q{A simple implmenetation of the Maybe pattern}
|
|
9
9
|
gem.homepage = "https://github.com/mgreenly/just_maybe"
|
|
10
10
|
|
|
11
11
|
gem.files = `git ls-files`.split($\)
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
class Just
|
|
2
|
+
def initialize(object)
|
|
3
|
+
@object = object
|
|
4
|
+
end
|
|
5
|
+
|
|
6
|
+
def nothing?
|
|
7
|
+
false
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def something?
|
|
11
|
+
true
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def try
|
|
15
|
+
yield @object if block_given?
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def to_s
|
|
19
|
+
"Just: #{@object}"
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def Just(object)
|
|
24
|
+
Just.new(object)
|
|
25
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
require 'singleton'
|
|
2
|
+
|
|
3
|
+
class Nothing
|
|
4
|
+
include Singleton
|
|
5
|
+
|
|
6
|
+
def initialize
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def nothing?
|
|
10
|
+
true
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def something?
|
|
14
|
+
false
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def try
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def to_s
|
|
21
|
+
"Nothing"
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
#def Nothing
|
|
26
|
+
# NothingSingleton.instance
|
|
27
|
+
#end
|
data/lib/just_maybe/version.rb
CHANGED
data/lib/just_maybe.rb
CHANGED
data/spec/just_spec.rb
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
require 'just_maybe/just'
|
|
2
|
+
|
|
3
|
+
describe Just do
|
|
4
|
+
|
|
5
|
+
it "just 'anything' is something" do
|
|
6
|
+
expect(Just('anything')).to be_something
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
it "just 'anything' is not nothing" do
|
|
10
|
+
expect(Just('anything')).not_to be_nothing
|
|
11
|
+
expect(Just(nil)).not_to be_nothing
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
it "just nil is something and not nothing" do
|
|
15
|
+
expect(Just(nil)).to be_something
|
|
16
|
+
expect(Just(nil)).not_to be_nothing
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
it "just 'anything' yields once with 'anything' to try" do
|
|
20
|
+
expect(Just('anything').try{|o| o.reverse }).to eq('gnihtyna')
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
require 'just_maybe/nothing'
|
|
2
|
+
|
|
3
|
+
describe Nothing.instance do
|
|
4
|
+
let(:nothing) { Nothing.instance }
|
|
5
|
+
|
|
6
|
+
it "Nothing is not something" do
|
|
7
|
+
expect(nothing).not_to be_something
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
it "Nothing is nothing" do
|
|
11
|
+
expect(nothing).to be_nothing
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
it "Nothing never yeilds to try" do
|
|
15
|
+
expect{ nothing.try{|n| raise "an error" } }.not_to raise_error
|
|
16
|
+
end
|
|
17
|
+
end
|
metadata
CHANGED
|
@@ -1,56 +1,57 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: just_maybe
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
5
|
-
prerelease:
|
|
4
|
+
version: 1.0.0
|
|
6
5
|
platform: ruby
|
|
7
6
|
authors:
|
|
8
7
|
- Michael Greenly
|
|
9
8
|
autorequire:
|
|
10
9
|
bindir: bin
|
|
11
10
|
cert_chain: []
|
|
12
|
-
date:
|
|
11
|
+
date: 2014-08-03 00:00:00.000000000 Z
|
|
13
12
|
dependencies: []
|
|
14
|
-
description: A simple implmenetation of the Maybe
|
|
13
|
+
description: A simple implmenetation of the Maybe pattern
|
|
15
14
|
email:
|
|
16
15
|
- mgreenly@gmail.com
|
|
17
16
|
executables: []
|
|
18
17
|
extensions: []
|
|
19
18
|
extra_rdoc_files: []
|
|
20
19
|
files:
|
|
21
|
-
- .gitignore
|
|
20
|
+
- ".gitignore"
|
|
22
21
|
- Gemfile
|
|
23
22
|
- LICENSE
|
|
24
23
|
- README.md
|
|
25
24
|
- Rakefile
|
|
26
25
|
- just_maybe.gemspec
|
|
27
26
|
- lib/just_maybe.rb
|
|
28
|
-
- lib/just_maybe/
|
|
27
|
+
- lib/just_maybe/just.rb
|
|
28
|
+
- lib/just_maybe/nothing.rb
|
|
29
29
|
- lib/just_maybe/version.rb
|
|
30
|
-
- spec/
|
|
30
|
+
- spec/just_spec.rb
|
|
31
|
+
- spec/nothing_spec.rb
|
|
31
32
|
homepage: https://github.com/mgreenly/just_maybe
|
|
32
33
|
licenses: []
|
|
34
|
+
metadata: {}
|
|
33
35
|
post_install_message:
|
|
34
36
|
rdoc_options: []
|
|
35
37
|
require_paths:
|
|
36
38
|
- lib
|
|
37
39
|
required_ruby_version: !ruby/object:Gem::Requirement
|
|
38
|
-
none: false
|
|
39
40
|
requirements:
|
|
40
|
-
- -
|
|
41
|
+
- - ">="
|
|
41
42
|
- !ruby/object:Gem::Version
|
|
42
43
|
version: '0'
|
|
43
44
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
44
|
-
none: false
|
|
45
45
|
requirements:
|
|
46
|
-
- -
|
|
46
|
+
- - ">="
|
|
47
47
|
- !ruby/object:Gem::Version
|
|
48
48
|
version: '0'
|
|
49
49
|
requirements: []
|
|
50
50
|
rubyforge_project:
|
|
51
|
-
rubygems_version:
|
|
51
|
+
rubygems_version: 2.2.2
|
|
52
52
|
signing_key:
|
|
53
|
-
specification_version:
|
|
54
|
-
summary: A simple implmenetation of the Maybe
|
|
53
|
+
specification_version: 4
|
|
54
|
+
summary: A simple implmenetation of the Maybe pattern
|
|
55
55
|
test_files:
|
|
56
|
-
- spec/
|
|
56
|
+
- spec/just_spec.rb
|
|
57
|
+
- spec/nothing_spec.rb
|
data/lib/just_maybe/maybe.rb
DELETED
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
class Maybe < BasicObject
|
|
2
|
-
def initialize(object)
|
|
3
|
-
begin
|
|
4
|
-
@object = object.__object__
|
|
5
|
-
rescue
|
|
6
|
-
@object = object
|
|
7
|
-
end
|
|
8
|
-
end
|
|
9
|
-
|
|
10
|
-
def __object__
|
|
11
|
-
@object
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
def inspect
|
|
15
|
-
::Kernel.sprintf('#<Maybe:0x%0.14x @object=%s>', __id__ * 2, @object.inspect)
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
def method_missing(method, *args, &block)
|
|
19
|
-
begin
|
|
20
|
-
::Maybe.new(@object.__send__(method, *args, &block))
|
|
21
|
-
rescue ::NoMethodError
|
|
22
|
-
::Maybe.new(nil)
|
|
23
|
-
end
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
def or_else(&block)
|
|
27
|
-
@object ? @object : yield
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
def or_a
|
|
31
|
-
or_else { [] }
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
def or_f
|
|
35
|
-
or_else { 0.0 }
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
def or_false
|
|
39
|
-
or_else { false }
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
def or_h
|
|
43
|
-
or_else { {} }
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
def or_i
|
|
47
|
-
or_else { 0 }
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
def or_nil
|
|
51
|
-
or_else { nil }
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
def or_s
|
|
55
|
-
or_else { '' }
|
|
56
|
-
end
|
|
57
|
-
end
|
|
58
|
-
|
|
59
|
-
def Maybe(object)
|
|
60
|
-
Maybe.new(object)
|
|
61
|
-
end
|
data/spec/maybe_spec.rb
DELETED
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
require 'just_maybe/maybe'
|
|
2
|
-
|
|
3
|
-
describe Maybe do
|
|
4
|
-
let(:object) { double }
|
|
5
|
-
|
|
6
|
-
before do
|
|
7
|
-
object.stub(:__object__).and_raise(NoMethodError)
|
|
8
|
-
end
|
|
9
|
-
|
|
10
|
-
it "delegates messages to wrapped object" do
|
|
11
|
-
object.should_receive(:foo).with('bar')
|
|
12
|
-
Maybe(object).foo('bar')
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
it "calling methods that don't exist return Maybe(nil)" do
|
|
16
|
-
Maybe(nil).foo.__object__.should be_nil
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
it "it doesn't nest" do
|
|
20
|
-
Maybe(Maybe(nil)).__object__.should_not be_instance_of(Maybe)
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
it "__object__ unwraps the underlying object" do
|
|
24
|
-
Maybe(object).__object__.should be(object)
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
it "#or_else returns the underlying object when it's not nil" do
|
|
28
|
-
Maybe(object).or_else{'unexpected result'}.should == object
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
it "#or_else yields to supplied block when the underlying object is nil" do
|
|
32
|
-
Maybe(nil).or_else{'expected result'}.should == 'expected result'
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
it "#or_a returns the underlying object when it's not nil" do
|
|
36
|
-
Maybe(object).or_a.should be(object)
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
it "#or_a defaults to []" do
|
|
40
|
-
Maybe(nil).or_a.should == []
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
it "#or_f returns the underlying object when it's not nil" do
|
|
44
|
-
Maybe(object).or_f.should be(object)
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
it "#or_f defaults to 0.0" do
|
|
48
|
-
Maybe(nil).or_f.should == 0.0
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
it "#or_false returns the underlying object when it's not nil" do
|
|
52
|
-
Maybe(object).or_false.should be(object)
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
it "#or_false defaults to false" do
|
|
56
|
-
Maybe(nil).or_false.should be(false)
|
|
57
|
-
end
|
|
58
|
-
|
|
59
|
-
it "#or_h returns the underlying object when it's not nil" do
|
|
60
|
-
Maybe(object).or_h.should be(object)
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
it "#or_h defaults to {}" do
|
|
64
|
-
Maybe(nil).or_h.should == {}
|
|
65
|
-
end
|
|
66
|
-
|
|
67
|
-
it "#or_i returns the underlying object when it's not nil" do
|
|
68
|
-
Maybe(object).or_i.should be(object)
|
|
69
|
-
end
|
|
70
|
-
|
|
71
|
-
it "#or_i defaults to 0" do
|
|
72
|
-
Maybe(nil).or_i.should == 0
|
|
73
|
-
end
|
|
74
|
-
|
|
75
|
-
it "#or_nil returns the underlying object when it's not nil" do
|
|
76
|
-
Maybe(object).or_nil.should be(object)
|
|
77
|
-
end
|
|
78
|
-
|
|
79
|
-
it "#or_nil defaults to nil" do
|
|
80
|
-
Maybe(nil).or_nil.should == nil
|
|
81
|
-
end
|
|
82
|
-
|
|
83
|
-
it "#or_s returns the underlying object when it's not nil" do
|
|
84
|
-
Maybe(object).or_s.should be(object)
|
|
85
|
-
end
|
|
86
|
-
|
|
87
|
-
it "#or_s defaults to ''" do
|
|
88
|
-
Maybe(nil).or_s.should == ''
|
|
89
|
-
end
|
|
90
|
-
end
|