dry-monads 1.3.5 → 1.5.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.
Files changed (64) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +152 -80
  3. data/LICENSE +1 -1
  4. data/README.md +5 -4
  5. data/dry-monads.gemspec +31 -30
  6. data/lib/dry/monads/all.rb +2 -3
  7. data/lib/dry/monads/constants.rb +0 -2
  8. data/lib/dry/monads/curry.rb +2 -2
  9. data/lib/dry/monads/do/all.rb +35 -18
  10. data/lib/dry/monads/do.rb +48 -20
  11. data/lib/dry/monads/errors.rb +8 -5
  12. data/lib/dry/monads/lazy.rb +13 -5
  13. data/lib/dry/monads/list.rb +27 -37
  14. data/lib/dry/monads/maybe.rb +85 -26
  15. data/lib/dry/monads/registry.rb +20 -20
  16. data/lib/dry/monads/result/fixed.rb +31 -24
  17. data/lib/dry/monads/result.rb +37 -19
  18. data/lib/dry/monads/right_biased.rb +38 -31
  19. data/lib/dry/monads/task.rb +25 -28
  20. data/lib/dry/monads/transformer.rb +2 -1
  21. data/lib/dry/monads/traverse.rb +5 -1
  22. data/lib/dry/monads/try.rb +45 -18
  23. data/lib/dry/monads/unit.rb +9 -3
  24. data/lib/dry/monads/validated.rb +18 -18
  25. data/lib/dry/monads/version.rb +1 -1
  26. data/lib/dry/monads.rb +25 -4
  27. data/lib/dry-monads.rb +1 -1
  28. data/lib/json/add/dry/monads/maybe.rb +5 -5
  29. metadata +22 -54
  30. data/.codeclimate.yml +0 -12
  31. data/.github/ISSUE_TEMPLATE/----please-don-t-ask-for-support-via-issues.md +0 -10
  32. data/.github/ISSUE_TEMPLATE/---bug-report.md +0 -30
  33. data/.github/ISSUE_TEMPLATE/---feature-request.md +0 -18
  34. data/.github/workflows/ci.yml +0 -52
  35. data/.github/workflows/docsite.yml +0 -34
  36. data/.github/workflows/sync_configs.yml +0 -56
  37. data/.gitignore +0 -10
  38. data/.rspec +0 -4
  39. data/.rubocop.yml +0 -101
  40. data/.yardopts +0 -4
  41. data/CODE_OF_CONDUCT.md +0 -13
  42. data/CONTRIBUTING.md +0 -29
  43. data/Gemfile +0 -19
  44. data/Gemfile.devtools +0 -14
  45. data/Rakefile +0 -8
  46. data/bin/.gitkeep +0 -0
  47. data/bin/console +0 -17
  48. data/bin/setup +0 -7
  49. data/docsite/source/case-equality.html.md +0 -42
  50. data/docsite/source/do-notation.html.md +0 -207
  51. data/docsite/source/getting-started.html.md +0 -142
  52. data/docsite/source/index.html.md +0 -179
  53. data/docsite/source/list.html.md +0 -87
  54. data/docsite/source/maybe.html.md +0 -146
  55. data/docsite/source/pattern-matching.html.md +0 -68
  56. data/docsite/source/result.html.md +0 -190
  57. data/docsite/source/task.html.md +0 -126
  58. data/docsite/source/tracing-failures.html.md +0 -32
  59. data/docsite/source/try.html.md +0 -76
  60. data/docsite/source/unit.html.md +0 -36
  61. data/docsite/source/validated.html.md +0 -88
  62. data/lib/dry/monads/either.rb +0 -66
  63. data/log/.gitkeep +0 -0
  64. data/project.yml +0 -2
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'dry/monads/do'
4
-
5
3
  module Dry
6
4
  module Monads
7
5
  module Do
@@ -68,9 +66,10 @@ module Dry
68
66
  tracker = self
69
67
 
70
68
  module_eval do
69
+ private
70
+
71
71
  define_method(:method_added) do |method|
72
72
  super(method)
73
-
74
73
  tracker.wrap_method(self, method)
75
74
  end
76
75
 
