maybe 1.0.0 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -8,22 +8,28 @@ Synopsis
8
8
 
9
9
  The Maybe class wraps any value (nil or non-nil) and lets you treat it as non-nil.
10
10
 
11
- "hello".upcase #=> "HELLO"
12
- nil.upcase #=> NoMethodError: undefined method `upcase' for nil:NilClass
13
- Maybe.new("hello").upcase.__value__ #=> "HELLO"
14
- Maybe.new(nil).upcase.__value__ #=> nil
11
+ require "maybe"
12
+ "hello".upcase #=> "HELLO"
13
+ nil.upcase #=> NoMethodError: undefined method `upcase' for nil:NilClass
14
+ Maybe.new("hello").upcase.__value__ #=> "HELLO"
15
+ Maybe.new(nil).upcase.__value__ #=> nil
15
16
 
16
17
  You can also use the method `Maybe` for convenience. The following are equivalent:
17
18
 
18
- Maybe.new("hello").__value__ #=> "hello"
19
- Maybe("hello").__value__ #=> "hello"
19
+ Maybe.new("hello").__value__ #=> "hello"
20
+ Maybe("hello").__value__ #=> "hello"
21
+
22
+ You can also optionally patch `Object` to include a `#maybe` method:
23
+
24
+ require "maybe/core_ext"
25
+ "hello".maybe.upcase #=> "HELLO"
20
26
 
21
27
  When you call `Maybe.new` with a value, that value is wrapped in a Maybe object. Whenever you call methods on that object, it does a simple check: if the wrapped value is nil, then it returns another Maybe object that wraps nil. If the wrapped object is not nil, it calls the method on that object, then wraps it back up in a Maybe object.
22
28
 
23
29
  This is especially handy for long chains of method calls, any of which could return nil.
24
30
 
25
- # foo, bar, and/or baz could return nil, but this will still work
26
- Maybe.new(foo).bar(1).baz(:x)
31
+ # foo, bar, and/or baz could return nil, but this will still work
32
+ Maybe.new(foo).bar(1).baz(:x)
27
33
 
28
34
  Here's a real world example. Instead of writing this:
29
35
 
@@ -48,6 +54,8 @@ instead of
48
54
  Examples
49
55
  --------
50
56
 
57
+ require "maybe"
58
+
51
59
  Maybe.new("10") #=> A Maybe object, wrapping "10"
52
60
 
53
61
  Maybe.new("10").to_i #=> A Maybe object, wrapping 10
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.0.0
1
+ 1.1.0
@@ -14,7 +14,7 @@ class Maybe
14
14
  @value = value
15
15
  __join__
16
16
  end
17
-
17
+
18
18
  def respond_to?(method_name)
19
19
  return true if LEGACY_METHODS.include?(method_name.to_s)
20
20
  super || @value.respond_to?(method_name)
@@ -62,7 +62,7 @@ class Maybe
62
62
  end
63
63
 
64
64
  # Only included to provide a complete Monad interface. Not recommended
65
- # for general use.
65
+ # for general use.
66
66
  # (Technically: Given that the value is of type A
67
67
  # takes a function from A->M[B] and returns
68
68
  # M[B] (a monad with a value of type B))
@@ -71,7 +71,7 @@ class Maybe
71
71
  end
72
72
 
73
73
  # Only included to provide a complete Monad interface. Not recommended
74
- # for general use.
74
+ # for general use.
75
75
  # (Technically: Given that the value is of type A
76
76
  # takes a function from A->B and returns
77
77
  # M[B] (a monad with a value of type B))
@@ -84,7 +84,7 @@ class Maybe
84
84
  end
85
85
 
86
86
  # Only included to provide a complete Monad interface. Not recommended
87
- # for general use.
87
+ # for general use.
88
88
  # (Technically: M[M[A]] is equivalent to M[A], that is, monads should be flat
89
89
  # rather than nested)
90
90
  def __join__
