rumonade 0.2.0 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
data/HISTORY.md ADDED
@@ -0,0 +1,29 @@
1
+ # HISTORY
2
+
3
+ ## v0.2.1 (Oct 22, 2011)
4
+
5
+ - fixed Option#map to disallow becoming None on a nil result
6
+ - other fixes and documentation updates
7
+ - See full list @ https://github.com/ms-ati/rumonade/compare/v0.2.0...v0.2.1
8
+
9
+ ## v0.2.0 (Oct 18, 2011)
10
+
11
+ - added a scala-like Either class w/ LeftProjection and RightProjection monads
12
+
13
+ ## v0.1.2 (Oct 12, 2011)
14
+
15
+ - progress towards Either class
16
+ - changed documentation to yard from rdoc
17
+
18
+ ## v0.1.1 (Sep 19, 2011)
19
+
20
+ - added a first stab at documentation for Option
21
+ - fixed certain errors with #map
22
+ - added #select
23
+
24
+ ## v0.1.0 (Sep 17, 2011)
25
+
26
+ - Initial Feature Set
27
+ - general implementation and testing of monadic laws based on `unit` and `bind`
28
+ - scala-like Option class w/ Some & None
29
+ - scala-like extensions to Array
data/README.rdoc CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Project: github[http://github.com/ms-ati/rumonade]
4
4
 
5
- Documentation: rubydoc.info[http://rubydoc.info/gems/rumonade/0.2.0/file/README.rdoc]
5
+ Documentation: rubydoc.info[http://rubydoc.info/gems/rumonade/0.2.1/file/README.rdoc]
6
6
 
7
7
  == A Ruby[http://www.ruby-lang.org] Monad[http://en.wikipedia.org/wiki/Monad_(functional_programming)] Library, Inspired by Scala[http://www.scala-lang.org]
8
8
 
data/lib/rumonade.rb CHANGED
@@ -27,6 +27,7 @@ require "rumonade/lazy_identity"
27
27
  require "rumonade/option"
28
28
  require "rumonade/array"
29
29
  require "rumonade/either"
30
+ require "rumonade/error_handling"
30
31
 
31
32
  # = Rumonade
32
33
  #
@@ -1,4 +1,3 @@
1
- require 'singleton'
2
1
  require 'rumonade/monad'
3
2
 
4
3
  module Rumonade
@@ -0,0 +1,67 @@
1
+ require "delegate"
2
+
3
+ module Rumonade
4
+
5
+ # A partial function is a unary function where the domain does not necessarily include all values.
6
+ # The function {#defined_at?} allows to test dynamically if a value is in the domain of the function.
7
+ #
8
+ # NOTE: This is only here to mimic the Scala library just enough to allow a close translation of the exception
9
+ # handling functionality. It's not because I'm the sort that just loves pure functional idioms so damn much for
10
+ # their own sake. Just FYI.
11
+ class PartialFunction < DelegateClass(Proc)
12
+ def initialize(defined_at_proc, call_proc)
13
+ super(call_proc)
14
+ @defined_at_proc = defined_at_proc
15
+ end
16
+
17
+ # Checks if a value is contained in the function's domain.
18
+ # @param x the value to test
19
+ # @return [Boolean] Returns +true+, iff +x+ is in the domain of this function, +false+ otherwise.
20
+ def defined_at?(x)
21
+ @defined_at_proc.call(x)
22
+ end
23
+
24
+ # Composes this partial function with a fallback partial function which
25
+ # gets applied where this partial function is not defined.
26
+ # @param [PartialFunction] other the fallback function
27
+ # @return [PartialFunction] a partial function which has as domain the union of the domains
28
+ # of this partial function and +other+. The resulting partial function takes +x+ to +self.call(x)+
29
+ # where +self+ is defined, and to +other.call(x)+ where it is not.
30
+ def or_else(other)
31
+ PartialFunction.new(lambda { |x| self.defined_at?(x) || other.defined_at?(x) },
32
+ lambda { |x| if self.defined_at?(x) then self.call(x) else other.call(x) end })
33
+ end
34
+
35
+ # Composes this partial function with a transformation function that
36
+ # gets applied to results of this partial function.
37
+ # @param [Proc] func the transformation function
38
+ # @return [PartialFunction] a partial function with the same domain as this partial function, which maps
39
+ # arguments +x+ to +func.call(self.call(x))+.
40
+ def and_then(func)
41
+ PartialFunction.new(@defined_at_proc, lambda { |x| func.call(self.call(x)) })
42
+ end
43
+ end
44
+
45
+ # Classes representing the components of exception handling.
46
+ # Each class is independently composable. Some example usages:
47
+ #
48
+ # require "rumonade"
49
+ # require "uri"
50
+ #
51
+ # s = "http://"
52
+ # x1 = catching(URI::InvalidURIError).opt { URI.parse(s) }
53
+ # x2 = catching(URI::InvalidURIError, NoMethodError).either { URI.parse(s) }
54
+ #
55
+ module ErrorHandling
56
+
57
+ # Should re-raise exceptions like +Interrupt+ and +NoMemoryError+ by default.
58
+ # @param [Exception] ex the exception to consider re-raising
59
+ # @return [Boolean] Returns +true+ if a subclass of +StandardError+, otherwise +false+.
60
+ def should_reraise?(ex)
61
+ case ex
62
+ when StandardError; false
63
+ else true
64
+ end
65
+ end
66
+ end
67
+ end
@@ -40,7 +40,7 @@ module Rumonade # :nodoc:
40
40
  class << self
41
41
  # @return [Option] Returns an +Option+ containing the given value
42
42
  def unit(value)
43
- Rumonade.Option(value)
43
+ Rumonade.Some(value)
44
44
  end
45
45
 
46
46
  # @return [Option] Returns the empty +Option+
@@ -101,7 +101,7 @@ module Rumonade # :nodoc:
101
101
  end
102
102
 
103
103
  def to_s
104
- "Some(#{value.to_s})"
104
+ "Some(#{value.nil? ? 'nil' : value.to_s})"
105
105
  end
106
106
  end
107
107
 
@@ -1,3 +1,3 @@
1
1
  module Rumonade
2
- VERSION = "0.2.0"
2
+ VERSION = "0.2.1"
3
3
  end
@@ -0,0 +1,40 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/test_helper')
2
+
3
+ class ErrorHandlingTest < Test::Unit::TestCase
4
+ include Rumonade
5
+ include Rumonade::ErrorHandling
6
+
7
+ def test_partial_function_constructor_delegates_call_and_defined_at_to_given_procs
8
+ pf = PartialFunction.new(lambda { |x| x < 1000 }, lambda { |x| x * 10 })
9
+ assert pf.defined_at?(999)
10
+ assert !pf.defined_at?(1000)
11
+ assert_equal 420, pf.call(42)
12
+ end
13
+
14
+ def test_partial_function_or_else_returns_a_partial_function_with_union_of_defined_at_predicates
15
+ pf = PartialFunction.new(lambda { |x| x < 1000 }, lambda { |x| x * 10 })
16
+ .or_else(PartialFunction.new(lambda { |x| x > 5000 }, lambda { |x| x / 5 }))
17
+ assert pf.defined_at?(999)
18
+ assert !pf.defined_at?(1000)
19
+ assert !pf.defined_at?(5000)
20
+ assert pf.defined_at?(5001)
21
+ end
22
+
23
+ def test_partial_function_or_else_returns_a_partial_function_with_fallback_when_outside_defined_at
24
+ pf = PartialFunction.new(lambda { |x| x < 1000 }, lambda { |x| x * 10 })
25
+ .or_else(PartialFunction.new(lambda { |x| x > 5000 }, lambda { |x| x / 5 }))
26
+ assert_equal 9990, pf.call(999)
27
+ assert_equal 1001, pf.call(5005)
28
+ end
29
+
30
+ def test_partial_function_and_then_returns_a_partial_function_with_func_called_on_result_of_pf_call
31
+ pf = PartialFunction.new(lambda { |x| x < 1000 }, lambda { |x| x * 10 })
32
+ .and_then(lambda { |x| x / 5 })
33
+ assert_equal 1800, pf.call(900)
34
+ end
35
+
36
+ def test_should_reraise_returns_true_if_not_subclass_of_standard_error
37
+ assert should_reraise?(NoMemoryError.new)
38
+ assert !should_reraise?(ZeroDivisionError.new)
39
+ end
40
+ end
data/test/option_test.rb CHANGED
@@ -4,10 +4,10 @@ class OptionTest < Test::Unit::TestCase
4
4
  include Rumonade
5
5
  include MonadAxiomTestHelpers
6
6
 
7
- def test_when_option_with_nil_returns_none_singleton
8
- assert_same None, Option.unit(nil)
7
+ def test_when_option_with_nil_returns_none_singleton_except_unit
9
8
  assert_same None, Option(nil)
10
9
  assert_same NoneClass.instance, None
10
+ assert_not_equal None, Option.unit(nil)
11
11
  end
12
12
 
13
13
  def test_when_option_with_value_returns_some
@@ -15,6 +15,7 @@ class OptionTest < Test::Unit::TestCase
15
15
  assert_equal Some(42), Option(42)
16
16
  assert_equal Some(42), Some.new(42)
17
17
  assert_not_equal None, Some(nil)
18
+ assert_equal Some(nil), Option.unit(nil)
18
19
  end
19
20
 
20
21
  def test_when_option_constructor_raises
@@ -85,6 +86,7 @@ class OptionTest < Test::Unit::TestCase
85
86
  assert_equal "Some(1)", Some(1).to_s
86
87
  assert_equal "None", None.to_s
87
88
  assert_equal "Some(Some(None))", Some(Some(None)).to_s
89
+ assert_equal "Some(nil)", Some(nil).to_s
88
90
  end
89
91
 
90
92
  def test_each_behaves_correctly
@@ -108,4 +110,10 @@ class OptionTest < Test::Unit::TestCase
108
110
  assert_equal None, Some(1).select { |n| n < 0 }
109
111
  assert_equal None, None.select { |n| n < 0 }
110
112
  end
113
+
114
+ def test_some_map_to_nil_follows_scala_behavior_returning_some_of_nil
115
+ # scala> Option(1).map { x => null }
116
+ # res0: Option[Null] = Some(null)
117
+ assert_equal Some(nil), Option(1).map { |n| nil }
118
+ end
111
119
  end
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: rumonade
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 0.2.0
5
+ version: 0.2.1
6
6
  platform: ruby
7
7
  authors:
8
8
  - Marc Siegel
@@ -10,7 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2011-10-18 00:00:00 Z
13
+ date: 2011-10-22 00:00:00 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: test-unit
@@ -34,14 +34,15 @@ extra_rdoc_files: []
34
34
 
35
35
  files:
36
36
  - .gitignore
37
- - CHANGELOG.rdoc
38
37
  - Gemfile
38
+ - HISTORY.md
39
39
  - MIT-LICENSE.txt
40
40
  - README.rdoc
41
41
  - Rakefile
42
42
  - lib/rumonade.rb
43
43
  - lib/rumonade/array.rb
44
44
  - lib/rumonade/either.rb
45
+ - lib/rumonade/error_handling.rb
45
46
  - lib/rumonade/errors.rb
46
47
  - lib/rumonade/lazy_identity.rb
47
48
  - lib/rumonade/monad.rb
@@ -50,6 +51,7 @@ files:
50
51
  - rumonade.gemspec
51
52
  - test/array_test.rb
52
53
  - test/either_test.rb
54
+ - test/error_handling_test.rb
53
55
  - test/lazy_identity_test.rb
54
56
  - test/option_test.rb
55
57
  - test/test_helper.rb
@@ -83,6 +85,7 @@ summary: A Scala-inspired Monad library for Ruby
83
85
  test_files:
84
86
  - test/array_test.rb
85
87
  - test/either_test.rb
88
+ - test/error_handling_test.rb
86
89
  - test/lazy_identity_test.rb
87
90
  - test/option_test.rb
88
91
  - test/test_helper.rb
data/CHANGELOG.rdoc DELETED
@@ -1,22 +0,0 @@
1
- === 0.2.0 / 2011-10-18
2
-
3
- * scala-like Either class w/ LeftProjection and RightProjection monads
4
-
5
- === 0.1.2 / 2011-10-12
6
-
7
- * Progress towards Either
8
- * changed documentation to yard from rdoc
9
-
10
- === 0.1.1 / 2011-09-19
11
-
12
- * Maintenance
13
- * added a first stab at documentation for Option
14
- * fixed certain errors with #map
15
- * added #select
16
-
17
- === 0.1.0 / 2011-09-17
18
-
19
- * Initial Feature Set
20
- * general implementation and testing of monadic laws based on `unit` and `bind`
21
- * scala-like Option class w/ Some & None
22
- * scala-like extensions to Array