dry-core 0.7.0 → 0.8.1

Sign up to get free protection for your applications and to get access to all the features.
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
  - - ">="