dry-core 0.7.0 → 0.8.1
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +28 -1
- data/README.md +3 -3
- data/dry-core.gemspec +2 -2
- data/lib/dry/core/basic_object.rb +144 -0
- data/lib/dry/core/cache.rb +2 -2
- data/lib/dry/core/class_attributes.rb +1 -1
- data/lib/dry/core/constants.rb +1 -1
- data/lib/dry/core/deprecations.rb +1 -1
- data/lib/dry/core/memoizable.rb +90 -24
- data/lib/dry/core/version.rb +1 -1
- metadata +5 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9d3ee16c97a04071316e718d8277a4a0ac5aea083b37ac7944d65fd3fd78dfc2
|
4
|
+
data.tar.gz: 44e0e7cb408530f47add47481dd393ba8544e2bcb41256fa0d88af915e7ce547
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0a9787d9d8514c54564448b7e38a5c52810dfd95f098c399c0067928c221357ee772273ca8d8d258e9305679ad3d2ff552b3ea38318a8872136e36d7c434d0b3
|
7
|
+
data.tar.gz: 8f073e6e1c574404f6df1b699470432e4406129a20d2a8d27b0de10db52a8363beb5aaa086fb4c8c629402e3d1d5735715c5126e38384e20519dbee4f30a233f
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,31 @@
|
|
1
1
|
<!--- DO NOT EDIT THIS FILE - IT'S AUTOMATICALLY GENERATED VIA DEVTOOLS --->
|
2
2
|
|
3
|
+
## 0.8.0
|
4
|
+
|
5
|
+
### Added
|
6
|
+
|
7
|
+
- `Dry::Core::BasicObject` ported from hanami-utils (@jodosha)
|
8
|
+
|
9
|
+
### Changed
|
10
|
+
|
11
|
+
- [BREAKING] [descendants tracker] switch to using `Class#subclasses` on Ruby 3.1+.
|
12
|
+
This changes the order of returned subclasses (immediate subclasses now go first) (@flash-gordon)
|
13
|
+
|
14
|
+
|
15
|
+
[Compare v0.7.1...v0.8.0](https://github.com/dry-rb/dry-core/compare/v0.7.1...master)
|
16
|
+
|
17
|
+
## 0.7.1 2021-07-10
|
18
|
+
|
19
|
+
|
20
|
+
### Fixed
|
21
|
+
|
22
|
+
- [memoizable] memoizable correctly handles cases where a method
|
23
|
+
has unnamed params (e.g. happens when the new `...` syntax is used) (@flash-gordon)
|
24
|
+
|
25
|
+
|
26
|
+
|
27
|
+
[Compare v0.7.0...v0.7.1](https://github.com/dry-rb/dry-core/compare/v0.7.0...v0.7.1)
|
28
|
+
|
3
29
|
## 0.7.0 2021-07-08
|
4
30
|
|
5
31
|
|
@@ -11,6 +37,7 @@
|
|
11
37
|
### Changed
|
12
38
|
|
13
39
|
- Minimal Ruby version is 2.6
|
40
|
+
- [memoizable] memoization of block-accepting methods is deprecated (@flash-gordon)
|
14
41
|
|
15
42
|
[Compare v0.6.0...v0.7.0](https://github.com/dry-rb/dry-core/compare/v0.6.0...v0.7.0)
|
16
43
|
|
@@ -30,7 +57,7 @@
|
|
30
57
|
|
31
58
|
[Compare v0.5.0...v0.6.0](https://github.com/dry-rb/dry-core/compare/v0.5.0...v0.6.0)
|
32
59
|
|
33
|
-
## 0.5.0
|
60
|
+
## 0.5.0 2020-12-12
|
34
61
|
|
35
62
|
|
36
63
|
### Added
|
data/README.md
CHANGED
@@ -11,7 +11,7 @@
|
|
11
11
|
[][actions]
|
12
12
|
[][codacy]
|
13
13
|
[][codacy]
|
14
|
-
[][inchpages]
|
15
15
|
|
16
16
|
## Links
|
17
17
|
|
@@ -22,8 +22,8 @@
|
|
22
22
|
|
23
23
|
This library officially supports the following Ruby versions:
|
24
24
|
|
25
|
-
* MRI `>= 2.
|
26
|
-
*
|
25
|
+
* MRI `>= 2.7.0`
|
26
|
+
* jruby `>= 9.3` (postponed until 2.7 is supported)
|
27
27
|
|
28
28
|
## License
|
29
29
|
|
data/dry-core.gemspec
CHANGED
@@ -22,11 +22,11 @@ Gem::Specification.new do |spec|
|
|
22
22
|
spec.require_paths = ["lib"]
|
23
23
|
|
24
24
|
spec.metadata["allowed_push_host"] = "https://rubygems.org"
|
25
|
-
spec.metadata["changelog_uri"] = "https://github.com/dry-rb/dry-core/blob/
|
25
|
+
spec.metadata["changelog_uri"] = "https://github.com/dry-rb/dry-core/blob/main/CHANGELOG.md"
|
26
26
|
spec.metadata["source_code_uri"] = "https://github.com/dry-rb/dry-core"
|
27
27
|
spec.metadata["bug_tracker_uri"] = "https://github.com/dry-rb/dry-core/issues"
|
28
28
|
|
29
|
-
spec.required_ruby_version = ">= 2.
|
29
|
+
spec.required_ruby_version = ">= 2.7.0"
|
30
30
|
|
31
31
|
# to update dependencies edit project.yml
|
32
32
|
spec.add_runtime_dependency "concurrent-ruby", "~> 1.0"
|
@@ -0,0 +1,144 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# This implementation was imported from `hanami-utils` gem.
|
4
|
+
module Dry
|
5
|
+
module Core
|
6
|
+
# BasicObject
|
7
|
+
#
|
8
|
+
# @since 0.8.0
|
9
|
+
class BasicObject < ::BasicObject
|
10
|
+
# Lookups constants at the top-level namespace, if they are missing in the
|
11
|
+
# current context.
|
12
|
+
#
|
13
|
+
# @param name [Symbol] the constant name
|
14
|
+
#
|
15
|
+
# @return [Object, Module] the constant
|
16
|
+
#
|
17
|
+
# @raise [NameError] if the constant cannot be found
|
18
|
+
#
|
19
|
+
# @since 0.8.0
|
20
|
+
# @api private
|
21
|
+
#
|
22
|
+
# @see https://ruby-doc.org/core/Module.html#method-i-const_missing
|
23
|
+
def self.const_missing(name)
|
24
|
+
::Object.const_get(name)
|
25
|
+
end
|
26
|
+
|
27
|
+
# Returns the class for debugging purposes.
|
28
|
+
#
|
29
|
+
# @since 0.8.0
|
30
|
+
#
|
31
|
+
# @see http://ruby-doc.org/core/Object.html#method-i-class
|
32
|
+
def class
|
33
|
+
(class << self; self; end).superclass
|
34
|
+
end
|
35
|
+
|
36
|
+
# Bare minimum inspect for debugging purposes.
|
37
|
+
#
|
38
|
+
# @return [String] the inspect string
|
39
|
+
#
|
40
|
+
# @since 0.8.0
|
41
|
+
#
|
42
|
+
# @see http://ruby-doc.org/core/Object.html#method-i-inspect
|
43
|
+
inspect_method = ::Kernel.instance_method(:inspect)
|
44
|
+
define_method(:inspect) do
|
45
|
+
original = inspect_method.bind_call(self)
|
46
|
+
"#{original[0...-1]}#{__inspect}>"
|
47
|
+
end
|
48
|
+
|
49
|
+
# @!macro [attach] instance_of?(class)
|
50
|
+
#
|
51
|
+
# Determines if self is an instance of given class or module
|
52
|
+
#
|
53
|
+
# @param class [Class,Module] the class of module to verify
|
54
|
+
#
|
55
|
+
# @return [TrueClass,FalseClass] the result of the check
|
56
|
+
#
|
57
|
+
# @raise [TypeError] if the given argument is not of the expected types
|
58
|
+
#
|
59
|
+
# @since 0.8.0
|
60
|
+
#
|
61
|
+
# @see http://ruby-doc.org/core/Object.html#method-i-instance_of-3F
|
62
|
+
define_method :instance_of?, ::Object.instance_method(:instance_of?)
|
63
|
+
|
64
|
+
# @!macro [attach] is_a?(class)
|
65
|
+
#
|
66
|
+
# Determines if self is of the type of the object class or module
|
67
|
+
#
|
68
|
+
# @param class [Class,Module] the class of module to verify
|
69
|
+
#
|
70
|
+
# @return [TrueClass,FalseClass] the result of the check
|
71
|
+
#
|
72
|
+
# @raise [TypeError] if the given argument is not of the expected types
|
73
|
+
#
|
74
|
+
# @since 0.8.0
|
75
|
+
#
|
76
|
+
# @see http://ruby-doc.org/core/Object.html#method-i-is_a-3F
|
77
|
+
define_method :is_a?, ::Object.instance_method(:is_a?)
|
78
|
+
|
79
|
+
# @!macro [attach] kind_of?(class)
|
80
|
+
#
|
81
|
+
# Determines if self is of the kind of the object class or module
|
82
|
+
#
|
83
|
+
# @param class [Class,Module] the class of module to verify
|
84
|
+
#
|
85
|
+
# @return [TrueClass,FalseClass] the result of the check
|
86
|
+
#
|
87
|
+
# @raise [TypeError] if the given argument is not of the expected types
|
88
|
+
#
|
89
|
+
# @since 0.8.0
|
90
|
+
#
|
91
|
+
# @see http://ruby-doc.org/core/Object.html#method-i-kind_of-3F
|
92
|
+
define_method :kind_of?, ::Object.instance_method(:kind_of?)
|
93
|
+
|
94
|
+
# Alias for __id__
|
95
|
+
#
|
96
|
+
# @return [Fixnum] the object id
|
97
|
+
#
|
98
|
+
# @since 0.8.0
|
99
|
+
#
|
100
|
+
# @see http://ruby-doc.org/core/Object.html#method-i-object_id
|
101
|
+
def object_id
|
102
|
+
__id__
|
103
|
+
end
|
104
|
+
|
105
|
+
# Interface for pp
|
106
|
+
#
|
107
|
+
# @param printer [PP] the Pretty Printable printer
|
108
|
+
# @return [String] the pretty-printable inspection of the object
|
109
|
+
#
|
110
|
+
# @since 0.8.0
|
111
|
+
#
|
112
|
+
# @see https://ruby-doc.org/stdlib/libdoc/pp/rdoc/PP.html
|
113
|
+
def pretty_print(printer)
|
114
|
+
printer.text(inspect)
|
115
|
+
end
|
116
|
+
|
117
|
+
# Returns true if responds to the given method.
|
118
|
+
#
|
119
|
+
# @return [TrueClass,FalseClass] the result of the check
|
120
|
+
#
|
121
|
+
# @since 0.8.0
|
122
|
+
#
|
123
|
+
# @see http://ruby-doc.org/core/Object.html#method-i-respond_to-3F
|
124
|
+
def respond_to?(method_name, include_all = false) # rubocop:disable Style/OptionalBooleanParameter
|
125
|
+
respond_to_missing?(method_name, include_all)
|
126
|
+
end
|
127
|
+
|
128
|
+
private
|
129
|
+
|
130
|
+
# Must be overridden by descendants
|
131
|
+
#
|
132
|
+
# @since 0.8.0
|
133
|
+
# @api private
|
134
|
+
def respond_to_missing?(_method_name, _include_all)
|
135
|
+
::Kernel.raise ::NotImplementedError
|
136
|
+
end
|
137
|
+
|
138
|
+
# @since 0.8.0
|
139
|
+
# @api private
|
140
|
+
def __inspect # rubocop:disable Style/EmptyMethod
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
data/lib/dry/core/cache.rb
CHANGED
data/lib/dry/core/constants.rb
CHANGED
data/lib/dry/core/memoizable.rb
CHANGED
@@ -6,12 +6,20 @@ module Dry
|
|
6
6
|
module Core
|
7
7
|
module Memoizable
|
8
8
|
MEMOIZED_HASH = {}.freeze
|
9
|
+
PARAM_PLACEHOLDERS = %i[* ** &].freeze
|
9
10
|
|
10
11
|
module ClassInterface
|
11
12
|
module Base
|
12
13
|
def memoize(*names)
|
13
14
|
prepend(Memoizer.new(self, names))
|
14
15
|
end
|
16
|
+
|
17
|
+
def inherited(base)
|
18
|
+
super
|
19
|
+
|
20
|
+
memoizer = base.ancestors.find { _1.is_a?(Memoizer) }
|
21
|
+
base.prepend(memoizer.dup)
|
22
|
+
end
|
15
23
|
end
|
16
24
|
|
17
25
|
module BasicObject
|
@@ -51,6 +59,12 @@ module Dry
|
|
51
59
|
|
52
60
|
# @api private
|
53
61
|
class Memoizer < ::Module
|
62
|
+
KERNEL = {
|
63
|
+
singleton: ::Kernel.instance_method(:singleton_class),
|
64
|
+
ivar_set: ::Kernel.instance_method(:instance_variable_set),
|
65
|
+
frozen: ::Kernel.instance_method(:frozen?)
|
66
|
+
}.freeze
|
67
|
+
|
54
68
|
# @api private
|
55
69
|
def initialize(klass, names)
|
56
70
|
super()
|
@@ -64,25 +78,56 @@ module Dry
|
|
64
78
|
private
|
65
79
|
|
66
80
|
# @api private
|
81
|
+
# rubocop:disable Metrics/AbcSize
|
82
|
+
# rubocop:disable Metrics/PerceivedComplexity
|
67
83
|
def define_memoizable(method:)
|
68
84
|
parameters = method.parameters
|
85
|
+
mod = self
|
86
|
+
kernel = KERNEL
|
69
87
|
|
70
88
|
if parameters.empty?
|
71
|
-
key = method.name.hash
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
89
|
+
key = "#{object_id}:#{method.name}".hash.abs
|
90
|
+
|
91
|
+
define_method(method.name) do
|
92
|
+
value = super()
|
93
|
+
|
94
|
+
if kernel[:frozen].bind(self).call
|
95
|
+
# It's not possible to modify singleton classes
|
96
|
+
# of frozen objects
|
97
|
+
mod.remove_method(method.name)
|
98
|
+
mod.module_eval(<<~RUBY, __FILE__, __LINE__ + 1)
|
99
|
+
def #{method.name} # def slow_calc
|
100
|
+
cached = @__memoized__[#{key}] # cached = @__memoized__[12345678]
|
101
|
+
#
|
102
|
+
if cached || @__memoized__.key?(#{key}) # if cached || @__memoized__.key?(12345678)
|
103
|
+
cached # cached
|
104
|
+
else # else
|
105
|
+
@__memoized__[#{key}] = super # @__memoized__[12345678] = super
|
106
|
+
end # end
|
107
|
+
end # end
|
108
|
+
RUBY
|
109
|
+
else
|
110
|
+
# We make an attr_reader for computed value.
|
111
|
+
# Readers are "special-cased" in ruby so such
|
112
|
+
# access will be the fastest way, faster than you'd
|
113
|
+
# expect :)
|
114
|
+
attr_name = :"__memozed_#{key}__"
|
115
|
+
ivar_name = :"@#{attr_name}"
|
116
|
+
kernel[:ivar_set].bind(self).(ivar_name, value)
|
117
|
+
eigenclass = kernel[:singleton].bind(self).call
|
118
|
+
eigenclass.attr_reader(attr_name)
|
119
|
+
eigenclass.alias_method(method.name, attr_name)
|
120
|
+
eigenclass.remove_method(attr_name)
|
79
121
|
end
|
80
|
-
|
122
|
+
|
123
|
+
value
|
124
|
+
end
|
81
125
|
else
|
82
126
|
mapping = parameters.to_h { |k, v = nil| [k, v] }
|
83
127
|
params, binds = declaration(parameters, mapping)
|
128
|
+
last_param = parameters.last
|
84
129
|
|
85
|
-
if
|
130
|
+
if last_param[0].eql?(:block) && !last_param[1].eql?(:&)
|
86
131
|
Deprecations.warn(<<~WARN)
|
87
132
|
Memoization for block-accepting methods isn't safe.
|
88
133
|
Every call creates a new block instance bloating cached results.
|
@@ -91,23 +136,27 @@ module Dry
|
|
91
136
|
WARN
|
92
137
|
end
|
93
138
|
|
94
|
-
module_eval
|
95
|
-
def #{method.name}(#{params.join(", ")})
|
96
|
-
key = [:"#{method.name}", #{binds.join(", ")}].hash
|
97
|
-
|
98
|
-
if @__memoized__.key?(key)
|
99
|
-
@__memoized__[key]
|
100
|
-
else
|
101
|
-
@__memoized__[key] = super
|
102
|
-
end
|
103
|
-
end
|
139
|
+
m = module_eval(<<~RUBY, __FILE__, __LINE__ + 1)
|
140
|
+
def #{method.name}(#{params.join(", ")}) # def slow_calc(arg1, arg2, arg3)
|
141
|
+
key = [:"#{method.name}", #{binds.join(", ")}].hash # key = [:slow_calc, arg1, arg2, arg3].hash
|
142
|
+
#
|
143
|
+
if @__memoized__.key?(key) # if @__memoized__.key?(key)
|
144
|
+
@__memoized__[key] # @__memoized__[key]
|
145
|
+
else # else
|
146
|
+
@__memoized__[key] = super # @__memoized__[key] = super
|
147
|
+
end # end
|
148
|
+
end # end
|
104
149
|
RUBY
|
105
150
|
|
106
151
|
if respond_to?(:ruby2_keywords, true) && mapping.key?(:reyrest)
|
107
152
|
ruby2_keywords(method.name)
|
108
153
|
end
|
154
|
+
|
155
|
+
m
|
109
156
|
end
|
110
157
|
end
|
158
|
+
# rubocop:enable Metrics/AbcSize
|
159
|
+
# rubocop:enable Metrics/PerceivedComplexity
|
111
160
|
|
112
161
|
# @api private
|
113
162
|
def declaration(definition, lookup)
|
@@ -116,13 +165,13 @@ module Dry
|
|
116
165
|
defined = {}
|
117
166
|
|
118
167
|
definition.each do |type, name|
|
119
|
-
mapped_type = map_bind_type(type, lookup, defined) do
|
168
|
+
mapped_type = map_bind_type(type, name, lookup, defined) do
|
120
169
|
raise ::NotImplementedError, "type: #{type}, name: #{name}"
|
121
170
|
end
|
122
171
|
|
123
172
|
if mapped_type
|
124
173
|
defined[mapped_type] = true
|
125
|
-
bind = name || make_bind_name(binds.size)
|
174
|
+
bind = name_from_param(name) || make_bind_name(binds.size)
|
126
175
|
|
127
176
|
binds << bind
|
128
177
|
params << param(bind, mapped_type)
|
@@ -132,18 +181,35 @@ module Dry
|
|
132
181
|
[params, binds]
|
133
182
|
end
|
134
183
|
|
184
|
+
# @api private
|
185
|
+
def name_from_param(name)
|
186
|
+
if PARAM_PLACEHOLDERS.include?(name)
|
187
|
+
nil
|
188
|
+
else
|
189
|
+
name
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
135
193
|
# @api private
|
136
194
|
def make_bind_name(idx)
|
137
195
|
:"__lv_#{idx}__"
|
138
196
|
end
|
139
197
|
|
140
198
|
# @api private
|
141
|
-
def map_bind_type(type, original_params, defined_types) # rubocop:disable Metrics/PerceivedComplexity
|
199
|
+
def map_bind_type(type, name, original_params, defined_types) # rubocop:disable Metrics/PerceivedComplexity
|
142
200
|
case type
|
143
201
|
when :req
|
144
202
|
:reqular
|
145
|
-
when :rest, :keyreq, :keyrest
|
203
|
+
when :rest, :keyreq, :keyrest
|
146
204
|
type
|
205
|
+
when :block
|
206
|
+
if name.eql?(:&)
|
207
|
+
# most likely this is a case of delegation
|
208
|
+
# rather than actual block
|
209
|
+
nil
|
210
|
+
else
|
211
|
+
type
|
212
|
+
end
|
147
213
|
when :opt
|
148
214
|
if original_params.key?(:rest) || defined_types[:rest]
|
149
215
|
nil
|
data/lib/dry/core/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dry-core
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.8.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nikita Shilnikov
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2022-07-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: concurrent-ruby
|
@@ -79,6 +79,7 @@ files:
|
|
79
79
|
- dry-core.gemspec
|
80
80
|
- lib/dry-core.rb
|
81
81
|
- lib/dry/core.rb
|
82
|
+
- lib/dry/core/basic_object.rb
|
82
83
|
- lib/dry/core/cache.rb
|
83
84
|
- lib/dry/core/class_attributes.rb
|
84
85
|
- lib/dry/core/class_builder.rb
|
@@ -96,7 +97,7 @@ licenses:
|
|
96
97
|
- MIT
|
97
98
|
metadata:
|
98
99
|
allowed_push_host: https://rubygems.org
|
99
|
-
changelog_uri: https://github.com/dry-rb/dry-core/blob/
|
100
|
+
changelog_uri: https://github.com/dry-rb/dry-core/blob/main/CHANGELOG.md
|
100
101
|
source_code_uri: https://github.com/dry-rb/dry-core
|
101
102
|
bug_tracker_uri: https://github.com/dry-rb/dry-core/issues
|
102
103
|
post_install_message:
|
@@ -107,7 +108,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
107
108
|
requirements:
|
108
109
|
- - ">="
|
109
110
|
- !ruby/object:Gem::Version
|
110
|
-
version: 2.
|
111
|
+
version: 2.7.0
|
111
112
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
112
113
|
requirements:
|
113
114
|
- - ">="
|