dry-core 0.4.9 → 0.7.1

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