just_maybe 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.
- data/.gitignore +18 -0
- data/Gemfile +8 -0
- data/LICENSE +22 -0
- data/README.md +73 -0
- data/Rakefile +11 -0
- data/just_maybe.gemspec +17 -0
- data/lib/just_maybe/maybe.rb +72 -0
- data/lib/just_maybe/version.rb +3 -0
- data/lib/just_maybe.rb +1 -0
- data/spec/maybe_spec.rb +26 -0
- metadata +56 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2012 Michael Greenly
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
# JustMaybe
|
2
|
+
|
3
|
+
A simple implementation of the "Maybe" special case pattern. It allows
|
4
|
+
you to safely chain any number of method calls on an object before fetching
|
5
|
+
the underlying result or a default value.
|
6
|
+
|
7
|
+
```ruby
|
8
|
+
Maybe(nil).foo.bar.or_else { 'default result' }
|
9
|
+
```
|
10
|
+
## Installation
|
11
|
+
|
12
|
+
Add this line to your application's Gemfile:
|
13
|
+
|
14
|
+
gem 'just_maybe', :git => "git://github.com/mgreenly/justmaybe.git"
|
15
|
+
|
16
|
+
And then execute:
|
17
|
+
|
18
|
+
$ bundle
|
19
|
+
|
20
|
+
## Background
|
21
|
+
|
22
|
+
I created JustMaybe because I wanted a really simple solution that didn't
|
23
|
+
introduce any changes to Object.
|
24
|
+
|
25
|
+
My paticular use case was in Presenter objects that needed to collect
|
26
|
+
information from the heirarchy of thier children for display. In this
|
27
|
+
use case the Presenter always knows what it wants, where it's at, and
|
28
|
+
what it should use as an alternative if it's not available.
|
29
|
+
|
30
|
+
## Examples
|
31
|
+
|
32
|
+
```ruby
|
33
|
+
# Objects wrapped in maybe accept any message and return the result wrapped in maybe
|
34
|
+
Maybe(42) * -1 # => Maybe(-42)
|
35
|
+
|
36
|
+
# If the Maybe's underlying value doesn't respond to the message it returns Maybe(nil)
|
37
|
+
Maybe(42).foo # => Maybe(nil)
|
38
|
+
|
39
|
+
# This allows you to use arbitrarily long method chains with no risk of raising
|
40
|
+
# NoMethodError on a nil object
|
41
|
+
Maybe(nil).foo.bar.baz # => Maybe(nil)
|
42
|
+
|
43
|
+
# Finally Maybe responds to #or_else { ... }. This causes the Maybe to return the
|
44
|
+
# underlying value if it exists or the result of the block if it does not.
|
45
|
+
Maybe([]).append('foo').append('bar').join(' ').or_else { 'baz' } # => "foo bar"
|
46
|
+
Maybe(nil).append('foo').append('bar').join(' ').or_else { 'baz' } # => "baz"
|
47
|
+
|
48
|
+
# There are a number of convenience methods that operate like or_else for common null values
|
49
|
+
Maybe(nil).foo.bar.or_a # => []
|
50
|
+
Maybe(nil).foo.bar.or_f # => 0.0
|
51
|
+
Maybe(nil).foo.bar.or_h # => {}
|
52
|
+
Maybe(nil).foo.bar.or_nil # => nil
|
53
|
+
Maybe(nil).foo.bar.or_s # => ''
|
54
|
+
|
55
|
+
# Remember if you don't call or_else or one of it's alternatives you will get back
|
56
|
+
# an instance of Maybe. It is possible to get the underlying value back by calling
|
57
|
+
# __value__ but I'd generally consider using this a code smell.
|
58
|
+
Maybe(42).__value__ # => 42
|
59
|
+
Maybe(42).foo.bar.baz.__value__ # => nil
|
60
|
+
```
|
61
|
+
|
62
|
+
## Related
|
63
|
+
* [Virtuous Code](http://devblog.avdi.org/2011/05/30/null-objects-and-falsiness/)
|
64
|
+
* [mondadic](https://github.com/pzol/monadic)
|
65
|
+
* [rumonade](https://github.com/ms-ati/rumonade)
|
66
|
+
|
67
|
+
## Contributing
|
68
|
+
|
69
|
+
1. Fork it
|
70
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
71
|
+
3. Commit your changes (`git commit -am 'Added some feature'`)
|
72
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
73
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
#!/usr/bin/env rake
|
2
|
+
require 'rspec'
|
3
|
+
require 'rspec/core/rake_task'
|
4
|
+
require "bundler/gem_tasks"
|
5
|
+
|
6
|
+
task :default => :spec
|
7
|
+
|
8
|
+
desc "Run unit specs"
|
9
|
+
RSpec::Core::RakeTask.new(:spec) do |task|
|
10
|
+
task.rspec_opts = %W[--format documentation --color]
|
11
|
+
end
|
data/just_maybe.gemspec
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/just_maybe/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |gem|
|
5
|
+
gem.authors = ["Michael Greenly"]
|
6
|
+
gem.email = ["mgreenly@gmail.com"]
|
7
|
+
gem.description = %q{A simple implmenetation of the Maybe special case pattern}
|
8
|
+
gem.summary = %q{A simple implmenetation of the Maybe special case pattern}
|
9
|
+
gem.homepage = "https://github.com/mgreenly/just_maybe"
|
10
|
+
|
11
|
+
gem.files = `git ls-files`.split($\)
|
12
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
13
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
14
|
+
gem.name = "just_maybe"
|
15
|
+
gem.require_paths = ["lib"]
|
16
|
+
gem.version = JustMaybe::VERSION
|
17
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
def Maybe(object)
|
2
|
+
Maybe.new(object)
|
3
|
+
end
|
4
|
+
|
5
|
+
class Maybe
|
6
|
+
def initialize(object)
|
7
|
+
if object.kind_of?(Maybe)
|
8
|
+
@value = object.__value__
|
9
|
+
else
|
10
|
+
@value = object
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def __value__
|
15
|
+
@value
|
16
|
+
end
|
17
|
+
|
18
|
+
def inspect
|
19
|
+
'#<%s:0x%0.14x> @value=%s' % [self.class, object_id * 2, @value.inspect]
|
20
|
+
end
|
21
|
+
|
22
|
+
def method_missing(method, *args)
|
23
|
+
if @value.respond_to?(method)
|
24
|
+
Maybe(@value.__send__(method, *args))
|
25
|
+
else
|
26
|
+
Maybe(nil)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def or_a
|
31
|
+
return @value unless @value.nil?
|
32
|
+
[]
|
33
|
+
end
|
34
|
+
|
35
|
+
def or_else(&block)
|
36
|
+
return @value unless @value.nil?
|
37
|
+
yield
|
38
|
+
end
|
39
|
+
|
40
|
+
def or_f
|
41
|
+
return @value unless @value.nil?
|
42
|
+
0.0
|
43
|
+
end
|
44
|
+
|
45
|
+
def or_h
|
46
|
+
return @value unless @value.nil?
|
47
|
+
{}
|
48
|
+
end
|
49
|
+
|
50
|
+
def or_i
|
51
|
+
return @value unless @value.nil?
|
52
|
+
0
|
53
|
+
end
|
54
|
+
|
55
|
+
def or_nil
|
56
|
+
return @value unless @value.nil?
|
57
|
+
nil
|
58
|
+
end
|
59
|
+
|
60
|
+
def or_s
|
61
|
+
return @value unless @value.nil?
|
62
|
+
''
|
63
|
+
end
|
64
|
+
|
65
|
+
def ==(other)
|
66
|
+
if other.kind_of?(Maybe)
|
67
|
+
@value == other.__value__
|
68
|
+
else
|
69
|
+
@value == other
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
data/lib/just_maybe.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'just_maybe/maybe'
|
data/spec/maybe_spec.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'just_maybe/maybe'
|
2
|
+
|
3
|
+
describe Maybe do
|
4
|
+
let(:object) { double }
|
5
|
+
|
6
|
+
it "value returns wrapped object" do
|
7
|
+
Maybe(object).__value__.should == object
|
8
|
+
end
|
9
|
+
|
10
|
+
it "return values for methods handled by underlying value are wrapped in new Maybe" do
|
11
|
+
object.stub(:some_method).and_return('this object')
|
12
|
+
Maybe(object).some_method.__value__.should == 'this object'
|
13
|
+
end
|
14
|
+
|
15
|
+
it "calling a method that does not exist returns Maybe(nil)" do
|
16
|
+
Maybe(object).method_that_does_not_exist.should == Maybe(nil)
|
17
|
+
end
|
18
|
+
|
19
|
+
it "#or_else returns object when object is not nil" do
|
20
|
+
Maybe(object).or_else{'unexpected result'}.should == object
|
21
|
+
end
|
22
|
+
|
23
|
+
it "#or_else returns default when object is nil" do
|
24
|
+
Maybe(nil).or_else{'expected result'}.should == 'expected result'
|
25
|
+
end
|
26
|
+
end
|
metadata
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: just_maybe
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Michael Greenly
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-06-16 00:00:00.000000000 Z
|
13
|
+
dependencies: []
|
14
|
+
description: A simple implmenetation of the Maybe special case pattern
|
15
|
+
email:
|
16
|
+
- mgreenly@gmail.com
|
17
|
+
executables: []
|
18
|
+
extensions: []
|
19
|
+
extra_rdoc_files: []
|
20
|
+
files:
|
21
|
+
- .gitignore
|
22
|
+
- Gemfile
|
23
|
+
- LICENSE
|
24
|
+
- README.md
|
25
|
+
- Rakefile
|
26
|
+
- just_maybe.gemspec
|
27
|
+
- lib/just_maybe.rb
|
28
|
+
- lib/just_maybe/maybe.rb
|
29
|
+
- lib/just_maybe/version.rb
|
30
|
+
- spec/maybe_spec.rb
|
31
|
+
homepage: https://github.com/mgreenly/just_maybe
|
32
|
+
licenses: []
|
33
|
+
post_install_message:
|
34
|
+
rdoc_options: []
|
35
|
+
require_paths:
|
36
|
+
- lib
|
37
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
38
|
+
none: false
|
39
|
+
requirements:
|
40
|
+
- - ! '>='
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: '0'
|
43
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
44
|
+
none: false
|
45
|
+
requirements:
|
46
|
+
- - ! '>='
|
47
|
+
- !ruby/object:Gem::Version
|
48
|
+
version: '0'
|
49
|
+
requirements: []
|
50
|
+
rubyforge_project:
|
51
|
+
rubygems_version: 1.8.19
|
52
|
+
signing_key:
|
53
|
+
specification_version: 3
|
54
|
+
summary: A simple implmenetation of the Maybe special case pattern
|
55
|
+
test_files:
|
56
|
+
- spec/maybe_spec.rb
|