dry-monads 1.3.2 → 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 +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