monadic 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # Changelog
2
2
 
3
+ ## v0.1.1
4
+
5
+ `Either()` coerces only `StandardError` to `Failure`, other exceptions higher in the hierarchy are will break the flow.
6
+ Thanks to @pithyless for the suggestion.
7
+
8
+ Monad is now a Module instead of a Class as previously. This fits the Monad metaphor better. Each monad must now implement the unit method itself, which is the correct way to do anyway.
9
+
10
+
3
11
  ## v0.1.0
4
12
 
5
13
  You can now chain Eithers with `+` without providing a block or a proc:
@@ -12,7 +20,10 @@ All monads now have the `#to_ary` and `#to_a` method, which coerces the inner va
12
20
  I am considering the Api now almost stable, the only thing I am not so sure about,
13
21
  is whether to apply the magic coercion or not.
14
22
 
15
- `Validation()` now returns the successfully validated values. See examples/validation.rb
23
+ `Validation()` now returns the successfully validated values.
24
+ See [examples/validation.rb](https://github.com/pzol/monadic/blob/master/examples/validation.rb)
25
+ and [examples/validation_module](https://github.com/pzol/monadic/blob/master/examples/validation_module.rb)
26
+
16
27
 
17
28
  ## v0.0.7
18
29
 
data/README.md CHANGED
@@ -23,61 +23,72 @@ Most people probably will be interested in the Maybe monad, as it solves the pro
23
23
 
24
24
  Maybe is an optional type, which helps to handle error conditions gracefully. The one thing to remember about option is: 'What goes into the Maybe, stays in the Maybe'.
25
25
 
26
- Maybe(User.find(123)).name._ # ._ is a shortcut for .fetch
27
26
 
28
- # if you prefer the alias Maybe instead of option
29
- Maybe(User.find(123)).name._
27
+ ```ruby
28
+ Maybe(User.find(123)).name._ # ._ is a shortcut for .fetch
30
29
 
31
- # confidently diving into nested hashes
32
- Maybe({})[:a][:b][:c] == Nothing
33
- Maybe({})[:a][:b][:c].fetch('unknown') == "unknown"
34
- Maybe(a: 1)[:a]._ == 1
30
+ # if you prefer the alias Maybe instead of option
31
+ Maybe(User.find(123)).name._
32
+
33
+ # confidently diving into nested hashes
34
+ Maybe({})[:a][:b][:c] == Nothing
35
+ Maybe({})[:a][:b][:c].fetch('unknown') == "unknown"
36
+ Maybe(a: 1)[:a]._ == 1
37
+ ```
35
38
 
36
39
  Basic usage examples:
37
40
 
38
- # handling nil (None serves as NullObject)
39
- Maybe(nil).a.b.c == Nothing
40
-
41
- # Nothing
42
- Maybe(nil)._ == Nothing
43
- "#{Maybe(nil)}" == "Nothing"
44
- Maybe(nil)._("unknown") == "unknown"
45
- Maybe(nil).empty? == true
46
- Maybe(nil).truly? == false
47
-
48
- # Just stays Just, unless you unbox it
49
- Maybe('FOO').downcase == Just('foo')
50
- Maybe('FOO').downcase.fetch == "foo" # unboxing the value
51
- Maybe('FOO').downcase._ == "foo"
52
- Maybe('foo').empty? == false # always non-empty
53
- Maybe('foo').truly? == true # depends on the boxed value
54
- Maybe(false).empty? == false
55
- Maybe(false).truly? == false
41
+ ```ruby
42
+ # handling nil (None serves as NullObject)
43
+ Maybe(nil).a.b.c == Nothing
44
+
45
+ # Nothing
46
+ Maybe(nil)._ == Nothing
47
+ "#{Maybe(nil)}" == "Nothing"
48
+ Maybe(nil)._("unknown") == "unknown"
49
+ Maybe(nil).empty? == true
50
+ Maybe(nil).truly? == false
51
+
52
+ # Just stays Just, unless you unbox it
53
+ Maybe('FOO').downcase == Just('foo')
54
+ Maybe('FOO').downcase.fetch == "foo" # unboxing the value
55
+ Maybe('FOO').downcase._ == "foo"
56
+ Maybe('foo').empty? == false # always non-empty
57
+ Maybe('foo').truly? == true # depends on the boxed value
58
+ Maybe(false).empty? == false
59
+ Maybe(false).truly? == false
60
+ ```
56
61
 
57
62
  Map, select:
58
63
 
59
- Maybe(123).map { |value| User.find(value) } == Just(someUser) # if user found
60
- Maybe(0).map { |value| User.find(value) } == Nothing # if user not found
61
- Maybe([1,2]).map { |value| value.to_s } == Just(["1", "2"]) # for all Enumerables
64
+ ```ruby
65
+ Maybe(123).map { |value| User.find(value) } == Just(someUser) # if user found
66
+ Maybe(0).map { |value| User.find(value) } == Nothing # if user not found
67
+ Maybe([1,2]).map { |value| value.to_s } == Just(["1", "2"]) # for all Enumerables
62
68
 
63
- Maybe('foo').select { |value| value.start_with?('f') } == Just('foo')
64
- Maybe('bar').select { |value| value.start_with?('f') } == Nothing
69
+ Maybe('foo').select { |value| value.start_with?('f') } == Just('foo')
70
+ Maybe('bar').select { |value| value.start_with?('f') } == Nothing
71
+ ```
65
72
 
66
73
  Treat it like an array:
67
74
 
68
- Maybe(123).to_a == [123]
69
- Maybe([123, 456]).to_a == [123, 456]
70
- Maybe(nil).to_a == []
75
+ ```ruby
76
+ Maybe(123).to_a == [123]
77
+ Maybe([123, 456]).to_a == [123, 456]
78
+ Maybe(nil).to_a == []
79
+ ```
71
80
 
72
81
  Falsey values (kind-of) examples:
73
82
 
74
- user = Maybe(User.find(123))
75
- user.name._
83
+ ```ruby
84
+ user = Maybe(User.find(123))
85
+ user.name._
76
86
 
77
- user.subscribed? # always true
78
- user.subscribed?.truly? # true if subscribed is true
79
- user.subscribed?.fetch(false) # same as above
80
- user.subscribed?.or(false) # same as above
87
+ user.subscribed? # always true
88
+ user.subscribed?.truly? # true if subscribed is true
89
+ user.subscribed?.fetch(false) # same as above
90
+ user.subscribed?.or(false) # same as above
91
+ ```
81
92
 
82
93
  Remember! a Maybe is never false (in Ruby terms), if you want to know if it is false, call `#empty?` of `#truly?`
83
94
 
@@ -85,32 +96,36 @@ Remember! a Maybe is never false (in Ruby terms), if you want to know if it is f
85
96
 
86
97
  Slug example
87
98
 
88
- # instead of
89
- def slug(title)
90
- if title
91
- title.strip.downcase.tr_s('^[a-z0-9]', '-')
92
- end
93
- end
99
+ ```ruby
100
+ # instead of
101
+ def slug(title)
102
+ if title
103
+ title.strip.downcase.tr_s('^[a-z0-9]', '-')
104
+ end
105
+ end
94
106
 
95
- # or
107
+ # or
96
108
 
97
- def slug(title)
98
- title && title.strip.downcase.tr_s('^[a-z0-9]', '-')
99
- end
109
+ def slug(title)
110
+ title && title.strip.downcase.tr_s('^[a-z0-9]', '-')
111
+ end
100
112
 
101
- # do it with a default
102
- def slug(title)
103
- Maybe(title).strip.downcase.tr_s('^[a-z0-9]', '-')._('unknown-title')
104
- end
113
+ # do it with a default
114
+ def slug(title)
115
+ Maybe(title).strip.downcase.tr_s('^[a-z0-9]', '-')._('unknown-title')
116
+ end
117
+ ```
105
118
 
106
119
  ### Object#_?
107
120
  Works similar to the Elvis operator _? - ruby does not allow ?: as operator and use it like the excellent [andand](https://github.com/raganwald/andand)
108
121
 
109
- require 'monadic/core_ext/object' # this will import _? into the global Object
110
- nil._? == Nothing
111
- "foo"._? == 'foo'
112
- {}._?.a.b == Nothing
113
- {}._?[:foo] == Nothing
122
+ ```ruby
123
+ require 'monadic/core_ext/object' # this will import _? into the global Object
124
+ nil._? == Nothing
125
+ "foo"._? == 'foo'
126
+ {}._?.a.b == Nothing
127
+ {}._?[:foo] == Nothing
128
+ ```
114
129
 
115
130
  In fact this is a shortcut notation for `Maybe(obj)`
116
131
 
@@ -124,61 +139,70 @@ What is specific to this implementation is that exceptions are caught within the
124
139
 
125
140
  The `Either()` wrapper will treat all falsey values `nil`, `false` or `empty?` as a `Failure` and all others as `Success`. If that does not suit you, use `Success` or `Failure` only.
126
141
 
127
- result = parse_and_validate_params(params). # must return a Success or Failure inside
128
- bind ->(user_id) { User.find(user_id) }. # if #find returns null it will become a Failure
129
- bind ->(user) { authorized?(user); user }. # if authorized? raises an Exception, it will be a Failure
130
- bind ->(user) { UserDecorator(user) }
131
-
132
- if result.success?
133
- @user = result.fetch # result.fetch or result._ contains the
134
- render 'page'
135
- else
136
- @error = result.fetch
137
- render 'error_page'
138
- end
142
+ ```ruby
143
+ result = parse_and_validate_params(params). # must return a Success or Failure inside
144
+ bind ->(user_id) { User.find(user_id) }. # if #find returns null it will become a Failure
145
+ bind ->(user) { authorized?(user); user }. # if authorized? raises an Exception, it will be a Failure
146
+ bind ->(user) { UserDecorator(user) }
147
+
148
+ if result.success?
149
+ @user = result.fetch # result.fetch or result._ contains the
150
+ render 'page'
151
+ else
152
+ @error = result.fetch
153
+ render 'error_page'
154
+ end
155
+ ```
139
156
 
140
157
  You can use alternate syntaxes to achieve the same goal:
141
158
 
142
- # block and Haskell like >= operator
143
- Either(operation).
144
- >= { successful_method }.
145
- >= { failful_operation }
159
+ ```ruby
160
+ # block and Haskell like >= operator
161
+ Either(operation).
162
+ >= { successful_method }.
163
+ >= { failful_operation }
146
164
 
147
- # start with a Success, for instance a parameter
148
- Success('pzol').
149
- bind ->(previous) { good }.
150
- bind -> { bad }
165
+ # start with a Success, for instance a parameter
166
+ Success('pzol').
167
+ bind ->(previous) { good }.
168
+ bind -> { bad }
151
169
 
152
- Either.chain do
153
- bind -> { good } # >= is not supported for Either.chain, only bind
154
- bind -> { better } # better returns Success(some_int)
155
- bind ->(previous_result) { previous_result + 1 }
156
- end
170
+ Either.chain do
171
+ bind -> { good } # >= is not supported for Either.chain, only bind
172
+ bind -> { better } # better returns Success(some_int)
173
+ bind ->(previous_result) { previous_result + 1 }
174
+ end
157
175
 
158
- either = Either(something)
159
- either += truth? Success('truth, only the truth') : Failure('lies, damn lies')
176
+ either = Either(something)
177
+ either += truth? Success('truth, only the truth') : Failure('lies, damn lies')
178
+ ```
160
179
 
161
180
  Exceptions are wrapped into a Failure:
162
181
 
163
- Either(true).
164
- bind -> { fail 'get me out of here' } # return a Failure(RuntimeError)
182
+ ```ruby
183
+ Either(true).
184
+ bind -> { fail 'get me out of here' } # return a Failure(RuntimeError)
185
+ ```
165
186
 
166
187
  Another example:
167
188
 
168
- Success(params).
169
- bind ->(params) { Either(params.fetch(:path)) } # fails if params does not contain :path
170
- bind ->(path) { load_stuff(params) } #
189
+ ```ruby
190
+ Success(params).
191
+ bind ->(params) { Either(params.fetch(:path)) } # fails if params does not contain :path
192
+ bind ->(path) { load_stuff(params) } #
193
+ ```
171
194
 
172
195
  Storing intermediate results in instance variables is possible, although it is not very elegant:
173
196
 
174
- result = Either.chain do
175
- bind { @map = { one: 1, two: 2 } }
176
- bind { @map.fetch(:one) }
177
- bind { |p| Success(p + 100) }
178
- end
179
-
180
- result == Success(101)
197
+ ```ruby
198
+ result = Either.chain do
199
+ bind { @map = { one: 1, two: 2 } }
200
+ bind { @map.fetch(:one) }
201
+ bind { |p| Success(p + 100) }
202
+ end
181
203
 
204
+ result == Success(101)
205
+ ```
182
206
 
183
207
  ### Validation
184
208
  The Validation applicative functor, takes a list of checks within a block. Each check must return either Success of Failure.
@@ -187,60 +211,68 @@ Within the Failure() provide the reason why the check failed.
187
211
 
188
212
  Example:
189
213
 
190
- def validate(person)
191
- check_age = ->(age_expr) {
192
- age = age_expr.to_i
193
- case
194
- when age <= 0; Failure('Age must be > 0')
195
- when age > 130; Failure('Age must be < 130')
196
- else Success(age)
197
- end
198
- }
199
-
200
- check_sobriety = ->(sobriety) {
201
- case sobriety
202
- when :sober, :tipsy; Success(sobriety)
203
- when :drunk ; Failure('No drunks allowed')
204
- else Failure("Sobriety state '#{sobriety}' is not allowed")
205
- end
206
- }
207
-
208
- check_gender = ->(gender) {
209
- gender == :male || gender == :female ? Success(gender) : Failure("Invalid gender #{gender}")
210
- }
211
-
212
- Validation() do
213
- check { check_age.(person.age); }
214
- check { check_sobriety.(person.sobriety) }
215
- check { check_gender.(person.gender) }
216
- end
214
+ ```ruby
215
+ def validate(person)
216
+ check_age = ->(age_expr) {
217
+ age = age_expr.to_i
218
+ case
219
+ when age <= 0; Failure('Age must be > 0')
220
+ when age > 130; Failure('Age must be < 130')
221
+ else Success(age)
217
222
  end
223
+ }
224
+
225
+ check_sobriety = ->(sobriety) {
226
+ case sobriety
227
+ when :sober, :tipsy; Success(sobriety)
228
+ when :drunk ; Failure('No drunks allowed')
229
+ else Failure("Sobriety state '#{sobriety}' is not allowed")
230
+ end
231
+ }
232
+
233
+ check_gender = ->(gender) {
234
+ gender == :male || gender == :female ? Success(gender) : Failure("Invalid gender #{gender}")
235
+ }
236
+
237
+ Validation() do
238
+ check { check_age.(person.age); }
239
+ check { check_sobriety.(person.sobriety) }
240
+ check { check_gender.(person.gender) }
241
+ end
242
+ end
243
+ ```
218
244
 
219
245
  The above example, returns either `Success([32, :sober, :male])` or `Failure(['Age must be > 0', 'No drunks allowed'])` with a list of what went wrong during the validation.
220
246
 
221
- See also exmaples/validation.rb
247
+ See also [examples/validation.rb](https://github.com/pzol/monadic/blob/master/examples/validation.rb) and [examples/validation_module](https://github.com/pzol/monadic/blob/master/examples/validation_module.rb)
222
248
 
223
249
  ### Monad
224
250
  All Monads inherit from this class. Standalone it is an Identity monad. Not useful on its own. It's methods are usable on all its descendants.
225
251
 
226
252
  __#map__ is used to map the inner value
227
253
 
228
- Monad.unit('FOO').map(&:capitalize).map {|v| "Hello #{v}"} == Monad(Hello Foo)
229
- Monad.unit([1,2]).map {|v| v + 1} == Monad([2, 3])
254
+ ```ruby
255
+ Monad.unit('FOO').map(&:capitalize).map {|v| "Hello #{v}"} == Monad(Hello Foo)
256
+ Monad.unit([1,2]).map {|v| v + 1} == Monad([2, 3])
257
+ ```
230
258
 
231
259
  __#bind__ allows (priviledged) access to the boxed value. This is the traditional _no-magic_ `#bind` as found in Haskell,
232
- You are responsible for re-wrapping the value into a Monad again.
260
+ You` are responsible for re-wrapping the value into a Monad again.
233
261
 
234
- # due to the way it works, it will simply return the value, don't rely on this though, different Monads may
235
- # implement bind differently (e.g. Maybe involves some _magic_)
236
- Monad.unit('foo').bind(&:capitalize) == Foo
262
+ ```ruby
263
+ # due to the way it works, it will simply return the value, don't rely on this though, different Monads may
264
+ # implement bind differently (e.g. Maybe involves some _magic_)
265
+ Monad.unit('foo').bind(&:capitalize) == Foo
237
266
 
238
- # proper use
239
- Monad.unit('foo').bind {|v| Monad.unit(v.capitalize) } == Monad(Foo)
267
+ # proper use
268
+ Monad.unit('foo').bind {|v| Monad.unit(v.capitalize) } == Monad(Foo)
269
+ ```
240
270
 
241
271
  __#fetch__ extracts the inner value of the Monad, some Monads will override this standard behaviour, e.g. the Maybe Monad
242
272
 
243
- Monad.unit('foo').fetch == "foo"
273
+ ```ruby
274
+ Monad.unit('foo').fetch == "foo"
275
+ ```
244
276
 
245
277
  ## References
246
278
 
@@ -1,10 +1,13 @@
1
1
  require 'monadic'
2
2
 
3
+ class AgeTooLowError < ArgumentError; end
4
+ class AgeTooHighError < ArgumentError; end
5
+
3
6
  valid_age = ->(age_expr) {
4
7
  age = age_expr.to_i
5
8
  case
6
- when age <= 0; Failure('Age must be > 0')
7
- when age > 130; Failure('Age must be < 130')
9
+ when age <= 0; Failure(AgeTooLowError.new(age_expr))
10
+ when age > 130; Failure(AgeTooHighError.new(age_expr))
8
11
  else Success(age)
9
12
  end
10
13
  }
@@ -21,11 +24,14 @@ params = {age: 32, name: 'Andrzej', postcode: '50000'}
21
24
  Person = Struct.new(:name, :age)
22
25
 
23
26
  result = Validation() do
24
- check { valid_age.(params[:age]) }
25
27
  check { valid_name.(params[:name]) }
28
+ check { valid_age.(params[:age]) }
26
29
  end
27
30
 
28
31
  case result
29
32
  when Failure; puts "Something went wrong: #{result.fetch}"
30
33
  when Success; person = Person.new(*result.fetch); puts "We have a person #{person.inspect}"
31
34
  end
35
+
36
+ # Failure: Something went wrong: [#<AgeTooHighError: 200>]
37
+ # Success: We have a person #<struct Person name="Andrzej", age=32>
@@ -0,0 +1,46 @@
1
+ require 'monadic'
2
+
3
+ Person = Struct.new(:name, :age)
4
+
5
+ module PersonValidation
6
+ class AgeTooLowError < ArgumentError; end
7
+ class AgeTooHighError < ArgumentError; end
8
+
9
+ def self.validate(params)
10
+ Validation() do
11
+ extend PersonValidation
12
+ check { valid_age(params[:age]) }
13
+ check { valid_name(params[:name])}
14
+ end
15
+ end
16
+
17
+ def valid_age(expr)
18
+ age = expr.to_i
19
+ case
20
+ when expr.nil?; Failure(ArgumentError.new(:age))
21
+ when age <= 0; Failure(AgeTooLowError.new(expr))
22
+ when age > 130; Failure(AgeTooHighError.new(expr))
23
+ else Success(age)
24
+ end
25
+ end
26
+
27
+ def valid_name(name)
28
+ case
29
+ when name =~ /\w{3,99}/i; Success(name)
30
+ else Failure('Invalid name')
31
+ end
32
+ end
33
+ end
34
+
35
+ module PersonBuild
36
+ def self.build(params)
37
+ result = PersonValidation.validate(params)
38
+ case result
39
+ when Failure; result
40
+ when Success; Person.new(*result.fetch)
41
+ end
42
+ end
43
+ end
44
+
45
+ p person1 = PersonBuild.build({ name: 'Andrzej' }) # Failure([#<ArgumentError: age>])
46
+ p person2 = PersonBuild.build({ name: 'Andrzej', age: 32 }) # <struct Person name=32, age="Andrzej">
@@ -1,6 +1,7 @@
1
1
  module Monadic
2
2
  # @abstract Chains function calls and stops executing if one of them fails.
3
- class Either < Monad
3
+ class Either
4
+ include Monadic::Monad
4
5
  def self.chain(initial=nil, &block)
5
6
  Either::Chain.new(&block).call(initial)
6
7
  end
@@ -24,8 +25,8 @@ module Monadic
24
25
 
25
26
  begin
26
27
  Either(call(proc, block))
27
- rescue Exception => ex
28
- Failure(ex)
28
+ rescue StandardError => error
29
+ Failure(error)
29
30
  end
30
31
  end
31
32
  alias :>= :bind
data/lib/monadic/maybe.rb CHANGED
@@ -1,5 +1,7 @@
1
1
  module Monadic
2
- class Maybe < Monad
2
+ class Maybe
3
+ include Monadic::Monad
4
+
3
5
  def self.unit(value)
4
6
  return Nothing if value.nil? || (value.respond_to?(:empty?) && value.empty?)
5
7
  return Just.new(value)
data/lib/monadic/monad.rb CHANGED
@@ -1,9 +1,5 @@
1
1
  module Monadic
2
- class Monad
3
- def self.unit(value)
4
- new(value)
5
- end
6
-
2
+ module Monad
7
3
  def initialize(value)
8
4
  @value = join(value)
9
5
  end
@@ -41,7 +37,7 @@ module Monadic
41
37
  Array(@value)
42
38
  end
43
39
  alias :to_a :to_ary
44
-
40
+
45
41
  # Return the string representation of the Monad
46
42
  def to_s
47
43
  pretty_class_name = self.class.name.split('::')[-1]
@@ -1,3 +1,3 @@
1
1
  module Monadic
2
- VERSION = "0.1.0"
2
+ VERSION = "0.1.1"
3
3
  end
data/spec/either_spec.rb CHANGED
@@ -43,7 +43,7 @@ describe Monadic::Either do
43
43
  Success(nil).bind { nil }.should == Failure(nil)
44
44
  end
45
45
 
46
- it 'catches exceptions and returns them as Failure' do
46
+ it 'catches StandardError exceptions and returns them as Failure' do
47
47
  either = Success(nil).
48
48
  bind { raise 'error' }
49
49
 
data/spec/monad_spec.rb CHANGED
@@ -1,34 +1,41 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Monadic::Monad do
4
+ class Identity
5
+ include Monadic::Monad
6
+ def self.unit(value)
7
+ new(value)
8
+ end
9
+ end
10
+
4
11
  it_behaves_like 'a Monad' do
5
- let(:monad) { Monad }
12
+ let(:monad) { Identity }
6
13
  end
7
14
 
8
15
  it '#to_s shows the monad name and its value' do
9
- Monad.unit(1).to_s.should == 'Monad(1)'
10
- Monad.unit(nil).to_s.should == 'Monad(nil)'
11
- Monad.unit([1, 2]).map(&:to_s).should == Monad.unit(["1", "2"])
16
+ Identity.unit(1).to_s.should == 'Identity(1)'
17
+ Identity.unit(nil).to_s.should == 'Identity(nil)'
18
+ Identity.unit([1, 2]).map(&:to_s).should == Identity.unit(["1", "2"])
12
19
 
13
20
  # can be done also
14
- Monad.unit([1, 2]).bind {|v| Monad.unit(v.map(&:to_s)) }.should == Monad.unit(["1", "2"])
21
+ Identity.unit([1, 2]).bind {|v| Identity.unit(v.map(&:to_s)) }.should == Identity.unit(["1", "2"])
15
22
  end
16
23
 
17
24
  describe '#map' do
18
25
  it 'applies the function to the underlying value directly' do
19
- Monad.unit(1).map {|v| v + 2}.should == Monad.unit(3)
20
- Monad.unit('foo').map(&:upcase).should == Monad.unit('FOO')
26
+ Identity.unit(1).map {|v| v + 2}.should == Identity.unit(3)
27
+ Identity.unit('foo').map(&:upcase).should == Identity.unit('FOO')
21
28
  end
22
29
 
23
30
  it 'delegates #map to an underlying collection and wraps the resulting collection' do
24
- Monad.unit([1,2]).map {|v| v + 1}.should == Monad.unit([2, 3])
25
- Monad.unit(['foo', 'bar']).map(&:upcase).should == Monad.unit(['FOO', 'BAR'])
31
+ Identity.unit([1,2]).map {|v| v + 1}.should == Identity.unit([2, 3])
32
+ Identity.unit(['foo', 'bar']).map(&:upcase).should == Identity.unit(['FOO', 'BAR'])
26
33
  end
27
34
  end
28
35
 
29
36
  describe '#to_ary #to_a' do
30
- Monad.unit([1, 2]).to_a.should == [1, 2]
31
- Monad.unit(nil).to_a.should == []
32
- Monad.unit('foo').to_a.should == ['foo']
37
+ Identity.unit([1, 2]).to_a.should == [1, 2]
38
+ Identity.unit(nil).to_a.should == []
39
+ Identity.unit('foo').to_a.should == ['foo']
33
40
  end
34
41
  end
data/spec/spec_helper.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  require 'bundler/setup'
2
- Bundler.require(:default, :test)
2
+ Bundler.require(:test)
3
3
 
4
4
  $LOAD_PATH << File.expand_path('../../lib', __FILE__)
5
5
  require File.expand_path('../../lib/monadic', __FILE__)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: monadic
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:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-05-06 00:00:00.000000000 Z
12
+ date: 2012-05-08 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rspec
@@ -140,6 +140,7 @@ files:
140
140
  - README.md
141
141
  - Rakefile
142
142
  - examples/validation.rb
143
+ - examples/validation_module.rb
143
144
  - lib/monadic.rb
144
145
  - lib/monadic/core_ext/object.rb
145
146
  - lib/monadic/either.rb