@@ -93,20 +92,37 @@ module Dry
93
92
  end
94
93
 
95
94
  def wrap_method(target, method)
96
- Do.wrap_method(wrappers[target], method)
95
+ visibility = Do.method_visibility(target, method)
96
+ Do.wrap_method(wrappers[target], method, visibility)
97
97
  end
98
98
  end
99
99
 
100
- # @api private
101
- def self.included(base)
102
- super
100
+ class << self
101
+ # @api private
102
+ def included(base)
103
+ super
104
+
105
+ wrappers = ::Hash.new { _1[_2] = ::Module.new }
106
+ tracker = MethodTracker.new(wrappers)
107
+ base.extend(tracker)
108
+ base.extend(InstanceMixin) unless base.is_a?(::Class)
109
+ wrap_defined_methods(base, wrappers[base])
110
+ end
103
111
 
104
- wrappers = ::Hash.new { |h, k| h[k] = ::Module.new }
105
- tracker = MethodTracker.new(wrappers)
106
- base.extend(tracker)
107
- base.instance_methods(false).each { |m| tracker.wrap_method(base, m) }
112
+ # @api private
113
+ def wrap_defined_methods(klass, target)
114
+ klass.public_instance_methods(false).each do |m|
115
+ Do.wrap_method(target, m, :public)
116
+ end
117
+
118
+ klass.protected_instance_methods(false).each do |m|
119
+ Do.wrap_method(target, m, :protected)
120
+ end
108
121
 
109
- base.extend(InstanceMixin) unless base.is_a?(::Class)
122
+ klass.private_instance_methods(false).each do |m|
123
+ Do.wrap_method(target, m, :private)
124
+ end
125
+ end
110
126
  end
111
127
 
112
128
  # @api private
@@ -116,17 +132,18 @@ module Dry
116
132
  super
117
133
 
118
134
  wrapper = ::Module.new
119
- object.singleton_class.prepend(wrapper)
135
+ eigenclass = object.singleton_class
136
+ eigenclass.prepend(wrapper)
120
137
  object.define_singleton_method(:singleton_method_added) do |method|
121
138
  super(method)
122
139
 
123
140
  next if method.equal?(:singleton_method_added)
124
141
 
125
- Do.wrap_method(wrapper, method)
126
- end
127
- object.singleton_class.instance_methods(false).each do |m|
128
- Do.wrap_method(wrapper, m)
142
+ visibility = Do.method_visibility(eigenclass, method)
143
+ Do.wrap_method(wrapper, method, visibility)
129
144
  end
145
+
146
+ All.wrap_defined_methods(eigenclass, wrapper)
130
147
  end
131
148
  end
132
149
 
@@ -134,7 +151,7 @@ module Dry
134
151
  end
135
152
  end
136
153
 
137
- require 'dry/monads/registry'
154
+ require "dry/monads/registry"
138
155
  register_mixin(:do, Do::All)
139
156
  end
140
157
  end
data/lib/dry/monads/do.rb CHANGED
@@ -1,9 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'dry/monads/list'
4
- require 'dry/monads/do/mixin'
5
- require 'dry/monads/constants'
6
-
7
3
  module Dry
8
4
  module Monads
9
5
  # An implementation of do-notation.
@@ -12,7 +8,11 @@ module Dry
12
8
  module Do
13
9
  extend Mixin
14
10
 
15
- DELEGATE = ::RUBY_VERSION < '2.7' ? '*' : '...'
11
+ VISIBILITY_WORD = {
12
+ public: "",
13
+ private: "private ",
14
+ protected: "protected "
15
+ }.freeze
16
16
 
17
17
  # @api private
18
18
  class Halt < StandardError
@@ -26,6 +26,25 @@ module Dry
26
26
  end
27
27
  end
28
28
 
29
+ # @api private
30
+ class MethodTracker < ::Module
31
+ # @api private
32
+ def initialize(tracked_methods, base, wrapper)
33
+ module_eval do
34
+ private
35
+
36
+ define_method(:method_added) do |method|
37
+ super(method)
38
+
39
+ if tracked_methods.include?(method)
40
+ visibility = Do.method_visibility(base, method)
41
+ Do.wrap_method(wrapper, method, visibility)
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
47
+
29
48
  class << self