@@ -0,0 +1,8 @@
1
+ require 'maybe'
2
+
3
+ class Object
4
+ def maybe
5
+ Maybe.new(self)
6
+ end
7
+ end
8
+
@@ -0,0 +1,24 @@
1
+ require File.expand_path("test_helper", File.dirname(__FILE__))
2
+
3
+ class CoreExtTest < Test::Unit::TestCase
4
+
5
+ context "Object#maybe" do
6
+
7
+ should "not include patching by default" do
8
+ assert_raises NoMethodError do
9
+ "foo".maybe
10
+ end
11
+ end
12
+
13
+ should "allow calling foo#maybe rather than Maybe.new(foo)" do
14
+ require 'maybe/core_ext'
15
+ assert_kind_of Maybe, "foo".maybe
16
+ end
17
+
18
+ teardown do
19
+ Object.send(:undef_method, :maybe) if Object.new.respond_to?(:maybe)
20
+ end
21
+
22
+ end
23
+
24
+ end
@@ -1,6 +1,7 @@
1
+ # -*- coding: utf-8 -*-
1
2
  require File.expand_path("test_helper", File.dirname(__FILE__))
2
3
  require 'cgi'
3
- require 'shoulda'
4
+ require 'maybe'
4
5
 
5
6
  class MaybeTest < Test::Unit::TestCase
6
7
 
@@ -14,14 +15,14 @@ class MaybeTest < Test::Unit::TestCase
14
15
  Maybe.any_instance.expects(:__pass__).never
15
16
  Maybe.new(Maybe.new(1)).__value__
16
17
  end
17
-
18
+
18
19
  end
19
20
 
20
21
  context "when calling methods" do
21
22
 
22
23
  should "return correct value for match operator" do
23
24
  assert_equal nil, (Maybe.new(nil)=~/b/).__value__
24
- assert_equal 1, (Maybe.new('abc')=~/b/).__value__
25
+ assert_equal 1, (Maybe.new('abc')=~/b/).__value__
25
26
  end
26
27
 
27
28
  should "return correct value for to_s" do
@@ -33,7 +34,7 @@ class MaybeTest < Test::Unit::TestCase
33
34
  assert_equal nil, Maybe.new(nil).to_int.__value__
34
35
  assert_equal 2, Maybe.new(2.3).to_int.__value__
35
36
  end
36
-
37
+
37
38
  should "work if method call takes a block" do
38
39
  assert_equal nil, Maybe.new(nil).map{|x|x*2}.__value__
39
40
  assert_equal [2,4,6], Maybe.new([1,2,3]).map{|x|x*2}.__value__
@@ -41,7 +42,7 @@ class MaybeTest < Test::Unit::TestCase
41
42
 
42
43
  should "work if methods takes args and a block" do
43
44
  assert_equal nil, Maybe.new(nil).gsub(/x/) {|m| m.upcase}.__value__
44
- str = Maybe.new('x').gsub(/x/) do |m|
45
+ str = Maybe.new('x').gsub(/x/) do |m|
45
46
  m.upcase
46
47
  end
47
48
  assert_equal 'X', str.__value__
@@ -56,7 +57,7 @@ class MaybeTest < Test::Unit::TestCase
56
57
  end
57
58
 
58
59
  context "when calling object_id" do
59
-
60
+
60
61
  should "have different object id than wrapped object" do
61
62
  wrapped = "hello"
62
63
  maybe = Maybe.new(wrapped)
@@ -68,7 +69,7 @@ class MaybeTest < Test::Unit::TestCase
68
69
  end
69
70
 
70
71
  context "#join" do
71
-
72
+
72
73
  should "not call #pass" do
73
74
  Maybe.any_instance.expects(:__pass__).never
74
75
  m = Maybe.new(nil)
@@ -86,7 +87,7 @@ class MaybeTest < Test::Unit::TestCase
86
87
  end
87
88
 
88
89
  context "respond_to?" do
89
-
90
+
90
91
  should "respond correctly" do
91
92
  klass = Class.new do
92
93
  def fmap
@@ -95,7 +96,7 @@ class MaybeTest < Test::Unit::TestCase
95
96
  def foo
96
97
  end
97
98
  end
98
-
99
+
99
100
  wrapped = klass.new
100
101
  maybe = Maybe.new(wrapped)
101
102
 
@@ -121,7 +122,7 @@ class MaybeTest < Test::Unit::TestCase
121
122
  assert_equal true, maybe.respond_to?(:__value__)
122
123
  assert_equal true, maybe.respond_to?(:__pass__)
123
124
  end
124
-
125
+
125
126
  end
126
127
 
127
128
  context "#methods" do
@@ -134,10 +135,10 @@ class MaybeTest < Test::Unit::TestCase
134
135
  def foo
135
136
  end
136
137
  end
137
-
138
+
138
139
  wrapped = klass.new
139
140
  maybe = Maybe.new(wrapped)
140
-
141
+
141
142
  methods = maybe.methods.map{|x| x.to_sym}
142
143
 
