dry-core 0.6.0 → 0.8.0

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: 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
  - - ">="