receptacle 0.1.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 +7 -0
- data/.dir-locals.el +1 -0
- data/.gitignore +11 -0
- data/.rubocop.yml +27 -0
- data/.travis.yml +27 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +4 -0
- data/Guardfile +30 -0
- data/LICENSE.txt +21 -0
- data/README.md +355 -0
- data/Rakefile +25 -0
- data/bin/console +11 -0
- data/bin/setup +8 -0
- data/examples/simple_repo.rb +103 -0
- data/lib/receptacle/errors.rb +13 -0
- data/lib/receptacle/interface_methods.rb +49 -0
- data/lib/receptacle/method_cache.rb +39 -0
- data/lib/receptacle/method_delegation.rb +114 -0
- data/lib/receptacle/registration.rb +34 -0
- data/lib/receptacle/test_support.rb +47 -0
- data/lib/receptacle/version.rb +4 -0
- data/lib/receptacle.rb +13 -0
- data/performance/benchmark.rb +44 -0
- data/performance/profile.rb +39 -0
- data/performance/speed_receptacle.rb +104 -0
- data/receptacle.gemspec +38 -0
- metadata +223 -0
@@ -0,0 +1,103 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
require 'bundler/inline'
|
4
|
+
|
5
|
+
gemfile true do
|
6
|
+
source 'https://rubygems.org'
|
7
|
+
gem 'receptacle', '../'
|
8
|
+
gem 'mongo'
|
9
|
+
end
|
10
|
+
|
11
|
+
User = Struct.new(:id, :name)
|
12
|
+
|
13
|
+
# define our Repository
|
14
|
+
module Repository
|
15
|
+
module User
|
16
|
+
include Receptacle::Repo
|
17
|
+
mediate :find
|
18
|
+
mediate :create
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
# we should have a global mongo connection which can be easily reused
|
23
|
+
module Connection
|
24
|
+
class Mongo
|
25
|
+
include Singleton
|
26
|
+
|
27
|
+
def initialize
|
28
|
+
@client = ::Mongo::Client.new
|
29
|
+
end
|
30
|
+
attr_reader :client
|
31
|
+
def self.client
|
32
|
+
instance.client
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# some strategies
|
38
|
+
module Repository
|
39
|
+
module User
|
40
|
+
module Strategy
|
41
|
+
class Mongo
|
42
|
+
def find(id:)
|
43
|
+
mongo_to_model(collection.find(_id: id))
|
44
|
+
rescue
|
45
|
+
nil
|
46
|
+
end
|
47
|
+
|
48
|
+
def create(name:)
|
49
|
+
ret = collection.insert_one(name: name)
|
50
|
+
find(id: ret['_id']) # TODO: check this
|
51
|
+
end
|
52
|
+
|
53
|
+
private
|
54
|
+
|
55
|
+
def mongo_to_model(doc)
|
56
|
+
::User.new(doc['_id'], doc['name'])
|
57
|
+
end
|
58
|
+
|
59
|
+
def collection
|
60
|
+
Connection::Mongo.client[:users]
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
# in memory is using a simple class instance variable as internal storage
|
65
|
+
|
66
|
+
class InMemory
|
67
|
+
class << self; attr_accessor :store end
|
68
|
+
@store = {}
|
69
|
+
def find(id:)
|
70
|
+
store[id]
|
71
|
+
end
|
72
|
+
|
73
|
+
def create(name:)
|
74
|
+
id = BSON::ObjectId.new
|
75
|
+
store[id] = User.new(id, name)
|
76
|
+
end
|
77
|
+
|
78
|
+
private
|
79
|
+
|
80
|
+
def store
|
81
|
+
self.class.store
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
# configure the repository and use it
|
89
|
+
Repository::User.strategy Repository::User::Strategy::InMemory
|
90
|
+
|
91
|
+
user = Repository::User.create(name: 'foo')
|
92
|
+
p user
|
93
|
+
p Repository::User.find(id: user.id)
|
94
|
+
|
95
|
+
# switching to mongo and we see it's using a different store but keeps the same interface
|
96
|
+
Repository::User.strategy Repository::User::Strategy::Mongo
|
97
|
+
|
98
|
+
p Repository::User.find(id: user.id)
|
99
|
+
#-> nil
|
100
|
+
|
101
|
+
user = Repository::User.create(name: 'foo')
|
102
|
+
p user
|
103
|
+
p Repository::User.find(id: user.id)
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module Receptacle
|
3
|
+
module Errors
|
4
|
+
class NotConfigured < StandardError
|
5
|
+
attr_reader :repo
|
6
|
+
def initialize(repo:)
|
7
|
+
@repo = repo
|
8
|
+
super("Missing Configuration for repository: <#{repo}>")
|
9
|
+
end
|
10
|
+
end
|
11
|
+
class ReservedMethodName < StandardError; end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'receptacle/registration'
|
3
|
+
require 'receptacle/errors'
|
4
|
+
|
5
|
+
module Receptacle
|
6
|
+
module InterfaceMethods
|
7
|
+
RESERVED_METHOD_NAMES = Set.new(%i(wrappers mediate strategy delegate_to_strategy))
|
8
|
+
private_constant :RESERVED_METHOD_NAMES
|
9
|
+
|
10
|
+
# registers a method_name for the to be mediated or forwarded to the configured strategy
|
11
|
+
#
|
12
|
+
# @param method_name [String] name of method to register
|
13
|
+
def mediate(method_name)
|
14
|
+
raise Errors::ReservedMethodName if RESERVED_METHOD_NAMES.include?(method_name)
|
15
|
+
Registration.repositories[self].methods << method_name
|
16
|
+
end
|
17
|
+
alias delegate_to_strategy mediate
|
18
|
+
|
19
|
+
# get or sets the strategy
|
20
|
+
#
|
21
|
+
# @note will set the strategy for this receptacle if passed in; will only
|
22
|
+
# return the current strategy if nil or no parameter passed include
|
23
|
+
# @param value [Class,nil]
|
24
|
+
# @return [Class] current configured strategy class
|
25
|
+
def strategy(value = nil)
|
26
|
+
if value
|
27
|
+
Registration.repositories[self].strategy = value
|
28
|
+
Registration.clear_method_cache(self)
|
29
|
+
else
|
30
|
+
Registration.repositories[self].strategy
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
# get or sets the wrappers
|
35
|
+
#
|
36
|
+
# @note will set the wrappers for this receptacle if passed in; will only
|
37
|
+
# return the current wrappers if nil or no parameter passed include
|
38
|
+
# @param value [Class,Array(Class),nil] wrappers
|
39
|
+
# @return [Array(Class)] current configured wrappers
|
40
|
+
def wrappers(value = nil)
|
41
|
+
if value
|
42
|
+
Registration.repositories[self].wrappers = Array(value)
|
43
|
+
Registration.clear_method_cache(self)
|
44
|
+
else
|
45
|
+
Registration.repositories[self].wrappers
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module Receptacle
|
3
|
+
# Cache describing which strategy and wrappers need to be applied for this method
|
4
|
+
# @api private
|
5
|
+
class MethodCache
|
6
|
+
# @return [Symbol] name of the method this cache belongs to
|
7
|
+
attr_reader :method_name
|
8
|
+
# @return [Class] strategy class currently setup
|
9
|
+
attr_reader :strategy
|
10
|
+
# @return [Array(Class)] Array of wrapper classes which implement a wrapper for this method
|
11
|
+
attr_reader :wrappers
|
12
|
+
# @return [Symbol] name of the before action method
|
13
|
+
attr_reader :before_method_name
|
14
|
+
# @return [Symbol] name of the after action method
|
15
|
+
attr_reader :after_method_name
|
16
|
+
|
17
|
+
def initialize(method_name:, strategy:, before_wrappers:, after_wrappers:)
|
18
|
+
@strategy = strategy
|
19
|
+
@before_method_name = :"before_#{method_name}"
|
20
|
+
@after_method_name = :"after_#{method_name}"
|
21
|
+
@method_name = method_name.to_sym
|
22
|
+
before_wrappers ||= []
|
23
|
+
after_wrappers ||= []
|
24
|
+
@wrappers = before_wrappers | after_wrappers
|
25
|
+
@skip_before_wrappers = before_wrappers.empty?
|
26
|
+
@skip_after_wrappers = after_wrappers.empty?
|
27
|
+
end
|
28
|
+
|
29
|
+
# @return [Boolean] true if no before wrappers need to be applied for this method
|
30
|
+
def skip_before_wrappers?
|
31
|
+
@skip_before_wrappers
|
32
|
+
end
|
33
|
+
|
34
|
+
# @return [Boolean] true if no after wrappers need to be applied for this method
|
35
|
+
def skip_after_wrappers?
|
36
|
+
@skip_after_wrappers
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,114 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'receptacle/method_cache'
|
3
|
+
require 'receptacle/registration'
|
4
|
+
require 'receptacle/errors'
|
5
|
+
|
6
|
+
module Receptacle
|
7
|
+
# module which enables a repository to mediate methods dynamically to wrappers and strategy
|
8
|
+
# @api private
|
9
|
+
module MethodDelegation
|
10
|
+
# dynamically build mediation method on first invocation if the method is registered
|
11
|
+
def method_missing(method_name, *arguments, &block)
|
12
|
+
if Registration.repositories[self].methods.include?(method_name)
|
13
|
+
public_send(__build_method(method_name), *arguments, &block)
|
14
|
+
else
|
15
|
+
super
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def respond_to_missing?(method_name, include_private = false)
|
20
|
+
Registration.repositories[self].methods.include?(method_name) || super
|
21
|
+
end
|
22
|
+
|
23
|
+
# @param method_name [#to_sym]
|
24
|
+
# @return [void]
|
25
|
+
def __build_method(method_name)
|
26
|
+
method_cache = __build_method_call_cache(method_name)
|
27
|
+
if method_cache.wrappers.nil? || method_cache.wrappers.empty?
|
28
|
+
__define_shortcut_method(method_cache)
|
29
|
+
else
|
30
|
+
__define_full_method(method_cache)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
# build method cache for given method name
|
35
|
+
# @param method_name [#to_sym]
|
36
|
+
# @return [MethodCache]
|
37
|
+
def __build_method_call_cache(method_name)
|
38
|
+
config = Registration.repositories[self]
|
39
|
+
before_method_name = :"before_#{method_name}"
|
40
|
+
after_method_name = :"after_#{method_name}"
|
41
|
+
|
42
|
+
raise Errors::NotConfigured, repo: self if config.strategy.nil?
|
43
|
+
MethodCache.new(
|
44
|
+
strategy: config.strategy,
|
45
|
+
before_wrappers: config.wrappers.select { |w| w.method_defined?(before_method_name) },
|
46
|
+
after_wrappers: config.wrappers.select { |w| w.method_defined?(after_method_name) },
|
47
|
+
method_name: method_name
|
48
|
+
)
|
49
|
+
end
|
50
|
+
|
51
|
+
# build lightweight method to mediate method calls to strategy without wrappers
|
52
|
+
# @param method_cache [MethodCache] method_cache of the method to be build
|
53
|
+
# @return [void]
|
54
|
+
def __define_shortcut_method(method_cache)
|
55
|
+
define_singleton_method(method_cache.method_name) do |*args, &inner_block|
|
56
|
+
method_cache.strategy.new.public_send(method_cache.method_name, *args, &inner_block)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
# build method to mediate method calls to strategy with full wrapper support
|
61
|
+
# @param method_cache [MethodCache] method_cache of the method to be build
|
62
|
+
# @return [void]
|
63
|
+
def __define_full_method(method_cache)
|
64
|
+
define_singleton_method(method_cache.method_name) do |*args, &inner_block|
|
65
|
+
__run_wrappers(method_cache, *args) do |*call_args|
|
66
|
+
method_cache.strategy.new.public_send(method_cache.method_name, *call_args, &inner_block)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
# runtime method to call before and after wrapper in correct order
|
72
|
+
# @param method_cache [MethodCache] method_cache for the current method
|
73
|
+
# @param input_args input parameter of the repository method call
|
74
|
+
# @return strategy method return value after all wrappers where applied
|
75
|
+
def __run_wrappers(method_cache, input_args)
|
76
|
+
wrappers = method_cache.wrappers.map(&:new)
|
77
|
+
args = if method_cache.skip_before_wrappers?
|
78
|
+
input_args
|
79
|
+
else
|
80
|
+
__run_before_wrappers(wrappers, method_cache.before_method_name, input_args)
|
81
|
+
end
|
82
|
+
ret = yield(args)
|
83
|
+
return ret if method_cache.skip_after_wrappers?
|
84
|
+
__run_after_wrappers(wrappers, method_cache.after_method_name, args, ret)
|
85
|
+
end
|
86
|
+
|
87
|
+
# runtime method to execute all before wrappers
|
88
|
+
# @param wrappers [Array] all wrapper instances to be executed
|
89
|
+
# @param method_name [Symbol] name of method to be executed on wrappers
|
90
|
+
# @param args input args of the repository method
|
91
|
+
# @return processed method args by before wrappers
|
92
|
+
def __run_before_wrappers(wrappers, method_name, args)
|
93
|
+
wrappers.each do |wrapper|
|
94
|
+
next unless wrapper.respond_to?(method_name)
|
95
|
+
args = wrapper.public_send(method_name, args)
|
96
|
+
end
|
97
|
+
args
|
98
|
+
end
|
99
|
+
|
100
|
+
# runtime method to execute all after wrappers
|
101
|
+
# @param wrappers [Array] all wrapper instances to be executed
|
102
|
+
# @param method_name [Symbol] name of method to be executed on wrappers
|
103
|
+
# @param args input args to the strategy method (after processing in before wrappers)
|
104
|
+
# @param return_value return value of strategy method
|
105
|
+
# @return processed return value by all after wrappers
|
106
|
+
def __run_after_wrappers(wrappers, method_name, args, return_value)
|
107
|
+
wrappers.reverse_each do |wrapper|
|
108
|
+
next unless wrapper.respond_to?(method_name)
|
109
|
+
return_value = wrapper.public_send(method_name, return_value, args)
|
110
|
+
end
|
111
|
+
return_value
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'singleton'
|
3
|
+
require 'set'
|
4
|
+
module Receptacle
|
5
|
+
# keeps global state of repositories, the defined strategy, set wrappers and methods to mediate
|
6
|
+
class Registration
|
7
|
+
include Singleton
|
8
|
+
Tuple = Struct.new(:strategy, :wrappers, :methods)
|
9
|
+
|
10
|
+
attr_reader :repositories
|
11
|
+
|
12
|
+
def initialize
|
13
|
+
@repositories = Hash.new do |h, k|
|
14
|
+
h[k] = Tuple.new(nil, [], Set.new)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.repositories
|
19
|
+
instance.repositories
|
20
|
+
end
|
21
|
+
|
22
|
+
# {clear_method_cache} removes dynamically defined methods
|
23
|
+
# this is needed to make strategy and wrappers changes inside the codebase possible
|
24
|
+
def self.clear_method_cache(receptacle)
|
25
|
+
instance.repositories[receptacle].methods.each do |method_name|
|
26
|
+
begin
|
27
|
+
receptacle.singleton_class.send(:remove_method, method_name)
|
28
|
+
rescue NameError
|
29
|
+
nil
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module Receptacle
|
3
|
+
module TestSupport
|
4
|
+
# provides helpful method to toggle strategies during testing
|
5
|
+
#
|
6
|
+
# can be used in rspec like this
|
7
|
+
#
|
8
|
+
# require 'receptacle/test_support'y
|
9
|
+
# RSpec.configure do |c|
|
10
|
+
# c.include Receptacle::TestSupport
|
11
|
+
# end
|
12
|
+
#
|
13
|
+
# RSpec.describe(UserRepository) do
|
14
|
+
# around do |example|
|
15
|
+
# with_strategy(strategy){example.run}
|
16
|
+
# end
|
17
|
+
# let(:strategy) { UserRepository::Strategy::MySQL }
|
18
|
+
# ...
|
19
|
+
# end
|
20
|
+
#
|
21
|
+
# or similar with minitest
|
22
|
+
#
|
23
|
+
# require 'receptacle/test_support'
|
24
|
+
# class UserRepositoryTest < Minitest::Test
|
25
|
+
# def described_class
|
26
|
+
# UserRepository
|
27
|
+
# end
|
28
|
+
# def repo_exists(strategy)
|
29
|
+
# with_strategy(strategy) do
|
30
|
+
# assert described_class.exists(id: 5)
|
31
|
+
# end
|
32
|
+
# end
|
33
|
+
# def test_mysql
|
34
|
+
# repo_exists(UserRepository::Strategy::MySQL)
|
35
|
+
# end
|
36
|
+
# def test_fake
|
37
|
+
# repo_exists(UserRepository::Strategy::Fake)
|
38
|
+
# end
|
39
|
+
# end
|
40
|
+
def with_strategy(strategy, repo = described_class)
|
41
|
+
original_strategy = repo.strategy
|
42
|
+
repo.strategy strategy
|
43
|
+
yield
|
44
|
+
repo.strategy original_strategy
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
data/lib/receptacle.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'receptacle/version'
|
3
|
+
require 'receptacle/interface_methods'
|
4
|
+
require 'receptacle/method_delegation'
|
5
|
+
|
6
|
+
module Receptacle
|
7
|
+
module Repo
|
8
|
+
def self.included(base)
|
9
|
+
base.extend(InterfaceMethods)
|
10
|
+
base.extend(MethodDelegation)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'bundler/inline'
|
3
|
+
|
4
|
+
gemfile false do
|
5
|
+
source 'https://rubygems.org'
|
6
|
+
gem 'benchmark-ips'
|
7
|
+
gem 'receptacle', path: './..'
|
8
|
+
end
|
9
|
+
|
10
|
+
require_relative 'speed_receptacle'
|
11
|
+
|
12
|
+
Speed.strategy(Speed::Strategy::One)
|
13
|
+
Speed.wrappers [Speed::Wrappers::W1,
|
14
|
+
Speed::Wrappers::W2,
|
15
|
+
Speed::Wrappers::W3,
|
16
|
+
Speed::Wrappers::W4,
|
17
|
+
Speed::Wrappers::W5,
|
18
|
+
Speed::Wrappers::W6]
|
19
|
+
|
20
|
+
print 'w/ wrappers'
|
21
|
+
Benchmark.ips do |x|
|
22
|
+
x.warmup = 10 if RUBY_ENGINE == 'jruby'
|
23
|
+
x.report('a: 2x around, 1x before, 1x after') { Speed.a(1) }
|
24
|
+
x.report('b: 1x around, 1x before, 1x after') { Speed.b(1) }
|
25
|
+
x.report('c: 1x before, 1x after') { Speed.c(1) }
|
26
|
+
x.report('d: 1x after') { Speed.d(1) }
|
27
|
+
x.report('e: 1x before') { Speed.e(1) }
|
28
|
+
x.report('f: 1x around') { Speed.f(1) }
|
29
|
+
x.report('g: no wrappers') { Speed.g(1) }
|
30
|
+
end
|
31
|
+
|
32
|
+
Speed.wrappers []
|
33
|
+
print 'method dispatching w/ wrappers'
|
34
|
+
Benchmark.ips do |x|
|
35
|
+
x.warmup = 10 if RUBY_ENGINE == 'jruby'
|
36
|
+
x.report('via receptacle') { Speed.a(:foo) }
|
37
|
+
x.report('direct via public_send') { Speed::Strategy::One.new.public_send(:a, :foo) }
|
38
|
+
x.report('direct via method-method') do
|
39
|
+
m = Speed::Strategy::One.new.method(:a)
|
40
|
+
m.call(:foo)
|
41
|
+
end
|
42
|
+
x.report('direct method-call') { Speed::Strategy::One.new.a(:foo) }
|
43
|
+
x.compare!
|
44
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
# run with --profile.api in JRUBY_OPTS
|
4
|
+
require 'bundler/inline'
|
5
|
+
require 'jruby/profiler'
|
6
|
+
PROFILE_NAME = 'receptacle'
|
7
|
+
|
8
|
+
gemfile false do
|
9
|
+
source 'https://rubygems.org'
|
10
|
+
gem 'receptacle', path: './..'
|
11
|
+
end
|
12
|
+
require_relative 'speed_receptacle'
|
13
|
+
|
14
|
+
Speed.strategy(Speed::Strategy::One)
|
15
|
+
Speed.wrappers [Speed::Wrappers::W1,
|
16
|
+
Speed::Wrappers::W2,
|
17
|
+
Speed::Wrappers::W3,
|
18
|
+
Speed::Wrappers::W4,
|
19
|
+
Speed::Wrappers::W5,
|
20
|
+
Speed::Wrappers::W6]
|
21
|
+
Speed.a(1)
|
22
|
+
Speed.b(1)
|
23
|
+
Speed.c(1)
|
24
|
+
Speed.d(1)
|
25
|
+
Speed.e(1)
|
26
|
+
Speed.f(1)
|
27
|
+
Speed.g(1)
|
28
|
+
|
29
|
+
GC.disable
|
30
|
+
profile_data = JRuby::Profiler.profile do
|
31
|
+
100_000.times { Speed.a(1) }
|
32
|
+
end
|
33
|
+
|
34
|
+
profile_printer = JRuby::Profiler::GraphProfilePrinter.new(profile_data)
|
35
|
+
profile_printer.printProfile(File.open("#{PROFILE_NAME}.graph.profile", 'w+'))
|
36
|
+
profile_printer.printProfile(STDOUT)
|
37
|
+
|
38
|
+
profile_printer = JRuby::Profiler::FlatProfilePrinter.new(profile_data)
|
39
|
+
profile_printer.printProfile(File.open("#{PROFILE_NAME}.flat.profile", 'w+'))
|
@@ -0,0 +1,104 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'receptacle'
|
3
|
+
module Speed
|
4
|
+
include Receptacle::Repo
|
5
|
+
mediate :a
|
6
|
+
mediate :b
|
7
|
+
mediate :c
|
8
|
+
mediate :d
|
9
|
+
mediate :e
|
10
|
+
mediate :f
|
11
|
+
mediate :g
|
12
|
+
module Strategy
|
13
|
+
class One
|
14
|
+
def a(arg)
|
15
|
+
arg
|
16
|
+
end
|
17
|
+
alias b a
|
18
|
+
alias c a
|
19
|
+
alias d a
|
20
|
+
alias e a
|
21
|
+
alias f a
|
22
|
+
alias g a
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
module Wrappers
|
27
|
+
class W1
|
28
|
+
def before_a(args)
|
29
|
+
args
|
30
|
+
end
|
31
|
+
|
32
|
+
def after_a(return_values, _)
|
33
|
+
return_values
|
34
|
+
end
|
35
|
+
|
36
|
+
def before_f(args)
|
37
|
+
args
|
38
|
+
end
|
39
|
+
|
40
|
+
def after_f(return_values, _)
|
41
|
+
return_values
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
class W2
|
46
|
+
# :a
|
47
|
+
def before_a(args)
|
48
|
+
args
|
49
|
+
end
|
50
|
+
|
51
|
+
def after_a(return_values, _)
|
52
|
+
return_values
|
53
|
+
end
|
54
|
+
|
55
|
+
# :b
|
56
|
+
def before_b(args)
|
57
|
+
args
|
58
|
+
end
|
59
|
+
|
60
|
+
def after_b(return_values, _)
|
61
|
+
return_values
|
62
|
+
end
|
63
|
+
end
|
64
|
+
class W3
|
65
|
+
def before_a(args)
|
66
|
+
args
|
67
|
+
end
|
68
|
+
|
69
|
+
def before_c(args)
|
70
|
+
args
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
class W4
|
75
|
+
def after_a(return_values, _)
|
76
|
+
return_values
|
77
|
+
end
|
78
|
+
|
79
|
+
def after_d(return_value, _)
|
80
|
+
return_value
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
class W5
|
85
|
+
def before_b(args)
|
86
|
+
args
|
87
|
+
end
|
88
|
+
|
89
|
+
def after_c(return_value, _)
|
90
|
+
return_value
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
class W6
|
95
|
+
def after_b(return_value, _)
|
96
|
+
return_value
|
97
|
+
end
|
98
|
+
|
99
|
+
def before_e(args)
|
100
|
+
args
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
data/receptacle.gemspec
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
lib = File.expand_path('../lib', __FILE__)
|
4
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
5
|
+
require 'receptacle/version'
|
6
|
+
|
7
|
+
Gem::Specification.new do |spec|
|
8
|
+
spec.name = 'receptacle'
|
9
|
+
spec.version = Receptacle::VERSION
|
10
|
+
spec.authors = ['Andreas Eger']
|
11
|
+
spec.email = ['dev@eger-andreas.de']
|
12
|
+
|
13
|
+
spec.summary = 'repository pattern'
|
14
|
+
spec.description = 'provides functionality for the repository or strategy pattern'
|
15
|
+
spec.homepage = 'https://github.com/andreaseger/receptacle'
|
16
|
+
spec.license = 'MIT'
|
17
|
+
|
18
|
+
spec.required_ruby_version = '~> 2.2'
|
19
|
+
|
20
|
+
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
21
|
+
f.match(%r{^(test|spec|features)/})
|
22
|
+
end
|
23
|
+
spec.bindir = 'exe'
|
24
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
25
|
+
spec.require_paths = ['lib']
|
26
|
+
|
27
|
+
spec.add_development_dependency 'bundler', '~> 1.13'
|
28
|
+
spec.add_development_dependency 'rake', '~> 10.0'
|
29
|
+
spec.add_development_dependency 'minitest', '~> 5.0'
|
30
|
+
spec.add_development_dependency 'pry'
|
31
|
+
spec.add_development_dependency 'rubocop_runner', '~> 2.0'
|
32
|
+
spec.add_development_dependency 'rubocop', '~> 0.46.0'
|
33
|
+
spec.add_development_dependency 'simplecov', '~> 0.13'
|
34
|
+
spec.add_development_dependency 'codecov'
|
35
|
+
spec.add_development_dependency 'guard'
|
36
|
+
spec.add_development_dependency 'guard-minitest'
|
37
|
+
spec.add_development_dependency 'guard-rubocop'
|
38
|
+
end
|