143
144
  assert_equal false, methods.include?(:far)
@@ -167,7 +168,7 @@ class MaybeTest < Test::Unit::TestCase
167
168
  end
168
169
 
169
170
  should "work with CGI.unescape" do
170
- # using CGI::unescape because that's the first function I had problems with
171
+ # using CGI::unescape because that's the first function I had problems with
171
172
  # when implementing Maybe
172
173
  assert_equal nil, Maybe.new(nil).pass {|v|CGI.unescapeHTML(v)}.value
173
174
  assert_equal '&', Maybe.new('&amp;').pass {|v|CGI.unescapeHTML(v)}.value
@@ -175,11 +176,11 @@ class MaybeTest < Test::Unit::TestCase
175
176
  assert_equal nil, Maybe.new(nil).__pass__ {|v|CGI.unescapeHTML(v)}.__value__
176
177
  assert_equal '&', Maybe.new('&amp;').__pass__ {|v|CGI.unescapeHTML(v)}.__value__
177
178
  end
178
-
179
+
179
180
  end
180
181
 
181
182
  context "#nil?" do
182
-
183
+
183
184
  should "be true for nil value" do
184
185
  assert_equal true, Maybe.new(nil).nil?
185
186
  end
@@ -209,7 +210,7 @@ class MaybeTest < Test::Unit::TestCase
209
210
  should "call wrapped object's #value if defined (with params and block)" do
210
211
  wrapped = Object.new
211
212
  def wrapped.value(value)
212
- value * yield
213
+ value * yield
213
214
  end
214
215
  assert_equal 4, Maybe.new(wrapped).value(2) { 2 }
215
216
  assert_equal 4, Maybe.new(Maybe.new(wrapped)).value(2) { 2 }
@@ -270,7 +271,7 @@ class MaybeTest < Test::Unit::TestCase
270
271
 
271
272
  # monad rules taken from http://moonbase.rydia.net/mental/writings/programming/monads-in-ruby/01identity
272
273
  # and http://james-iry.blogspot.com/2007_10_01_archive.html
273
-
274
+
274
275
  #1. Calling pass on a newly-wrapped value should have the same effect as giving that value directly to the block.
275
276
  # (this is actually the second law at http://james-iry.blogspot.com/2007/10/monads-are-elephants-part-3.html)
276
277
  # scala version: unit(x) flatMap f ≡ f(x)
@@ -280,7 +281,7 @@ class MaybeTest < Test::Unit::TestCase
280
281
  assert_equal f[x], Maybe.new(x).pass {|y| f[y]}.value
281
282
  assert_equal f[x], Maybe.new(x).__pass__ {|y| f[y]}.__value__
282
283
  end
283
-
284
+
284
285
  #2. pass with a block that simply calls wrap on its value should produce the exact same values, wrapped up again.
285
286
  # (this is actually the first law at http://james-iry.blogspot.com/2007/10/monads-are-elephants-part-3.html)
286
287
  # scala version: m flatMap unit ≡ m
@@ -1,10 +1,10 @@
1
1
  require 'rubygems'
2
2
  require 'test/unit'
3
3
  require 'mocha'
4
+ require 'shoulda'
4
5
 
5
6
  $LOAD_PATH.unshift(File.dirname(__FILE__))
6
7
  $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
7
- require 'maybe'
8
8
 
9
9
  class Test::Unit::TestCase
10
10
  end
metadata CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
4
4
  prerelease: false
5
5
  segments:
6
6
  - 1
7
+ - 1
7
8
  - 0
8
- - 0
9
- version: 1.0.0
9
+ version: 1.1.0
10
10
  platform: ruby
11
11
  authors:
12
12
  - Ben Brinckerhoff
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2010-12-12 00:00:00 -07:00
17
+ date: 2012-07-01 00:00:00 +01:00
18
18
  default_executable:
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
@@ -40,25 +40,24 @@ extensions: []
40
40
  extra_rdoc_files:
41
41
  - LICENSE
42
42
  - README.md
43
- - README.rdoc
44
43
  files:
45
44
  - .document
46
- - .gitignore
47
45
  - LICENSE
48
46
  - README.md
49
47
  - Rakefile
50
48
  - VERSION
51
49
  - lib/maybe.rb
50
+ - lib/maybe/core_ext.rb
51
+ - test/core_ext_test.rb
52
52
  - test/maybe_test.rb
53
53
  - test/test_helper.rb
54
- - README.rdoc
55
54
  has_rdoc: true
