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.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/.codeclimate.yml +10 -39
  3. data/.github/ISSUE_TEMPLATE/----please-don-t-ask-for-support-via-issues.md +10 -0
  4. data/.github/ISSUE_TEMPLATE/---bug-report.md +34 -0
  5. data/.github/ISSUE_TEMPLATE/---feature-request.md +18 -0
  6. data/.github/workflows/ci.yml +74 -0
  7. data/.github/workflows/docsite.yml +34 -0
  8. data/.github/workflows/sync_configs.yml +34 -0
  9. data/.rspec +1 -0
  10. data/.rubocop.yml +89 -0
  11. data/CHANGELOG.md +21 -0
  12. data/CODE_OF_CONDUCT.md +13 -0
  13. data/CONTRIBUTING.md +4 -4
  14. data/Gemfile +4 -1
  15. data/LICENSE +17 -17
  16. data/README.md +2 -2
  17. data/docsite/source/case-equality.html.md +42 -0
  18. data/docsite/source/do-notation.html.md +207 -0
  19. data/docsite/source/getting-started.html.md +142 -0
  20. data/docsite/source/index.html.md +179 -0
  21. data/docsite/source/list.html.md +87 -0
  22. data/docsite/source/maybe.html.md +146 -0
  23. data/docsite/source/pattern-matching.html.md +68 -0
  24. data/docsite/source/result.html.md +190 -0
  25. data/docsite/source/task.html.md +126 -0
  26. data/docsite/source/tracing-failures.html.md +32 -0
  27. data/docsite/source/try.html.md +76 -0
  28. data/docsite/source/unit.html.md +36 -0
  29. data/docsite/source/validated.html.md +88 -0
  30. data/lib/dry/monads.rb +1 -0
  31. data/lib/dry/monads/{undefined.rb → constants.rb} +3 -1
  32. data/lib/dry/monads/do.rb +2 -1
  33. data/lib/dry/monads/do/all.rb +2 -2
  34. data/lib/dry/monads/do/mixin.rb +2 -3
  35. data/lib/dry/monads/maybe.rb +2 -4
  36. data/lib/dry/monads/result.rb +1 -1
  37. data/lib/dry/monads/right_biased.rb +52 -7
  38. data/lib/dry/monads/validated.rb +1 -1
  39. data/lib/dry/monads/version.rb +1 -1
  40. metadata +25 -5
  41. 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
@@ -1,3 +1,4 @@
1
+ require 'dry/core/constants'
1
2
  require 'dry/monads/registry'
2
3
 
3
4
  module Dry
@@ -1,8 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'dry/core/constants'
2
4
 
3
5
  module Dry
4
6
  module Monads
5
7
  # @private
6
- Undefined = Dry::Core::Constants::Undefined
8
+ include Core::Constants
7
9
  end
8
10
  end
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
@@ -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
- Dry::Monads::Do::All.included(base)
83
+ All.included(base)
84
84
  end
85
85
  end
86
86
  end
@@ -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 { |result|
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
-
@@ -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/undefined'
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 Dry::Core::Deprecations[:'dry-monads']
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)
@@ -1,6 +1,6 @@
1
1
  require 'dry/equalizer'
2
2
 
3
- require 'dry/monads/undefined'
3
+ require 'dry/monads/constants'
4
4
  require 'dry/monads/right_biased'
5
5
  require 'dry/monads/transformer'
6
6
  require 'dry/monads/conversion_stubs'
@@ -1,5 +1,4 @@
1
- require 'dry/core/constants'
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
- # @api private
211
- def destructure(*args, **kwargs)
212
- [args, kwargs]
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
@@ -1,5 +1,5 @@
1
1
  require 'dry/monads/conversion_stubs'
2
- require 'dry/monads/undefined'
2
+ require 'dry/monads/constants'
3
3
  require 'dry/monads/right_biased'
4
4
 
5
5
  module Dry
@@ -1,6 +1,6 @@
1
1
  module Dry
2
2
  module Monads
3
3
  # Gem version
4
- VERSION = '1.3.1'.freeze
4
+ VERSION = '1.3.2'.freeze
5
5
  end
6
6
  end
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.1
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-09-07 00:00:00.000000000 Z
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
- - ".travis.yml"
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.3
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