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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 6cdf2c9dad1c8995f8853db69da3d6804daf2029
4
- data.tar.gz: bfc2e9093a371c54ee2c39c273c2c5ffea14ba18
3
+ metadata.gz: 5c2b7b3c259799b0b5a6c368a64a1f7bc0f12d6a
4
+ data.tar.gz: e441c9585001b3c347f74d129eeac6273e8e9ecd
5
5
  SHA512:
6
- metadata.gz: 3066cbf8aa5a1415c37788e81f550c9ad96cc6b4a69604c26a2bc2ac8936e9ee610edc20b49bb694f37082b8cc8a084c0e9660f9e4bfb0085a00622550c0014b
7
- data.tar.gz: 845c28a333e1ef7676cba5bbb6af7846eed3af5495e184b64a60f64adc7ebf3e128684886f59122d9bc804874f196154f77664cf5d0a1cc91622c3f56dbb6f71
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
- Monad implementation to be used with [contracts.ruby](https://github.com/egonSchiele/contracts.ruby)
5
+ Simple monad implementation with clear and consistent syntax.
6
6
 
7
- ## Example Usage
7
+ ## Usage
8
8
 
9
9
  ``` ruby
10
10
  require 'consequence'
11
11
 
12
- class HirePirate
13
- include Consequence
14
- alias_method :m, :method
12
+ Foo = Class.new(Consequence::Monad)
13
+ Bar = Class.new(Consequence::Monad)
15
14
 
16
- def apply(applicant)
17
- Success[applicant] >> m(:eye_patch_check) << m(:log) >> :sign_and_date
18
- end
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
- private
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
- Contract Applicant => Monad
23
- def eye_patch_check(applicant)
24
- applicant.working_eyes > 1 ? Failure['Too many eyes'] : Success[Pirate.new(applicant)]
25
- end
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
- def log(pirate)
28
- puts "#{pirate.name} has joined the crew"
29
- end
30
- end
30
+ p result # Bar[12]
31
+ p @side_effect # "144"
31
32
  ```
32
33
 
33
- ## Monad Methods
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
- Chains a method with the result being passed down the chain.
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 method has a contract that requires a Monad, then the method is passed the Monad, otherwise it is passed it's value.
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
- If the method has a contract that returns a Monad, then that Monad is passed down the chain, otherwise the result of the method is taken as the value for a new Monad.
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
- If called with a Symbol instead of a method, it is sent as a message to the value, and the result is taken as the value for a new Monad.
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 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.
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
- ### Option
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
- class Crab
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
- Contract Monad => Monad
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
 
@@ -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
- Contract Symbol => Monad
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
- Contract Func[Monad => Any] => Monad
41
- define_method(:<<) { |proc| bind(proc); self }
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
- "#{self.class}[#{value}]"
27
+ value.to_s
49
28
  end
50
29
 
51
30
  def inspect
52
- to_s
31
+ "#{self.class}[#{value}]"
53
32
  end
54
33
 
55
34
  private
56
35
 
57
36
  def bind(proc)
58
- proc.call(self)
37
+ proc.call(*args_for(proc))
59
38
  end
60
39
 
61
- def vbind(proc)
62
- proc.call(value)
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
@@ -0,0 +1,12 @@
1
+ module Consequence
2
+ class Something < Monad
3
+ def >>(proc)
4
+ result = super
5
+ result.value.nil? ? Nothing[nil] : result
6
+ end
7
+ end
8
+
9
+ class Nothing < NullMonad
10
+ def nil?; true end
11
+ end
12
+ end
@@ -15,4 +15,9 @@ module Consequence
15
15
  def succeeded?; true end
16
16
  def failed?; false end
17
17
  end
18
+
19
+ class Failure < NullMonad
20
+ def succeeded?; false end
21
+ def failed?; true end
22
+ end
18
23
  end
@@ -0,0 +1,11 @@
1
+ module Consequence
2
+ module Utils
3
+ def send_to_value(*args)
4
+ ->(v) { v.send(*args) }
5
+ end
6
+
7
+ def send_to_monad(*args)
8
+ ->(v, m) { m.send(*args) }
9
+ end
10
+ end
11
+ end
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/option'
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.2
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/option.rb
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: Monad implementation to used in with contracts.ruby
69
+ summary: Simple monad implementation with clear and consistent syntax.
90
70
  test_files: []
@@ -1,8 +0,0 @@
1
- module Consequence
2
- class Failure < Monad
3
- def >>(_); self end
4
- def <<(_); self end
5
- def succeeded?; false end
6
- def failed?; true end
7
- end
8
- end
@@ -1,13 +0,0 @@
1
- module Consequence
2
- class Option < Monad
3
- def >>(proc)
4
- value ? super : self
5
- end
6
-
7
- def <<(proc)
8
- super if value
9
- end
10
-
11
- def nil?; value.nil? end
12
- end
13
- end