consequence 0.0.2 → 0.1.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/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
|
[](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