consequence 0.0.2 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +28 -82
- data/lib/consequence/monad.rb +18 -34
- data/lib/consequence/something.rb +12 -0
- data/lib/consequence/success.rb +5 -0
- data/lib/consequence/utils.rb +11 -0
- data/lib/consequence.rb +1 -7
- metadata +4 -24
- data/lib/consequence/failure.rb +0 -8
- data/lib/consequence/option.rb +0 -13
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5c2b7b3c259799b0b5a6c368a64a1f7bc0f12d6a
|
4
|
+
data.tar.gz: e441c9585001b3c347f74d129eeac6273e8e9ecd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 645626fc457cec8d73894930e7f94df018f71874c9766d39d5420a134d8d47024697b91cf1373ea997c1b6eca8435f1a0d0292f8be32951ea19c9cfbd79bd579
|
7
|
+
data.tar.gz: 86b2c7ead5e669d41a84567799c313cfbe4892e9a868e826d31489bf238d3596ee5391ca767964f359decec147b6c77881ba54f8021018fb79cdaa47fe5d787d
|
data/README.md
CHANGED
@@ -2,110 +2,56 @@
|
|
2
2
|
|
3
3
|
[![Gem Version](https://badge.fury.io/rb/consequence.svg)](http://badge.fury.io/rb/consequence)
|
4
4
|
|
5
|
-
|
5
|
+
Simple monad implementation with clear and consistent syntax.
|
6
6
|
|
7
|
-
##
|
7
|
+
## Usage
|
8
8
|
|
9
9
|
``` ruby
|
10
10
|
require 'consequence'
|
11
11
|
|
12
|
-
|
13
|
-
|
14
|
-
alias_method :m, :method
|
12
|
+
Foo = Class.new(Consequence::Monad)
|
13
|
+
Bar = Class.new(Consequence::Monad)
|
15
14
|
|
16
|
-
|
17
|
-
|
18
|
-
|
15
|
+
compare = ->(v, m) { m == Foo[0] ? Foo[1] : Bar[v] }
|
16
|
+
transform = ->(v, m) { m == Foo[1] ? 10 : 3 }
|
17
|
+
validate = ->(v) { v > 4 ? Bar[v] : Foo[v] }
|
18
|
+
increment = ->(v) { v + 1 }
|
19
19
|
|
20
|
-
|
20
|
+
react = ->(v, m) { @side_effect = v ** 2 if m.is_a?(Bar) }
|
21
|
+
log = ->(v) { @side_effect = @side_effect.to_s }
|
21
22
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
23
|
+
result = Foo[0] >>
|
24
|
+
compare >> # Foo[1]
|
25
|
+
transform >> # Foo[10]
|
26
|
+
validate >> # Bar[10]
|
27
|
+
increment >> # Bar[11]
|
28
|
+
:next << react << log
|
26
29
|
|
27
|
-
|
28
|
-
|
29
|
-
end
|
30
|
-
end
|
30
|
+
p result # Bar[12]
|
31
|
+
p @side_effect # "144"
|
31
32
|
```
|
32
33
|
|
33
|
-
##
|
34
|
+
## Operations
|
34
35
|
|
35
|
-
|
36
|
+
* `>>` - Chains a proc with the result being passed along. If the result is not a `Monad`, it is wrapped up in one.
|
36
37
|
|
37
|
-
|
38
|
+
* `<<` - The supplied proc is applied with the result being ignored and the unchanged `Monad` is passed down the chain.
|
38
39
|
|
39
|
-
If the
|
40
|
+
If the proc accepts one argument, it is passed only the `value` of the `Monad`. If it accepts two values, it is passed both the `value` and the `Monad`.
|
40
41
|
|
41
|
-
|
42
|
+
Before being called, the proc have their `#to_proc` method called. This allows a `Symbol` to be passed in, whose `#to_proc` method sends the symbol as a message to the `value` of the `Monad`.
|
42
43
|
|
43
|
-
|
44
|
-
|
45
|
-
### <<
|
46
|
-
|
47
|
-
Method is applied with the result being ignored and the unchanged Monad is passed down the chain.
|
48
|
-
|
49
|
-
If the method has a contract that requires a Monad, then the method is passed the Monad, otherwise it is passed it's value.
|
50
|
-
|
51
|
-
If called with a Symbol instead of a method, it is sent as a message to the value.
|
52
|
-
|
53
|
-
## Monad Types
|
44
|
+
## Types
|
54
45
|
|
55
46
|
### Success & Failure
|
56
47
|
|
57
|
-
A Success
|
48
|
+
A `Success` monad wraps up all exceptions in a `Failed` monad and a `Failed` monad ignores all chained methods. This allows all possible failures in a long process to be dealt with at the end.
|
58
49
|
|
59
|
-
###
|
60
|
-
|
61
|
-
A Option Monad only applies a method if it's value is not nil, otherwise it ignores them. This prevents MissingMethod errors from methods trying to be applied to nil.
|
62
|
-
|
63
|
-
## Example Implementation of Left and Right
|
64
|
-
|
65
|
-
``` ruby
|
66
|
-
require 'consequence'
|
50
|
+
### Something & Nothing
|
67
51
|
|
68
|
-
|
69
|
-
include Consequence
|
70
|
-
alias_method :m, :method
|
52
|
+
A `Something` monad wraps up a nil result in a `Nothing` monad and a `Nothing` monad ignores all chained methods. This prevents `MissingMethod` errors from trying to be call a method on `nil`.
|
71
53
|
|
72
|
-
|
73
|
-
def begin(direction = Left[0])
|
74
|
-
direction >> m(:turn) >> m(:move) << m(:log) >> m(:continue?)
|
75
|
-
end
|
76
|
-
|
77
|
-
private
|
78
|
-
|
79
|
-
Left = Class.new(Monad)
|
80
|
-
Right = Class.new(Monad)
|
81
|
-
|
82
|
-
Contract Left => Num
|
83
|
-
def move(monad)
|
84
|
-
monad.value + 5
|
85
|
-
end
|
86
|
-
|
87
|
-
Contract Right => Num
|
88
|
-
def move(monad)
|
89
|
-
monad.value - 5
|
90
|
-
end
|
91
|
-
|
92
|
-
Contract Num => Monad
|
93
|
-
def turn(value)
|
94
|
-
rand > 0.5 ? Left[value] : Right[value]
|
95
|
-
end
|
96
|
-
|
97
|
-
def log(value)
|
98
|
-
puts value
|
99
|
-
end
|
100
|
-
|
101
|
-
Contract Monad => Monad
|
102
|
-
def continue?(monad)
|
103
|
-
monad.value.abs > 25 ? monad : monad >> m(:begin)
|
104
|
-
end
|
105
|
-
end
|
106
|
-
|
107
|
-
Crab.new.begin
|
108
|
-
```
|
54
|
+
### More to come...
|
109
55
|
|
110
56
|
## Installation
|
111
57
|
|
data/lib/consequence/monad.rb
CHANGED
@@ -1,7 +1,5 @@
|
|
1
1
|
module Consequence
|
2
2
|
class Monad
|
3
|
-
include Contracts
|
4
|
-
|
5
3
|
def self.[](value)
|
6
4
|
new(value)
|
7
5
|
end
|
@@ -12,58 +10,44 @@ module Consequence
|
|
12
10
|
|
13
11
|
attr_reader :value
|
14
12
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
define_method(:>>) { |symbol| wrap(vbind(symbol.to_proc)) }
|
19
|
-
|
20
|
-
Contract Func[Not[Monad] => Not[Monad]] => Monad
|
21
|
-
define_method(:>>) { |proc| wrap(vbind(proc)) }
|
22
|
-
|
23
|
-
Contract Func[Not[Monad] => Monad] => Monad
|
24
|
-
define_method(:>>) { |proc| vbind(proc) }
|
25
|
-
|
26
|
-
Contract Func[Monad => Monad] => Monad
|
27
|
-
define_method(:>>) { |proc| bind(proc) }
|
28
|
-
|
29
|
-
Contract Func[Monad => Not[Monad]] => Monad
|
30
|
-
define_method(:>>) { |proc| wrap(bind(proc)) }
|
31
|
-
|
32
|
-
# <<
|
33
|
-
#########
|
34
|
-
Contract Symbol => Monad
|
35
|
-
define_method(:<<) { |symbol| vbind(symbol.to_proc); self }
|
36
|
-
|
37
|
-
Contract Func[Not[Monad] => Any] => Monad
|
38
|
-
define_method(:<<) { |proc| vbind(proc); self }
|
13
|
+
def >>(proc)
|
14
|
+
wrap(bind(proc.to_proc))
|
15
|
+
end
|
39
16
|
|
40
|
-
|
41
|
-
|
17
|
+
def <<(proc)
|
18
|
+
bind(proc.to_proc)
|
19
|
+
self
|
20
|
+
end
|
42
21
|
|
43
22
|
def ==(other)
|
44
23
|
self.class == other.class && value == other.value
|
45
24
|
end
|
46
25
|
|
47
26
|
def to_s
|
48
|
-
|
27
|
+
value.to_s
|
49
28
|
end
|
50
29
|
|
51
30
|
def inspect
|
52
|
-
|
31
|
+
"#{self.class}[#{value}]"
|
53
32
|
end
|
54
33
|
|
55
34
|
private
|
56
35
|
|
57
36
|
def bind(proc)
|
58
|
-
proc.call(
|
37
|
+
proc.call(*args_for(proc))
|
59
38
|
end
|
60
39
|
|
61
|
-
def
|
62
|
-
proc.
|
40
|
+
def args_for(proc)
|
41
|
+
proc.arity.abs == 1 ? [value] : [value, self]
|
63
42
|
end
|
64
43
|
|
65
44
|
def wrap(value)
|
66
|
-
self.class[value]
|
45
|
+
value.is_a?(Monad) ? value : self.class[value]
|
67
46
|
end
|
68
47
|
end
|
48
|
+
|
49
|
+
class NullMonad < Monad
|
50
|
+
def >>(_); self end
|
51
|
+
def <<(_); self end
|
52
|
+
end
|
69
53
|
end
|
data/lib/consequence/success.rb
CHANGED
data/lib/consequence.rb
CHANGED
@@ -1,12 +1,6 @@
|
|
1
|
-
require 'contracts'
|
2
|
-
|
3
1
|
module Consequence
|
4
|
-
def self.included(base)
|
5
|
-
base.include(Contracts)
|
6
|
-
end
|
7
2
|
end
|
8
3
|
|
9
4
|
require 'consequence/monad'
|
10
|
-
require 'consequence/failure'
|
11
5
|
require 'consequence/success'
|
12
|
-
require 'consequence/
|
6
|
+
require 'consequence/something'
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: consequence
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Max White
|
@@ -10,26 +10,6 @@ bindir: bin
|
|
10
10
|
cert_chain: []
|
11
11
|
date: 2015-01-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
-
- !ruby/object:Gem::Dependency
|
14
|
-
name: contracts
|
15
|
-
requirement: !ruby/object:Gem::Requirement
|
16
|
-
requirements:
|
17
|
-
- - "~>"
|
18
|
-
- !ruby/object:Gem::Version
|
19
|
-
version: '0.4'
|
20
|
-
- - ">="
|
21
|
-
- !ruby/object:Gem::Version
|
22
|
-
version: 0.4.0
|
23
|
-
type: :runtime
|
24
|
-
prerelease: false
|
25
|
-
version_requirements: !ruby/object:Gem::Requirement
|
26
|
-
requirements:
|
27
|
-
- - "~>"
|
28
|
-
- !ruby/object:Gem::Version
|
29
|
-
version: '0.4'
|
30
|
-
- - ">="
|
31
|
-
- !ruby/object:Gem::Version
|
32
|
-
version: 0.4.0
|
33
13
|
- !ruby/object:Gem::Dependency
|
34
14
|
name: rspec
|
35
15
|
requirement: !ruby/object:Gem::Requirement
|
@@ -59,10 +39,10 @@ files:
|
|
59
39
|
- LICENSE.txt
|
60
40
|
- README.md
|
61
41
|
- lib/consequence.rb
|
62
|
-
- lib/consequence/failure.rb
|
63
42
|
- lib/consequence/monad.rb
|
64
|
-
- lib/consequence/
|
43
|
+
- lib/consequence/something.rb
|
65
44
|
- lib/consequence/success.rb
|
45
|
+
- lib/consequence/utils.rb
|
66
46
|
homepage:
|
67
47
|
licenses:
|
68
48
|
- MIT
|
@@ -86,5 +66,5 @@ rubyforge_project:
|
|
86
66
|
rubygems_version: 2.2.2
|
87
67
|
signing_key:
|
88
68
|
specification_version: 4
|
89
|
-
summary:
|
69
|
+
summary: Simple monad implementation with clear and consistent syntax.
|
90
70
|
test_files: []
|
data/lib/consequence/failure.rb
DELETED