30
49
  # Generates a module that passes a block to methods
31
50
  # that either unwraps a single-valued monadic value or halts
@@ -84,13 +103,11 @@ module Dry
84
103
  # @param [Array<Symbol>] methods
85
104
  # @return [Module]
86
105
  def for(*methods)
87
- mod = ::Module.new do
88
- methods.each { |method_name| Do.wrap_method(self, method_name) }
89
- end
90
-
91
106
  ::Module.new do
92
- singleton_class.send(:define_method, :included) do |base|
107
+ singleton_class.define_method(:included) do |base|
108
+ mod = ::Module.new
93
109
  base.prepend(mod)
110
+ base.extend(MethodTracker.new(methods, base, mod))
94
111
  end
95
112
  end
96
113
  end
@@ -100,23 +117,34 @@ module Dry
100
117
  super
101
118
 
102
119
  # Actually mixes in Do::All
103
- require 'dry/monads/do/all'
120
+ require "dry/monads/do/all"
104
121
  base.include All
105
122
  end
106
123
 
107
124
  # @api private
108
- def wrap_method(target, method_name)
125
+ def wrap_method(target, method, visibility)
109
126
  target.module_eval(<<-RUBY, __FILE__, __LINE__ + 1)
110
- def #{method_name}(#{DELEGATE})
111
- if block_given?
112
- super
113
- else
114
- Do.() { super { |*ms| Do.bind(ms) } }
115
- end
116
- end
127
+ #{VISIBILITY_WORD[visibility]} def #{method}(...) # private def create_acccount(...)
128
+ if block_given? # if block_given?
129
+ super # super
130
+ else # else
131
+ Do.() { super { |*ms| Do.bind(ms) } } # Do.() { super { |*ms| Do.bind(ms) } }
132
+ end # end
133
+ end # end
117
134
  RUBY
118
135
  end
119
136
 
137
+ # @api private
138
+ def method_visibility(mod, method)
139
+ if mod.public_method_defined?(method)
140
+ :public
141
+ elsif mod.private_method_defined?(method)
142
+ :private
143
+ else
144
+ :protected
145
+ end
146
+ end
147
+
120
148
  # @api private
121
149
  def coerce_to_monad(monads)
122
150
  return monads if monads.size != 1
@@ -135,7 +163,7 @@ module Dry
135
163
 
136
164
  # @api private
137
165
  def halt(result)
138
- raise Halt.new(result), EMPTY_STRING, []
166
+ raise Halt.new(result), "", []
139
167
  end
140
168
  end
141
169
  end
@@ -3,21 +3,24 @@
3
3
  module Dry
4
4
  module Monads
5
5
  # An unsuccessful result of extracting a value from a monad.
6
- class UnwrapError < StandardError
7
- def initialize(ctx)
8
- super("value! was called on #{ctx.inspect}")
6
+ class UnwrapError < ::StandardError
7
+ attr_reader :receiver
8
+
9
+ def initialize(receiver)
10
+ @receiver = receiver
11
+ super("value! was called on #{receiver.inspect}")
9
12
  end
10
13
  end
11
14
 
12
15
  # An error thrown on returning a Failure of unknown type.
13
- class InvalidFailureTypeError < StandardError
16
+ class InvalidFailureTypeError < ::StandardError
14
17
  def initialize(failure)
15
18
  super("Cannot create Failure from #{failure.inspect}, it doesn't meet the constraints")
16
19
  end
17
20
  end
18
21
 
19
22
  # Improper use of None
20
- class ConstructorNotAppliedError < NoMethodError
23
+ class ConstructorNotAppliedError < ::NoMethodError
21
24
  def initialize(method_name, constructor_name)
