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 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