dry-monads 1.3.2 → 1.4.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 (63) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +157 -73
  3. data/LICENSE +1 -1
  4. data/README.md +18 -38
  5. data/dry-monads.gemspec +32 -30
  6. data/lib/dry-monads.rb +3 -1
  7. data/lib/dry/monads.rb +4 -2
  8. data/lib/dry/monads/all.rb +4 -2
  9. data/lib/dry/monads/constants.rb +1 -1
  10. data/lib/dry/monads/conversion_stubs.rb +2 -0
  11. data/lib/dry/monads/curry.rb +2 -0
  12. data/lib/dry/monads/do.rb +55 -17
  13. data/lib/dry/monads/do/all.rb +39 -17
  14. data/lib/dry/monads/do/mixin.rb +2 -0
  15. data/lib/dry/monads/either.rb +9 -7
  16. data/lib/dry/monads/errors.rb +8 -3
  17. data/lib/dry/monads/lazy.rb +19 -6
  18. data/lib/dry/monads/list.rb +31 -30
  19. data/lib/dry/monads/maybe.rb +90 -19
  20. data/lib/dry/monads/registry.rb +15 -12
  21. data/lib/dry/monads/result.rb +42 -15
  22. data/lib/dry/monads/result/fixed.rb +35 -24
  23. data/lib/dry/monads/right_biased.rb +45 -24
  24. data/lib/dry/monads/task.rb +25 -22
  25. data/lib/dry/monads/transformer.rb +4 -1
  26. data/lib/dry/monads/traverse.rb +9 -1
  27. data/lib/dry/monads/try.rb +51 -13
  28. data/lib/dry/monads/unit.rb +6 -2
  29. data/lib/dry/monads/validated.rb +27 -20
  30. data/lib/dry/monads/version.rb +3 -1
  31. data/lib/json/add/dry/monads/maybe.rb +4 -3
  32. metadata +27 -75
  33. data/.codeclimate.yml +0 -12
  34. data/.github/ISSUE_TEMPLATE/----please-don-t-ask-for-support-via-issues.md +0 -10
  35. data/.github/ISSUE_TEMPLATE/---bug-report.md +0 -34
  36. data/.github/ISSUE_TEMPLATE/---feature-request.md +0 -18
  37. data/.github/workflows/ci.yml +0 -74
  38. data/.github/workflows/docsite.yml +0 -34
  39. data/.github/workflows/sync_configs.yml +0 -34
  40. data/.gitignore +0 -10
  41. data/.rspec +0 -4
  42. data/.rubocop.yml +0 -89
  43. data/.yardopts +0 -4
  44. data/CODE_OF_CONDUCT.md +0 -13
  45. data/CONTRIBUTING.md +0 -29
  46. data/Gemfile +0 -23
  47. data/Rakefile +0 -6
  48. data/bin/console +0 -16
  49. data/bin/setup +0 -7
  50. data/docsite/source/case-equality.html.md +0 -42
  51. data/docsite/source/do-notation.html.md +0 -207
  52. data/docsite/source/getting-started.html.md +0 -142
  53. data/docsite/source/index.html.md +0 -179
  54. data/docsite/source/list.html.md +0 -87
  55. data/docsite/source/maybe.html.md +0 -146
  56. data/docsite/source/pattern-matching.html.md +0 -68
  57. data/docsite/source/result.html.md +0 -190
  58. data/docsite/source/task.html.md +0 -126
  59. data/docsite/source/tracing-failures.html.md +0 -32
  60. data/docsite/source/try.html.md +0 -76
  61. data/docsite/source/unit.html.md +0 -36
  62. data/docsite/source/validated.html.md +0 -88
  63. data/log/.gitkeep +0 -0
data/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  The MIT License (MIT)
2
2
 
3
- Copyright (c) 2015-2019 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,50 +1,30 @@
1
- [gitter]: https://gitter.im/dry-rb/chat
1
+ <!--- this file is synced from dry-rb/template-gem project -->
2
2
  [gem]: https://rubygems.org/gems/dry-monads
3
- [ci]: https://github.com/dry-rb/dry-monads/actions?query=workflow%3Aci
4
- [code_climate]: https://codeclimate.com/github/dry-rb/dry-monads
5
- [inch]: http://inch-ci.org/github/dry-rb/dry-monads
3
+ [actions]: https://github.com/dry-rb/dry-monads/actions
4
+ [codacy]: https://www.codacy.com/gh/dry-rb/dry-monads
6
5
  [chat]: https://dry-rb.zulipchat.com
