dry-monads 0.3.1 → 0.4.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: 613808228df63dd17a3199ed374ed227b5286340
4
- data.tar.gz: df17cfd8dafdee56feb611a0acae4dca01c6a17c
3
+ metadata.gz: 90f99efaec5f7f88c8f150a6af7d9f3ee2bc2a64
4
+ data.tar.gz: 82c6bb698fa47243c44367c14ab182d893c0b59c
5
5
  SHA512:
6
- metadata.gz: be3207f4e98696f3f4abc2f9b72d3c912198a1581492a9190c6d6388d86613484b6577db46138e2725cf2e6bdf078150ba8185586a1d0a8e66e4d528ab6c163d
7
- data.tar.gz: 5349bf6489ed7ec11b1300858e74a321ec963a7475465560a49318200286632fad5c06dda39e525cf6d7f5d05d3ce56bf5af776dd23543bb7bb123d8f3d066a4
6
+ metadata.gz: 559a48263fd284e9c93c1773846b66960653a37ca811b249f5482a1cc518aa83a40e71e7adb5d206c50066293e353317793cb68893935c37f8f12a36654ad854
7
+ data.tar.gz: 8c06400c56a9b753d83df82cd011477cc29ba492a3383d1df325e9fa7eaafd56bef653590cde58c4b415994c63817eac1574b12a769267cf2060ab8c0eead8d5
data/.gitignore CHANGED
@@ -7,3 +7,4 @@
7
7
  /pkg/
8
8
  /spec/reports/
9
9
  /tmp/
10
+ log/
@@ -2,32 +2,24 @@ language: ruby
2
2
  dist: trusty
3
3
  sudo: false
4
4
  cache: bundler
5
- bundler_args: --without benchmarks
5
+ bundler_args: --without benchmarks docs
6
6
  script:
7
7
  - bundle exec rake spec
8
8
  after_success:
9
- # Send coverage report from the job #1 == current MRI release
10
- - '[ "${TRAVIS_JOB_NUMBER#*.}" = "1" ] && [ "$TRAVIS_BRANCH" = "master" ] && bundle exec codeclimate-test-reporter'
9
+ - '[ -d coverage ] && bundle exec codeclimate-test-reporter'
11
10
  rvm:
12
- - 2.4.0
13
- - 2.3.3
14
- - 2.2.6
15
- - 2.1.10
16
- - jruby-9.1.7.0
11
+ - 2.2.8
12
+ - 2.3.5
13
+ - 2.4.2
14
+ - jruby-9.1.13.0
17
15
  - ruby-head
18
16
  env:
19
17
  global:
20
18
  - JRUBY_OPTS='--dev -J-Xmx1024M'
19
+ - COVERAGE=true
21
20
  matrix:
22
21
  allow_failures:
23
22
  - rvm: ruby-head
24
- - rvm: jruby-head
25
- - rvm: rbx-3
26
- include:
27
- - rvm: jruby-head
28
- before_install: gem update bundler
29
- - rvm: rbx-3
30
- before_install: gem update bundler
31
23
 
32
24
  notifications:
33
25
  email:
@@ -0,0 +1,4 @@
1
+ --markup-provider=redcarpet
2
+ --markup=markdown
3
+ --plugin junk
4
+ lib/**/*.rb
@@ -1,10 +1,39 @@
1
+ # v0.4.0 2017-11-11
2
+
3
+ ## Changed
4
+
5
+ * The `Either` monad was renamed to `Result` which sounds less nerdy but better reflects the purpose of the type. `Either::Right` became `Result::Success` and `Either::Left` became `Result::Failure`. This change is backward-compatible overall but you will see the new names when using old `Left` and `Right` methods (citizen428)
6
+ * Consequently, `Try::Success` and `Try::Failure` were renamed to `Try::Value` and `Try::Error` (flash-gordon)
7
+
8
+ ## Added
9
+
10
+ * `Try#or`, works as `Result#or` (flash-gordon)
11
+ * `Maybe#success?` and `Maybe#failure?` (aliases for `#some?` and `#none?`) (flash-gordon)
12
+ * `Either#flip` inverts a `Result` value (flash-gordon)
13
+ * `List#map` called without a block returns an `Enumerator` object (flash-gordon)
14
+ * Right-biased monads (`Maybe`, `Result`, and `Try`) now implement the `===` operator which is used for equality checks in the `case` statement (flash-gordon)
15
+ ```ruby
16
+ case value
17
+ when Some(1..100) then :ok
18
+ when Some { |x| x < 0 } then :negative
19
+ when Some(Integer) then :invalid
20
+ else raise TypeError
21
+ end
22
+ ```
23
+
24
+ ## Deprecated
25
+
26
+ * Direct accessing `value` on right-biased monads has been deprecated, use the `value!` method instead. `value!` will raise an exception if it is called on a Sailure/None/Error instance (flash-gordon)
27
+
28
+ [Compare v0.3.1...v0.4.0](https://github.com/dry-rb/dry-monads/compare/v0.3.1...v0.4.0)
29
+
1
30
  # v0.3.1 2017-03-18
2
31
 
3
32
  ## Fixed
4
33
 
5
34
  * Fixed unexpected coercing to `Hash` on `.bind` call (flash-gordon)
6
35
 
7
- [Compare v0.3.1...v0.3.0](https://github.com/dry-rb/dry-monads/compare/v0.3.0...v0.3.1)
36
+ [Compare v0.3.0...v0.3.1](https://github.com/dry-rb/dry-monads/compare/v0.3.0...v0.3.1)
8
37
 
9
38
  # v0.3.0 2017-03-16
10
39
 
@@ -17,7 +46,7 @@
17
46
  * Added `List#traverse` that "flips" the list with an embedded monad (flash-gordon + damncabbage)
18
47
  * Added `#tee` for all right-biased monads (flash-gordon)
19
48
 
20
- [Compare v0.3.0...v0.2.1](https://github.com/dry-rb/dry-monads/compare/v0.2.1...v0.3.0)
49
+ [Compare v0.2.1...v0.3.0](https://github.com/dry-rb/dry-monads/compare/v0.2.1...v0.3.0)
21
50
 
22
51
  # v0.2.1 2016-11-13
23
52
 
@@ -30,7 +59,7 @@
30
59
  * `Right(nil).to_maybe` now returns `None` with a warning instead of failing (orisaka)
31
60
  * `Some#value_or` doesn't require an argument because `None#value_or` doesn't require it either if a block was passed (flash-gordon)
32
61
 
33
- [Compare v0.2.1...v0.2.0](https://github.com/dry-rb/dry-monads/compare/v0.2.0...v0.2.1)
62
+ [Compare v0.2.0...v0.2.1](https://github.com/dry-rb/dry-monads/compare/v0.2.0...v0.2.1)
34
63
 
35
64
  # v0.2.0 2016-09-18
36
65
 
@@ -0,0 +1,29 @@
1
+ # Issue Guidelines
2
+
3
+ ## Reporting bugs
4
+
5
+ If you found a bug, report an issue and describe what's the expected behavior versus what actually happens. If the bug causes a crash, attach a full backtrace. If possible, a reproduction script showing the problem is highly appreciated.
6
+
7
+ ## Reporting feature requests
8
+
9
+ Report a feature request **only after discourseing it first on [discourse.dry-rb.org](https://discourse.dry-rb.org)** where it was accepted. Please provide a concise description of the feature, don't link to a discourseion thread, and instead summarize what was discourseed.
10
+
11
+ ## Reporting questions, support requests, ideas, concerns etc.
12
+
13
+ **PLEASE DON'T** - use [discourse.dry-rb.org](https://discourse.dry-rb.org) instead.
14
+
15
+ # Pull Request Guidelines
16
+
17
+ A Pull Request will only be accepted if it addresses a specific issue that was reported previously, or fixes typos, mistakes in documentation etc.
18
+
19
+ Other requirements:
20
+
21
+ 1) Do not open a pull request if you can't provide tests along with it. If you have problems writing tests, ask for help in the related issue.
22
+ 2) Follow the style conventions of the surrounding code. In most cases, this is standard ruby style.
23
+ 3) Add API documentation if it's a new feature
24
+ 4) Update API documentation if it changes an existing feature
25
+ 5) Bonus points for sending a PR to [github.com/dry-rb/dry-rb.org](github.com/dry-rb/dry-rb.org) which updates user documentation and guides
26
+
27
+ # Asking for help
28
+
29
+ If these guidelines aren't helpful, and you're stuck, please post a message on [discourse.dry-rb.org](https://discourse.dry-rb.org).
data/Gemfile CHANGED
@@ -9,5 +9,11 @@ end
9
9
 
10
10
  group :tools do
11
11
  gem 'pry-byebug', platform: :mri
12
- gem 'pry'
12
+ gem 'pry', platform: :jruby
13
+ end
14
+
15
+ group :docs do
16
+ gem 'yard'
17
+ gem 'yard-junk'
18
+ gem 'redcarpet'
13
19
  end
@@ -25,11 +25,12 @@ Gem::Specification.new do |spec|
25
25
  spec.bindir = 'exe'
26
26
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
27
27
  spec.require_paths = ['lib']
28
- spec.required_ruby_version = ">= 2.1.0"
28
+ spec.required_ruby_version = ">= 2.2.0"
29
29
  spec.add_dependency 'dry-equalizer'
30
- spec.add_dependency 'dry-core'
30
+ spec.add_dependency 'dry-core', '~> 0.3', '>= 0.3.3'
31
31
 
32
32
  spec.add_development_dependency 'bundler'
33
33
  spec.add_development_dependency 'rake'
34
34
  spec.add_development_dependency 'rspec'
35
+ spec.add_development_dependency 'dry-types', '>= 0.12'
35
36
  end
@@ -1,43 +1,66 @@
1
- require 'dry/monads/either'
1
+ require 'dry/core/constants'
2
2
  require 'dry/monads/maybe'
3
3
  require 'dry/monads/try'
4
4
  require 'dry/monads/list'
5
+ require 'dry/monads/result'
6
+ require 'dry/monads/result/fixed'
5
7
 
6
8
  module Dry
7
9
  # @api public
8
10
  module Monads
9
- extend self
11
+ Undefined = Dry::Core::Constants::Undefined
10
12
 
11
- # Stores the given value in one of the subtypes of {Maybe} monad.
12
- # It is essentially a wrapper for {Maybe.lift}.
13
- #
14
- # @param value [Object] the value to be stored in the monad
15
- # @return [Maybe::Some, Maybe::None]
16
- def Maybe(value)
17
- Maybe.lift(value)
18
- end
13
+ CONSTRUCTORS = [
14
+ Maybe::Mixin::Constructors,
15
+ Result::Mixin::Constructors
16
+ ].freeze
19
17
 
20
- # @param value [Object] the value to be stored in the monad
21
- # @return [Maybe::Some]
22
- def Some(value)
23
- Maybe::Some.new(value)
24
- end
18
+ Some = Maybe::Some
19
+ None = Maybe::None
20
+ Success = Result::Success
21
+ Failure = Result::Failure
25
22
 
26
- # @return [Maybe::None]
27
- def None
28
- Maybe::Some::None.instance
29
- end
23
+ extend(*CONSTRUCTORS)
24
+
25
+ def self.included(base)
26
+ super
30
27
 
31
- # @param value [Object] the value to be stored in the monad
32
- # @return [Either::Right]
33
- def Right(value)
34
- Either::Right.new(value)
28
+ base.include(*CONSTRUCTORS)
35
29
  end
36
30
 
37
- # @param value [Object] the value to be stored in the monad
38
- # @return [Either::Left]
39
- def Left(value)
40
- Either::Left.new(value)
31
+ # Creates a module that has two methods: `Success` and `Failure`.
32
+ # `Success` is identical to {Result::Mixin::Constructors#Success} and Failure
33
+ # rejects values that don't conform the value of the `error`
34
+ # parameter. This is essentially a Result type with the `Failure` part
35
+ # fixed.
36
+ #
37
+ # @example using dry-types
38
+ # module Types
39
+ # include Dry::Types.module
40
+ # end
41
+ #
42
+ # class Operation
43
+ # # :user_not_found and :account_not_found are the only
44
+ # # values allowed as failure results
45
+ # Error =
46
+ # Types.Value(:user_not_found) |
47
+ # Types.Value(:account_not_found)
48
+ #
49
+ # def find_account(id)
50
+ # account = acount_repo.find(id)
51
+ #
52
+ # account ? Success(account) : Failure(:account_not_found)
53
+ # end
54
+ #
55
+ # def find_user(id)
56
+ # # ...
57
+ # end
58
+ # end
59
+ #
60
+ # @param error [#===] the type of allowed failures
61
+ # @return [Module]
62
+ def self.Result(error, **options)
63
+ Result::Fixed[error, **options]
41
64
  end
42
65
  end
43
66
  end
@@ -1,193 +1 @@
1
- require 'dry/equalizer'
2
-
3
- require 'dry/monads/right_biased'
4
- require 'dry/monads/transformer'
5
-
6
- module Dry
7
- module Monads
8
- # Represents a value which is either correct or an error.
9
- #
10
- # @api public
11
- class Either
12
- include Dry::Equalizer(:right, :left)
13
- include Transformer
14
-
15
- attr_reader :right, :left
16
-
17
- class << self
18
- # Wraps the given value with Right
19
- #
20
- # @param value [Object] the value to be stored inside Right
21
- # @return [Either::Right]
22
- def pure(value)
23
- Right.new(value)
24
- end
25
- end
26
-
27
- # Returns self, added to keep the interface compatible with other monads.
28
- #
29
- # @return [Either::Right, Either::Left]
30
- def to_either
31
- self
32
- end
33
-
34
- # Returns the Either monad.
35
- # This is how we're doing polymorphism in Ruby 😕
36
- #
37
- # @return [Monad]
38
- def monad
39
- Either
40
- end
41
-
42
- # Represents a value that is in a correct state, i.e. everything went right.
43
- #
44
- # @api public
45
- class Right < Either
46
- include RightBiased::Right
47
-
48
- alias value right
49
-
50
- # @param right [Object] a value in a correct state
51
- def initialize(right)
52
- @right = right
53
- end
54
-
55
- # Apply the second function to value.
56
- #
57
- # @api public
58
- def either(_, f)
59
- f.call(value)
60
- end
61
-
62
- # Returns false
63
- def left?
64
- false
65
- end
66
- alias failure? left?
67
-
68
- # Returns true
69
- def right?
70
- true
71
- end
72
- alias success? right?
73
-
74
- # Does the same thing as #bind except it also wraps the value
75
- # in an instance of Either::Right monad. This allows for easier
76
- # chaining of calls.
77
- #
78
- # @example
79
- # Dry::Monads.Right(4).fmap(&:succ).fmap(->(n) { n**2 }) # => Right(25)
80
- #
81
- # @param args [Array<Object>] arguments will be transparently passed through to #bind
82
- # @return [Either::Right]
83
- def fmap(*args, &block)
84
- Right.new(bind(*args, &block))
85
- end
86
-
87
- # @return [String]
88
- def to_s
89
- "Right(#{value.inspect})"
90
- end
91
- alias inspect to_s
92
-
93
- # @return [Maybe::Some]
94
- def to_maybe
95
- Kernel.warn 'Right(nil) transformed to None' if value.nil?
96
- Dry::Monads::Maybe(value)
97
- end
98
- end
99
-
100
- # Represents a value that is in an incorrect state, i.e. something went wrong.
101
- #
102
- # @api public
103
- class Left < Either
104
- include RightBiased::Left
105
-
106
- alias value left
107
-
108
- # @param left [Object] a value in an error state
109
- def initialize(left)
110
- @left = left
111
- end
112
-
113
- # Apply the first function to value.
114
- #
115
- # @api public
116
- def either(f, _)
117
- f.call(value)
118
- end
119
-
120
- # Returns true
121
- def left?
122
- true
123
- end
124
- alias failure? left?
125
-
126
- # Returns false
127
- def right?
128
- false
129
- end
130
- alias success? right?
131
-
132
- # If a block is given passes internal value to it and returns the result,
133
- # otherwise simply returns the parameter val.
134
- #
135
- # @example
136
- # Dry::Monads.Left(ArgumentError.new('error message')).or(&:message) # => "error message"
137
- #
138
- # @param args [Array<Object>] arguments that will be passed to a block
139
- # if one was given, otherwise the first
140
- # value will be returned
141
- # @return [Object]
142
- def or(*args)
143
- if block_given?
144
- yield(value, *args)
145
- else
146
- args[0]
147
- end
148
- end
149
-
150
- # A lifted version of `#or`. Wraps the passed value or the block result with Either::Right.
151
- #
152
- # @example
153
- # Dry::Monads.Left.new('no value').or_fmap('value') # => Right("value")
154
- # Dry::Monads.Left.new('no value').or_fmap { 'value' } # => Right("value")
155
- #
156
- # @param args [Array<Object>] arguments will be passed to the underlying `#or` call
157
- # @return [Either::Right] Wrapped value
158
- def or_fmap(*args, &block)
159
- Right.new(self.or(*args, &block))
160
- end
161
-
162
- # @return [String]
163
- def to_s
164
- "Left(#{value.inspect})"
165
- end
166
- alias inspect to_s
167
-
168
- # @return [Maybe::None]
169
- def to_maybe
170
- Maybe::None.instance
171
- end
172
- end
173
-
174
- # A module that can be included for easier access to Either monads.
175
- module Mixin
176
- Right = Right
177
- Left = Left
178
-
179
- # @param value [Object] the value to be stored in the monad
180
- # @return [Either::Right]
181
- def Right(value)
182
- Right.new(value)
183
- end
184
-
185
- # @param value [Object] the value to be stored in the monad
186
- # @return [Either::Left]
187
- def Left(value)
188
- Left.new(value)
189
- end
190
- end
191
- end
192
- end
193
- end
1
+ require 'dry/monads/result'