dry-core 0.6.0 → 0.7.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 45f3b305a44c07e1b2de42160317f823835eafc272bffad043ffdf98e3fcd67c
4
- data.tar.gz: 5d040687f80c2c6d03a55bc228027f4d094820b7a7f8bcc22edec3e32e99a1a4
3
+ metadata.gz: 5bebc041fb4b4179274ef429212f91054377d05b6d4e6f353eb515a008794bff
4
+ data.tar.gz: 58401fbebb0f25c9990d5f3f7a5dad7e5bc0512c1aa2787732e7c35016d913f8
5
5
  SHA512:
6
- metadata.gz: 418356154a80dfd5cc2e31e04c84eeac838ff6d0d37c463db58ae68000d51b3eadb43f62ad5b41b3965b823967cd11967170dd38bc4ca71019ab54f098b14db0
7
- data.tar.gz: 1afa97c77840ed121fb2b501e3bbafb3854d34aefc47596d435ad405c83153ca4e18fbf2e15e929093a90f81e4113bfd339c80d67056e86d3c349c607cf95749
6
+ metadata.gz: da17cd2eecc9cfdc1ac6210161b94cbf46a5e572a563ab4e1173fed488ad2690fedee3c64dcb8db55285dfc3277b988de794800d21a23161b8f537c14ec6ceff
7
+ data.tar.gz: 9a7530f8bdc1e5398638562a00021d689da2de8c52b704d4dc59817f0a70ce640b1e0fcc618690ff59853e437adc8456e3d8a4830978f2b0217c8bbe845bd352
data/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  <!--- DO NOT EDIT THIS FILE - IT'S AUTOMATICALLY GENERATED VIA DEVTOOLS --->
2
2
 
