dry-core 0.4.9 → 0.7.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.
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'set'
3
+ require "set"
4
4
 
5
5
  module Dry
6
6
  module Core
@@ -7,15 +7,15 @@ module Dry
7
7
  # List of supported backends
8
8
  BACKENDS = {
9
9
  activesupport: [
10
- 'active_support/inflector',
10
+ "active_support/inflector",
11
11
  proc { ::ActiveSupport::Inflector }
12
12
  ],
13
13
  dry_inflector: [
14
- 'dry/inflector',
14
+ "dry/inflector",
15
15
  proc { Dry::Inflector.new }
16
16
  ],
17
17
  inflecto: [
18
- 'inflecto',
18
+ "inflecto",
19
19
  proc { ::Inflecto }
20
20
  ]
21
21
  }.freeze
@@ -49,6 +49,7 @@ module Dry
49
49
  if name && !BACKENDS.key?(name)
50
50
  raise NameError, "Invalid inflector library selection: '#{name}'"
51
51
  end
52
+
52
53
  @inflector = name ? realize_backend(*BACKENDS[name]) : detect_backend
53
54
  end
54
55
 
@@ -1,67 +1,200 @@
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
- def memoize(*names)
10
- prepend(Memoizer.new(self, names))
12
+ module Base
13
+ def memoize(*names)
14
+ prepend(Memoizer.new(self, names))
15
+ end
11
16
  end
12
17
 
13
- def new(*)
14
- obj = super
15
- obj.instance_variable_set(:'@__memoized__', MEMOIZED_HASH.dup)
16
- obj
18
+ module BasicObject
19
+ include Base
20
+
21
+ def new(*)
22
+ obj = super
23
+ obj.instance_eval { @__memoized__ = MEMOIZED_HASH.dup }
24
+ obj
25
+ end
26
+ end
27
+
28
+ module Object
29
+ include Base
30
+
31
+ def new(*)
32
+ obj = super
33
+ obj.instance_variable_set(:@__memoized__, MEMOIZED_HASH.dup)
34
+ obj
35
+ end
36
+
37
+ if respond_to?(:ruby2_keywords, true)
38
+ ruby2_keywords(:new)
39
+ end
17
40
  end
18
41
  end
19
42
 
20
43
  def self.included(klass)
21
44
  super
22
- klass.extend(ClassInterface)
23
- end
24
45
 
25
- attr_reader :__memoized__
46
+ if klass <= Object
47
+ klass.extend(ClassInterface::Object)
48
+ else
49
+ klass.extend(ClassInterface::BasicObject)
50
+ end
51
+ end
26
52
 
27
53
  # @api private
28
- class Memoizer < Module
29
- attr_reader :klass
30
- attr_reader :names
31
-
54
+ class Memoizer < ::Module
32
55
  # @api private
33
56
  def initialize(klass, names)
34
- @names = names
35
- @klass = klass
36
- define_memoizable_names!
57
+ super()
58
+ names.each do |name|
59
+ define_memoizable(
60
+ method: klass.instance_method(name)
61
+ )
62
+ end
37
63
  end
38
64
 
39
65
  private
40
66
 
41
67
  # @api private