56
55
  homepage: http://github.com/bhb/maybe
57
56
  licenses: []
58
57
 
59
58
  post_install_message:
60
- rdoc_options:
61
- - --charset=UTF-8
59
+ rdoc_options: []
60
+
62
61
  require_paths:
63
62
  - lib
64
63
  required_ruby_version: !ruby/object:Gem::Requirement
@@ -82,6 +81,5 @@ rubygems_version: 1.3.6
82
81
  signing_key:
83
82
  specification_version: 3
84
83
  summary: A library for treating nil and non-nil objects in a similar manner.
85
- test_files:
86
- - test/maybe_test.rb
87
- - test/test_helper.rb
84
+ test_files: []
85
+
@@ -1,83 +0,0 @@
1
- maybe
2
- =====
3
-
4
- A library for treating nil and non-nil objects in a similar manner. Technically speaking, Maybe is an implemenation of the maybe monad.
5
-
6
- Synopsis
7
- --------
8
-
9
- The Maybe class wraps any value (nil or non-nil) and lets you treat it as non-nil.
10
-
11
- "hello".upcase #=> "HELLO"
12
- nil.upcase #=> NoMethodError: undefined method `upcase' for nil:NilClass
13
- Maybe.new("hello").upcase.__value__ #=> "HELLO"
14
- Maybe.new(nil).upcase.__value__ #=> nil
15
-
16
- You can also use the method Maybe for convenience. The following are equivalent:
17
-
18
- Maybe.new("hello").__value__ #=> "hello"
19
- Maybe("hello").__value__ #=> "hello"
20
-
21
- When you call Maybe.new with a value, that value is wrapped in a Maybe object. Whenever you call methods on that object, it does a simple check: if the wrapped value is nil, then it returns another Maybe object that wraps nil. If the wrapped object is not nil, it calls the method on that object, then wraps it back up in a Maybe object.
22
-
23
- This is especially handy for long chains of method calls, any of which could return nil.
24
-
25
- # foo, bar, and/or baz could return nil, but this will still work
26
- Maybe.new(foo).bar(1).baz(:x)
27
-
28
- Here's a real world example. Instead of writing this:
29
-
30
- if(customer && customer.order && customer.order.id==newest_customer_id)
31
- # ... do something with customer
32
- end
33
-
34
- just write this:
35
-
36
- if(Maybe.new(customer).order.id.__value__==newest_customer_id)
37
- # ... do something with customer
38
- end
39
-
40
- If your wrapped object does not have a `#value` method, you can call
41
-
42
- Maybe.new(obj).value
43
-
44
- instead of
45
-
46
- Maybe.new(obj).__value__
47
-
48
- Examples
49
- --------
50
-
51
- Maybe.new("10") #=> A Maybe object, wrapping "10"
52
-
53
- Maybe.new("10").to_i #=> A Maybe object, wrapping 10
54
-
55
- Maybe.new("10").to_i.__value__ #=> 10
56
-
57
- Maybe.new(nil) #=> A Maybe object, wrapping nil
58
-
59
- Maybe.new(nil).to_i #=> A Maybe object, still wrapping nil
60
-
61
- Maybe.new(nil).to_i.__value__ #=> nil
62
-
63
- == Related Reading
64
-
65
- * {MenTaLguY has a great tutorial on Monads in Ruby over at Moonbase}[http://moonbase.rydia.net/mental/writings/programming/monads-in-ruby/00introduction.html]
66
- * {Oliver Steele explores the problem in depth and looks at a number of different solutions}[http://osteele.com/archives/2007/12/cheap-monads]
67
- * {Reg Braithwaite explores this same problem and comes up with a different, but very cool solution in Ruby}[http://weblog.raganwald.com/2008/01/objectandand-objectme-in-ruby.html]
68
- * {Weave Jester has another solution, inspired by the Maybe monad}[http://weavejester.com/node/10]
69
-
70
- == Note on Patches/Pull Requests
71
-
72
- * Fork the project.
73
- * Make your feature addition or bug fix.
74
- * Add tests for it. This is important so I don't break it in a
75
- future version unintentionally.
76
- * Commit, do not mess with rakefile, version, or history.
77
- (if you want to have your own version, that is fine but
78
- bump version in a commit by itself I can ignore when I pull)
79
- * Send me a pull request. Bonus points for topic branches.
80
-
81
- == Copyright
82
-
83
- Copyright (c) 2010 Ben Brinckerhoff. See LICENSE for details.