3
+ ## 0.7.0 2021-07-08
4
+
5
+
6
+ ### Fixed
7
+
8
+ - [memoizable] warnings when using keyword arguments (@flash-gordon)
9
+ - [deprecations] warnings show more relevant information about caller by default (@timriley)
10
+
11
+ ### Changed
12
+
13
+ - Minimal Ruby version is 2.6
14
+
15
+ [Compare v0.6.0...v0.7.0](https://github.com/dry-rb/dry-core/compare/v0.6.0...v0.7.0)
16
+
3
17
  ## 0.6.0 2021-06-03
4
18
 
5
19
 
data/README.md CHANGED
@@ -1,3 +1,4 @@
1
+ <!--- this file is synced from dry-rb/template-gem project -->
1
2
  [gem]: https://rubygems.org/gems/dry-core
2
3
  [actions]: https://github.com/dry-rb/dry-core/actions
3
4
  [codacy]: https://www.codacy.com/gh/dry-rb/dry-core
@@ -14,15 +15,15 @@
14
15
 
15
16
  ## Links
16
17
 
17
- * [User documentation](http://dry-rb.org/gems/dry-core)
18
+ * [User documentation](https://dry-rb.org/gems/dry-core)
18
19
  * [API documentation](http://rubydoc.info/gems/dry-core)
19
20
 
20
21
  ## Supported Ruby versions
21
22
 
22
23
  This library officially supports the following Ruby versions:
23
24
 
24
- * MRI >= `2.5`
25
- * jruby >= `9.2`
25
+ * MRI `>= 2.6.0`
26
+ * ~~jruby~~ `>= 9.3` (we are waiting for [2.6 support](https://github.com/jruby/jruby/issues/6161))
26
27
 
27
28
  ## License
28
29
 
data/dry-core.gemspec CHANGED
@@ -26,7 +26,7 @@ Gem::Specification.new do |spec|
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.5.0"
29
+ spec.required_ruby_version = ">= 2.6.0"
30
30
 
31
31
  # to update dependencies edit project.yml
32
32
  spec.add_runtime_dependency "concurrent-ruby", "~> 1.0"
@@ -46,7 +46,8 @@ module Dry
46
46
  # this means you shouldn't pass Procs in args unless you're sure
47
47
  # they are always the same instances, otherwise you introduce a memory leak
48
48
  #
49
- # @return [Object] block's return value (cached for subsequent calls with the same argument values)
49
+ # @return [Object] block's return value (cached for subsequent calls with
50
+ # the same argument values)
50
51
  def fetch_or_store(*args, &block)
51
52
  cache.fetch_or_store(args.hash, &block)
52
53
  end
@@ -67,7 +67,7 @@ module Dry
67
67
  # defines :one, coerce: Dry::Types['coercible.string']
68
68
  # end
69
69
  #
70
- def defines(*args, type: ::Object, coerce: IDENTITY)
70
+ def defines(*args, type: ::Object, coerce: IDENTITY) # rubocop:disable Metrics/PerceivedComplexity
71
71
  unless coerce.respond_to?(:call)
72
72
  raise ::ArgumentError, "Non-callable coerce option: #{coerce.inspect}"
73
73
  end
@@ -80,10 +80,10 @@ module Dry
80
80
  if Undefined.equal?(value)
81
81
  if instance_variable_defined?(ivar)
82
82
  instance_variable_get(ivar)
83
- else
83
+ else # rubocop:disable Style/EmptyElse
84
84
  nil
85
85
  end
86
- elsif type === value
86
+ elsif type === value # rubocop:disable Style/CaseEquality
87
87
  instance_variable_set(ivar, coerce.call(value))
88
88
  else
89
89
  raise InvalidClassAttributeValue.new(name, value)
@@ -6,9 +6,7 @@ module Dry
6
6
  class ClassBuilder
7
7
  ParentClassMismatch = Class.new(TypeError)
8
8
 
9
- attr_reader :name
10
- attr_reader :parent
11
- attr_reader :namespace
9
+ attr_reader :name, :parent, :namespace
12
10
 
13
11
  def initialize(name:, parent: nil, namespace: nil)
14
12
  @name = name
@@ -83,7 +81,7 @@ module Dry
83
81
  def create_base(namespace, name, parent)
84
82
  begin
85
83
  namespace.const_get(name)
86
- rescue NameError
84
+ rescue NameError # rubocop:disable Lint/SuppressedException
87
85
  end
88
86
 
89
87
  if namespace.const_defined?(name, false)
@@ -25,7 +25,7 @@ module Dry
25
25
  # An empty set
26
26
  EMPTY_SET = ::Set.new.freeze
27
27
  # An empty string
28
- EMPTY_STRING = "".freeze
28
+ EMPTY_STRING = ""
29
29
  # Identity function
30
30
  IDENTITY = (-> x { x }).freeze
31
31
 
@@ -42,7 +42,7 @@ module Dry
42
42
  # end
43
43
  Undefined = Object.new.tap do |undefined|
44
44
  # @api private
45
- Self = -> { Undefined }
45
+ Self = -> { Undefined } # rubocop:disable Lint/ConstantDefinitionInBlock
46
46
 
47
47
  # @api public
48
48
  def undefined.to_s
@@ -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)
65
+ def undefined.default(x, y = self) # rubocop:disable Naming/MethodParameterName
66
66
  if equal?(x)
67
67
  if equal?(y)
68
68
  yield
@@ -37,12 +37,11 @@ module Dry
37
37
  # Defaults to "deprecated"
38
38
  # @param [Integer] Caller frame to add to the message
39
39
  def warn(msg, tag: nil, uplevel: nil)
40
- caller_info = uplevel.nil? ? nil : caller[uplevel]
41
- tag = "[#{tag || "deprecated"}]"
40
+ caller_info = uplevel.nil? ? nil : "#{caller_locations(uplevel + 2, 1)[0]} "
41
+ tag = "[#{tag || "deprecated"}] "
42
42
  hint = msg.gsub(/^\s+/, "")
43
- logger.warn(
44
- [caller_info, tag, hint].compact.join(" ")
45
- )
43
+
44
+ logger.warn("#{caller_info}#{tag}#{hint}")
46
45
  end
47
46
 
48
47
  # Wraps arguments with a standard message format and prints a warning
@@ -50,6 +49,10 @@ module Dry
50
49
  # @param [Object] name what is deprecated
51
50
  # @param [String] msg additional message usually containing upgrade instructions
52
51
  def announce(name, msg, tag: nil, uplevel: nil)
52
+ # Bump the uplevel (if provided) by one to account for the uplevel calculation
53
+ # taking place one frame deeper in `.warn`
54
+ uplevel += 1 if uplevel
55
+
53
56
  warn(deprecation_message(name, msg), tag: tag, uplevel: uplevel)
54
57
  end
55
58
 
@@ -99,7 +102,7 @@ module Dry
99
102
  # @param [#warn] logger
100
103
  #
101
104
  # @api public
102
- def set_logger!(output = $stderr)
105
+ def set_logger!(output = $stderr) # rubocop:disable Naming/AccessorMethodName
103
106
  if output.respond_to?(:warn)
104
107
  @logger = output
105
108
  else
@@ -115,8 +118,9 @@ module Dry
115
118
  end
116
119
 
117
120
  # @api private
118
- class Tagged < Module
121
+ class Tagged < ::Module
119
122
  def initialize(tag)
123
+ super()
120
124
  @tag = tag
121
125
  end
122
126
 
@@ -152,8 +156,8 @@ module Dry
152
156
  # @option [String] message optional deprecation message
153
157
  def deprecate(old_name, new_name = nil, message: nil)
154
158
  full_msg = Deprecations.deprecated_name_message(
155
- "#{self.name}##{old_name}",
156
- new_name ? "#{self.name}##{new_name}" : nil,
159
+ "#{name}##{old_name}",
160
+ new_name ? "#{name}##{new_name}" : nil,
157
161
  message
158
162
  )
159
163
  mod = self
@@ -185,8 +189,8 @@ module Dry
185
189
  # @option [String] message optional deprecation message
186
190
  def deprecate_class_method(old_name, new_name = nil, message: nil)
187
191
  full_msg = Deprecations.deprecated_name_message(
188
- "#{self.name}.#{old_name}",
189
- new_name ? "#{self.name}.#{new_name}" : nil,
192
+ "#{name}.#{old_name}",
193
+ new_name ? "#{name}.#{new_name}" : nil,
190
194
  message
191
195
  )
192
196
 
@@ -210,7 +214,7 @@ module Dry
210
214
  remove_const(constant_name)
211
215
 
212
216
  full_msg = Deprecations.deprecated_name_message(
213
- "#{self.name}::#{constant_name}",
217
+ "#{name}::#{constant_name}",
214
218
  message
215
219
  )
216
220
 
@@ -14,7 +14,7 @@ module Dry
14
14
 
15
15
  module Core
16
16
  # Define equality, equivalence and inspection methods
17
- class Equalizer < Module
17
+ class Equalizer < ::Module
18
18
  # Initialize an Equalizer with the given keys
19
19
  #
20
20
  # Will use the keys with which it is initialized to define #cmp?,
@@ -29,6 +29,7 @@ module Dry
29
29
  #
30
30
  # @api private
31
31
  def initialize(*keys, **options)
32
+ super()
32
33
  @keys = keys.uniq
33
34
  define_methods(**options)
34
35
  freeze
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "dry/core/deprecations"
4
+
3
5
  module Dry
4
6
  module Core
5
7
  module Memoizable
@@ -27,7 +29,7 @@ module Dry
27
29
 
28
30
  def new(*)
29
31
  obj = super
30
- obj.instance_variable_set(:'@__memoized__', MEMOIZED_HASH.dup)
32
+ obj.instance_variable_set(:@__memoized__, MEMOIZED_HASH.dup)
31
33
  obj
32
34
  end
33
35
 
@@ -48,9 +50,10 @@ module Dry
48
50
  end
49
51
 
50
52
  # @api private
51
- class Memoizer < Module
53
+ class Memoizer < ::Module
52
54
  # @api private
53
55
  def initialize(klass, names)
56
+ super()
54
57
  names.each do |name|
55
58
  define_memoizable(
56
59
  method: klass.instance_method(name)
@@ -62,45 +65,116 @@ module Dry
62
65
 
63
66
  # @api private
64
67
  def define_memoizable(method:)
65
- module_eval <<~RUBY, __FILE__, __LINE__ + 1
66
- def #{method.name}(#{to_declaration(method.parameters)})
67
- key = [Kernel.__method__] + Kernel.local_variables.map { |var| Kernel.eval(var.to_s) }
68
-
69
- if @__memoized__.key?(key)
70
- @__memoized__[key]
71
- else
72
- @__memoized__[key] = super
68
+ parameters = method.parameters
69
+
70
+ 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
73
79
  end
80
+ RUBY
81
+ else
82
+ mapping = parameters.to_h { |k, v = nil| [k, v] }
83
+ params, binds = declaration(parameters, mapping)
84
+
85
+ if parameters.last[0].eql?(:block)
86
+ Deprecations.warn(<<~WARN)
87
+ Memoization for block-accepting methods isn't safe.
88
+ Every call creates a new block instance bloating cached results.
89
+ In the future, blocks will still be allowed but won't participate in
90
+ cache key calculation.
91
+ WARN
74
92
  end
75
- RUBY
76
93
 
77
- if respond_to?(:ruby2_keywords, true)
78
- ruby2_keywords(method.name)
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
104
+ RUBY
105
+
106
+ if respond_to?(:ruby2_keywords, true) && mapping.key?(:reyrest)
107
+ ruby2_keywords(method.name)
108
+ end
109
+ end
110
+ end
111
+
112
+ # @api private
113
+ def declaration(definition, lookup)
114
+ params = []
115
+ binds = []
116
+ defined = {}
117
+
118
+ definition.each do |type, name|
119
+ mapped_type = map_bind_type(type, lookup, defined) do
120
+ raise ::NotImplementedError, "type: #{type}, name: #{name}"
121
+ end
122
+
123
+ if mapped_type
124
+ defined[mapped_type] = true
125
+ bind = name || make_bind_name(binds.size)
126
+
127
+ binds << bind
128
+ params << param(bind, mapped_type)
129
+ end
79
130
  end
131
+
132
+ [params, binds]
133
+ end
134
+
135
+ # @api private
136
+ def make_bind_name(idx)
137
+ :"__lv_#{idx}__"
80
138
  end
81
139
 
82
140
  # @api private
83
- def to_declaration(params, lookup = params.to_h)
84
- params.map do |type, name|
85
- case type
86
- when :req
87
- name
88
- when :rest
89
- "*#{name}"
90
- when :keyreq
91
- "#{name}:"
92
- when :keyrest
93
- "**#{name}"
94
- when :block
95
- "&#{name}"
96
- when :opt
97
- lookup.key?(:rest) ? nil : "*args"
98
- when :key
99
- lookup.key?(:keyrest) ? nil : "**kwargs"
141
+ def map_bind_type(type, original_params, defined_types) # rubocop:disable Metrics/PerceivedComplexity
142
+ case type
143
+ when :req
144
+ :reqular
145
+ when :rest, :keyreq, :keyrest, :block
146
+ type
147
+ when :opt
148
+ if original_params.key?(:rest) || defined_types[:rest]
149
+ nil
100
150
  else
101
- raise NotImplementedError, "type: #{type}, name: #{name}"
151
+ :rest
102
152
  end
103
- end.compact.join(", ")
153
+ when :key
154
+ if original_params.key?(:keyrest) || defined_types[:keyrest]
155
+ nil
156
+ else
157
+ :keyrest
158
+ end
159
+ else
160
+ yield
161
+ end
162
+ end
163
+
164
+ # @api private
165
+ def param(name, type)
166
+ case type
167
+ when :reqular
168
+ name
169
+ when :rest
170
+ "*#{name}"
171
+ when :keyreq
172
+ "#{name}:"
173
+ when :keyrest
174
+ "**#{name}"
175
+ when :block
176
+ "&#{name}"
177
+ end
104
178
  end
105
179
  end
106
180
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Dry
4
4
  module Core
5
- VERSION = "0.6.0".freeze
5
+ VERSION = "0.7.0"
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.6.0
4
+ version: 0.7.0
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-06-03 00:00:00.000000000 Z
11
+ date: 2021-07-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: concurrent-ruby
@@ -107,7 +107,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
107
107
  requirements:
108
108
  - - ">="
109
109
  - !ruby/object:Gem::Version
110
- version: 2.5.0
110
+ version: 2.6.0
111
111
  required_rubygems_version: !ruby/object:Gem::Requirement
112
112
  requirements:
113
113
  - - ">="