dry-monads 1.3.5 → 1.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (63) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +140 -80
  3. data/LICENSE +1 -1
  4. data/README.md +5 -4
  5. data/dry-monads.gemspec +30 -30
  6. data/lib/dry-monads.rb +1 -1
  7. data/lib/dry/monads.rb +2 -2
  8. data/lib/dry/monads/all.rb +2 -2
  9. data/lib/dry/monads/constants.rb +1 -1
  10. data/lib/dry/monads/do.rb +52 -18
  11. data/lib/dry/monads/do/all.rb +36 -17
  12. data/lib/dry/monads/either.rb +7 -7
  13. data/lib/dry/monads/errors.rb +5 -2
  14. data/lib/dry/monads/lazy.rb +15 -4
  15. data/lib/dry/monads/list.rb +28 -28
  16. data/lib/dry/monads/maybe.rb +87 -19
  17. data/lib/dry/monads/registry.rb +10 -10
  18. data/lib/dry/monads/result.rb +38 -12
  19. data/lib/dry/monads/result/fixed.rb +33 -24
  20. data/lib/dry/monads/right_biased.rb +35 -16
  21. data/lib/dry/monads/task.rb +20 -20
  22. data/lib/dry/monads/transformer.rb +2 -1
  23. data/lib/dry/monads/traverse.rb +7 -1
  24. data/lib/dry/monads/try.rb +45 -12
  25. data/lib/dry/monads/unit.rb +6 -2
  26. data/lib/dry/monads/validated.rb +20 -16
  27. data/lib/dry/monads/version.rb +1 -1
  28. data/lib/json/add/dry/monads/maybe.rb +3 -3
  29. metadata +18 -69
  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/log/.gitkeep +0 -0
  63. data/project.yml +0 -2
data/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  The MIT License (MIT)
2
2
 
3
- Copyright (c) 2015-2020 dry-rb team
3
+ Copyright (c) 2015-2021 dry-rb team
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy of
6
6
  this software and associated documentation files (the "Software"), to deal in
data/README.md CHANGED
@@ -1,3 +1,4 @@
1
+ <!--- this file is synced from dry-rb/template-gem project -->
1
2
  [gem]: https://rubygems.org/gems/dry-monads
2
3
  [actions]: https://github.com/dry-rb/dry-monads/actions
3
4
  [codacy]: https://www.codacy.com/gh/dry-rb/dry-monads
@@ -7,22 +8,22 @@
7
8
  # dry-monads [![Join the chat at https://dry-rb.zulipchat.com](https://img.shields.io/badge/dry--rb-join%20chat-%23346b7a.svg)][chat]
8
9
 
