just_maybe 0.1.0 → 0.1.1

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/README.md CHANGED
@@ -1,17 +1,22 @@
1
1
  # JustMaybe
2
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.
3
+ A simple implementation of the "Maybe" - "Special Case" pattern.
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.
8
+
9
+ Specifically they allow you to safely chain any number of method
10
+ calls on an object before returning it or a default value.
6
11
 
7
12
  ```ruby
8
- Maybe(nil).foo.bar.or_else { 'default result' }
13
+ Maybe(nil).foo.bar.or_else { 'default' }
9
14
  ```
10
15
  ## Installation
11
16
 
12
17
  Add this line to your application's Gemfile:
13
18
 
14
- gem 'just_maybe', :git => "git://github.com/mgreenly/justmaybe.git"
19
+ gem "just_maybe", "~> 0.1.0"
15
20
 
16
21
  And then execute:
17
22
 
@@ -20,30 +25,48 @@ And then execute:
20
25
  ## Background
21
26
 
22
27
  I created JustMaybe because I wanted a really simple solution that didn't
23
- introduce any changes to Object.
28
+ introduce any changes on Object and I found this paticular syntax very
29
+ readable.
30
+
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.
24
35
 
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.
36
+ Using Maybe allows me to get the benefit of null objects without having
37
+ to modify the underlying code.
29
38
 
30
39
  ## Examples
31
40
 
32
41
  ```ruby
33
- # Objects wrapped in maybe accept any message and return the result wrapped in maybe
34
- Maybe(42) * -1 # => Maybe(-42)
42
+ require 'just_maybe'
43
+ # => true
35
44
 
36
- # If the Maybe's underlying value doesn't respond to the message it returns Maybe(nil)
37
- Maybe(42).foo # => Maybe(nil)
45
+ # Calling Maybe(object) returns that object wrapped in a instance of Maybe
46
+ Maybe(42)
47
+ # => #<Maybe:0x000000010e7c88> @value=42
38
48
 
39
- # This allows you to use arbitrarily long method chains with no risk of raising
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
40
60
  # NoMethodError on a nil object
41
61
  Maybe(nil).foo.bar.baz # => Maybe(nil)
62
+ # => #<Maybe:0x00000001120830> @value=nil
42
63
 
43
64
  # Finally Maybe responds to #or_else { ... }. This causes the Maybe to return the
44
65
  # 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"
66
+ Maybe('FOO').downcase.or_else { 'unknown' }
67
+ # => "foo"
68
+ Maybe(nil).downcase.or_else { 'unknown' }
69
+ # => "unknown"
47
70
 
48
71
  # There are a number of convenience methods that operate like or_else for common null values
49
72
  Maybe(nil).foo.bar.or_a # => []
@@ -58,11 +81,11 @@ Maybe(nil).foo.bar.or_s # => ''
58
81
  Maybe(42).__value__ # => 42
59
82
  Maybe(42).foo.bar.baz.__value__ # => nil
60
83
  ```
61
-
62
84
  ## Related