22
25
  super(
23
26
  "For calling .#{method_name} on #{constructor_name}() build a value "\
@@ -1,8 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'concurrent/promise'
4
-
5
- require 'dry/monads/task'
3
+ require "concurrent/promise"
6
4
 
7
5
  module Dry
8
6
  module Monads
@@ -11,6 +9,8 @@ module Dry
11
9
  # computation is evaluated not more than once (compare with the built-in
12
10
  # lazy assignement ||= which does not guarantee this).
13
11
  class Lazy < Task
12
+ extend ::Dry::Core::Deprecations[:"dry-monads"]
13
+
14
14
  class << self
15
15
  # @private
16
16
  def new(promise = nil, &block)
@@ -41,6 +41,14 @@ module Dry
41
41
  self
42
42
  end
43
43
 
44
+ # @return [Boolean]
45
+ def evaluated?
46
+ @promise.complete?
47
+ end
48
+ deprecate :complete?, :evaluated?
49
+
50
+ undef_method :wait
51
+
44
52
  # @return [String]
45
53
  def to_s
46
54
  state = case promise.state
@@ -49,7 +57,7 @@ module Dry
49
57
  when :rejected
50
58
  "!#{promise.reason.inspect}"
51
59
  else
52
- '?'
60
+ "?"
53
61
  end
54
62
 
55
63
  "Lazy(#{state})"
@@ -80,7 +88,7 @@ module Dry
80
88
  end
81
89
  end
82
90
 
83
- require 'dry/monads/registry'
91
+ require "dry/monads/registry"
84
92
  register_mixin(:lazy, Lazy::Mixin)
85
93
  end
86
94
  end
@@ -1,15 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'dry/equalizer'
4
-
5
- require 'dry/monads/maybe'
6
- require 'dry/monads/task'
7
- require 'dry/monads/result'
8
- require 'dry/monads/try'
9
- require 'dry/monads/validated'
10
- require 'dry/monads/transformer'
11
- require 'dry/monads/curry'
12
-
13
3
  module Dry
14
4
  module Monads
15
5
  # The List monad.
@@ -83,7 +73,7 @@ module Dry
83
73
  end
84
74
  end
85
75
 
86
- extend Dry::Core::Deprecations[:'dry-monads']
76
+ extend Dry::Core::Deprecations[:"dry-monads"]
87
77
 
88
78
  include Dry::Equalizer(:value, :type)
89
79
  include Transformer
@@ -110,10 +100,10 @@ module Dry
110
100
  # @return [List]
111
101
  def bind(*args)
112
102
  if block_given?
113
- List.coerce(value.map { |v| yield(v, *args) }.reduce([], &:+))
103
+ List.coerce(value.map { yield(_1, *args) }.reduce([], &:+))
114
104
  else
115
105
  obj, *rest = args
116
- List.coerce(value.map { |v| obj.(v, *rest) }.reduce([], &:+))
106
+ List.coerce(value.map { obj.(_1, *rest) }.reduce([], &:+))
117
107
  end
118
108
  end
119
109
 
@@ -128,22 +118,22 @@ module Dry
128
118
  # @return [List]
129
119
  def fmap(*args)
130
120
  if block_given?
131
- List.new(value.map { |v| yield(v, *args) })
121
+ List.new(value.map { yield(_1, *args) })
132
122
  else
133
123
  obj, *rest = args
134
- List.new(value.map { |v| obj.(v, *rest) })
124
+ List.new(value.map { obj.(_1, *rest) })
135
125
  end
136
126
  end
137
127
 
138
128
  # Maps a block over the list. Acts as `Array#map`.
139
- # Note that this method returns an Array instance, not a List
129
+ # If called without a block, this method returns an enumerator, not a List
140
130
  #
141
131
  # @return [List,Enumerator]
142
132
  def map(&block)
143
- if block
133
+ if block_given?
144
134
  fmap(block)
145
135
  else
146
- value.map(&block)
136
+ value.map
147
137
  end
148
138
  end
149
139
 
@@ -165,7 +155,7 @@ module Dry
165
155
  #
166
156
  # @return [String]
167
157
  def inspect
168
- type_ann = typed? ? "<#{type.name.split('::').last}>" : ''
158
+ type_ann = typed? ? "<#{type.name.split("::").last}>" : ""
169
159
  "List#{type_ann}#{value.inspect}"
170
160
  end
171
161
  alias_method :to_s, :inspect
@@ -192,8 +182,8 @@ module Dry
192
182
  #
193
183
  # @param initial [Object] Initial value
194
184
  # @return [Object]
195
- def fold_left(initial)
196
- value.reduce(initial) { |acc, v| yield(acc, v) }
185
+ def fold_left(initial, &block)
186
+ value.reduce(initial, &block)
197
187
  end
198
188
  alias_method :foldl, :fold_left
199
189
  alias_method :reduce, :fold_left
@@ -224,8 +214,8 @@ module Dry
224
214
  # Filters elements with a block
225
215
  #
226
216
  # @return [List]
227
- def filter
228
- coerce(value.select { |e| yield(e) })
217
+ def filter(&block)
218
+ coerce(value.select(&block))
229
219
  end
230
220
  alias_method :select, :filter
231
221
 
@@ -265,12 +255,12 @@ module Dry
265
255
  def typed(type = nil)
266
256
  if type.nil?
267
257
  if size.zero?
268
- raise ArgumentError, 'Cannot infer a monad for an empty list'
258
+ raise ArgumentError, "Cannot infer a monad for an empty list"
269
259
  else
270
260
  self.class.warn(
271
- 'Automatic monad inference is deprecated, pass a type explicitly '\
261
+ "Automatic monad inference is deprecated, pass a type explicitly "\
272
262
  "or use a predefined constant, e.g. List::Result\n"\
273
- "#{caller.find { |l| l !~ %r{(lib/dry/monads)|(gems)} }}"
263
+ "#{caller.find { _1 !~ %r{(lib/dry/monads)|(gems)} }}"
274
264
  )
275
265
  self.class.new(value, value[0].monad)
276
266
  end
@@ -298,7 +288,7 @@ module Dry
298
288
  # @return [Monad] Result is a monadic value
299
289
  def traverse(proc = nil, &block)
300
290
  unless typed?
301
- raise StandardError, 'Cannot traverse an untyped list'
291
+ raise StandardError, "Cannot traverse an untyped list"
302
292
  end
303
293
 
304
294
  cons = type.pure { |list, i| list + List.pure(i) }
@@ -315,9 +305,9 @@ module Dry
315
305
  #
316
306
  # @param list [List]
317
307
  # @return [List]
318
- def apply(list = Undefined)
319
- v = Undefined.default(list) { yield }
320
- fmap(Curry).bind { |f| v.fmap { |x| f.(x) } }
308
+ def apply(list = Undefined, &block)
309
+ v = Undefined.default(list, &block)
310
+ fmap(Curry).bind { |f| v.fmap { f.(_1) } }
321
311
  end
322
312
 
323
313
  # Returns the List monad.
@@ -329,7 +319,7 @@ module Dry
329
319
 
330
320
  # Returns self.
331
321
  #
332
- # @return [Result::Success, Result::Failure]
322
+ # @return [List]
333
323
  def to_monad
334
324
  self
335
325
  end
@@ -345,7 +335,7 @@ module Dry
345
335
  # Some(n / divisor)
346
336
  # end
347
337
  # end
348
- # # => List[4, 2]
338
+ # # => List[2, 4]
349
339
  #
350
340
  # @example without block
351
341
  # List[Some(5), None(), Some(3)].collect.map { |x| x * 2 }
@@ -362,7 +352,7 @@ module Dry
362
352
  List.new(collected)
363
353
  else
364
354
  Enumerator.new do |g|
365
- value.each { |x| g << x.value! if x.some? }
355
+ value.each { g << _1.value! if _1.some? }
366
356
  end
367
357
  end
368
358
  end
@@ -422,10 +412,10 @@ module Dry
422
412
  # List of results
423
413
  Result = ListBuilder[Result]
424
414
 
425
- # List of results
415
+ # List of maybes
426
416
  Maybe = ListBuilder[Maybe]
427
417
 
428
- # List of results
418
+ # List of tries
429
419
  Try = ListBuilder[Try]
430
420
 
431
421
  # List of validation results
@@ -449,9 +439,9 @@ module Dry
449
439
  end
450
440
  end
451
441
 
452
- require 'dry/monads/registry'
442
+ require "dry/monads/registry"
453
443
  register_mixin(:list, List::Mixin)
454
444
  end
455
445
  end
456
446
 
457
- require 'dry/monads/traverse'
447
+ require "dry/monads/traverse"
@@ -1,13 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'dry/equalizer'
4
- require 'dry/core/deprecations'
5
-
6
- require 'dry/monads/right_biased'
7
- require 'dry/monads/transformer'
8
- require 'dry/monads/unit'
9
- require 'dry/monads/constants'
10
-
11
3
  module Dry
12
4
  module Monads
13
5
  # Represents a value which can exist or not, i.e. it could be nil.
@@ -15,9 +7,13 @@ module Dry
15
7
  # @api public
16
8
  class Maybe
17
9
  include Transformer
10
+ extend Core::ClassAttributes
11
+
12
+ defines :warn_on_implicit_nil_coercion
13
+ warn_on_implicit_nil_coercion true
18
14
 
19
15
  class << self
20
- extend Core::Deprecations[:'dry-monads']
16
+ extend Core::Deprecations[:"dry-monads"]
21
17
 
22
18
  # Wraps the given value with into a Maybe object.
23
19
  #
@@ -105,7 +101,9 @@ module Dry
105
101
  end
106
102
 
107
103
  def initialize(value = Undefined)
108
- raise ArgumentError, 'nil cannot be some' if value.nil?
104
+ raise ArgumentError, "nil cannot be some" if value.nil?
105
+
106
+ super()
109
107
 
110
108
  @value = Undefined.default(value, Unit)
111
109
  end
@@ -120,15 +118,66 @@ module Dry
120
118
  # @param args [Array<Object>] arguments will be transparently passed through to #bind
121
119
  # @return [Maybe::Some, Maybe::None] Wrapped result, i.e. nil will be mapped to None,
122
120
  # other values will be wrapped with Some
123
- def fmap(*args, &block)
124
- Maybe.coerce(bind(*args, &block))
121
+ def fmap(...)
122
+ next_value = bind(...)
123
+
124
+ if next_value.nil?
125
+ if self.class.warn_on_implicit_nil_coercion
126
+ Core::Deprecations.warn(
127
+ "Block passed to Some#fmap returned `nil` and was chained to None. "\
128
+ "This is literally an unlawful behavior and it will not be supported in "\
129
+ "dry-monads 2. \nPlease, replace `.fmap` with `.maybe` in places where you "\
130
+ "expect `nil` as block result.\n"\
131
+ "You can opt out of these warnings with\n"\
132
+ "Dry::Monads::Maybe.warn_on_implicit_nil_coercion false",
133
+ uplevel: 0,
134
+ tag: :"dry-monads"
135
+ )
136
+ end
137
+ Monads.None()
138
+ else
139
+ Some.new(next_value)
140
+ end
141
+ end
142
+
143
+ # Does the same thing as #bind except it also wraps the value
144
+ # in an instance of the Maybe monad. This allows for easier
145
+ # chaining of calls.
146
+ #
147
+ # @example
148
+ # Dry::Monads.Some(4).maybe(&:succ).maybe(->(n) { n**2 }) # => Some(25)
149
+ # Dry::Monads.Some(4).maybe(&:succ).maybe(->(_) { nil }) # => None()
150
+ #
151
+ # @param args [Array<Object>] arguments will be transparently passed through to #bind
152
+ # @return [Maybe::Some, Maybe::None] Wrapped result, i.e. nil will be mapped to None,
153
+ # other values will be wrapped with Some
154
+ def maybe(...)
155
+ Maybe.coerce(bind(...))
156
+ end
157
+
158
+ # Accepts a block and runs it against the wrapped value.
159
+ # If the block returns a trurhy value the result is self,
160
+ # otherwise None. If no block is given, the value serves
161
+ # and its result.
162
+ #
163
+ # @param with [#call] positional block
164
+ # @param block [Proc] block
165
+ #
166
+ # @return [Maybe::None, Maybe::Some]
167
+ def filter(with = Undefined, &block)
168
+ block = Undefined.default(with, block || IDENTITY)
169
+
170
+ if block.(@value)
171
+ self
172
+ else
173
+ Monads.None()
174
+ end
125
175
  end
126
- alias_method :maybe, :fmap
127
176
 
128
177
  # @return [String]
129
178
  def to_s
130
179
  if Unit.equal?(@value)
131
- 'Some()'
180
+ "Some()"
132
181
  else
133
182
  "Some(#{@value.inspect})"
134
183
  end
@@ -143,10 +192,10 @@ module Dry
143
192
  include RightBiased::Left
144
193
 
145
194
  @instance = new.freeze
146
- singleton_class.send(:attr_reader, :instance)
195
+ singleton_class.attr_reader(:instance)
147
196
 
148
197
  # @api private
149
- def self.method_missing(m, *)
198
+ def self.method_missing(m, *) # rubocop:disable Style/MissingRespondToMissing
150
199
  if (instance.methods(true) - methods(true)).include?(m)
151
200
  raise ConstructorNotAppliedError.new(m, :None)
152
201
  else
@@ -161,6 +210,7 @@ module Dry
161
210
  attr_reader :trace
162
211
 
163
212
  def initialize(trace = RightBiased::Left.trace_caller)
213
+ super()
164
214
  @trace = trace
165
215
  end
166
216
 
@@ -196,13 +246,13 @@ module Dry
196
246
  # @param args [Array<Object>] arguments will be passed to the underlying `#or` call
197
247
  # @return [Maybe::Some, Maybe::None] Lifted `#or` result, i.e. nil will be mapped to None,
198
248
  # other values will be wrapped with Some
199
- def or_fmap(*args, &block)
200
- Maybe.coerce(self.or(*args, &block))
249
+ def or_fmap(...)
250
+ Maybe.coerce(self.or(...))
201
251
  end
202
252
 
203
253
  # @return [String]
204
254
  def to_s
205
- 'None'
255
+ "None"
206
256
  end
207
257
  alias_method :inspect, :to_s
208
258
 
@@ -230,6 +280,13 @@ module Dry
230
280
  def deconstruct
231
281
  EMPTY_ARRAY
232
282
  end
283
+
284
+ # @see Maybe::Some#filter
285
+ #
286
+ # @return [Maybe::None]
287
+ def filter(_ = Undefined)
288
+ self
289
+ end
233
290
  end
234
291
 
235
292
  # A module that can be included for easier access to Maybe monads.
@@ -301,9 +358,9 @@ module Dry
301
358
  # None values are removed
302
359
  #
303
360
  # @example
304
- # Maybe::Hash.filter(foo: Some(1), bar: Some(2)) # => Some(foo: 1, bar: 2)
305
- # Maybe::Hash.filter(foo: Some(1), bar: None()) # => None()
306
- # Maybe::Hash.filter(foo: None(), bar: Some(2)) # => None()
361
+ # Maybe::Hash.filter(foo: Some(1), bar: Some(2)) # => { foo: 1, bar: 2 }
362
+ # Maybe::Hash.filter(foo: Some(1), bar: None()) # => { foo: 1 }
363
+ # Maybe::Hash.filter(foo: None(), bar: Some(2)) # => { bar: 2 }
307
364
  #
308
365
  # @param hash [::Hash<Object,Maybe>]
309
366
  # @return [::Hash]
@@ -325,10 +382,12 @@ module Dry
325
382
 
326
383
  class Result
327
384
  class Success < Result
328
- # @return [Maybe::Some]
385
+ extend Core::Deprecations[:"dry-monads"]
386
+
387
+ # @return [Maybe]
329
388
  def to_maybe
330
- Kernel.warn 'Success(nil) transformed to None' if @value.nil?
331
- Dry::Monads::Maybe(@value)
389
+ warn "Success(nil) transformed to None" if @value.nil?
390
+ ::Dry::Monads::Maybe(@value)
332
391
  end
333
392
  end
334
393
 
@@ -389,7 +448,7 @@ module Dry
389
448
  end
390
449
  end
391
450
 
392
- require 'dry/monads/registry'
451
+ require "dry/monads/registry"
393
452
  register_mixin(:maybe, Maybe::Mixin)
394
453
  end
395
454
  end