6
+ [inchpages]: http://inch-ci.org/github/dry-rb/dry-monads
7
7
 
8
8
  # dry-monads [![Join the chat at https://dry-rb.zulipchat.com](https://img.shields.io/badge/dry--rb-join%20chat-%23346b7a.svg)][chat]
9
9
 
10
- [![Gem Version](https://img.shields.io/gem/v/dry-monads.svg)][gem]
11
- [![Build Status](https://github.com/dry-rb/dry-monads/workflows/ci/badge.svg)][ci]
12
- [![Code Climate](https://api.codeclimate.com/v1/badges/b0ea4d8023d53b7f0f50/maintainability)][code_climate]
13
- [![Test Coverage](https://api.codeclimate.com/v1/badges/b0ea4d8023d53b7f0f50/test_coverage)][code_climate]
14
- [![API Documentation Coverage](http://inch-ci.org/github/dry-rb/dry-monads.svg)][inch]
15
-
16
- Monads for Ruby.
17
-
18
- ## Installation
19
-
20
- Add this line to your application's Gemfile:
21
-
22
- ```ruby
23
- gem 'dry-monads'
24
- ```
25
-
26
- And then execute:
27
-
28
- ```sh
29
- $ bundle
30
- ```
31
-
32
- Or install it yourself as:
33
-
34
- ```sh
35
- $ gem install dry-monads
36
- ```
10
+ [![Gem Version](https://badge.fury.io/rb/dry-monads.svg)][gem]
11
+ [![CI Status](https://github.com/dry-rb/dry-monads/workflows/CI/badge.svg)][actions]
12
+ [![Codacy Badge](https://api.codacy.com/project/badge/Grade/f2eed41bf7f04b38b0a7691c2cf6e73c)][codacy]
13
+ [![Codacy Badge](https://api.codacy.com/project/badge/Coverage/f2eed41bf7f04b38b0a7691c2cf6e73c)][codacy]
14
+ [![Inline docs](http://inch-ci.org/github/dry-rb/dry-monads.svg?branch=master)][inchpages]
37
15
 
38
16
  ## Links
39
17
 
40
- - [Documentation](http://dry-rb.org/gems/dry-monads)
18
+ * [User documentation](https://dry-rb.org/gems/dry-monads)
19
+ * [API documentation](http://rubydoc.info/gems/dry-monads)
20
+
21
+ ## Supported Ruby versions
41
22
 
42
- ## Development
23
+ This library officially supports the following Ruby versions:
43
24
 
44
- After checking out the repo, run `bin/setup` to install dependencies. Then, run
45
- `rake spec` to run the tests. You can also run `bin/console` for an interactive
46
- prompt that will allow you to experiment.
25
+ * MRI `>= 2.6.0`
26
+ * ~~jruby~~ `>= 9.3` (we are waiting for [2.6 support](https://github.com/jruby/jruby/issues/6161))
47
27
 
48
- ## Contributing
28
+ ## License
49
29
 
50
- Bug reports and pull requests are welcome on GitHub at <https://github.com/dry-rb/dry-monads>.
30
+ See `LICENSE` file.
data/dry-monads.gemspec CHANGED
@@ -1,37 +1,39 @@
1
- lib = File.expand_path('../lib', __FILE__)
1
+ # frozen_string_literal: true
2
+
3
+ # this file is synced from dry-rb/template-gem project
4
+
5
+ lib = File.expand_path("lib", __dir__)
2
6
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
- require 'dry/monads/version'
7
+ require "dry/monads/version"
4
8
 
5
9
  Gem::Specification.new do |spec|
6
- spec.name = 'dry-monads'
10
+ spec.name = "dry-monads"
11
+ spec.authors = ["Nikita Shilnikov"]
12
+ spec.email = ["fg@flashgordon.ru"]
13
+ spec.license = "MIT"
7
14
  spec.version = Dry::Monads::VERSION.dup
8
- spec.authors = ['Nikita Shilnikov']
9
- spec.email = ['fg@flashgordon.ru']
10
- spec.license = 'MIT'
11
15
 
12
- spec.summary = 'Common monads for Ruby.'
16
+ spec.summary = "Common monads for Ruby"
13
17
  spec.description = spec.summary
14
- spec.homepage = 'https://github.com/dry-rb/dry-monads'
15
-
16
- # Prevent pushing this gem to RubyGems.org by setting 'allowed_push_host', or
17
- # delete this section to allow pushing this gem to any host.
18
- if spec.respond_to?(:metadata)
19
- spec.metadata['allowed_push_host'] = 'https://rubygems.org'
20
- else
21
- raise 'RubyGems 2.0 or newer is required to protect against public gem pushes.'
22
- end
23
-
24
- spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
25
- spec.bindir = 'exe'
26
- spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
27
- spec.require_paths = ['lib']
28
- spec.required_ruby_version = ">= 2.4.0"
29
- spec.add_dependency 'dry-equalizer'
30
- spec.add_dependency 'dry-core', '~> 0.4', '>= 0.4.4'
31
- spec.add_dependency 'concurrent-ruby', '~> 1.0'
32
-
33
- spec.add_development_dependency 'bundler'
34
- spec.add_development_dependency 'rake'
35
- spec.add_development_dependency 'rspec'
36
- spec.add_development_dependency 'dry-types', '>= 0.12'
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"
37
39
  end
data/lib/dry-monads.rb CHANGED
@@ -1 +1,3 @@
1
- require 'dry/monads'
1
+ # frozen_string_literal: true
2
+
3
+ require "dry/monads"
data/lib/dry/monads.rb CHANGED
@@ -1,5 +1,7 @@
1
- require 'dry/core/constants'
2
- require 'dry/monads/registry'
1
+ # frozen_string_literal: true
2
+
3
+ require "dry/core/constants"
4
+ require "dry/monads/registry"
3
5
 
4
6
  module Dry
5
7
  # Common, idiomatic monads for Ruby
@@ -1,5 +1,7 @@
1
- require 'dry/monads'
2
- require 'dry/monads/registry'
1
+ # frozen_string_literal: true
2
+
3
+ require "dry/monads"
4
+ require "dry/monads/registry"
3
5
 
4
6
  module Dry
5
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
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Dry
2
4
  module Monads
3
5
  module ConversionStubs
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Dry
2
4
  module Monads
3
5
  # @private
data/lib/dry/monads/do.rb CHANGED
@@ -1,6 +1,8 @@
1
- require 'dry/monads/list'
2
- require 'dry/monads/do/mixin'
3
- require 'dry/monads/constants'
1
+ # frozen_string_literal: true
2
+
3
+ require "dry/monads/list"
4
+ require "dry/monads/do/mixin"
5
+ require "dry/monads/constants"
4
6
 
5
7
  module Dry
6
8
  module Monads
@@ -10,6 +12,14 @@ module Dry
10
12
  module Do
11
13
  extend Mixin
12
14
 
15
+ DELEGATE = ::RUBY_VERSION < "2.7" ? "*" : "..."
16
+
17
+ VISIBILITY_WORD = {
18
+ public: "",
19
+ private: "private ",
20
+ protected: "protected "
21
+ }.freeze
22
+
13
23
  # @api private
14
24
  class Halt < StandardError
15
25
  # @api private
@@ -22,6 +32,25 @@ module Dry
22
32
  end
23
33
  end
24
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
+
25
54
  class << self
26
55
  # Generates a module that passes a block to methods
27
56
  # that either unwraps a single-valued monadic value or halts
@@ -80,13 +109,11 @@ module Dry
80
109
  # @param [Array<Symbol>] methods
81
110
  # @return [Module]
82
111
  def for(*methods)
83
- mod = ::Module.new do
84
- methods.each { |method_name| Do.wrap_method(self, method_name) }
85
- end
86
-
87
112
  ::Module.new do
88
113
  singleton_class.send(:define_method, :included) do |base|
114
+ mod = ::Module.new
89
115
  base.prepend(mod)
116
+ base.extend(MethodTracker.new(methods, base, mod))
90
117
  end
91
118
  end
92
119
  end
@@ -96,23 +123,34 @@ module Dry
96
123
  super
97
124
 
98
125
  # Actually mixes in Do::All
99
- require 'dry/monads/do/all'
126
+ require "dry/monads/do/all"
100
127
  base.include All
101
128
  end
102
129
 
103
130
  # @api private
104
- def wrap_method(target, method_name)
131
+ def wrap_method(target, method, visibility)
105
132
  target.module_eval(<<-RUBY, __FILE__, __LINE__ + 1)
106
- def #{method_name}(*)
107
- if block_given?
108
- super
109
- else
110
- Do.() { super { |*ms| Do.bind(ms) } }
111
- end
112
- 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
113
140
  RUBY
114
141
  end
115
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
+
116
154
  # @api private
117
155
  def coerce_to_monad(monads)
118
156
  return monads if monads.size != 1
@@ -131,7 +169,7 @@ module Dry
131
169
 
132
170
  # @api private
133
171
  def halt(result)
134
- raise Halt.new(result), EMPTY_STRING, EMPTY_ARRAY
172
+ raise Halt.new(result), "", []
135
173
  end
136
174
  end
137
175
  end
@@ -1,4 +1,6 @@
1
- require 'dry/monads/do'
1
+ # frozen_string_literal: true
2
+
3
+ require "dry/monads/do"
2
4
 
3
5
  module Dry
4
6
  module Monads
@@ -66,9 +68,10 @@ module Dry
66
68
  tracker = self
67
69
 
68
70
  module_eval do
71
+ private
72
+
69
73
  define_method(:method_added) do |method|
70
74
  super(method)
71
-
72
75
  tracker.wrap_method(self, method)
73
76
  end
74
77
 
@@ -91,20 +94,37 @@ module Dry
91
94
  end
92
95
 
93
96
  def wrap_method(target, method)
94
- Do.wrap_method(wrappers[target], method)
97
+ visibility = Do.method_visibility(target, method)
98
+ Do.wrap_method(wrappers[target], method, visibility)
95
99
  end
96
100
  end
97
101
 
98
- # @api private
99
- def self.included(base)
100
- super
102
+ class << self
103
+ # @api private
104
+ def included(base)
105
+ super
101
106
 
102
- wrappers = ::Hash.new { |h, k| h[k] = ::Module.new }
103
- tracker = MethodTracker.new(wrappers)
104
- base.extend(tracker)
105
- 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
106
113
 
107
- 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
108
128
  end
109
129
 
110
130
  # @api private
@@ -114,16 +134,18 @@ module Dry
114
134
  super
115
135
 
116
136
  wrapper = ::Module.new
117
- object.singleton_class.prepend(wrapper)
137
+ eigenclass = object.singleton_class
138
+ eigenclass.prepend(wrapper)
118
139
  object.define_singleton_method(:singleton_method_added) do |method|
119
140
  super(method)
120
141
 
121
142
  next if method.equal?(:singleton_method_added)
122
- Do.wrap_method(wrapper, method)
123
- end
124
- object.singleton_class.instance_methods(false).each do |m|
125
- Do.wrap_method(wrapper, m)
143
+
144
+ visibility = Do.method_visibility(eigenclass, method)
145
+ Do.wrap_method(wrapper, method, visibility)
126
146
  end
147
+
148
+ All.wrap_defined_methods(eigenclass, wrapper)
127
149
  end
128
150
  end
129
151
 
@@ -131,7 +153,7 @@ module Dry
131
153
  end
132
154
  end
133
155
 
134
- require 'dry/monads/registry'
156
+ require "dry/monads/registry"
135
157
  register_mixin(:do, Do::All)
136
158
  end
137
159
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Dry
2
4
  module Monads
3
5
  module Do
@@ -1,8 +1,10 @@
1
- require 'dry/core/deprecations'
1
+ # frozen_string_literal: true
2
2
 
3
- Dry::Core::Deprecations.warn('Either monad was renamed to Result', tag: :'dry-monads')
3
+ require "dry/core/deprecations"
4
4
 
5
- require 'dry/monads/result'
5
+ Dry::Core::Deprecations.warn("Either monad was renamed to Result", tag: :"dry-monads")
6
+
7
+ require "dry/monads/result"
6
8
 
7
9
  module Dry
8
10
  module Monads
@@ -10,7 +12,7 @@ module Dry
10
12
  deprecate_constant :Either
11
13
 
12
14
  class Result
13
- extend Dry::Core::Deprecations[:'dry-monads']
15
+ extend ::Dry::Core::Deprecations[:"dry-monads"]
14
16
 
15
17
  deprecate :to_either, :to_result
16
18
 
@@ -22,7 +24,7 @@ module Dry
22
24
 
23
25
  module Mixin
24
26
  module Constructors
25
- extend Dry::Core::Deprecations[:'dry-monads']
27
+ extend Dry::Core::Deprecations[:"dry-monads"]
26
28
 
27
29
  Right = Success
28
30
  Left = Failure
@@ -49,13 +51,13 @@ module Dry
49
51
 
50
52
  class Try
51
53
  class Value
52
- extend Dry::Core::Deprecations[:'dry-monads']
54
+ extend Dry::Core::Deprecations[:"dry-monads"]
53
55
 
54
56
  deprecate :to_either, :to_result
55
57
  end
56
58
 
57
59
  class Error
58
- extend Dry::Core::Deprecations[:'dry-monads']
60
+ extend Dry::Core::Deprecations[:"dry-monads"]
59
61
 
60
62
  deprecate :to_either, :to_result
61
63
  end