rumonade 0.2.0 → 0.2.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/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