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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5bebc041fb4b4179274ef429212f91054377d05b6d4e6f353eb515a008794bff
4
- data.tar.gz: 58401fbebb0f25c9990d5f3f7a5dad7e5bc0512c1aa2787732e7c35016d913f8
3
+ metadata.gz: 9d3ee16c97a04071316e718d8277a4a0ac5aea083b37ac7944d65fd3fd78dfc2
4
+ data.tar.gz: 44e0e7cb408530f47add47481dd393ba8544e2bcb41256fa0d88af915e7ce547
5
5
  SHA512:
6
- metadata.gz: da17cd2eecc9cfdc1ac6210161b94cbf46a5e572a563ab4e1173fed488ad2690fedee3c64dcb8db55285dfc3277b988de794800d21a23161b8f537c14ec6ceff
7
- data.tar.gz: 9a7530f8bdc1e5398638562a00021d689da2de8c52b704d4dc59817f0a70ce640b1e0fcc618690ff59853e437adc8456e3d8a4830978f2b0217c8bbe845bd352
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 2012-12-12
60
+ ## 0.5.0 2020-12-12
34
61
 
35
62
 
36
63
  ### Added
data/README.md CHANGED
@@ -11,7 +11,7 @@
11
11
  [![CI Status](https://github.com/dry-rb/dry-core/workflows/ci/badge.svg)][actions]
12
12
  [![Codacy Badge](https://api.codacy.com/project/badge/Grade/40946292b9094624beec604a149a6023)][codacy]
13
13
  [![Codacy Badge](https://api.codacy.com/project/badge/Coverage/40946292b9094624beec604a149a6023)][codacy]
14
- [![Inline docs](http://inch-ci.org/github/dry-rb/dry-core.svg?branch=master)][inchpages]
14
+ [![Inline docs](http://inch-ci.org/github/dry-rb/dry-core.svg?branch=main)][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.6.0`
26
- * ~~jruby~~ `>= 9.3` (we are waiting for [2.6 support](https://github.com/jruby/jruby/issues/6161))
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/master/CHANGELOG.md"
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.6.0"
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
@@ -60,8 +60,8 @@ module Dry
60
60
  # @yield An arbitrary block
61
61
  #
62
62
  # @return [Object] block's return value
63
- def fetch_or_store(*args, &block)
64
- self.class.fetch_or_store(*args, &block)
63
+ def fetch_or_store(...)
64
+ self.class.fetch_or_store(...)
65
65
  end
66
66
  end
67
67
  end
@@ -80,7 +80,7 @@ module Dry
80
80
  if Undefined.equal?(value)
81
81
  if instance_variable_defined?(ivar)
82
82
  instance_variable_get(ivar)
83
- else # rubocop:disable Style/EmptyElse
83
+ else
84
84
  nil
85
85
  end
86
86
  elsif type === value # rubocop:disable Style/CaseEquality
@@ -62,7 +62,7 @@ module Dry
62
62
  # 1 + Undefined.default(val, 2)
63
63
  # end
64
64
  #
65
- def undefined.default(x, y = self) # rubocop:disable Naming/MethodParameterName
65
+ def undefined.default(x, y = self)
66
66
  if equal?(x)
67
67
  if equal?(y)
68
68
  yield
@@ -4,7 +4,7 @@ require "logger"
4
4
 
5
5
  module Dry
6
6
  module Core
7
- # An extension for issueing warnings on using deprecated methods.
7
+ # An extension for issuing warnings on using deprecated methods.
8
8
  #
9
9
  # @example
10
10
  #
@@ -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
- module_eval <<~RUBY, __FILE__, __LINE__ + 1
73
- def #{method.name}
74
- if @__memoized__.key?(#{key})
75
- @__memoized__[#{key}]
76
- else
77
- @__memoized__[#{key}] = super
78
- end
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
- RUBY
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 parameters.last[0].eql?(:block)
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 <<~RUBY, __FILE__, __LINE__ + 1
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, :block
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
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Dry
4
4
  module Core
5
- VERSION = "0.7.0"
5
+ VERSION = "0.8.1"
6
6
  end
7
7
  end
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.7.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: 2021-07-08 00:00:00.000000000 Z
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/master/CHANGELOG.md
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.6.0
111
+ version: 2.7.0
111
112
  required_rubygems_version: !ruby/object:Gem::Requirement
112
113
  requirements:
113
114
  - - ">="