just_maybe 0.2.2 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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
- A simple implementation of the "Maybe" - "Special Case" pattern.
3
+ An implementation of the "Maybe" pattern.
4
4
 
5
- Maybe provides a generic null object that allows you to defer
6
- the interpretation of what it means to be null until you need
7
- to use the object.
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 application's Gemfile:
14
+ Add this line to your applications Gemfile:
18
15
 
19
- gem "just_maybe", "~> 0.2.1"
16
+ ```ruby
17
+ gem 'just_maybe'
18
+ ```
20
19
 
21
20
  And then execute:
22
21
 
23
- $ bundle
22
+ ```console
23
+ bundle
24
+ ```
24
25
 
25
- ## Background
26
+ Or install it locally with:
26
27
 
27
- I created JustMaybe because I wanted a really simple solution that didn't
28
- introduce any changes on Object and I found this paticular syntax very
29
- readable.
28
+ ```console
29
+ gem install just_maybe
30
+ ```
30
31
 
31
- My paticular use case was for presenter objects that needed to aggregate
32
- lots of information by walking method chains of a supplied objects. In
33
- this sitation the Presenter is aware of the appropriate default value to
34
- use if the reference fails.
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 a instance of Maybe
46
- Maybe(42)
47
- # => #<Maybe:0x000000010e7c88 @value=42>
48
-
49
- # An instance of maybe will pass all valid messages to the underlying value
50
- # and wrap the result in a new instance Maybe
51
- Maybe(42).next
52
- # => <Maybe:0x0000000110b0e8 @value=43>
53
-
54
- # If the Maybe's underlying value doesn't respond to the message it returns
55
- # nil wrapped in a new instance of Maybe
56
- Maybe(42).foo
57
- # => #<Maybe:0x00000001113540 @value=nil>
58
-
59
- # This allows you to make arbitrarily long method chains with no risk of raising
60
- # NoMethodError on a nil object
61
- Maybe(nil).foo.bar.baz
62
- # => #<Maybe:0x00000001120830 @value=nil>
63
-
64
- # Finally Maybe responds to #or_else { ... }. This causes the Maybe to return the
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 special case pattern}
8
- gem.summary = %q{A simple implmenetation of the Maybe special case pattern}
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
@@ -1,3 +1,3 @@
1
1
  module JustMaybe
2
- VERSION = "0.2.2"
2
+ VERSION = "1.0.0"
3
3
  end
data/lib/just_maybe.rb CHANGED
@@ -1 +1,11 @@
1
- require 'just_maybe/maybe'
1
+ require 'just_maybe/just'
2
+ require 'just_maybe/nothing'
3
+
4
+
5
+ def Maybe(object)
6
+ if object.nil?
7
+ Nothing.instance
8
+ else
9
+ Just(object)
10
+ end
11
+ end
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.2.2
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: 2012-06-17 00:00:00.000000000 Z
11
+ date: 2014-08-03 00:00:00.000000000 Z
13
12
  dependencies: []
14
- description: A simple implmenetation of the Maybe special case pattern
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/maybe.rb
27
+ - lib/just_maybe/just.rb
28
+ - lib/just_maybe/nothing.rb
29
29
  - lib/just_maybe/version.rb
30
- - spec/maybe_spec.rb
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: 1.8.19
51
+ rubygems_version: 2.2.2
52
52
  signing_key:
53
- specification_version: 3
54
- summary: A simple implmenetation of the Maybe special case pattern
53
+ specification_version: 4
54
+ summary: A simple implmenetation of the Maybe pattern
55
55
  test_files:
56
- - spec/maybe_spec.rb
56
+ - spec/just_spec.rb
57
+ - spec/nothing_spec.rb
@@ -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