9
10
  [![Gem Version](https://badge.fury.io/rb/dry-monads.svg)][gem]
10
- [![CI Status](https://github.com/dry-rb/dry-monads/workflows/ci/badge.svg)][actions]
11
+ [![CI Status](https://github.com/dry-rb/dry-monads/workflows/CI/badge.svg)][actions]
11
12
  [![Codacy Badge](https://api.codacy.com/project/badge/Grade/f2eed41bf7f04b38b0a7691c2cf6e73c)][codacy]
12
13
  [![Codacy Badge](https://api.codacy.com/project/badge/Coverage/f2eed41bf7f04b38b0a7691c2cf6e73c)][codacy]
13
14
  [![Inline docs](http://inch-ci.org/github/dry-rb/dry-monads.svg?branch=master)][inchpages]
14
15
 
15
16
  ## Links
16
17
 
17
- * [User documentation](http://dry-rb.org/gems/dry-monads)
18
+ * [User documentation](https://dry-rb.org/gems/dry-monads)
18
19
  * [API documentation](http://rubydoc.info/gems/dry-monads)
19
20
 
20
21
  ## Supported Ruby versions
21
22
 
22
23
  This library officially supports the following Ruby versions:
23
24
 
24
- * MRI >= `2.4`
25
- * jruby >= `9.2`
25
+ * MRI `>= 2.6.0`
26
+ * ~~jruby~~ `>= 9.3` (we are waiting for [2.6 support](https://github.com/jruby/jruby/issues/6161))
26
27
 
27
28
  ## License
28
29
 
data/dry-monads.gemspec CHANGED
@@ -1,39 +1,39 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- lib = File.expand_path('lib', __dir__)
3
+ # this file is synced from dry-rb/template-gem project
4
+
5
+ lib = File.expand_path("lib", __dir__)
4
6
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
- require 'dry/monads/version'
7
+ require "dry/monads/version"
6
8
 
7
9
  Gem::Specification.new do |spec|
8
- spec.name = 'dry-monads'
10
+ spec.name = "dry-monads"
11
+ spec.authors = ["Nikita Shilnikov"]
12
+ spec.email = ["fg@flashgordon.ru"]
13
+ spec.license = "MIT"
9
14
  spec.version = Dry::Monads::VERSION.dup
10
- spec.authors = ['Nikita Shilnikov']
11
- spec.email = ['fg@flashgordon.ru']
12
- spec.license = 'MIT'
13
15
 
14
- spec.summary = 'Common monads for Ruby.'
16
+ spec.summary = "Common monads for Ruby"
15
17
  spec.description = spec.summary
16
- spec.homepage = 'https://github.com/dry-rb/dry-monads'
17
-
18
- # Prevent pushing this gem to RubyGems.org by setting 'allowed_push_host', or
19
- # delete this section to allow pushing this gem to any host.
20
- if spec.respond_to?(:metadata)
21
- spec.metadata['allowed_push_host'] = 'https://rubygems.org'
22
- else
23
- raise 'RubyGems 2.0 or newer is required to protect against public gem pushes.'
24
- end
25
-
26
- spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
27
- spec.bindir = 'exe'
28
- spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
29
- spec.require_paths = ['lib']
30
- spec.required_ruby_version = '>= 2.4.0'
31
- spec.add_dependency 'concurrent-ruby', '~> 1.0'
32
- spec.add_dependency 'dry-core', '~> 0.4', '>= 0.4.4'
33
- spec.add_dependency 'dry-equalizer'
34
-
35
- spec.add_development_dependency 'bundler'
36
- spec.add_development_dependency 'dry-types', '>= 0.12'
37
- spec.add_development_dependency 'rake'
38
- spec.add_development_dependency 'rspec'
18
+ spec.homepage = "https://dry-rb.org/gems/dry-monads"
19
+ spec.files = Dir["CHANGELOG.md", "LICENSE", "README.md", "dry-monads.gemspec", "lib/**/*"]
20
+ spec.bindir = "bin"
21
+ spec.executables = []
22
+ spec.require_paths = ["lib"]
23
+
24
+ spec.metadata["allowed_push_host"] = "https://rubygems.org"
25
+ spec.metadata["changelog_uri"] = "https://github.com/dry-rb/dry-monads/blob/master/CHANGELOG.md"
26
+ spec.metadata["source_code_uri"] = "https://github.com/dry-rb/dry-monads"
27
+ spec.metadata["bug_tracker_uri"] = "https://github.com/dry-rb/dry-monads/issues"
28
+
29
+ spec.required_ruby_version = ">= 2.6.0"
30
+
31
+ # to update dependencies edit project.yml
32
+ spec.add_runtime_dependency "concurrent-ruby", "~> 1.0"
33
+ spec.add_runtime_dependency "dry-core", "~> 0.7"
34
+
35
+ spec.add_development_dependency "bundler"
36
+ spec.add_development_dependency "dry-types", ">= 0.1.2"
37
+ spec.add_development_dependency "rake"
38
+ spec.add_development_dependency "rspec"
39
39
  end
data/lib/dry-monads.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'dry/monads'
3
+ require "dry/monads"
data/lib/dry/monads.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'dry/core/constants'
4
- require 'dry/monads/registry'
3
+ require "dry/core/constants"
4
+ require "dry/monads/registry"
5
5
 
6
6
  module Dry
7
7
  # Common, idiomatic monads for Ruby
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'dry/monads'
4
- require 'dry/monads/registry'
3
+ require "dry/monads"
4
+ require "dry/monads/registry"
5
5
 
6
6
  module Dry
7
7
  module Monads
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'dry/core/constants'
3
+ require "dry/core/constants"
4
4
 
5
5
  module Dry
6
6
  module Monads
data/lib/dry/monads/do.rb CHANGED
@@ -1,8 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'dry/monads/list'
4
- require 'dry/monads/do/mixin'
5
- require 'dry/monads/constants'
3
+ require "dry/monads/list"
4
+ require "dry/monads/do/mixin"
5
+ require "dry/monads/constants"
6
6
 
7
7
  module Dry
8
8
  module Monads
@@ -12,7 +12,13 @@ module Dry
12
12
  module Do
13
13
  extend Mixin
14
14
 
15
- DELEGATE = ::RUBY_VERSION < '2.7' ? '*' : '...'
15
+ DELEGATE = ::RUBY_VERSION < "2.7" ? "*" : "..."
16
+
17
+ VISIBILITY_WORD = {
18
+ public: "",
19
+ private: "private ",
20
+ protected: "protected "
21
+ }.freeze
16
22
 
17
23
  # @api private
18
24
  class Halt < StandardError
@@ -26,6 +32,25 @@ module Dry
26
32
  end
27
33
  end
28
34
 
35
+ # @api private
36
+ class MethodTracker < ::Module
37
+ # @api private
38
+ def initialize(tracked_methods, base, wrapper)
39
+ module_eval do
40
+ private
41
+
42
+ define_method(:method_added) do |method|
43
+ super(method)
44
+
45
+ if tracked_methods.include?(method)
46
+ visibility = Do.method_visibility(base, method)
47
+ Do.wrap_method(wrapper, method, visibility)
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
53
+
29
54
  class << self
30
55
  # Generates a module that passes a block to methods
31
56
  # that either unwraps a single-valued monadic value or halts
@@ -84,13 +109,11 @@ module Dry
84
109
  # @param [Array<Symbol>] methods
85
110
  # @return [Module]
86
111
  def for(*methods)
87
- mod = ::Module.new do
88
- methods.each { |method_name| Do.wrap_method(self, method_name) }
89
- end
90
-
91
112
  ::Module.new do
92
113
  singleton_class.send(:define_method, :included) do |base|
114
+ mod = ::Module.new
93
115
  base.prepend(mod)
116
+ base.extend(MethodTracker.new(methods, base, mod))
94
117
  end
95
118
  end
96
119
  end
@@ -100,23 +123,34 @@ module Dry
100
123
  super
101
124
 
102
125
  # Actually mixes in Do::All
103
- require 'dry/monads/do/all'
126
+ require "dry/monads/do/all"
104
127
  base.include All
105
128
  end
106
129
 
107
130
  # @api private
108
- def wrap_method(target, method_name)
131
+ def wrap_method(target, method, visibility)
109
132
  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
133
+ #{VISIBILITY_WORD[visibility]} def #{method}(#{DELEGATE}) # private def create_acccount(...)
134
+ if block_given? # if block_given?
135
+ super # super
136
+ else # else
137
+ Do.() { super { |*ms| Do.bind(ms) } } # Do.() { super { |*ms| Do.bind(ms) } }
138
+ end # end
139
+ end # end
117
140
  RUBY
118
141
  end
119
142
 
143
+ # @api private
144
+ def method_visibility(mod, method)
145
+ if mod.public_method_defined?(method)
146
+ :public
147
+ elsif mod.private_method_defined?(method)
148
+ :private
149
+ else
150
+ :protected
151
+ end
152
+ end
153
+
120
154
  # @api private
121
155
  def coerce_to_monad(monads)
122
156
  return monads if monads.size != 1
@@ -135,7 +169,7 @@ module Dry
135
169
 
136
170
  # @api private
137
171
  def halt(result)
138
- raise Halt.new(result), EMPTY_STRING, []
172
+ raise Halt.new(result), "", []
139
173
  end
140
174
  end
141
175
  end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'dry/monads/do'
3
+ require "dry/monads/do"
4
4
 
5
5
  module Dry
6
6
  module Monads
@@ -68,9 +68,10 @@ module Dry
68
68
  tracker = self
69
69
 
70
70
  module_eval do
71
+ private
72
+
71
73
  define_method(:method_added) do |method|
72
74
  super(method)
73
-
74
75
  tracker.wrap_method(self, method)
75
76
  end
76
77
 
@@ -93,20 +94,37 @@ module Dry
93
94
  end
94
95
 
95
96
  def wrap_method(target, method)
96
- Do.wrap_method(wrappers[target], method)
97
+ visibility = Do.method_visibility(target, method)
98
+ Do.wrap_method(wrappers[target], method, visibility)
97
99
  end
98
100
  end
99
101
 
100
- # @api private
101
- def self.included(base)
102
- super
102
+ class << self
103
+ # @api private
104
+ def included(base)
105
+ super
103
106
 
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) }
107
+ wrappers = ::Hash.new { |h, k| h[k] = ::Module.new }
108
+ tracker = MethodTracker.new(wrappers)
109
+ base.extend(tracker)
110
+ base.extend(InstanceMixin) unless base.is_a?(::Class)
111
+ wrap_defined_methods(base, wrappers[base])
112
+ end
108
113
 
109
- base.extend(InstanceMixin) unless base.is_a?(::Class)
114
+ # @api private
115
+ def wrap_defined_methods(klass, target)
116
+ klass.public_instance_methods(false).each do |m|
117
+ Do.wrap_method(target, m, :public)
118
+ end
119
+
120
+ klass.protected_instance_methods(false).each do |m|
121
+ Do.wrap_method(target, m, :protected)
122
+ end
123
+
124
+ klass.private_instance_methods(false).each do |m|
125
+ Do.wrap_method(target, m, :private)
126
+ end
127
+ end
110
128
  end
111
129
 
112
130
  # @api private
@@ -116,17 +134,18 @@ module Dry
116
134
  super
117
135
 
118
136
  wrapper = ::Module.new
119
- object.singleton_class.prepend(wrapper)
137
+ eigenclass = object.singleton_class
138
+ eigenclass.prepend(wrapper)
120
139
  object.define_singleton_method(:singleton_method_added) do |method|
121
140
  super(method)
122
141
 
123
142
  next if method.equal?(:singleton_method_added)
124
143
 
125
- Do.wrap_method(wrapper, method)
126
- end
127
- object.singleton_class.instance_methods(false).each do |m|
128
- Do.wrap_method(wrapper, m)
144
+ visibility = Do.method_visibility(eigenclass, method)
145
+ Do.wrap_method(wrapper, method, visibility)
129
146
  end
147
+
148
+ All.wrap_defined_methods(eigenclass, wrapper)
130
149
  end
131
150
  end
132
151
 
@@ -134,7 +153,7 @@ module Dry
134
153
  end
135
154
  end
136
155
 
137
- require 'dry/monads/registry'
156
+ require "dry/monads/registry"
138
157
  register_mixin(:do, Do::All)
139
158
  end
140
159
  end
@@ -1,10 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'dry/core/deprecations'
3
+ require "dry/core/deprecations"
4
4
 
5
- Dry::Core::Deprecations.warn('Either monad was renamed to Result', tag: :'dry-monads')
5
+ Dry::Core::Deprecations.warn("Either monad was renamed to Result", tag: :"dry-monads")
6
6
 
7
- require 'dry/monads/result'
7
+ require "dry/monads/result"
8
8
 
9
9
  module Dry
10
10
  module Monads
@@ -12,7 +12,7 @@ module Dry
12
12
  deprecate_constant :Either
13
13
 
14
14
  class Result
15
- extend Dry::Core::Deprecations[:'dry-monads']
15
+ extend ::Dry::Core::Deprecations[:"dry-monads"]
16
16
 
17
17
  deprecate :to_either, :to_result
18
18
 
@@ -24,7 +24,7 @@ module Dry
24
24
 
25
25
  module Mixin
26
26
  module Constructors
27
- extend Dry::Core::Deprecations[:'dry-monads']
27
+ extend Dry::Core::Deprecations[:"dry-monads"]
28
28
 
29
29
  Right = Success
30
30
  Left = Failure
@@ -51,13 +51,13 @@ module Dry
51
51
 
52
52
  class Try
53
53
  class Value
54
- extend Dry::Core::Deprecations[:'dry-monads']
54
+ extend Dry::Core::Deprecations[:"dry-monads"]
55
55
 
56
56
  deprecate :to_either, :to_result
57
57
  end
58
58
 
59
59
  class Error
60
- extend Dry::Core::Deprecations[:'dry-monads']
60
+ extend Dry::Core::Deprecations[:"dry-monads"]
61
61
 
62
62
  deprecate :to_either, :to_result
63
63
  end
@@ -4,8 +4,11 @@ module Dry
4
4
  module Monads
5
5
  # An unsuccessful result of extracting a value from a monad.
6
6
  class UnwrapError < StandardError
7
- def initialize(ctx)
8
- super("value! was called on #{ctx.inspect}")
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
 
@@ -1,8 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'concurrent/promise'
3
+ require "concurrent/promise"
4
4
 
5
- require 'dry/monads/task'
5
+ require "dry/core/deprecations"
6
+ require "dry/monads/task"
6
7
 
7
8
  module Dry
8
9
  module Monads
@@ -11,6 +12,8 @@ module Dry
11
12
  # computation is evaluated not more than once (compare with the built-in
12
13
  # lazy assignement ||= which does not guarantee this).
13
14
  class Lazy < Task
15
+ extend ::Dry::Core::Deprecations[:"dry-monads"]
16
+
14
17
  class << self
15
18
  # @private
16
19
  def new(promise = nil, &block)
@@ -41,6 +44,14 @@ module Dry
41
44
  self
42
45
  end
43
46
 
47
+ # @return [Boolean]
48
+ def evaluated?
49
+ @promise.complete?
50
+ end
51
+ deprecate :complete?, :evaluated?
52
+
53
+ undef_method :wait
54
+
44
55
  # @return [String]
45
56
  def to_s
46
57
  state = case promise.state
@@ -49,7 +60,7 @@ module Dry
49
60
  when :rejected
50
61
  "!#{promise.reason.inspect}"
51
62
  else
52
- '?'
63
+ "?"
53
64
  end
54
65
 
55
66
  "Lazy(#{state})"
@@ -80,7 +91,7 @@ module Dry
80
91
  end
81
92
  end
82
93
 
83
- require 'dry/monads/registry'
94
+ require "dry/monads/registry"
84
95
  register_mixin(:lazy, Lazy::Mixin)
85
96
  end
86
97
  end