63
85
  * [Virtuous Code](http://devblog.avdi.org/2011/05/30/null-objects-and-falsiness/)
64
86
  * [mondadic](https://github.com/pzol/monadic)
65
87
  * [rumonade](https://github.com/ms-ati/rumonade)
88
+ * [thoughtbot](http://robots.thoughtbot.com/post/8181879506/if-you-gaze-into-nil-nil-gazes-also-into-you)
66
89
 
67
90
  ## Contributing
68
91
 
@@ -1,72 +1,68 @@
1
- def Maybe(object)
2
- Maybe.new(object)
3
- end
4
-
5
- class Maybe
1
+ class Maybe < BasicObject
6
2
  def initialize(object)
7
- if object.kind_of?(Maybe)
8
- @value = object.__value__
3
+ if object.kind_of?(::Maybe)
4
+ @object = object.__value__
9
5
  else
10
- @value = object
6
+ @object = object
11
7
  end
12
8
  end
13
9
 
10
+ def instance_of?(klass)
11
+ ::Maybe == klass
12
+ end
13
+
14
14
  def __value__
15
- @value
15
+ @object
16
16
  end
17
-
17
+
18
18
  def inspect
19
- '#<%s:0x%0.14x> @value=%s' % [self.class, object_id * 2, @value.inspect]
19
+ ::Kernel.sprintf('#<Maybe:0x%0.14x> @object=%s', __id__ * 2, @object.inspect)
20
20
  end
21
21
 
22
- def method_missing(method, *args)
23
- if @value.respond_to?(method)
24
- Maybe(@value.__send__(method, *args))
25
- else
26
- Maybe(nil)
22
+ def method_missing(method, *args, &block)
23
+ begin
24
+ ::Maybe.new(@object.__send__(method, *args, &block))
25
+ rescue ::NoMethodError
26
+ ::Maybe.new(nil)
27
27
  end
28
28
  end
29
29
 
30
30
  def or_a
31
- return @value unless @value.nil?
31
+ return @object unless @object.nil?
32
32
  []
33
33
  end
34
34
 
35
35
  def or_else(&block)
36
- return @value unless @value.nil?
36
+ return @object unless @object.nil?
37
37
  yield
38
38
  end
39
39
 
40
40
  def or_f
41
- return @value unless @value.nil?
41
+ return @object unless @object.nil?
42
42
  0.0
43
43
  end
44
44
 
45
45
  def or_h
46
- return @value unless @value.nil?
46
+ return @object unless @object.nil?
47
47
  {}
48
48
  end
49
49
 
50
50
  def or_i
51
- return @value unless @value.nil?
51
+ return @object unless @object.nil?
52
52
  0
53
53
  end
54
54
 
55
55
  def or_nil
56
- return @value unless @value.nil?
56
+ return @object unless @object.nil?
57
57
  nil
58
58
  end
59
59
 
60
60
  def or_s
61
- return @value unless @value.nil?
61
+ return @object unless @object.nil?
62
62
  ''
63
63
  end
64
+ end
64
65
 
65
- def ==(other)
66
- if other.kind_of?(Maybe)
67
- @value == other.__value__
68
- else
69
- @value == other
70
- end
71
- end
66
+ def Maybe(object)
67
+ Maybe.new(object)
72
68
  end
@@ -1,3 +1,3 @@
1
1
  module JustMaybe
2
- VERSION = "0.1.0"
2
+ VERSION = "0.1.1"
3
3
  end
data/spec/maybe_spec.rb CHANGED
@@ -3,24 +3,76 @@ require 'just_maybe/maybe'
3
3
  describe Maybe do
4
4
  let(:object) { double }
5
5
 
6
- it "value returns wrapped object" do
7
- Maybe(object).__value__.should == object
6
+ it "delegates messages to wrapped object" do
7
+ object.should_receive(:foo).with('bar')
8
+ Maybe(object).foo('bar')
8
9
  end
9
10
 
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'
11
+ it "calling methods that don't exist return Maybe(nil)" do
12
+ Maybe(nil).foo.__value__.should be_nil
13
13
  end
14
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)
15
+ it "it doesn't nest" do
16
+ Maybe(Maybe(nil)).__value__.should_not be_instance_of(Maybe)
17
17
  end
18
18
 
19
- it "#or_else returns object when object is not nil" do
19
+ it "__value__ unwraps the underlying object" do
20
+ Maybe(object).__value__.should be(object)
21
+ end
22
+
23
+ it "#or_else returns then underlying object when it's not nil" do
20
24
  Maybe(object).or_else{'unexpected result'}.should == object
21
25
  end
22
26
 
23
- it "#or_else returns default when object is nil" do
27
+ it "#or_else yields to supplied block when the underlying object is nil" do
24
28
  Maybe(nil).or_else{'expected result'}.should == 'expected result'
25
29
  end
30
+
31
+ it "#or_a returns then underlying object when it's not nil" do
32
+ Maybe(object).or_a.should be(object)
33
+ end
34
+
35
+ it "#or_a defaults to []" do
36
+ Maybe(nil).or_a.should == []
37
+ end
38
+
39
+ it "#or_f returns then underlying object when it's not nil" do
40
+ Maybe(object).or_f.should be(object)
41
+ end
42
+
43
+ it "#or_f defaults to 0.0" do
44
+ Maybe(nil).or_f.should == 0.0
45
+ end
46
+
47
+ it "#or_h returns then underlying object when it's not nil" do
48
+ Maybe(object).or_h.should be(object)
49
+ end
50
+
51
+ it "#or_h defaults to {}" do
52
+ Maybe(nil).or_h.should == {}
53
+ end
54
+
55
+ it "#or_i returns then underlying object when it's not nil" do
56
+ Maybe(object).or_i.should be(object)
57
+ end
58
+
59
+ it "#or_i defaults to 0" do
60
+ Maybe(nil).or_i.should == 0
61
+ end
62
+
63
+ it "#or_nil returns then underlying object when it's not nil" do
64
+ Maybe(object).or_nil.should be(object)
65
+ end
66
+
67
+ it "#or_nil defaults to nil" do
68
+ Maybe(nil).or_nil.should == nil
69
+ end
70
+
71
+ it "#or_s returns then underlying object when it's not nil" do
72
+ Maybe(object).or_s.should be(object)
73
+ end
74
+
75
+ it "#or_s defaults to ''" do
76
+ Maybe(nil).or_s.should == ''
77
+ end
26
78
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: just_maybe
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors: