dry-monads 1.3.1 → 1.3.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.codeclimate.yml +10 -39
- data/.github/ISSUE_TEMPLATE/----please-don-t-ask-for-support-via-issues.md +10 -0
- data/.github/ISSUE_TEMPLATE/---bug-report.md +34 -0
- data/.github/ISSUE_TEMPLATE/---feature-request.md +18 -0
- data/.github/workflows/ci.yml +74 -0
- data/.github/workflows/docsite.yml +34 -0
- data/.github/workflows/sync_configs.yml +34 -0
- data/.rspec +1 -0
- data/.rubocop.yml +89 -0
- data/CHANGELOG.md +21 -0
- data/CODE_OF_CONDUCT.md +13 -0
- data/CONTRIBUTING.md +4 -4
- data/Gemfile +4 -1
- data/LICENSE +17 -17
- data/README.md +2 -2
- data/docsite/source/case-equality.html.md +42 -0
- data/docsite/source/do-notation.html.md +207 -0
- data/docsite/source/getting-started.html.md +142 -0
- data/docsite/source/index.html.md +179 -0
- data/docsite/source/list.html.md +87 -0
- data/docsite/source/maybe.html.md +146 -0
- data/docsite/source/pattern-matching.html.md +68 -0
- data/docsite/source/result.html.md +190 -0
- data/docsite/source/task.html.md +126 -0
- data/docsite/source/tracing-failures.html.md +32 -0
- data/docsite/source/try.html.md +76 -0
- data/docsite/source/unit.html.md +36 -0
- data/docsite/source/validated.html.md +88 -0
- data/lib/dry/monads.rb +1 -0
- data/lib/dry/monads/{undefined.rb → constants.rb} +3 -1
- data/lib/dry/monads/do.rb +2 -1
- data/lib/dry/monads/do/all.rb +2 -2
- data/lib/dry/monads/do/mixin.rb +2 -3
- data/lib/dry/monads/maybe.rb +2 -4
- data/lib/dry/monads/result.rb +1 -1
- data/lib/dry/monads/right_biased.rb +52 -7
- data/lib/dry/monads/validated.rb +1 -1
- data/lib/dry/monads/version.rb +1 -1
- metadata +25 -5
- data/.travis.yml +0 -38
@@ -0,0 +1,88 @@
|
|
1
|
+
---
|
2
|
+
title: Validated
|
3
|
+
layout: gem-single
|
4
|
+
name: dry-monads
|
5
|
+
---
|
6
|
+
|
7
|
+
Suppose you've got a form to validate. If you are using `Result` combined with `Do` your code might look like this:
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
require 'dry/monads'
|
11
|
+
|
12
|
+
class CreateAccount
|
13
|
+
include Dry::Monads[:result, :do]
|
14
|
+
|
15
|
+
def call(form)
|
16
|
+
name = yield validate_name(form)
|
17
|
+
email = yield validate_email(form)
|
18
|
+
password = yield validate_password(form)
|
19
|
+
|
20
|
+
user = repo.create_user(
|
21
|
+
name: name,
|
22
|
+
email: email,
|
23
|
+
password: password
|
24
|
+
)
|
25
|
+
|
26
|
+
Success(user)
|
27
|
+
end
|
28
|
+
|
29
|
+
def validate_name(form)
|
30
|
+
# Success(name) or Failure(:invalid_name)
|
31
|
+
end
|
32
|
+
|
33
|
+
def validate_email(form)
|
34
|
+
# Success(email) or Failure(:invalid_email)
|
35
|
+
end
|
36
|
+
|
37
|
+
def validate_password(form)
|
38
|
+
# Success(password) or Failure(:invalid_password)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
```
|
42
|
+
|
43
|
+
If any of the validation steps fails the user will see an error. The problem is if `name` is not valid the user won't see errors about invalid `email` and `password`, if any. `Validated` circumvents this particular problem.
|
44
|
+
|
45
|
+
`Validated` is actually not a monad but an applicative functor. This means you can't call `bind` on it. Instead, it can accumulate values in combination with `List`:
|
46
|
+
|
47
|
+
```ruby
|
48
|
+
require 'dry/monads'
|
49
|
+
|
50
|
+
class CreateAccount
|
51
|
+
include Dry::Monads[:list, :result, :validated, :do]
|
52
|
+
|
53
|
+
def call(form)
|
54
|
+
name, email, password = yield List::Validated[
|
55
|
+
validate_name(form),
|
56
|
+
validate_email(form),
|
57
|
+
validate_password(form)
|
58
|
+
].traverse.to_result
|
59
|
+
|
60
|
+
user = repo.create_user(
|
61
|
+
name: name,
|
62
|
+
email: email,
|
63
|
+
password: password
|
64
|
+
)
|
65
|
+
|
66
|
+
Success(user)
|
67
|
+
end
|
68
|
+
|
69
|
+
def validate_name(form)
|
70
|
+
# Valid(name) or Invalid(:invalid_name)
|
71
|
+
end
|
72
|
+
|
73
|
+
def validate_email(form)
|
74
|
+
# Valid(email) or Invalid(:invalid_email)
|
75
|
+
end
|
76
|
+
|
77
|
+
def validate_password(form)
|
78
|
+
# Valid(password) or Invalid(:invalid_password)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
```
|
82
|
+
|
83
|
+
Here all validations will be processed at once, if any of them fails the result will be converted to a `Failure` wrapping the `List` of errors:
|
84
|
+
|
85
|
+
```ruby
|
86
|
+
create_account.(form)
|
87
|
+
# => Failure(List[:invalid_name, :invalid_email])
|
88
|
+
```
|
data/lib/dry/monads.rb
CHANGED
data/lib/dry/monads/do.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'dry/monads/list'
|
2
2
|
require 'dry/monads/do/mixin'
|
3
|
+
require 'dry/monads/constants'
|
3
4
|
|
4
5
|
module Dry
|
5
6
|
module Monads
|
@@ -130,7 +131,7 @@ module Dry
|
|
130
131
|
|
131
132
|
# @api private
|
132
133
|
def halt(result)
|
133
|
-
raise Halt.new(result)
|
134
|
+
raise Halt.new(result), EMPTY_STRING, EMPTY_ARRAY
|
134
135
|
end
|
135
136
|
end
|
136
137
|
end
|
data/lib/dry/monads/do/all.rb
CHANGED
@@ -56,7 +56,7 @@ module Dry
|
|
56
56
|
#
|
57
57
|
module All
|
58
58
|
# @private
|
59
|
-
class MethodTracker < Module
|
59
|
+
class MethodTracker < ::Module
|
60
60
|
attr_reader :wrappers
|
61
61
|
|
62
62
|
def initialize(wrappers)
|
@@ -80,7 +80,7 @@ module Dry
|
|
80
80
|
|
81
81
|
def included(base)
|
82
82
|
super
|
83
|
-
|
83
|
+
All.included(base)
|
84
84
|
end
|
85
85
|
end
|
86
86
|
end
|
data/lib/dry/monads/do/mixin.rb
CHANGED
@@ -43,14 +43,13 @@ module Dry
|
|
43
43
|
# @api public
|
44
44
|
def bind(monads)
|
45
45
|
monads = Do.coerce_to_monad(Array(monads))
|
46
|
-
unwrapped = monads.map
|
46
|
+
unwrapped = monads.map do |result|
|
47
47
|
monad = result.to_monad
|
48
48
|
monad.or { Do.halt(monad) }.value!
|
49
|
-
|
49
|
+
end
|
50
50
|
monads.size == 1 ? unwrapped[0] : unwrapped
|
51
51
|
end
|
52
52
|
end
|
53
53
|
end
|
54
54
|
end
|
55
55
|
end
|
56
|
-
|
data/lib/dry/monads/maybe.rb
CHANGED
@@ -1,11 +1,10 @@
|
|
1
1
|
require 'dry/equalizer'
|
2
|
-
require 'dry/core/constants'
|
3
2
|
require 'dry/core/deprecations'
|
4
3
|
|
5
4
|
require 'dry/monads/right_biased'
|
6
5
|
require 'dry/monads/transformer'
|
7
6
|
require 'dry/monads/unit'
|
8
|
-
require 'dry/monads/
|
7
|
+
require 'dry/monads/constants'
|
9
8
|
|
10
9
|
module Dry
|
11
10
|
module Monads
|
@@ -16,7 +15,7 @@ module Dry
|
|
16
15
|
include Transformer
|
17
16
|
|
18
17
|
class << self
|
19
|
-
extend
|
18
|
+
extend Core::Deprecations[:'dry-monads']
|
20
19
|
|
21
20
|
# Wraps the given value with into a Maybe object.
|
22
21
|
#
|
@@ -139,7 +138,6 @@ module Dry
|
|
139
138
|
# @api public
|
140
139
|
class None < Maybe
|
141
140
|
include RightBiased::Left
|
142
|
-
include Core::Constants
|
143
141
|
|
144
142
|
@instance = new.freeze
|
145
143
|
singleton_class.send(:attr_reader, :instance)
|
data/lib/dry/monads/result.rb
CHANGED
@@ -1,5 +1,4 @@
|
|
1
|
-
require 'dry/
|
2
|
-
|
1
|
+
require 'dry/monads/constants'
|
3
2
|
require 'dry/monads/unit'
|
4
3
|
require 'dry/monads/curry'
|
5
4
|
require 'dry/monads/errors'
|
@@ -12,8 +11,6 @@ module Dry
|
|
12
11
|
#
|
13
12
|
# @api public
|
14
13
|
module Right
|
15
|
-
include Dry::Core::Constants
|
16
|
-
|
17
14
|
# @private
|
18
15
|
def self.included(m)
|
19
16
|
super
|
@@ -194,6 +191,7 @@ module Dry
|
|
194
191
|
# in Success(2..100) then ...
|
195
192
|
# in Success(2..200 => code) then ...
|
196
193
|
# end
|
194
|
+
#
|
197
195
|
# @api private
|
198
196
|
def deconstruct
|
199
197
|
if Unit.equal?(@value)
|
@@ -205,11 +203,41 @@ module Dry
|
|
205
203
|
end
|
206
204
|
end
|
207
205
|
|
206
|
+
# Pattern matching hash values
|
207
|
+
#
|
208
|
+
# @example
|
209
|
+
# case Success(x)
|
210
|
+
# in Success(code: 200...300) then :ok
|
211
|
+
# in Success(code: 300...400) then :redirect
|
212
|
+
# in Success(code: 400...500) then :user_error
|
213
|
+
# in Success(code: 500...600) then :server_error
|
214
|
+
# end
|
215
|
+
#
|
216
|
+
# @api private
|
217
|
+
def deconstruct_keys(_)
|
218
|
+
if @value.is_a?(::Hash)
|
219
|
+
@value
|
220
|
+
else
|
221
|
+
EMPTY_HASH
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
208
225
|
private
|
209
226
|
|
210
|
-
|
211
|
-
|
212
|
-
|
227
|
+
if RUBY_VERSION >= '2.7'
|
228
|
+
# @api private
|
229
|
+
def destructure(value)
|
230
|
+
if value.is_a?(::Hash)
|
231
|
+
[EMPTY_ARRAY, value]
|
232
|
+
else
|
233
|
+
[[value], EMPTY_HASH]
|
234
|
+
end
|
235
|
+
end
|
236
|
+
else
|
237
|
+
# @api private
|
238
|
+
def destructure(*args, **kwargs)
|
239
|
+
[args, kwargs]
|
240
|
+
end
|
213
241
|
end
|
214
242
|
|
215
243
|
# @api private
|
@@ -343,6 +371,23 @@ module Dry
|
|
343
371
|
[@value]
|
344
372
|
end
|
345
373
|
end
|
374
|
+
|
375
|
+
# Pattern matching hash values
|
376
|
+
#
|
377
|
+
# @example
|
378
|
+
# case Failure(x)
|
379
|
+
# in Failure(code: 400...500) then :user_error
|
380
|
+
# in Failure(code: 500...600) then :server_error
|
381
|
+
# end
|
382
|
+
#
|
383
|
+
# @api private
|
384
|
+
def deconstruct_keys(_)
|
385
|
+
if @value.is_a?(::Hash)
|
386
|
+
@value
|
387
|
+
else
|
388
|
+
EMPTY_HASH
|
389
|
+
end
|
390
|
+
end
|
346
391
|
end
|
347
392
|
end
|
348
393
|
end
|
data/lib/dry/monads/validated.rb
CHANGED
data/lib/dry/monads/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dry-monads
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.3.
|
4
|
+
version: 1.3.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nikita Shilnikov
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-
|
11
|
+
date: 2019-11-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: dry-equalizer
|
@@ -122,11 +122,18 @@ extensions: []
|
|
122
122
|
extra_rdoc_files: []
|
123
123
|
files:
|
124
124
|
- ".codeclimate.yml"
|
125
|
+
- ".github/ISSUE_TEMPLATE/----please-don-t-ask-for-support-via-issues.md"
|
126
|
+
- ".github/ISSUE_TEMPLATE/---bug-report.md"
|
127
|
+
- ".github/ISSUE_TEMPLATE/---feature-request.md"
|
128
|
+
- ".github/workflows/ci.yml"
|
129
|
+
- ".github/workflows/docsite.yml"
|
130
|
+
- ".github/workflows/sync_configs.yml"
|
125
131
|
- ".gitignore"
|
126
132
|
- ".rspec"
|
127
|
-
- ".
|
133
|
+
- ".rubocop.yml"
|
128
134
|
- ".yardopts"
|
129
135
|
- CHANGELOG.md
|
136
|
+
- CODE_OF_CONDUCT.md
|
130
137
|
- CONTRIBUTING.md
|
131
138
|
- Gemfile
|
132
139
|
- LICENSE
|
@@ -134,10 +141,24 @@ files:
|
|
134
141
|
- Rakefile
|
135
142
|
- bin/console
|
136
143
|
- bin/setup
|
144
|
+
- docsite/source/case-equality.html.md
|
145
|
+
- docsite/source/do-notation.html.md
|
146
|
+
- docsite/source/getting-started.html.md
|
147
|
+
- docsite/source/index.html.md
|
148
|
+
- docsite/source/list.html.md
|
149
|
+
- docsite/source/maybe.html.md
|
150
|
+
- docsite/source/pattern-matching.html.md
|
151
|
+
- docsite/source/result.html.md
|
152
|
+
- docsite/source/task.html.md
|
153
|
+
- docsite/source/tracing-failures.html.md
|
154
|
+
- docsite/source/try.html.md
|
155
|
+
- docsite/source/unit.html.md
|
156
|
+
- docsite/source/validated.html.md
|
137
157
|
- dry-monads.gemspec
|
138
158
|
- lib/dry-monads.rb
|
139
159
|
- lib/dry/monads.rb
|
140
160
|
- lib/dry/monads/all.rb
|
161
|
+
- lib/dry/monads/constants.rb
|
141
162
|
- lib/dry/monads/conversion_stubs.rb
|
142
163
|
- lib/dry/monads/curry.rb
|
143
164
|
- lib/dry/monads/do.rb
|
@@ -156,7 +177,6 @@ files:
|
|
156
177
|
- lib/dry/monads/transformer.rb
|
157
178
|
- lib/dry/monads/traverse.rb
|
158
179
|
- lib/dry/monads/try.rb
|
159
|
-
- lib/dry/monads/undefined.rb
|
160
180
|
- lib/dry/monads/unit.rb
|
161
181
|
- lib/dry/monads/validated.rb
|
162
182
|
- lib/dry/monads/version.rb
|
@@ -182,7 +202,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
182
202
|
- !ruby/object:Gem::Version
|
183
203
|
version: '0'
|
184
204
|
requirements: []
|
185
|
-
rubygems_version: 3.0.
|
205
|
+
rubygems_version: 3.0.6
|
186
206
|
signing_key:
|
187
207
|
specification_version: 4
|
188
208
|
summary: Common monads for Ruby.
|
data/.travis.yml
DELETED
@@ -1,38 +0,0 @@
|
|
1
|
-
language: ruby
|
2
|
-
dist: trusty
|
3
|
-
cache: bundler
|
4
|
-
bundler_args: --without benchmarks docs
|
5
|
-
script:
|
6
|
-
- bundle exec rspec spec
|
7
|
-
before_install:
|
8
|
-
- gem update --system
|
9
|
-
- gem install bundler
|
10
|
-
after_success:
|
11
|
-
- "[ -d coverage ] && bundle exec codeclimate-test-reporter"
|
12
|
-
rvm:
|
13
|
-
- 2.4.7
|
14
|
-
- 2.5.6
|
15
|
-
- 2.6.4
|
16
|
-
- ruby-head
|
17
|
-
- jruby-9.2.7.0
|
18
|
-
env:
|
19
|
-
global:
|
20
|
-
- JRUBY_OPTS='--dev -J-Xmx1024M'
|
21
|
-
- COVERAGE=true
|
22
|
-
matrix:
|
23
|
-
allow_failures:
|
24
|
-
- rvm: ruby-head
|
25
|
-
|
26
|
-
notifications:
|
27
|
-
email:
|
28
|
-
recipients:
|
29
|
-
- fg@flashgordon.ru
|
30
|
-
on_success: change
|
31
|
-
on_failure: always
|
32
|
-
on_start: false # default: false
|
33
|
-
webhooks:
|
34
|
-
urls:
|
35
|
-
- https://webhooks.gitter.im/e/19098b4253a72c9796db
|
36
|
-
on_success: change # options: [always|never|change] default: always
|
37
|
-
on_failure: always # options: [always|never|change] default: always
|
38
|
-
on_start: false # default: false
|