dry-monads 1.3.5 → 1.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (64) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +161 -80
  3. data/LICENSE +1 -1
  4. data/README.md +5 -4
  5. data/dry-monads.gemspec +30 -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 -68
  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