dry-monads 1.3.1 → 1.3.2

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