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 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