42
- def define_memoizable_names!
43
- names.each do |name|
44
- meth = klass.instance_method(name)
45
-
46
- if meth.parameters.size > 0
47
- define_method(name) do |*args|
48
- name_with_args = :"#{name}_#{args.hash}"
49
-
50
- if __memoized__.key?(name_with_args)
51
- __memoized__[name_with_args]
52
- else
53
- __memoized__[name_with_args] = super(*args)
54
- end
55
- end
68
+ def define_memoizable(method:) # rubocop:disable Metrics/AbcSize
69
+ parameters = method.parameters
70
+
71
+ if parameters.empty?
72
+ key = method.name.hash
73
+ module_eval(<<~RUBY, __FILE__, __LINE__ + 1)
74
+ def #{method.name} # def slow_fetch
75
+ if @__memoized__.key?(#{key}) # if @__memoized__.key?(12345678)
76
+ @__memoized__[#{key}] # @__memoized__[12345678]
77
+ else # else
78
+ @__memoized__[#{key}] = super # @__memoized__[12345678] = super
79
+ end # end
80
+ end # end
81
+ RUBY
82
+ else
83
+ mapping = parameters.to_h { |k, v = nil| [k, v] }
84
+ params, binds = declaration(parameters, mapping)
85
+ last_param = parameters.last
86
+
87
+ if last_param[0].eql?(:block) && !last_param[1].eql?(:&)
88
+ Deprecations.warn(<<~WARN)
89
+ Memoization for block-accepting methods isn't safe.
90
+ Every call creates a new block instance bloating cached results.
91
+ In the future, blocks will still be allowed but won't participate in
92
+ cache key calculation.
93
+ WARN
94
+ end
95
+
96
+ m = module_eval(<<~RUBY, __FILE__, __LINE__ + 1)
97
+ def #{method.name}(#{params.join(", ")}) # def slow_calc(arg1, arg2, arg3)
98
+ key = [:"#{method.name}", #{binds.join(", ")}].hash # [:slow_calc, arg1, arg2, arg3].hash
99
+ #
100
+ if @__memoized__.key?(key) # if @__memoized__.key?(key)
101
+ @__memoized__[key] # @__memoized__[key]
102
+ else # else
103
+ @__memoized__[key] = super # @__memoized__[key] = super
104
+ end # end
105
+ end # end
106
+ RUBY
107
+
108
+ if respond_to?(:ruby2_keywords, true) && mapping.key?(:reyrest)
109
+ ruby2_keywords(method.name)
110
+ end
111
+
112
+ m
113
+ end
114
+ end
115
+
116
+ # @api private
117
+ def declaration(definition, lookup)
118
+ params = []
119
+ binds = []
120
+ defined = {}
121
+
122
+ definition.each do |type, name|
123
+ mapped_type = map_bind_type(type, name, lookup, defined) do
124
+ raise ::NotImplementedError, "type: #{type}, name: #{name}"
125
+ end
126
+
127
+ if mapped_type
128
+ defined[mapped_type] = true
129
+ bind = name_from_param(name) || make_bind_name(binds.size)
130
+
131
+ binds << bind
132
+ params << param(bind, mapped_type)
133
+ end
134
+ end
135
+
136
+ [params, binds]
137
+ end
138
+
139
+ # @api private
140
+ def name_from_param(name)
141
+ if PARAM_PLACEHOLDERS.include?(name)
142
+ nil
143
+ else
144
+ name
145
+ end
146
+ end
147
+
148
+ # @api private
149
+ def make_bind_name(idx)
150
+ :"__lv_#{idx}__"
151
+ end
152
+
153
+ # @api private
154
+ def map_bind_type(type, name, original_params, defined_types) # rubocop:disable Metrics/PerceivedComplexity
155
+ case type
156
+ when :req
157
+ :reqular
158
+ when :rest, :keyreq, :keyrest
159
+ type
160
+ when :block
161
+ if name.eql?(:&)
162
+ # most likely this is a case of delegation
163
+ # rather than actual block
164
+ nil
165
+ else
166
+ type
167
+ end
168
+ when :opt
169
+ if original_params.key?(:rest) || defined_types[:rest]
170
+ nil
56
171
  else
57
- define_method(name) do
58
- if __memoized__.key?(name)
59
- __memoized__[name]
60
- else
61
- __memoized__[name] = super()
62
- end
63
- end
172
+ :rest
64
173
  end
174
+ when :key
175
+ if original_params.key?(:keyrest) || defined_types[:keyrest]
176
+ nil
177
+ else
178
+ :keyrest
179
+ end
180
+ else
181
+ yield
182
+ end
183
+ end
184
+
185
+ # @api private
186
+ def param(name, type)
187
+ case type
188
+ when :reqular
189
+ name
190
+ when :rest
191
+ "*#{name}"
192
+ when :keyreq
193
+ "#{name}:"
194
+ when :keyrest
195
+ "**#{name}"
196
+ when :block
197
+ "&#{name}"
65
198
  end
66
199
  end
67
200
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Dry
4
4
  module Core
5
- VERSION = '0.4.9'.freeze
5
+ VERSION = "0.7.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.4.9
4
+ version: 0.7.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nikita Shilnikov
8
8
  autorequire:
9
- bindir: exe
9
+ bindir: bin
10
10
  cert_chain: []
11
- date: 2019-08-09 00:00:00.000000000 Z
11
+ date: 2021-07-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: concurrent-ruby
@@ -42,48 +42,40 @@ dependencies:
42
42
  name: rake
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - "~>"
45
+ - - ">="
46
46
  - !ruby/object:Gem::Version
47
- version: '10.0'
47
+ version: '0'
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - "~>"
52
+ - - ">="
53
53
  - !ruby/object:Gem::Version
54
- version: '10.0'
54
+ version: '0'
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: rspec
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - "~>"
59
+ - - ">="
60
60
  - !ruby/object:Gem::Version
61
- version: '3.0'
61
+ version: '0'
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
- - - "~>"
66
+ - - ">="
67
67
  - !ruby/object:Gem::Version
68
- version: '3.0'
69
- description: A toolset of small support modules used throughout the dry-rb ecosystem.
68
+ version: '0'
69
+ description: A toolset of small support modules used throughout the dry-rb ecosystem
70
70
  email:
71
71
  - fg@flashgordon.ru
72
72
  executables: []
73
73
  extensions: []
74
74
  extra_rdoc_files: []
75
75
  files:
76
- - ".codeclimate.yml"
77
- - ".gitignore"
78
- - ".inch.yml"
79
- - ".rspec"
80
- - ".travis.yml"
81
76
  - CHANGELOG.md
82
- - CONTRIBUTING.md
83
- - Gemfile
84
- - LICENSE.txt
77
+ - LICENSE
85
78
  - README.md
86
- - Rakefile
87
79
  - dry-core.gemspec
88
80
  - lib/dry-core.rb
89
81
  - lib/dry/core.rb
@@ -93,16 +85,20 @@ files:
93
85
  - lib/dry/core/constants.rb
94
86
  - lib/dry/core/deprecations.rb
95
87
  - lib/dry/core/descendants_tracker.rb
88
+ - lib/dry/core/equalizer.rb
96
89
  - lib/dry/core/errors.rb
97
90
  - lib/dry/core/extensions.rb
98
91
  - lib/dry/core/inflector.rb
99
92
  - lib/dry/core/memoizable.rb
100
93
  - lib/dry/core/version.rb
101
- homepage: https://github.com/dry-rb/dry-core
94
+ homepage: https://dry-rb.org/gems/dry-core
102
95
  licenses:
103
96
  - MIT
104
97
  metadata:
105
98
  allowed_push_host: https://rubygems.org
99
+ changelog_uri: https://github.com/dry-rb/dry-core/blob/master/CHANGELOG.md
100
+ source_code_uri: https://github.com/dry-rb/dry-core
101
+ bug_tracker_uri: https://github.com/dry-rb/dry-core/issues
106
102
  post_install_message:
107
103
  rdoc_options: []
108
104
  require_paths:
@@ -111,15 +107,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
111
107
  requirements:
112
108
  - - ">="
113
109
  - !ruby/object:Gem::Version
114
- version: 2.1.0
110
+ version: 2.6.0
115
111
  required_rubygems_version: !ruby/object:Gem::Requirement
116
112
  requirements:
117
113
  - - ">="
118
114
  - !ruby/object:Gem::Version
119
115
  version: '0'
120
116
  requirements: []
121
- rubygems_version: 3.0.3
117
+ rubygems_version: 3.1.6
122
118
  signing_key:
123
119
  specification_version: 4
124
- summary: A toolset of small support modules used throughout the dry-rb ecosystem.
120
+ summary: A toolset of small support modules used throughout the dry-rb ecosystem
125
121
  test_files: []
data/.codeclimate.yml DELETED
@@ -1,15 +0,0 @@
1
- version: "2"
2
-
3
- prepare:
4
- fetch:
5
- - url: "https://raw.githubusercontent.com/dry-rb/devtools/master/.rubocop.yml"
6
- path: ".rubocop.yml"
7
-
8
- exclude_patterns:
9
- - "benchmarks/"
10
- - "examples/"
11
- - "spec/"
12
-
13
- plugins:
14
- rubocop:
15
- enabled: true
data/.gitignore DELETED
@@ -1,11 +0,0 @@
1
- /.bundle/
2
- /.yardoc
3
- /Gemfile.lock
4
- /_yardoc/
5
- /coverage/
6
- /doc/
7
- /pkg/
8
- /spec/reports/
9
- /tmp/
10
- spec/examples.txt
11
- .rubocop.yml
data/.inch.yml DELETED
@@ -1,4 +0,0 @@
1
- files:
2
- excluded:
3
- - lib/dry/core.rb
4
- - lib/dry/core/version.rb
data/.rspec DELETED
@@ -1,3 +0,0 @@
1
- --format progress
2
- --color
3
- --require ./spec/spec_helper.rb
data/.travis.yml DELETED
@@ -1,34 +0,0 @@
1
- language: ruby
2
- dist: trusty
3
- sudo: required
4
- cache: bundler
5
- bundler_args: --without benchmarks tools
6
- after_success:
7
- - '[ -d coverage ] && bundle exec codeclimate-test-reporter'
8
- before_install:
9
- - gem install bundler
10
- after_success:
11
- - '[ -d coverage ] && bundle exec codeclimate-test-reporter'
12
- rvm:
13
- - 2.4.6
14
- - 2.5.5
15
- - 2.6.3
16
- - truffleruby
17
- env:
18
- global:
19
- - COVERAGE=true
20
- - JRUBY_OPTS='--dev -J-Xmx1024M'
21
- matrix:
22
- allow_failures:
23
- - rvm: truffleruby
24
- include:
25
- - rvm: jruby-9.2.7.0
26
- jdk: openjdk8
27
- notifications:
28
- email: false
29
- webhooks:
30
- urls:
31
- - https://webhooks.gitter.im/e/19098b4253a72c9796db
32
- on_success: change # options: [always|never|change] default: always
33
- on_failure: always # options: [always|never|change] default: always
34
- on_start: false # default: false