ruby-monads 0.3.0 → 1.0.0
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.
- checksums.yaml +4 -4
- data/.gems +2 -0
- data/.rubocop.yml +4 -0
- data/README.md +22 -22
- data/lib/ruby-monads/maybe.rb +3 -3
- data/lib/ruby-monads/monad.rb +2 -2
- data/lib/ruby-monads/result.rb +2 -2
- data/ruby-monads.gemspec +3 -1
- data/test/helper.rb +1 -1
- data/test/maybe_test.rb +10 -10
- data/test/result_test.rb +9 -9
- metadata +44 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: dd389d5593547aeb5a98a2402ea559b823c6e02ad46e78b70ccb62749cfccc4f
|
4
|
+
data.tar.gz: 92e10a0337e1a48fb836bdcc0ee1817b39eae244196ab690f5cb8c0a8e880886
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8a05486f93f6600331a38debb0a141dee45e863edd58063f78eebc691f8d97dc8a6f184f213fe058c5f8cab2c88dcf737754d0cbcc7855943de2b228f5cd0212
|
7
|
+
data.tar.gz: 53653541065be86d29394279b76fe17aa29d6685b246eb70d85b9adda7293201c2a0f2047bd2e8d189bd3c2367fee3addcf1cda3f8bfbcbd50f5b2d18170e8b0
|
data/.gems
CHANGED
data/.rubocop.yml
ADDED
data/README.md
CHANGED
@@ -24,43 +24,43 @@ include Monads
|
|
24
24
|
|
25
25
|
The maybe monad returns one of the following classes, wether it wraps a value or not:
|
26
26
|
|
27
|
-
- `Maybe.
|
28
|
-
- `Maybe.
|
27
|
+
- `Maybe.wrap(42)` returns an instance of `Just` wrapping the `42` value
|
28
|
+
- `Maybe.wrap(nil)` returns an instance of `Nothing` wrapping no value
|
29
29
|
|
30
30
|
#### Examples
|
31
31
|
|
32
32
|
```ruby
|
33
|
-
Maybe.
|
34
|
-
Maybe.
|
35
|
-
|
36
|
-
Maybe.
|
37
|
-
Maybe.
|
38
|
-
Maybe.
|
39
|
-
Maybe.
|
40
|
-
Maybe.
|
41
|
-
|
42
|
-
Maybe.
|
43
|
-
Maybe.
|
44
|
-
Maybe.
|
45
|
-
Maybe.
|
46
|
-
Maybe.
|
33
|
+
Maybe.wrap("Hello, World!") # => #<Monads::Just @value="Hello, World!">
|
34
|
+
Maybe.wrap(nil) # => #<Monads::Nothing>
|
35
|
+
|
36
|
+
Maybe.wrap("Hello, World!").upcase # => #<Monads::Just @value="HELLO, WORLD!">
|
37
|
+
Maybe.wrap("Hello, World!").upcase.split.unwrap([]) # => ["HELLO,", "WORLD!"]
|
38
|
+
Maybe.wrap("Hello, World!").bind { |v| Maybe.wrap(nil) } # => #<Monads::Nothing>
|
39
|
+
Maybe.wrap("Hello, World!").fmap { |v| v.gsub(/\w/, "*") } # => #<Monads::Just @value="*****, *****!">
|
40
|
+
Maybe.wrap(Maybe.wrap("Hello, World!")).join # => #<Monads::Just @value="Hello, World!">
|
41
|
+
|
42
|
+
Maybe.wrap(nil).upcase # => #<Monads::Nothing>
|
43
|
+
Maybe.wrap(nil).upcase.split.unwrap([]) # => []
|
44
|
+
Maybe.wrap(nil).bind { |v| Maybe.wrap("Hello, World!") } # => #<Monads::Maybe.wrap(nil)>
|
45
|
+
Maybe.wrap(nil).fmap { |v| v.gsub(/\w/, "*") } # => #<Monads::Nothing>
|
46
|
+
Maybe.wrap(Maybe.wrap(nil)).join # => #<Monads::Nothing>
|
47
47
|
```
|
48
48
|
|
49
49
|
### Result
|
50
50
|
|
51
51
|
The result monad returns one of the following classes, wether it wraps an error or not:
|
52
52
|
|
53
|
-
- `Result.
|
54
|
-
- `Result.
|
53
|
+
- `Result.wrap(42)` returns an instance of `Success` wrapping the `42` value
|
54
|
+
- `Result.wrap(StandardError.new)` returns an instance of `Failure` wrapping the given error
|
55
55
|
|
56
56
|
#### Examples
|
57
57
|
|
58
58
|
```ruby
|
59
|
-
Result.
|
60
|
-
Result.
|
59
|
+
Result.wrap("Hello, World!") # => #<Monads::Success @value="Hello, World!">
|
60
|
+
Result.wrap(StandardError.new("Wrong!")) # => #<Monads::Failure @value=#<StandardError: Wrong!>>
|
61
61
|
|
62
62
|
Result
|
63
|
-
.
|
63
|
+
.wrap("Hello, World!") # => #<Monads::Success @value="Hello, World!">
|
64
64
|
.upcase # => #<Monads::Success @value="HELLO, WORLD!">
|
65
65
|
.even # => #<Monads::Failure @value=#<NoMethodError: undefined method `even?' for "HELLO, WORLD!":String>>
|
66
66
|
.split # => #<Monads::Failure @value=#<NoMethodError: undefined method `even?' for "HELLO, WORLD!":String>>
|
@@ -77,7 +77,7 @@ This gem is heavily inspired by the following monads implementations:
|
|
77
77
|
These gems, and many others are really great, and it was very instructive to learn about this topic in my beloved language. However, after reading a lot of implementations and articles, I had a clear opinion of how I wanted it:
|
78
78
|
|
79
79
|
- _Minimalist:_ as simple an lightweight as possible
|
80
|
-
- _Respectful of uses:_ respectful of the usual terms ([Monad (functional programming)](https://en.wikipedia.org/wiki/Monad_(functional_programming))), like `Maybe`, `
|
80
|
+
- _Respectful of uses:_ respectful of the usual terms ([Monad (functional programming)](https://en.wikipedia.org/wiki/Monad_(functional_programming))), like `Maybe`, `wrap`, `bind`, `join`, etc.
|
81
81
|
- _Vanilla Ruby syntax:_ I love some of the abstractions I discovered (`>=` operator, `Just(value)` syntax). However, I also love vanilla Ruby. So, I wanted to target new methods and abstractions, not new syntaxes comming from other languages.
|
82
82
|
|
83
83
|
## Tests
|
data/lib/ruby-monads/maybe.rb
CHANGED
@@ -2,9 +2,9 @@ module Monads
|
|
2
2
|
class Maybe
|
3
3
|
include Monads::Monad
|
4
4
|
|
5
|
-
#
|
6
|
-
def self.
|
7
|
-
value.nil? || value.is_a?(Nothing) ? Nothing.new : Just.new(value)
|
5
|
+
# wrap :: a -> M a
|
6
|
+
def self.wrap(value)
|
7
|
+
(value.nil? || value.is_a?(Nothing)) ? Nothing.new : Just.new(value)
|
8
8
|
end
|
9
9
|
|
10
10
|
# bind :: (a -> M b) -> M a -> M b
|
data/lib/ruby-monads/monad.rb
CHANGED
@@ -13,14 +13,14 @@ module Monads
|
|
13
13
|
# fmap :: (a -> b) -> M a -> M b
|
14
14
|
def fmap(&block)
|
15
15
|
bind do |value|
|
16
|
-
self.class.
|
16
|
+
self.class.wrap(block.call(value))
|
17
17
|
end
|
18
18
|
end
|
19
19
|
|
20
20
|
# join :: M (M a) -> M a
|
21
21
|
def join
|
22
22
|
value = @value.is_a?(monad_type) ? @value.unwrap(nil) : @value
|
23
|
-
monad_type.
|
23
|
+
monad_type.wrap(value)
|
24
24
|
end
|
25
25
|
|
26
26
|
def method_missing(method, *args, &block)
|
data/lib/ruby-monads/result.rb
CHANGED
data/ruby-monads.gemspec
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
s.name = "ruby-monads"
|
3
|
-
s.version = "0.
|
3
|
+
s.version = "1.0.0"
|
4
4
|
s.summary = "Some common monads"
|
5
5
|
s.description = "Simple and minimalist ruby implementation of some common monads"
|
6
6
|
s.author = "Guillaume BOUDON"
|
@@ -11,4 +11,6 @@ Gem::Specification.new do |s|
|
|
11
11
|
s.files = `git ls-files`.split("\n")
|
12
12
|
|
13
13
|
s.add_development_dependency "cutest", "~> 1.2", ">= 1.2.3"
|
14
|
+
s.add_development_dependency "rubocop", "~> 1", ">= 1.68"
|
15
|
+
s.add_development_dependency "standard", "~> 1.42", ">= 1.42.1"
|
14
16
|
end
|
data/test/helper.rb
CHANGED
data/test/maybe_test.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
print "\n\"Maybe\" monad test suite"
|
2
2
|
|
3
3
|
setup do
|
4
|
-
[Maybe.
|
4
|
+
[Maybe.wrap("Hello, World!"), Maybe.wrap(nil)]
|
5
5
|
end
|
6
6
|
|
7
7
|
test "Maybe::new" do
|
@@ -14,7 +14,7 @@ test "Maybe::new" do
|
|
14
14
|
assert Nothing.new.is_a?(Nothing)
|
15
15
|
end
|
16
16
|
|
17
|
-
test "Maybe::
|
17
|
+
test "Maybe::wrap" do |just, nothing|
|
18
18
|
assert just.is_a?(Maybe)
|
19
19
|
assert just.is_a?(Just)
|
20
20
|
assert !just.is_a?(Nothing)
|
@@ -23,17 +23,17 @@ test "Maybe::unit" do |just, nothing|
|
|
23
23
|
assert !nothing.is_a?(Just)
|
24
24
|
assert nothing.is_a?(Nothing)
|
25
25
|
|
26
|
-
assert Maybe.
|
27
|
-
assert Maybe.
|
26
|
+
assert Maybe.wrap(just).is_a?(Just)
|
27
|
+
assert Maybe.wrap(nothing).is_a?(Nothing)
|
28
28
|
end
|
29
29
|
|
30
30
|
test "Maybe#bind" do |just, nothing|
|
31
|
-
assert just.bind { |v| Maybe.
|
32
|
-
assert just.bind { |v| Maybe.
|
31
|
+
assert just.bind { |v| Maybe.wrap(v.to_sym) }.is_a?(Just)
|
32
|
+
assert just.bind { |v| Maybe.wrap(nil) }.is_a?(Nothing)
|
33
33
|
assert_raise TypeError do just.bind { |v| v.to_sym } end
|
34
34
|
|
35
|
-
assert nothing.bind { |v| Maybe.
|
36
|
-
assert nothing.bind { |v| Maybe.
|
35
|
+
assert nothing.bind { |v| Maybe.wrap(42) }.is_a?(Nothing)
|
36
|
+
assert nothing.bind { |v| Maybe.wrap(nil) }.is_a?(Nothing)
|
37
37
|
assert nothing.bind { |v| v.to_sym }.is_a?(Nothing)
|
38
38
|
end
|
39
39
|
|
@@ -46,8 +46,8 @@ test "Maybe#fmap" do |just, nothing|
|
|
46
46
|
end
|
47
47
|
|
48
48
|
test "Maybe#join" do |just, nothing|
|
49
|
-
assert_equal Maybe.
|
50
|
-
assert_equal Maybe.
|
49
|
+
assert_equal Maybe.wrap(just).join.unwrap("default"), "Hello, World!"
|
50
|
+
assert_equal Maybe.wrap(nothing).join.unwrap("default"), "default"
|
51
51
|
end
|
52
52
|
|
53
53
|
test "Maybe#unwrap" do |just, nothing|
|
data/test/result_test.rb
CHANGED
@@ -14,7 +14,7 @@ test "Result::new" do
|
|
14
14
|
assert Failure.new(StandardError.new).is_a?(Failure)
|
15
15
|
end
|
16
16
|
|
17
|
-
test "Result::
|
17
|
+
test "Result::wrap" do |success, failure|
|
18
18
|
assert success.is_a?(Result)
|
19
19
|
assert success.is_a?(Success)
|
20
20
|
assert !success.is_a?(Failure)
|
@@ -23,17 +23,17 @@ test "Result::unit" do |success, failure|
|
|
23
23
|
assert !failure.is_a?(Success)
|
24
24
|
assert failure.is_a?(Failure)
|
25
25
|
|
26
|
-
assert Result.
|
27
|
-
assert Result.
|
26
|
+
assert Result.wrap(success).is_a?(Success)
|
27
|
+
assert Result.wrap(failure).is_a?(Failure)
|
28
28
|
end
|
29
29
|
|
30
30
|
test "Result#bind" do |success, failure|
|
31
|
-
assert success.bind { |v| Result.
|
32
|
-
assert success.bind { |v| Result.
|
31
|
+
assert success.bind { |v| Result.wrap(v / 2) }.is_a?(Success)
|
32
|
+
assert success.bind { |v| Result.wrap(v / 0) }.is_a?(Failure)
|
33
33
|
assert success.bind { |v| v / 0 }.is_a?(Failure)
|
34
34
|
|
35
|
-
assert failure.bind { |v| Result.
|
36
|
-
assert failure.bind { |v| Result.
|
35
|
+
assert failure.bind { |v| Result.wrap(42) }.is_a?(Failure)
|
36
|
+
assert failure.bind { |v| Result.wrap(StandardError.new) }.is_a?(Failure)
|
37
37
|
assert failure.bind { |v| v / 2 }.is_a?(Failure)
|
38
38
|
end
|
39
39
|
|
@@ -46,8 +46,8 @@ test "Result#fmap" do |success, failure|
|
|
46
46
|
end
|
47
47
|
|
48
48
|
test "Result#join" do |success, failure|
|
49
|
-
assert_equal Result.
|
50
|
-
assert_equal Result.
|
49
|
+
assert_equal Result.wrap(success).join.unwrap("default"), 42
|
50
|
+
assert_equal Result.wrap(failure).join.unwrap("default"), "default"
|
51
51
|
end
|
52
52
|
|
53
53
|
test "Result#unwrap" do |success, failure|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ruby-monads
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Guillaume BOUDON
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2024-11-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: cutest
|
@@ -30,6 +30,46 @@ dependencies:
|
|
30
30
|
- - ">="
|
31
31
|
- !ruby/object:Gem::Version
|
32
32
|
version: 1.2.3
|
33
|
+
- !ruby/object:Gem::Dependency
|
34
|
+
name: rubocop
|
35
|
+
requirement: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - "~>"
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '1'
|
40
|
+
- - ">="
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: '1.68'
|
43
|
+
type: :development
|
44
|
+
prerelease: false
|
45
|
+
version_requirements: !ruby/object:Gem::Requirement
|
46
|
+
requirements:
|
47
|
+
- - "~>"
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: '1'
|
50
|
+
- - ">="
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
version: '1.68'
|
53
|
+
- !ruby/object:Gem::Dependency
|
54
|
+
name: standard
|
55
|
+
requirement: !ruby/object:Gem::Requirement
|
56
|
+
requirements:
|
57
|
+
- - "~>"
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
version: '1.42'
|
60
|
+
- - ">="
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: 1.42.1
|
63
|
+
type: :development
|
64
|
+
prerelease: false
|
65
|
+
version_requirements: !ruby/object:Gem::Requirement
|
66
|
+
requirements:
|
67
|
+
- - "~>"
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '1.42'
|
70
|
+
- - ">="
|
71
|
+
- !ruby/object:Gem::Version
|
72
|
+
version: 1.42.1
|
33
73
|
description: Simple and minimalist ruby implementation of some common monads
|
34
74
|
email: guillaumeboudon@gmail.com
|
35
75
|
executables: []
|
@@ -38,6 +78,7 @@ extra_rdoc_files: []
|
|
38
78
|
files:
|
39
79
|
- ".gems"
|
40
80
|
- ".gitignore"
|
81
|
+
- ".rubocop.yml"
|
41
82
|
- LICENSE
|
42
83
|
- Makefile
|
43
84
|
- README.md
|
@@ -68,7 +109,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
68
109
|
- !ruby/object:Gem::Version
|
69
110
|
version: '0'
|
70
111
|
requirements: []
|
71
|
-
rubygems_version: 3.
|
112
|
+
rubygems_version: 3.3.7
|
72
113
|
signing_key:
|
73
114
|
specification_version: 4
|
74
115
|
summary: Some common monads
|