monadic 0.4.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG.md CHANGED
@@ -1,5 +1,16 @@
1
1
  # Changelog
2
2
 
3
+ ## v0.5.0
4
+
5
+ Add the `Try` helper which works similar to Either, but takes a block
6
+
7
+ Try { Date.parse('2012-02-30') } == Failure
8
+ Try { Date.parse('2012-02-28') } == Success
9
+
10
+ `Either` else now supports also a block
11
+
12
+ Failure(1).else {|other| 1 + 2 } == Failure(3)
13
+
3
14
  ## v0.4.0
4
15
  `#or` returns for Nothing an alternative
5
16
 
data/Guardfile CHANGED
@@ -8,6 +8,7 @@ end
8
8
 
9
9
  guard 'rspec', :version => 2 do
10
10
  watch(%r{^spec/.+_spec\.rb$})
11
- watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
12
- watch('spec/spec_helper.rb') { "spec" }
11
+ watch(%r{^lib/monadic/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
12
+ watch(%r{^lib/monadic.rb$}) { "spec" }
13
+ watch('spec/spec_helper.rb') { "spec" }
13
14
  end
data/README.md CHANGED
@@ -1,9 +1,9 @@
1
1
  # Monadic
2
- [![Build Status](https://secure.travis-ci.org/pzol/monadic.png?branch=master)](http://travis-ci.org/pzol/monadic)
2
+ [![Build Status](https://secure.travis-ci.org/pzol/monadic.png?branch=master)](http://travis-ci.org/pzol/monadic) [![endorse](http://api.coderwall.com/pzol/endorsecount.png)](http://coderwall.com/pzol)
3
3
 
4
4
  helps dealing with exceptional situations, it comes from the sphere of functional programming and bringing the goodies I have come to love in [Scala](http://www.scala-lang.org/) and [Haskell](http://www.haskell.org/) to my ruby projects.
5
5
 
6
- My motivation to create this gem was that I often work with nested Hashes and need to reach deeply inside of them so my code is sprinkled with things like some_hash.fetch(:one, {}).fetch(:two, {}).fetch(:three, "unknown").
6
+ My motivation to create this gem was that I often work with nested Hashes and need to reach deeply inside of them so my code is sprinkled with things like some_hash.fetch(:one, {}).fetch(:two, {}).fetch(:three, "unknown").
7
7
 
8
8
  We have the following monadics (monads, functors, applicatives and variations):
9
9
 
@@ -13,7 +13,7 @@ We have the following monadics (monads, functors, applicatives and variations):
13
13
 
14
14
  What's the point of using monads in ruby? To me it started with having a safe way to deal with nil objects and other exceptions.
15
15
  Thus you contain the erroneous behaviour within a monad - an indivisible, impenetrable unit. Functional programming considers _throwing_ exceptions to be a side-effect, instead we _propagate_ exceptions, i.e. return them as a result of a function call.
16
-
16
+
17
17
  A monad is most effectively described as a computation that eventually returns a value. -- Wolfgang De Meuter
18
18
 
19
19
  ## Usage
@@ -50,7 +50,7 @@ Maybe(nil).empty? == true
50
50
  Maybe(nil).truly? == false
51
51
 
52
52
  # Just stays Just, unless you unbox it
53
- Maybe('FOO').downcase == Just('foo')
53
+ Maybe('FOO').downcase == Just('foo')
54
54
  Maybe('FOO').downcase.fetch == "foo" # unboxing the value
55
55
  Maybe('FOO').downcase._ == "foo"
56
56
  Maybe('foo').empty? == false # always non-empty
@@ -92,6 +92,7 @@ Maybe(1).to_s == '1'
92
92
  `#or`
93
93
  Maybe(nil).or(1) == 1
94
94
  Maybe(1).or(2) == 1
95
+ Maybe(nil).or(nil) == Just(nil)
95
96
 
96
97
  Falsey values (kind-of) examples:
97
98
 
@@ -214,6 +215,12 @@ Either(false == true).else('false was not true') == Failure(false was n
214
215
  Success('truth needs no sugar coating').else('all lies') == Success('truth needs no sugar coating')
215
216
  ```
216
217
 
218
+ `Either#else` supports also a block
219
+
220
+ ```ruby
221
+ Failure(1).else {|other| 1 + 2 } == Failure(3)
222
+ ```
223
+
217
224
  Storing intermediate results in instance variables is possible, although it is not very elegant:
218
225
 
219
226
  ```ruby
@@ -224,9 +231,20 @@ result = Either.chain do
224
231
  end
225
232
 
226
233
  result == Success(101)
227
- ```
234
+ ```
235
+
236
+ #### Try
237
+
238
+ `Try` helper which works similar to Either, but takes a block
239
+
240
+ ```ruby
241
+ Try { Date.parse('2012-02-30') } == Failure
242
+ Try { Date.parse('2012-02-28') } == Success
243
+ Try { Date.parse('2012-02-30') }.else {|e| "Exception: #{e.message}" } == Failure("Exception: invalid date")
244
+ ```
245
+
228
246
 
229
- ### Validation
247
+ ### Validation
230
248
  The Validation applicative functor, takes a list of checks within a block. Each check must return either Success of Failure.
231
249
  If Successful, it will return Success, if not a Failure monad, containing a list of failures.
232
250
  Within the Failure() provide the reason why the check failed.
@@ -237,7 +255,7 @@ Example:
237
255
  def validate(person)
238
256
  check_age = ->(age_expr) {
239
257
  age = age_expr.to_i
240
- case
258
+ case
241
259
  when age <= 0; Failure('Age must be > 0')
242
260
  when age > 130; Failure('Age must be < 130')
243
261
  else Success(age)
@@ -266,16 +284,16 @@ end
266
284
 
267
285
  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.
268
286
 
269
- 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)
287
+ 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)
270
288
 
271
- ### Monad
289
+ ### Monad
272
290
  All Monads include this module. Standalone it is an Identity monad. Not useful on its own. It's methods are usable on all its descendants.
273
291
 
274
292
  __#map__ is used to map the inner value
275
293
 
276
294
  ```ruby
277
295
  # minimum implementation of a monad
278
- class Identity
296
+ class Identity
279
297
  include Monadic::Monad
280
298
  def self.unit(value)
281
299
  new(value)
@@ -5,7 +5,7 @@ class AgeTooHighError < ArgumentError; end
5
5
 
6
6
  valid_age = ->(age_expr) {
7
7
  age = age_expr.to_i
8
- case
8
+ case
9
9
  when age <= 0; Failure(AgeTooLowError.new(age_expr))
10
10
  when age > 130; Failure(AgeTooHighError.new(age_expr))
11
11
  else Success(age)
@@ -13,7 +13,7 @@ valid_age = ->(age_expr) {
13
13
  }
14
14
 
15
15
  valid_name = ->(name) {
16
- case
16
+ case
17
17
  when name =~ /\w{3,99}/i; Success(name)
18
18
  else Failure('Invalid name')
19
19
  end
@@ -1,6 +1,6 @@
1
1
  module Monadic
2
2
  # @abstract Chains function calls and stops executing if one of them fails.
3
- class Either
3
+ class Either
4
4
  include Monadic::Monad
5
5
  def self.chain(initial=nil, &block)
6
6
  Either::Chain.new(&block).call(initial)
@@ -12,11 +12,11 @@ module Monadic
12
12
  return Success.new(value)
13
13
  end
14
14
 
15
- # Initialize is private, because it always would return an instance of Either, but Success or Failure
15
+ # Initialize is private, because it always would return an instance of Either, but Success or Failure
16
16
  # are required (Either is abstract).
17
17
  private_class_method :new
18
18
 
19
- # Allows privileged access to the +Either+'s inner value from within a block.
19
+ # Allows privileged access to the +Either+'s inner value from within a block.
20
20
  # This block should return a +Success+ or +Failure+ itself. It will be coerced into #Either
21
21
  # @return [Success, Failure]
22
22
  def bind(proc=nil, &block)
@@ -26,15 +26,16 @@ module Monadic
26
26
  begin
27
27
  Either(call(proc, block))
28
28
  rescue StandardError => error
29
- Failure(error)
29
+ Failure(error)
30
30
  end
31
31
  end
32
32
  alias :>= :bind
33
33
  alias :+ :bind
34
34
 
35
35
  # If it is a Failure it will return a new Failure with the provided value
36
- # @return [Success, Failure]
37
- def else(value)
36
+ # @return [Success, Failure]
37
+ def else(value=nil, &block)
38
+ return Failure(block.call(@value)) if failure? && block_given?
38
39
  return Failure(value) if failure?
39
40
  return self
40
41
  end
@@ -53,7 +54,7 @@ module Monadic
53
54
  is_a? Failure
54
55
  end
55
56
 
56
- private
57
+ private
57
58
  def call(proc=nil, block)
58
59
  func = (proc || block)
59
60
  raise "No block or lambda given" unless func.is_a? Proc
@@ -99,7 +100,7 @@ module Monadic
99
100
  module InstanceMethods
100
101
  def initialize(value)
101
102
  @value = join(value)
102
- end
103
+ end
103
104
  end
104
105
  end
105
106
 
@@ -115,7 +116,7 @@ module Monadic
115
116
  Failure.new(value)
116
117
  end
117
118
 
118
- # Factory method
119
+ # Factory method
119
120
  # @return [Success]
120
121
  def Success(value)
121
122
  Success.new(value)
data/lib/monadic/maybe.rb CHANGED
@@ -24,6 +24,7 @@ module Monadic
24
24
  return self
25
25
  end
26
26
 
27
+ # @return [true, false] true if the underlying value is true
27
28
  def truly?
28
29
  @value == true
29
30
  end
@@ -33,6 +34,7 @@ module Monadic
33
34
  class Just < Maybe
34
35
  public_class_method :new
35
36
 
37
+ # @return the underlying value
36
38
  def fetch(default=nil)
37
39
  @value
38
40
  end
@@ -42,13 +44,10 @@ module Monadic
42
44
  Maybe(@value.__send__(m, *args))
43
45
  end
44
46
 
47
+ # @return always self for Just
45
48
  def or(other)
46
49
  self
47
50
  end
48
-
49
- def to_s
50
- @value.to_s
51
- end
52
51
  end
53
52
 
54
53
  # Represents a NullObject
@@ -56,6 +55,7 @@ module Monadic
56
55
  class << self
57
56
  undef name
58
57
 
58
+ # @return the default value passed
59
59
  def fetch(default=nil)
60
60
  return self if default.nil?
61
61
  return default
@@ -66,10 +66,15 @@ module Monadic
66
66
  self
67
67
  end
68
68
 
69
+ # @return an alternative value, the passed value is NOT coerced into Maybe, thus Nothing.or(nil) will be Just(nil)
69
70
  def or(other)
70
- Maybe(other)
71
+ Just.new(other)
71
72
  end
72
73
 
74
+ # def respond_to?
75
+
76
+ # end
77
+
73
78
  def to_ary
74
79
  []
75
80
  end
data/lib/monadic/monad.rb CHANGED
@@ -45,7 +45,7 @@ module Monadic
45
45
  # Return the string representation of the Monad
46
46
  def to_s
47
47
  pretty_class_name = self.class.name.split('::')[-1]
48
- "#{pretty_class_name}(#{@value.nil? ? 'nil' : @value.to_s})"
48
+ "#{pretty_class_name}(#{self.fetch.inspect})"
49
49
  end
50
50
 
51
51
  def ==(other)
@@ -0,0 +1,10 @@
1
+ module Monadic
2
+ def Try(proc = nil, &block)
3
+ begin
4
+ return Either(proc) unless proc.nil? || proc.is_a?(Proc)
5
+ return Either((proc || block).call)
6
+ rescue => error
7
+ Failure(error)
8
+ end
9
+ end
10
+ end
@@ -1,3 +1,3 @@
1
1
  module Monadic
2
- VERSION = "0.4.0"
2
+ VERSION = "0.5.0"
3
3
  end
data/lib/monadic.rb CHANGED
@@ -4,6 +4,7 @@ require 'monadic/errors'
4
4
  require 'monadic/monad'
5
5
  require 'monadic/maybe'
6
6
  require 'monadic/either'
7
+ require 'monadic/try'
7
8
  require 'monadic/validation'
8
9
 
9
10
  include Monadic
data/spec/either_spec.rb CHANGED
@@ -16,7 +16,7 @@ describe Monadic::Either do
16
16
  it 'Failure.new and Failure.unit and Failure() return the same' do
17
17
  Failure(1).should == Failure.unit(1)
18
18
  Failure.new(1).should == Failure.unit(1)
19
-
19
+
20
20
  Failure(nil).should == Failure.unit(nil)
21
21
  Failure.new(nil).should == Failure.unit(nil)
22
22
  end
@@ -27,7 +27,7 @@ describe Monadic::Either do
27
27
  end
28
28
 
29
29
  it '#to_s works' do
30
- Success.unit("it worked!").to_s.should == "Success(it worked!)"
30
+ Success.unit("it worked!").to_s.should == 'Success("it worked!")'
31
31
  Failure.unit(nil).to_s.should == "Failure(nil)"
32
32
  end
33
33
 
@@ -56,15 +56,20 @@ describe Monadic::Either do
56
56
  it '#else returns an alternative value considered Success if it is Nothing' do
57
57
  Failure(false).else(true).should == Failure(true)
58
58
  Either(nil).else(true).should == Failure(true)
59
+ Failure(1).else(nil).should == Failure(nil)
59
60
  Success(true).else(false).should == Success(true)
60
61
  Either(true).else(false).should == Success(true)
61
62
  Success(false).else(true).should == Success(false)
62
63
  end
63
64
 
65
+ it '#else with a block gets the original value passed' do
66
+ (Failure(1).else { |other| other + 1 }).should == Failure(2)
67
+ end
68
+
64
69
  class User
65
70
  attr :age, :gender, :sobriety
66
71
  def self.find(id)
67
- case id
72
+ case id
68
73
  when -1; raise 'invalid user id'
69
74
  when 0; nil
70
75
  else User.new(id)
@@ -149,7 +154,7 @@ describe Monadic::Either do
149
154
 
150
155
  it 'passes the result value from the previous call to the next' do
151
156
  either = Success(1).
152
- >= {|prev| Success(prev + 1) }. # a block
157
+ >= {|prev| Success(prev + 1) }. # a block
153
158
  >= -> prev { Success(prev + 100) } # lambda/proc
154
159
 
155
160
  either.should == Success(102)
@@ -160,7 +165,7 @@ describe Monadic::Either do
160
165
  end
161
166
 
162
167
  it 'allows you to use parameterless lambdas (#arity == 0)' do
163
- (Success(0) >=
168
+ (Success(0) >=
164
169
  -> { Success(1) }
165
170
  ).should == Success(1)
166
171
  end
@@ -198,12 +203,12 @@ describe Monadic::Either do
198
203
  end
199
204
 
200
205
  it 'supports Either.chain' do
201
- Either.chain do
206
+ Either.chain do
202
207
  bind -> { Success(1) }
203
208
  bind -> { Success(2) }
204
209
  end.should == Success(2)
205
210
 
206
- Either.chain do
211
+ Either.chain do
207
212
  bind -> { Success(1) }
208
213
  bind ->(p) { Success(p + 1) }
209
214
  end.should == Success(2)
@@ -215,9 +220,9 @@ describe Monadic::Either do
215
220
 
216
221
  it 'README example' do
217
222
  params = { :path => 'foo' }
218
- def load_file(path);
223
+ def load_file(path);
219
224
  fail "invalid path" unless path
220
- Success("bar");
225
+ Success("bar");
221
226
  end
222
227
  def process_content(content); content.start_with?('b') ? Success(content.upcase) : Failure('invalid content'); end
223
228
 
@@ -10,11 +10,11 @@ module Applicative
10
10
  alias :<< :apply
11
11
  end
12
12
 
13
- class Maybe
13
+ class Monadic::Just
14
14
  include Applicative
15
15
  end
16
16
 
17
- class Either
17
+ class Monadic::Either
18
18
  include Applicative
19
19
  end
20
20
 
@@ -0,0 +1,133 @@
1
+ require 'spec_helper'
2
+ require 'active_support/time'
3
+
4
+ describe 'Hotel Booking Example' do
5
+
6
+ class Request < Struct
7
+ def self.create(params, params_module)
8
+ value = self.create_value(params || {}, params_module)
9
+
10
+ if value.values.all?(&:success?)
11
+ Success(value)
12
+ else
13
+ Failure(value)
14
+ end
15
+ end
16
+
17
+ def to_hash
18
+ Hash[*members.zip(values).flatten]
19
+ end
20
+
21
+ def unwrap
22
+ Struct.new(*members).new(*values.map(&:fetch))
23
+ # self.class.new(*values.map(&:fetch))
24
+ end
25
+
26
+ private
27
+ def self.create_value(params, params_module)
28
+ properties = params_module.methods - Module.methods
29
+ request_klas = self.new(*properties)
30
+ properties.reduce(request_klas.new) do |request, property|
31
+ request[property] = params_module.send(property, params)
32
+ request
33
+ end
34
+ end
35
+ end
36
+
37
+ module HotelBookingRequestParams
38
+ extend self
39
+
40
+ def hotel_code(params)
41
+ value = params['hotel_code']
42
+ case
43
+ when value.nil?
44
+ Failure('hotel_code must not be empty')
45
+ when not(value =~ /^[A-Z]{3}[A-Z0-9]{4}$/)
46
+ Failure('hotel_code must be of pattern XXX0001')
47
+ else
48
+ Success(value)
49
+ end
50
+ end
51
+
52
+ def nights(params)
53
+ value = params.fetch('nights', 0).to_i
54
+ if value <= 0
55
+ Failure("nights must be a number greater than 0 (got '#{params['nights']}')")
56
+ else
57
+ Success(value)
58
+ end
59
+ end
60
+
61
+ VALID_ROOM_TYPE = %w[SR DR TR QR]
62
+ def room_type(params)
63
+ case value = params['room_type']
64
+ when nil
65
+ Failure('room_type must not be empty')
66
+ when is_valid_room_type
67
+ Success(value)
68
+ else
69
+ Failure("room_type '#{value}' must be one of #{VALID_ROOM_TYPE.join(', ')}")
70
+ end
71
+ end
72
+
73
+ def check_in(params)
74
+ param = params['check_in']
75
+ return Failure("check_in must not be empty") if param.nil?
76
+ return Try { Date.parse(param) }.else {|e| "check_in #{e.message} '#{param}'" }
77
+ end
78
+
79
+ private
80
+ def is_valid_room_type
81
+ Object.new.tap {|matcher|
82
+ def matcher.===(value)
83
+ VALID_ROOM_TYPE.include? value
84
+ end
85
+ }
86
+ end
87
+ end
88
+
89
+ let(:params_proto) do
90
+ {'hotel_code' => 'STO0001',
91
+ 'check_in' => '2012-06-15',
92
+ 'nights' => '3',
93
+ 'room_type' => 'DR',
94
+ 'guest1' => 'Max Payne',
95
+ 'guest2' => 'Jenny Payne'}
96
+ end
97
+
98
+ it 'builds a valid request' do
99
+ result = Request.create(params_proto, HotelBookingRequestParams)
100
+ result.should be_a Success
101
+ request = result.fetch.unwrap
102
+ request.hotel_code.should eq "STO0001"
103
+ request.nights.should eq 3
104
+ end
105
+
106
+ it 'reports an invalid room_type' do
107
+ params = params_proto.merge 'room_type' => 'XX'
108
+ result = Request.create(params, HotelBookingRequestParams)
109
+ result.should be_a Failure
110
+ request = result.fetch
111
+ request.room_type.should be_a Failure
112
+ end
113
+
114
+ it 'reports an invalid check_in time' do
115
+ params = params_proto.merge 'check_in' => '2012-11-31'
116
+ result = Request.create(params, HotelBookingRequestParams)
117
+ result.should be_a Failure
118
+ request = result.fetch
119
+ request.check_in.should be_a Failure
120
+ request.check_in.should == Failure("check_in invalid date '2012-11-31'")
121
+ end
122
+
123
+ it 'builds a failure request with no params' do
124
+ result = Request.create(nil, HotelBookingRequestParams)
125
+ result.should be_a Failure
126
+ request = result.fetch
127
+ request.hotel_code.should be_a Failure
128
+ request.nights.should be_a Failure
129
+ request.room_type.should be_a Failure
130
+ request.check_in.should be_a Failure
131
+ end
132
+
133
+ end
data/spec/maybe_spec.rb CHANGED
@@ -69,11 +69,21 @@ describe Monadic::Maybe do
69
69
  end
70
70
 
71
71
  it 'Just#to_s is "value"' do
72
- Just.unit(123).to_s.should == "123"
72
+ Just.unit(123).to_s.should == "Just(123)"
73
73
  end
74
74
 
75
75
  it 'Just#or return self' do
76
- Maybe(1).or(2).should == Just(1)
76
+ Maybe(1).or(2).should == Just(1)
77
+ Maybe(nil).or(nil).should == Just.new(nil)
78
+ Maybe(nil).something.or('').fetch.should == ''
79
+ end
80
+
81
+ it 'Just#inspect returns Just(value)' do
82
+ Just(1).inspect.should == 'Just(1)'
83
+ end
84
+
85
+ it 'works with method_missing !caution! with Monad.methods like #join' do
86
+ Maybe([1, 2]).join(' ').should == ' '
77
87
  end
78
88
 
79
89
  end
data/spec/try_spec.rb ADDED
@@ -0,0 +1,36 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Monadic::Try' do
4
+ it 'catches exceptions' do
5
+ Try { Date.parse('2012-02-30') }.should be_a Failure
6
+ end
7
+
8
+ it 'returns Failure when the value is nil or false' do
9
+ Try { nil }.should be_a Failure
10
+ Try { false }.should be_a Failure
11
+ end
12
+
13
+ it 'returns Failure for an empty collection' do
14
+ Try { [] }.should be_a Failure
15
+ end
16
+
17
+ it 'without a block it works like Either' do
18
+ Try(true).should be_a Success
19
+ Try(false).should be_a Failure
20
+ Try(nil).should be_a Failure
21
+ end
22
+
23
+ it 'with a proc' do
24
+ pending
25
+ end
26
+
27
+ it 'returns Success for non-nil values' do
28
+ Try { 1 }.should == Success(1)
29
+ Try { "string" }.should == Success("string")
30
+ end
31
+
32
+ it 'combined with else and a block' do
33
+ Try { Date.parse('2012-02-30') }.else {|e| "Exception: #{e.message}" }.should == Failure("Exception: invalid date")
34
+ Try { Date.parse('2012-02-28') }.else {|e| "Exception: #{e.message}" }.should == Success(Date.parse('2012-02-28'))
35
+ end
36
+ end
@@ -8,7 +8,7 @@ describe Monadic::Validation do
8
8
  def validate(person)
9
9
  check_age = ->(age_expr) {
10
10
  age = age_expr.to_i
11
- case
11
+ case
12
12
  when age <= 0; Failure('Age must be > 0')
13
13
  when age > 130; Failure('Age must be < 130')
14
14
  else Success(age)
@@ -20,13 +20,13 @@ describe Monadic::Validation do
20
20
  when :sober, :tipsy; Success(sobriety)
21
21
  when :drunk ; Failure('No drunks allowed')
22
22
  else Failure("Sobriety state '#{sobriety}' is not allowed")
23
- end
23
+ end
24
24
  }
25
25
 
26
26
  check_gender = ->(gender) {
27
27
  gender == :male || gender == :female ? Success(gender) : Failure("Invalid gender #{gender}")
28
28
  }
29
-
29
+
30
30
  Validation() do
31
31
  check { check_age.(person.age); }
32
32
  check { check_sobriety.(person.sobriety) }
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.4.0
4
+ version: 0.5.0
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-29 00:00:00.000000000 Z
12
+ date: 2012-06-17 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rspec
@@ -147,17 +147,20 @@ files:
147
147
  - lib/monadic/errors.rb
148
148
  - lib/monadic/maybe.rb
149
149
  - lib/monadic/monad.rb
150
+ - lib/monadic/try.rb
150
151
  - lib/monadic/validation.rb
151
152
  - lib/monadic/version.rb
152
153
  - monadic.gemspec
153
154
  - spec/core_ext/object_spec.rb
154
155
  - spec/either_spec.rb
155
156
  - spec/examples/applicative_spec.rb
157
+ - spec/examples/hotel_booking_spec.rb
156
158
  - spec/jruby_fixes.rb
157
159
  - spec/maybe_spec.rb
158
160
  - spec/monad_axioms.rb
159
161
  - spec/monad_spec.rb
160
162
  - spec/spec_helper.rb
163
+ - spec/try_spec.rb
161
164
  - spec/validation_spec.rb
162
165
  homepage: http://github.com/pzol/monadic
163
166
  licenses: []
@@ -173,7 +176,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
173
176
  version: '0'
174
177
  segments:
175
178
  - 0
176
- hash: -4582123822322674017
179
+ hash: 44748107420070269
177
180
  required_rubygems_version: !ruby/object:Gem::Requirement
178
181
  none: false
179
182
  requirements:
@@ -182,7 +185,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
182
185
  version: '0'
183
186
  segments:
184
187
  - 0
185
- hash: -4582123822322674017
188
+ hash: 44748107420070269
186
189
  requirements: []
187
190
  rubyforge_project:
188
191
  rubygems_version: 1.8.24
@@ -193,9 +196,11 @@ test_files:
193
196
  - spec/core_ext/object_spec.rb
194
197
  - spec/either_spec.rb
195
198
  - spec/examples/applicative_spec.rb
199
+ - spec/examples/hotel_booking_spec.rb
196
200
  - spec/jruby_fixes.rb
197
201
  - spec/maybe_spec.rb
198
202
  - spec/monad_axioms.rb
199
203
  - spec/monad_spec.rb
200
204
  - spec/spec_helper.rb
205
+ - spec/try_spec.rb
201
206
  - spec/validation_spec.rb