receptacle 1.0.0 → 2.0.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 +4 -4
- data/.github/workflows/matrix.yml +32 -0
- data/.gitignore +1 -1
- data/.rubocop.yml +4 -7
- data/CHANGELOG.md +27 -22
- data/Gemfile +0 -6
- data/Gemfile.lock +92 -0
- data/LICENSE.txt +1 -1
- data/README.md +22 -52
- data/Rakefile +0 -3
- data/examples/simple_repo.rb +2 -1
- data/lib/receptacle/errors.rb +1 -1
- data/lib/receptacle/repo.rb +51 -0
- data/lib/receptacle/test_support.rb +0 -16
- data/lib/receptacle/version.rb +1 -1
- data/lib/receptacle.rb +1 -8
- data/receptacle.gemspec +23 -18
- data/upgrade_notes.md +45 -0
- metadata +36 -62
- data/.circleci/config.yml +0 -64
- data/.dir-locals.el +0 -1
- data/Dangerfile +0 -31
- data/Guardfile +0 -32
- data/lib/receptacle/interface_methods.rb +0 -51
- data/lib/receptacle/method_cache.rb +0 -43
- data/lib/receptacle/method_delegation.rb +0 -141
- data/lib/receptacle/registration.rb +0 -35
- data/performance/benchmark.rb +0 -45
- data/performance/profile.rb +0 -40
- data/performance/speed_receptacle.rb +0 -105
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: receptacle
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andreas Eger
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2023-01-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -31,7 +31,7 @@ dependencies:
|
|
31
31
|
- !ruby/object:Gem::Version
|
32
32
|
version: '3'
|
33
33
|
- !ruby/object:Gem::Dependency
|
34
|
-
name:
|
34
|
+
name: pry
|
35
35
|
requirement: !ruby/object:Gem::Requirement
|
36
36
|
requirements:
|
37
37
|
- - ">="
|
@@ -45,35 +45,35 @@ dependencies:
|
|
45
45
|
- !ruby/object:Gem::Version
|
46
46
|
version: '0'
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
|
-
name:
|
48
|
+
name: rake
|
49
49
|
requirement: !ruby/object:Gem::Requirement
|
50
50
|
requirements:
|
51
|
-
- - "
|
51
|
+
- - "~>"
|
52
52
|
- !ruby/object:Gem::Version
|
53
|
-
version: '0'
|
53
|
+
version: '10.0'
|
54
54
|
type: :development
|
55
55
|
prerelease: false
|
56
56
|
version_requirements: !ruby/object:Gem::Requirement
|
57
57
|
requirements:
|
58
|
-
- - "
|
58
|
+
- - "~>"
|
59
59
|
- !ruby/object:Gem::Version
|
60
|
-
version: '0'
|
60
|
+
version: '10.0'
|
61
61
|
- !ruby/object:Gem::Dependency
|
62
|
-
name:
|
62
|
+
name: rspec
|
63
63
|
requirement: !ruby/object:Gem::Requirement
|
64
64
|
requirements:
|
65
|
-
- - "
|
65
|
+
- - "~>"
|
66
66
|
- !ruby/object:Gem::Version
|
67
|
-
version: '
|
67
|
+
version: '3.11'
|
68
68
|
type: :development
|
69
69
|
prerelease: false
|
70
70
|
version_requirements: !ruby/object:Gem::Requirement
|
71
71
|
requirements:
|
72
|
-
- - "
|
72
|
+
- - "~>"
|
73
73
|
- !ruby/object:Gem::Version
|
74
|
-
version: '
|
74
|
+
version: '3.11'
|
75
75
|
- !ruby/object:Gem::Dependency
|
76
|
-
name:
|
76
|
+
name: rspec_junit_formatter
|
77
77
|
requirement: !ruby/object:Gem::Requirement
|
78
78
|
requirements:
|
79
79
|
- - ">="
|
@@ -87,81 +87,61 @@ dependencies:
|
|
87
87
|
- !ruby/object:Gem::Version
|
88
88
|
version: '0'
|
89
89
|
- !ruby/object:Gem::Dependency
|
90
|
-
name:
|
90
|
+
name: rt_rubocop_defaults
|
91
91
|
requirement: !ruby/object:Gem::Requirement
|
92
92
|
requirements:
|
93
93
|
- - "~>"
|
94
94
|
- !ruby/object:Gem::Version
|
95
|
-
version: '
|
95
|
+
version: '2.4'
|
96
96
|
type: :development
|
97
97
|
prerelease: false
|
98
98
|
version_requirements: !ruby/object:Gem::Requirement
|
99
99
|
requirements:
|
100
100
|
- - "~>"
|
101
101
|
- !ruby/object:Gem::Version
|
102
|
-
version: '
|
103
|
-
- !ruby/object:Gem::Dependency
|
104
|
-
name: pry
|
105
|
-
requirement: !ruby/object:Gem::Requirement
|
106
|
-
requirements:
|
107
|
-
- - ">="
|
108
|
-
- !ruby/object:Gem::Version
|
109
|
-
version: '0'
|
110
|
-
type: :development
|
111
|
-
prerelease: false
|
112
|
-
version_requirements: !ruby/object:Gem::Requirement
|
113
|
-
requirements:
|
114
|
-
- - ">="
|
115
|
-
- !ruby/object:Gem::Version
|
116
|
-
version: '0'
|
102
|
+
version: '2.4'
|
117
103
|
- !ruby/object:Gem::Dependency
|
118
|
-
name:
|
104
|
+
name: rubocop
|
119
105
|
requirement: !ruby/object:Gem::Requirement
|
120
106
|
requirements:
|
121
107
|
- - "~>"
|
122
108
|
- !ruby/object:Gem::Version
|
123
|
-
version: '
|
109
|
+
version: '1.37'
|
124
110
|
type: :development
|
125
111
|
prerelease: false
|
126
112
|
version_requirements: !ruby/object:Gem::Requirement
|
127
113
|
requirements:
|
128
114
|
- - "~>"
|
129
115
|
- !ruby/object:Gem::Version
|
130
|
-
version: '
|
116
|
+
version: '1.37'
|
131
117
|
- !ruby/object:Gem::Dependency
|
132
|
-
name:
|
118
|
+
name: rubocop-rspec
|
133
119
|
requirement: !ruby/object:Gem::Requirement
|
134
120
|
requirements:
|
135
|
-
- - "
|
136
|
-
- !ruby/object:Gem::Version
|
137
|
-
version: 1.0.2
|
138
|
-
- - "<"
|
121
|
+
- - "~>"
|
139
122
|
- !ruby/object:Gem::Version
|
140
|
-
version: '2'
|
123
|
+
version: '2.14'
|
141
124
|
type: :development
|
142
125
|
prerelease: false
|
143
126
|
version_requirements: !ruby/object:Gem::Requirement
|
144
127
|
requirements:
|
145
|
-
- - "
|
146
|
-
- !ruby/object:Gem::Version
|
147
|
-
version: 1.0.2
|
148
|
-
- - "<"
|
128
|
+
- - "~>"
|
149
129
|
- !ruby/object:Gem::Version
|
150
|
-
version: '2'
|
130
|
+
version: '2.14'
|
151
131
|
- !ruby/object:Gem::Dependency
|
152
132
|
name: rubocop_runner
|
153
133
|
requirement: !ruby/object:Gem::Requirement
|
154
134
|
requirements:
|
155
135
|
- - "~>"
|
156
136
|
- !ruby/object:Gem::Version
|
157
|
-
version: '2.
|
137
|
+
version: '2.2'
|
158
138
|
type: :development
|
159
139
|
prerelease: false
|
160
140
|
version_requirements: !ruby/object:Gem::Requirement
|
161
141
|
requirements:
|
162
142
|
- - "~>"
|
163
143
|
- !ruby/object:Gem::Version
|
164
|
-
version: '2.
|
144
|
+
version: '2.2'
|
165
145
|
- !ruby/object:Gem::Dependency
|
166
146
|
name: simplecov
|
167
147
|
requirement: !ruby/object:Gem::Requirement
|
@@ -183,15 +163,13 @@ executables: []
|
|
183
163
|
extensions: []
|
184
164
|
extra_rdoc_files: []
|
185
165
|
files:
|
186
|
-
- ".
|
187
|
-
- ".dir-locals.el"
|
166
|
+
- ".github/workflows/matrix.yml"
|
188
167
|
- ".gitignore"
|
189
168
|
- ".rubocop.yml"
|
190
169
|
- CHANGELOG.md
|
191
170
|
- CODE_OF_CONDUCT.md
|
192
|
-
- Dangerfile
|
193
171
|
- Gemfile
|
194
|
-
-
|
172
|
+
- Gemfile.lock
|
195
173
|
- LICENSE.txt
|
196
174
|
- README.md
|
197
175
|
- Rakefile
|
@@ -200,36 +178,32 @@ files:
|
|
200
178
|
- examples/simple_repo.rb
|
201
179
|
- lib/receptacle.rb
|
202
180
|
- lib/receptacle/errors.rb
|
203
|
-
- lib/receptacle/
|
204
|
-
- lib/receptacle/method_cache.rb
|
205
|
-
- lib/receptacle/method_delegation.rb
|
206
|
-
- lib/receptacle/registration.rb
|
181
|
+
- lib/receptacle/repo.rb
|
207
182
|
- lib/receptacle/test_support.rb
|
208
183
|
- lib/receptacle/version.rb
|
209
|
-
- performance/benchmark.rb
|
210
|
-
- performance/profile.rb
|
211
|
-
- performance/speed_receptacle.rb
|
212
184
|
- receptacle.gemspec
|
185
|
+
- upgrade_notes.md
|
213
186
|
homepage: https://github.com/andreaseger/receptacle
|
214
187
|
licenses:
|
215
188
|
- MIT
|
216
|
-
metadata:
|
189
|
+
metadata:
|
190
|
+
rubygems_mfa_required: 'true'
|
217
191
|
post_install_message:
|
218
192
|
rdoc_options: []
|
219
193
|
require_paths:
|
220
194
|
- lib
|
221
195
|
required_ruby_version: !ruby/object:Gem::Requirement
|
222
196
|
requirements:
|
223
|
-
- - "
|
197
|
+
- - ">="
|
224
198
|
- !ruby/object:Gem::Version
|
225
|
-
version: '2.
|
199
|
+
version: '2.7'
|
226
200
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
227
201
|
requirements:
|
228
202
|
- - ">="
|
229
203
|
- !ruby/object:Gem::Version
|
230
204
|
version: '0'
|
231
205
|
requirements: []
|
232
|
-
rubygems_version: 3.
|
206
|
+
rubygems_version: 3.4.1
|
233
207
|
signing_key:
|
234
208
|
specification_version: 4
|
235
209
|
summary: repository pattern
|
data/.circleci/config.yml
DELETED
@@ -1,64 +0,0 @@
|
|
1
|
-
# Ruby CircleCI 2.0 configuration file
|
2
|
-
#
|
3
|
-
# Check https://circleci.com/docs/2.0/language-ruby/ for more details
|
4
|
-
#
|
5
|
-
|
6
|
-
version: 2
|
7
|
-
|
8
|
-
common_steps: &common_steps
|
9
|
-
- checkout
|
10
|
-
- run: gem update --system
|
11
|
-
- restore_cache:
|
12
|
-
key: gem-cache-{{ .Branch }}-{{ checksum "Gemfile" }}
|
13
|
-
- run:
|
14
|
-
name: install dependencies
|
15
|
-
command: |
|
16
|
-
gem update bundler
|
17
|
-
bundle install --jobs=4 --retry=3 --path vendor/bundle
|
18
|
-
- save_cache:
|
19
|
-
key: gem-cache-{{ .Branch }}-{{ checksum "Gemfile" }}
|
20
|
-
paths:
|
21
|
-
- vendor/bundle
|
22
|
-
- run: bundle exec danger
|
23
|
-
- run: bundle exec rake test
|
24
|
-
|
25
|
-
jobs:
|
26
|
-
ruby-2.4:
|
27
|
-
docker:
|
28
|
-
- image: circleci/ruby:2.4
|
29
|
-
steps:
|
30
|
-
*common_steps
|
31
|
-
ruby-2.5:
|
32
|
-
docker:
|
33
|
-
- image: circleci/ruby:2.5
|
34
|
-
steps:
|
35
|
-
*common_steps
|
36
|
-
ruby-2.6:
|
37
|
-
docker:
|
38
|
-
- image: circleci/ruby:2.6
|
39
|
-
steps:
|
40
|
-
*common_steps
|
41
|
-
jruby-9.2:
|
42
|
-
docker:
|
43
|
-
- image: circleci/jruby:9.2
|
44
|
-
environment:
|
45
|
-
JRUBY_OPTS: '--dev'
|
46
|
-
steps:
|
47
|
-
*common_steps
|
48
|
-
jruby-9.2-indy:
|
49
|
-
docker:
|
50
|
-
- image: circleci/jruby:9.2
|
51
|
-
environment:
|
52
|
-
JRUBY_OPTS: '-Xcompile.invokedynamic=true'
|
53
|
-
steps:
|
54
|
-
*common_steps
|
55
|
-
|
56
|
-
workflows:
|
57
|
-
version: 2
|
58
|
-
build:
|
59
|
-
jobs:
|
60
|
-
- ruby-2.4
|
61
|
-
- ruby-2.5
|
62
|
-
- ruby-2.6
|
63
|
-
- jruby-9.2
|
64
|
-
- jruby-9.2-indy
|
data/.dir-locals.el
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
((ruby-mode . ( (ruby-test-runner . minitest)) ) )
|
data/Dangerfile
DELETED
@@ -1,31 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# -------------------------------------------------------------------------
|
4
|
-
# Has any changes happened inside the actual library code?
|
5
|
-
# -------------------------------------------------------------------------
|
6
|
-
has_app_changes = !git.modified_files.grep(/lib/).empty?
|
7
|
-
has_test_changes = !git.modified_files.grep(/test/).empty?
|
8
|
-
is_version_bump = git.modified_files.sort == ["CHANGELOG.md", "lib/receptacle/version.rb"].sort
|
9
|
-
|
10
|
-
if has_app_changes && !has_test_changes && !is_version_bump
|
11
|
-
warn("Tests were not updated. That's OK if you're refactoring existing code.", sticky: false)
|
12
|
-
end
|
13
|
-
|
14
|
-
if !git.modified_files.include?("CHANGELOG.md") && has_app_changes
|
15
|
-
fail(<<~MSG)
|
16
|
-
Please include a CHANGELOG entry.
|
17
|
-
You can find it at [CHANGELOG.md](https://github.com/andreaseger/receptacle/blob/master/CHANGELOG.md).
|
18
|
-
MSG
|
19
|
-
message "Note, we hard-wrap at 80 chars and use 2 spaces after the last line."
|
20
|
-
end
|
21
|
-
|
22
|
-
# Make it more obvious that a PR is a work in progress and shouldn't be merged yet
|
23
|
-
warn("PR is classed as Work in Progress") if github.pr_title.include? "WIP"
|
24
|
-
|
25
|
-
# Warn when there is a big PR
|
26
|
-
warn("Big PR") if git.lines_of_code > 500
|
27
|
-
|
28
|
-
commit_lint.check warn: :all, disable: [:subject_cap]
|
29
|
-
|
30
|
-
# rubocop
|
31
|
-
rubocop.lint force_exclusion: true
|
data/Guardfile
DELETED
@@ -1,32 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# A sample Guardfile
|
4
|
-
# More info at https://github.com/guard/guard#readme
|
5
|
-
|
6
|
-
## Uncomment and set this to only include directories you want to watch
|
7
|
-
# directories %w(app lib config test spec features) \
|
8
|
-
# .select{|d| Dir.exists?(d) ? d : UI.warning("Directory #{d} does not exist")}
|
9
|
-
|
10
|
-
## Note: if you are using the `directories` clause above and you are not
|
11
|
-
## watching the project directory ('.'), then you will want to move
|
12
|
-
## the Guardfile to a watched dir and symlink it back, e.g.
|
13
|
-
#
|
14
|
-
# $ mkdir config
|
15
|
-
# $ mv Guardfile config/
|
16
|
-
# $ ln -s config/Guardfile .
|
17
|
-
#
|
18
|
-
# and, you'll have to watch "config/Guardfile" instead of "Guardfile"
|
19
|
-
group :red_green_refactor, halt_on_fail: true do
|
20
|
-
guard :minitest do
|
21
|
-
# with Minitest::Unit
|
22
|
-
watch(%r{^test/(.*)\/?test_(.*)\.rb$})
|
23
|
-
# watch(%r{^lib/(.*/)?([^/]+)\.rb$}) { |m| "test/#{m[1]}test_#{m[2]}.rb" }
|
24
|
-
watch(%r{^lib/(.*/)?([^/]+)\.rb$}) { "test" }
|
25
|
-
watch(%r{^test/test_helper\.rb$}) { "test" }
|
26
|
-
watch(%r{^test/fixture\.rb$}) { "test" }
|
27
|
-
end
|
28
|
-
guard :rubocop, all_on_start: false, cli: ["--auto-correct"] do
|
29
|
-
watch(/.+\.rb$/)
|
30
|
-
watch(%r{(?:.+/)?\.rubocop\.yml%}) { |m| File.dirname(m[0]) }
|
31
|
-
end
|
32
|
-
end
|
@@ -1,51 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "receptacle/registration"
|
4
|
-
require "receptacle/errors"
|
5
|
-
|
6
|
-
module Receptacle
|
7
|
-
module InterfaceMethods
|
8
|
-
RESERVED_METHOD_NAMES = Set.new(%i[wrappers mediate strategy delegate_to_strategy])
|
9
|
-
private_constant :RESERVED_METHOD_NAMES
|
10
|
-
|
11
|
-
# registers a method_name for the to be mediated or forwarded to the configured strategy
|
12
|
-
#
|
13
|
-
# @param method_name [String] name of method to register
|
14
|
-
def mediate(method_name)
|
15
|
-
raise Errors::ReservedMethodName if RESERVED_METHOD_NAMES.include?(method_name)
|
16
|
-
|
17
|
-
Registration.repositories[self].methods << method_name
|
18
|
-
end
|
19
|
-
alias delegate_to_strategy mediate
|
20
|
-
|
21
|
-
# get or sets the strategy
|
22
|
-
#
|
23
|
-
# @note will set the strategy for this receptacle if passed in; will only
|
24
|
-
# return the current strategy if nil or no parameter passed include
|
25
|
-
# @param value [Class,nil]
|
26
|
-
# @return [Class] current configured strategy class
|
27
|
-
def strategy(value = nil)
|
28
|
-
if value
|
29
|
-
Registration.repositories[self].strategy = value
|
30
|
-
Registration.clear_method_cache(self)
|
31
|
-
else
|
32
|
-
Registration.repositories[self].strategy
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
# get or sets the wrappers
|
37
|
-
#
|
38
|
-
# @note will set the wrappers for this receptacle if passed in; will only
|
39
|
-
# return the current wrappers if nil or no parameter passed include
|
40
|
-
# @param value [Class,Array(Class),nil] wrappers
|
41
|
-
# @return [Array(Class)] current configured wrappers
|
42
|
-
def wrappers(value = nil)
|
43
|
-
if value
|
44
|
-
Registration.repositories[self].wrappers = Array(value)
|
45
|
-
Registration.clear_method_cache(self)
|
46
|
-
else
|
47
|
-
Registration.repositories[self].wrappers
|
48
|
-
end
|
49
|
-
end
|
50
|
-
end
|
51
|
-
end
|
@@ -1,43 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Receptacle
|
4
|
-
# Cache describing which strategy and wrappers need to be applied for this method
|
5
|
-
# @api private
|
6
|
-
class MethodCache
|
7
|
-
# @return [Symbol] name of the method this cache belongs to
|
8
|
-
attr_reader :method_name
|
9
|
-
# @return [Class] strategy class currently setup
|
10
|
-
attr_reader :strategy
|
11
|
-
# @return [Array(Class)] Array of wrapper classes which implement a wrapper for this method
|
12
|
-
attr_reader :wrappers
|
13
|
-
# @return [Symbol] name of the before action method
|
14
|
-
attr_reader :before_method_name
|
15
|
-
# @return [Symbol] name of the after action method
|
16
|
-
attr_reader :after_method_name
|
17
|
-
# @return [Integer] arity of strategy method according to https://ruby-doc.org/core-2.3.3/Method.html#method-i-arity
|
18
|
-
attr_reader :arity
|
19
|
-
|
20
|
-
def initialize(method_name:, strategy:, wrappers:)
|
21
|
-
@strategy = strategy
|
22
|
-
@before_method_name = :"before_#{method_name}"
|
23
|
-
@after_method_name = :"after_#{method_name}"
|
24
|
-
@method_name = method_name.to_sym
|
25
|
-
before_wrappers = wrappers.select { |w| w.method_defined?(@before_method_name) }
|
26
|
-
after_wrappers = wrappers.select { |w| w.method_defined?(@after_method_name) }
|
27
|
-
@wrappers = wrappers & (before_wrappers | after_wrappers)
|
28
|
-
@skip_before_wrappers = before_wrappers.empty?
|
29
|
-
@skip_after_wrappers = after_wrappers.empty?
|
30
|
-
@arity = strategy.new.method(method_name).arity
|
31
|
-
end
|
32
|
-
|
33
|
-
# @return [Boolean] true if no before wrappers need to be applied for this method
|
34
|
-
def skip_before_wrappers?
|
35
|
-
@skip_before_wrappers
|
36
|
-
end
|
37
|
-
|
38
|
-
# @return [Boolean] true if no after wrappers need to be applied for this method
|
39
|
-
def skip_after_wrappers?
|
40
|
-
@skip_after_wrappers
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|
@@ -1,141 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "receptacle/method_cache"
|
4
|
-
require "receptacle/registration"
|
5
|
-
require "receptacle/errors"
|
6
|
-
|
7
|
-
module Receptacle
|
8
|
-
# module which enables a repository to mediate methods dynamically to wrappers and strategy
|
9
|
-
# @api private
|
10
|
-
module MethodDelegation
|
11
|
-
# dynamically build mediation method on first invocation if the method is registered
|
12
|
-
def method_missing(method_name, *arguments, &block)
|
13
|
-
if Registration.repositories[self].methods.include?(method_name)
|
14
|
-
public_send(__build_method(method_name), *arguments, &block)
|
15
|
-
else
|
16
|
-
super
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
def respond_to_missing?(method_name, include_private = false)
|
21
|
-
Registration.repositories[self].methods.include?(method_name) || super
|
22
|
-
end
|
23
|
-
|
24
|
-
# @param method_name [#to_sym]
|
25
|
-
# @return [void]
|
26
|
-
def __build_method(method_name)
|
27
|
-
method_cache = __build_method_call_cache(method_name)
|
28
|
-
if method_cache.wrappers.nil? || method_cache.wrappers.empty?
|
29
|
-
__define_shortcut_method(method_cache)
|
30
|
-
elsif method_cache.arity.abs > 1
|
31
|
-
__define_full_method_high_arity(method_cache)
|
32
|
-
else
|
33
|
-
__define_full_method(method_cache)
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
# build method cache for given method name
|
38
|
-
# @param method_name [#to_sym]
|
39
|
-
# @return [MethodCache]
|
40
|
-
def __build_method_call_cache(method_name)
|
41
|
-
config = Registration.repositories[self]
|
42
|
-
|
43
|
-
raise Errors::NotConfigured.new(repo: self) if config.strategy.nil?
|
44
|
-
|
45
|
-
MethodCache.new(
|
46
|
-
strategy: config.strategy,
|
47
|
-
wrappers: config.wrappers,
|
48
|
-
method_name: method_name
|
49
|
-
)
|
50
|
-
end
|
51
|
-
|
52
|
-
# build lightweight method to mediate method calls to strategy without wrappers
|
53
|
-
# @param method_cache [MethodCache] method_cache of the method to be build
|
54
|
-
# @return [void]
|
55
|
-
def __define_shortcut_method(method_cache)
|
56
|
-
define_singleton_method(method_cache.method_name) do |*args, &inner_block|
|
57
|
-
method_cache.strategy.new.public_send(method_cache.method_name, *args, &inner_block)
|
58
|
-
end
|
59
|
-
end
|
60
|
-
|
61
|
-
# build method to mediate method calls of arity 1 to strategy with full wrapper support
|
62
|
-
# @param method_cache [MethodCache] method_cache of the method to be build
|
63
|
-
# @return [void]
|
64
|
-
def __define_full_method(method_cache)
|
65
|
-
define_singleton_method(method_cache.method_name) do |*args, &inner_block|
|
66
|
-
__run_wrappers(method_cache, *args) do |*call_args|
|
67
|
-
method_cache.strategy.new.public_send(method_cache.method_name, *call_args, &inner_block)
|
68
|
-
end
|
69
|
-
end
|
70
|
-
end
|
71
|
-
|
72
|
-
# build method to mediate method calls of higher arity to strategy with full wrapper support
|
73
|
-
# @param method_cache [MethodCache] method_cache of the method to be build
|
74
|
-
# @return [void]
|
75
|
-
def __define_full_method_high_arity(method_cache)
|
76
|
-
define_singleton_method(method_cache.method_name) do |*args, &inner_block|
|
77
|
-
__run_wrappers(method_cache, args, true) do |*call_args|
|
78
|
-
method_cache.strategy.new.public_send(method_cache.method_name, *call_args, &inner_block)
|
79
|
-
end
|
80
|
-
end
|
81
|
-
end
|
82
|
-
|
83
|
-
# runtime method to call before and after wrapper in correct order
|
84
|
-
# @param method_cache [MethodCache] method_cache for the current method
|
85
|
-
# @param input_args input parameter of the repository method call
|
86
|
-
# @param high_arity [Boolean] if are intended for a higher arity method
|
87
|
-
# @return strategy method return value after all wrappers where applied
|
88
|
-
def __run_wrappers(method_cache, input_args, high_arity = false)
|
89
|
-
wrappers = method_cache.wrappers.map(&:new)
|
90
|
-
args =
|
91
|
-
if method_cache.skip_before_wrappers?
|
92
|
-
input_args
|
93
|
-
else
|
94
|
-
__run_before_wrappers(wrappers, method_cache.before_method_name, input_args, high_arity)
|
95
|
-
end
|
96
|
-
ret = high_arity ? yield(*args) : yield(args)
|
97
|
-
return ret if method_cache.skip_after_wrappers?
|
98
|
-
|
99
|
-
__run_after_wrappers(wrappers, method_cache.after_method_name, args, ret, high_arity)
|
100
|
-
end
|
101
|
-
|
102
|
-
# runtime method to execute all before wrappers
|
103
|
-
# @param wrappers [Array] all wrapper instances to be executed
|
104
|
-
# @param method_name [Symbol] name of method to be executed on wrappers
|
105
|
-
# @param args input args of the repository method
|
106
|
-
# @param high_arity [Boolean] if are intended for a higher arity method
|
107
|
-
# @return processed method args by before wrappers
|
108
|
-
def __run_before_wrappers(wrappers, method_name, args, high_arity = false)
|
109
|
-
wrappers.each do |wrapper|
|
110
|
-
next unless wrapper.respond_to?(method_name)
|
111
|
-
|
112
|
-
args = if high_arity
|
113
|
-
wrapper.public_send(method_name, *args)
|
114
|
-
else
|
115
|
-
wrapper.public_send(method_name, args)
|
116
|
-
end
|
117
|
-
end
|
118
|
-
args
|
119
|
-
end
|
120
|
-
|
121
|
-
# runtime method to execute all after wrappers
|
122
|
-
# @param wrappers [Array] all wrapper instances to be executed
|
123
|
-
# @param method_name [Symbol] name of method to be executed on wrappers
|
124
|
-
# @param args input args to the strategy method (after processing in before wrappers)
|
125
|
-
# @param return_value return value of strategy method
|
126
|
-
# @param high_arity [Boolean] if are intended for a higher arity method
|
127
|
-
# @return processed return value by all after wrappers
|
128
|
-
def __run_after_wrappers(wrappers, method_name, args, return_value, high_arity = false)
|
129
|
-
wrappers.reverse_each do |wrapper|
|
130
|
-
next unless wrapper.respond_to?(method_name)
|
131
|
-
|
132
|
-
return_value = if high_arity
|
133
|
-
wrapper.public_send(method_name, return_value, *args)
|
134
|
-
else
|
135
|
-
wrapper.public_send(method_name, return_value, args)
|
136
|
-
end
|
137
|
-
end
|
138
|
-
return_value
|
139
|
-
end
|
140
|
-
end
|
141
|
-
end
|
@@ -1,35 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "singleton"
|
4
|
-
require "set"
|
5
|
-
module Receptacle
|
6
|
-
# keeps global state of repositories, the defined strategy, set wrappers and methods to mediate
|
7
|
-
class Registration
|
8
|
-
include Singleton
|
9
|
-
Tuple = Struct.new(:strategy, :wrappers, :methods)
|
10
|
-
|
11
|
-
attr_reader :repositories
|
12
|
-
|
13
|
-
def initialize
|
14
|
-
@repositories = Hash.new do |h, k|
|
15
|
-
h[k] = Tuple.new(nil, [], Set.new)
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
def self.repositories
|
20
|
-
instance.repositories
|
21
|
-
end
|
22
|
-
|
23
|
-
# {clear_method_cache} removes dynamically defined methods
|
24
|
-
# this is needed to make strategy and wrappers changes inside the codebase possible
|
25
|
-
def self.clear_method_cache(receptacle)
|
26
|
-
instance.repositories[receptacle].methods.each do |method_name|
|
27
|
-
begin
|
28
|
-
receptacle.singleton_class.send(:remove_method, method_name)
|
29
|
-
rescue NameError
|
30
|
-
nil
|
31
|
-
end
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end
|
data/performance/benchmark.rb
DELETED
@@ -1,45 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "bundler/inline"
|
4
|
-
|
5
|
-
gemfile false do
|
6
|
-
source "https://rubygems.org"
|
7
|
-
gem "benchmark-ips"
|
8
|
-
gem "receptacle", path: "./.."
|
9
|
-
end
|
10
|
-
|
11
|
-
require_relative "speed_receptacle"
|
12
|
-
|
13
|
-
Speed.strategy(Speed::Strategy::One)
|
14
|
-
Speed.wrappers [Speed::Wrappers::W1,
|
15
|
-
Speed::Wrappers::W2,
|
16
|
-
Speed::Wrappers::W3,
|
17
|
-
Speed::Wrappers::W4,
|
18
|
-
Speed::Wrappers::W5,
|
19
|
-
Speed::Wrappers::W6]
|
20
|
-
|
21
|
-
print "w/ wrappers"
|
22
|
-
Benchmark.ips do |x|
|
23
|
-
x.warmup = 10 if RUBY_ENGINE == "jruby"
|
24
|
-
x.report("a: 2x around, 1x before, 1x after") { Speed.a(1) }
|
25
|
-
x.report("b: 1x around, 1x before, 1x after") { Speed.b(1) }
|
26
|
-
x.report("c: 1x before, 1x after") { Speed.c(1) }
|
27
|
-
x.report("d: 1x after") { Speed.d(1) }
|
28
|
-
x.report("e: 1x before") { Speed.e(1) }
|
29
|
-
x.report("f: 1x around") { Speed.f(1) }
|
30
|
-
x.report("g: no wrappers") { Speed.g(1) }
|
31
|
-
end
|
32
|
-
|
33
|
-
Speed.wrappers []
|
34
|
-
print "method dispatching w/ wrappers"
|
35
|
-
Benchmark.ips do |x|
|
36
|
-
x.warmup = 10 if RUBY_ENGINE == "jruby"
|
37
|
-
x.report("via receptacle") { Speed.a(:foo) }
|
38
|
-
x.report("direct via public_send") { Speed::Strategy::One.new.public_send(:a, :foo) }
|
39
|
-
x.report("direct via method-method") do
|
40
|
-
m = Speed::Strategy::One.new.method(:a)
|
41
|
-
m.call(:foo)
|
42
|
-
end
|
43
|
-
x.report("direct method-call") { Speed::Strategy::One.new.a(:foo) }
|
44
|
-
x.compare!
|
45
|
-
end
|