dry-core 0.6.0 → 0.8.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: 1f8c83e96398be4753d6ac800d164612021350dcabb3b2cdd3caa448984bb6cc
4
+ data.tar.gz: 1fa35af111908ebf221e6c494b53c253172df017a5ffcb2f4fe16ff0b0c29649
5
5
  SHA512:
6
- metadata.gz: 418356154a80dfd5cc2e31e04c84eeac838ff6d0d37c463db58ae68000d51b3eadb43f62ad5b41b3965b823967cd11967170dd38bc4ca71019ab54f098b14db0
7
- data.tar.gz: 1afa97c77840ed121fb2b501e3bbafb3854d34aefc47596d435ad405c83153ca4e18fbf2e15e929093a90f81e4113bfd339c80d67056e86d3c349c607cf95749
6
+ metadata.gz: '09529feae5672f027a2da7d0c9e3172f0575813fda68f689f1cdf3dfd5b0301686539bd6d843aef0c862c14831af1a166a2caf9f6f44e68521903d835195018b'
7
+ data.tar.gz: e5a2d5fa7d7c7ffca14b5fec56fe495627fb829beb9ca6b20014e9a9b66f6bbce1506df72edbc481db3816839b011be3a9c144f8e3f62f764b392b30e37fbce5
data/CHANGELOG.md CHANGED
@@ -1,5 +1,46 @@
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
+
29
+ ## 0.7.0 2021-07-08
30
+
31
+
32
+ ### Fixed
33
+
34
+ - [memoizable] warnings when using keyword arguments (@flash-gordon)
35
+ - [deprecations] warnings show more relevant information about caller by default (@timriley)
36
+
37
+ ### Changed
38
+
39
+ - Minimal Ruby version is 2.6
40
+ - [memoizable] memoization of block-accepting methods is deprecated (@flash-gordon)
41
+
42
+ [Compare v0.6.0...v0.7.0](https://github.com/dry-rb/dry-core/compare/v0.6.0...v0.7.0)
43
+
3
44
  ## 0.6.0 2021-06-03
4
45
 
5
46
 
@@ -16,7 +57,7 @@
16
57
 
17
58
  [Compare v0.5.0...v0.6.0](https://github.com/dry-rb/dry-core/compare/v0.5.0...v0.6.0)
18
59
 
19
- ## 0.5.0 2012-12-12
60
+ ## 0.5.0 2020-12-12
20
61
 
21
62
 
22
63
  ### Added
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
@@ -10,19 +11,19 @@
10
11
  [![CI Status](https://github.com/dry-rb/dry-core/workflows/ci/badge.svg)][actions]
11
12
  [![Codacy Badge](https://api.codacy.com/project/badge/Grade/40946292b9094624beec604a149a6023)][codacy]
12
13
  [![Codacy Badge](https://api.codacy.com/project/badge/Coverage/40946292b9094624beec604a149a6023)][codacy]
13
- [![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]
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.7.0`
26
+ * jruby `>= 9.3` (postponed until 2.7 is supported)
26
27
 
27
28
  ## License
28
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.5.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
@@ -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
@@ -59,8 +60,8 @@ module Dry
59
60
  # @yield An arbitrary block
60
61
  #
61
62
  # @return [Object] block's return value
62
- def fetch_or_store(*args, &block)
63
- self.class.fetch_or_store(*args, &block)
63
+ def fetch_or_store(...)
64
+ self.class.fetch_or_store(...)
64
65
  end
65
66
  end
66
67
  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
@@ -83,7 +83,7 @@ module Dry
83
83
  else
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
@@ -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
  #
@@ -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,9 +1,12 @@
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
6
8
  MEMOIZED_HASH = {}.freeze
9
+ PARAM_PLACEHOLDERS = %i[* ** &].freeze
7
10
 
8
11
  module ClassInterface
9
12
  module Base
@@ -27,7 +30,7 @@ module Dry
27
30
 
28
31
  def new(*)
29
32
  obj = super
30
- obj.instance_variable_set(:'@__memoized__', MEMOIZED_HASH.dup)
33
+ obj.instance_variable_set(:@__memoized__, MEMOIZED_HASH.dup)
31
34
  obj
32
35
  end
33
36
 
@@ -48,9 +51,16 @@ module Dry
48
51
  end
49
52
 
50
53
  # @api private
51
- class Memoizer < Module
54
+ class Memoizer < ::Module
55
+ KERNEL = {
56
+ singleton: ::Kernel.instance_method(:singleton_class),
57
+ ivar_set: ::Kernel.instance_method(:instance_variable_set),
58
+ frozen: ::Kernel.instance_method(:frozen?)
59
+ }.freeze
60
+
52
61
  # @api private
53
62
  def initialize(klass, names)
63
+ super()
54
64
  names.each do |name|
55
65
  define_memoizable(
56
66
  method: klass.instance_method(name)
@@ -61,46 +71,169 @@ module Dry
61
71
  private
62
72
 
63
73
  # @api private
74
+ # rubocop:disable Metrics/AbcSize
75
+ # rubocop:disable Metrics/PerceivedComplexity
64
76
  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) }
77
+ parameters = method.parameters
78
+ mod = self
79
+ kernel = KERNEL
80
+
81
+ if parameters.empty?
82
+ key = method.name.hash.abs
68
83
 
69
- if @__memoized__.key?(key)
70
- @__memoized__[key]
84
+ define_method(method.name) do
85
+ value = super()
86
+
87
+ if kernel[:frozen].bind(self).call
88
+ # It's not possible to modify singleton classes
89
+ # of frozen objects
90
+ mod.remove_method(method.name)
91
+ mod.module_eval(<<~RUBY, __FILE__, __LINE__ + 1)
92
+ def #{method.name} # def slow_calc
93
+ cached = @__memoized__[#{key}] # cached = @__memoized__[12345678]
94
+ #
95
+ if cached || @__memoized__.key?(#{key}) # if cached || @__memoized__.key?(12345678)
96
+ cached # cached
97
+ else # else
98
+ @__memoized__[#{key}] = super # @__memoized__[12345678] = super
99
+ end # end
100
+ end # end
101
+ RUBY
71
102
  else
72
- @__memoized__[key] = super
103
+ # We make an attr_reader for computed value.
104
+ # Readers are "special-cased" in ruby so such
105
+ # access will be the fastest way, faster than you'd
106
+ # expect :)
107
+ attr_name = :"__memozed_#{key}__"
108
+ ivar_name = :"@#{attr_name}"
109
+ kernel[:ivar_set].bind(self).(ivar_name, value)
110
+ eigenclass = kernel[:singleton].bind(self).call
111
+ eigenclass.attr_reader(attr_name)
112
+ eigenclass.alias_method(method.name, attr_name)
113
+ eigenclass.remove_method(attr_name)
73
114
  end
115
+
116
+ value
74
117
  end
75
- RUBY
118
+ else
119
+ mapping = parameters.to_h { |k, v = nil| [k, v] }
120
+ params, binds = declaration(parameters, mapping)
121
+ last_param = parameters.last
76
122
 
77
- if respond_to?(:ruby2_keywords, true)
78
- ruby2_keywords(method.name)
123
+ if last_param[0].eql?(:block) && !last_param[1].eql?(:&)
124
+ Deprecations.warn(<<~WARN)
125
+ Memoization for block-accepting methods isn't safe.
126
+ Every call creates a new block instance bloating cached results.
127
+ In the future, blocks will still be allowed but won't participate in
128
+ cache key calculation.
129
+ WARN
130
+ end
131
+
132
+ m = module_eval(<<~RUBY, __FILE__, __LINE__ + 1)
133
+ def #{method.name}(#{params.join(", ")}) # def slow_calc(arg1, arg2, arg3)
134
+ key = [:"#{method.name}", #{binds.join(", ")}].hash # key = [:slow_calc, arg1, arg2, arg3].hash
135
+ #
136
+ if @__memoized__.key?(key) # if @__memoized__.key?(key)
137
+ @__memoized__[key] # @__memoized__[key]
138
+ else # else
139
+ @__memoized__[key] = super # @__memoized__[key] = super
140
+ end # end
141
+ end # end
142
+ RUBY
143
+
144
+ if respond_to?(:ruby2_keywords, true) && mapping.key?(:reyrest)
145
+ ruby2_keywords(method.name)
146
+ end
147
+
148
+ m
79
149
  end
80
150
  end
151
+ # rubocop:enable Metrics/AbcSize
152
+ # rubocop:enable Metrics/PerceivedComplexity
81
153
 
82
154
  # @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"
155
+ def declaration(definition, lookup)
156
+ params = []
157
+ binds = []
158
+ defined = {}
159
+
160
+ definition.each do |type, name|
161
+ mapped_type = map_bind_type(type, name, lookup, defined) do
162
+ raise ::NotImplementedError, "type: #{type}, name: #{name}"
163
+ end
164
+
165
+ if mapped_type
166
+ defined[mapped_type] = true
167
+ bind = name_from_param(name) || make_bind_name(binds.size)
168
+
169
+ binds << bind
170
+ params << param(bind, mapped_type)
171
+ end
172
+ end
173
+
174
+ [params, binds]
175
+ end
176
+
177
+ # @api private
178
+ def name_from_param(name)
179
+ if PARAM_PLACEHOLDERS.include?(name)
180
+ nil
181
+ else
182
+ name
183
+ end
184
+ end
185
+
186
+ # @api private
187
+ def make_bind_name(idx)
188
+ :"__lv_#{idx}__"
189
+ end
190
+
191
+ # @api private
192
+ def map_bind_type(type, name, original_params, defined_types) # rubocop:disable Metrics/PerceivedComplexity
193
+ case type
194
+ when :req
195
+ :reqular
196
+ when :rest, :keyreq, :keyrest
197
+ type
198
+ when :block
199
+ if name.eql?(:&)
200
+ # most likely this is a case of delegation
201
+ # rather than actual block
202
+ nil
100
203
  else
101
- raise NotImplementedError, "type: #{type}, name: #{name}"
204
+ type
102
205
  end
103
- end.compact.join(", ")
206
+ when :opt
207
+ if original_params.key?(:rest) || defined_types[:rest]
208
+ nil
209
+ else
210
+ :rest
211
+ end
212
+ when :key
213
+ if original_params.key?(:keyrest) || defined_types[:keyrest]
214
+ nil
215
+ else
216
+ :keyrest
217
+ end
218
+ else
219
+ yield
220
+ end
221
+ end
222
+
223
+ # @api private
224
+ def param(name, type)
225
+ case type
226
+ when :reqular
227
+ name
228
+ when :rest
229
+ "*#{name}"
230
+ when :keyreq
231
+ "#{name}:"
232
+ when :keyrest
233
+ "**#{name}"
234
+ when :block
235
+ "&#{name}"
236
+ end
104
237
  end
105
238
  end
106
239
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Dry
4
4
  module Core
5
- VERSION = "0.6.0".freeze
5
+ VERSION = "0.8.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.8.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: 2022-07-15 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.5.0
111
+ version: 2.7.0
111
112
  required_rubygems_version: !ruby/object:Gem::Requirement
112
113
  requirements:
113
114
  - - ">="