sqreen 1.17.0-java → 1.17.2.beta1-java
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/CHANGELOG.md +418 -0
- data/README.md +5 -5
- data/lib/sqreen.rb +2 -72
- data/lib/sqreen/agent.rb +37 -0
- data/lib/sqreen/call_countable.rb +6 -6
- data/lib/sqreen/conditionable.rb +6 -6
- data/lib/sqreen/dependency.rb +18 -0
- data/lib/sqreen/dependency/callback.rb +34 -0
- data/lib/sqreen/dependency/detector.rb +97 -0
- data/lib/sqreen/dependency/hook.rb +102 -0
- data/lib/sqreen/dependency/hook_point.rb +219 -0
- data/lib/sqreen/dependency/new_relic.rb +17 -0
- data/lib/sqreen/dependency/rack.rb +36 -0
- data/lib/sqreen/dependency/rails.rb +30 -0
- data/lib/sqreen/dependency/sentry.rb +17 -0
- data/lib/sqreen/exception.rb +3 -0
- data/lib/sqreen/frameworks/generic.rb +2 -97
- data/lib/sqreen/frameworks/rails.rb +4 -13
- data/lib/sqreen/frameworks/sinatra.rb +0 -25
- data/lib/sqreen/instrumentation.rb +5 -4
- data/lib/sqreen/rules_callbacks/execjs.rb +3 -0
- data/lib/sqreen/rules_callbacks/record_request_context.rb +4 -1
- data/lib/sqreen/runner.rb +0 -3
- data/lib/sqreen/session.rb +40 -45
- data/lib/sqreen/version.rb +1 -1
- data/lib/sqreen/web_server.rb +54 -0
- data/lib/sqreen/web_server/generic.rb +24 -0
- data/lib/sqreen/web_server/passenger.rb +33 -0
- data/lib/sqreen/web_server/puma.rb +62 -0
- data/lib/sqreen/web_server/rainbows.rb +14 -0
- data/lib/sqreen/web_server/thin.rb +14 -0
- data/lib/sqreen/web_server/unicorn.rb +52 -0
- data/lib/sqreen/web_server/webrick.rb +14 -0
- data/lib/sqreen/worker.rb +68 -0
- metadata +28 -6
data/lib/sqreen/agent.rb
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
# Copyright (c) 2015 Sqreen. All Rights Reserved.
|
2
|
+
# Please refer to our terms for more information: https://www.sqreen.io/terms.html
|
3
|
+
|
4
|
+
require 'sqreen/version'
|
5
|
+
require 'sqreen/instrumentation'
|
6
|
+
require 'sqreen/session'
|
7
|
+
require 'sqreen/runner'
|
8
|
+
require 'sqreen/callbacks'
|
9
|
+
require 'sqreen/log'
|
10
|
+
require 'sqreen/exception'
|
11
|
+
require 'sqreen/configuration'
|
12
|
+
require 'sqreen/events/attack'
|
13
|
+
require 'sqreen/sdk'
|
14
|
+
require 'sqreen/dependency/detector'
|
15
|
+
require 'sqreen/worker'
|
16
|
+
require 'sqreen/web_server'
|
17
|
+
|
18
|
+
module Sqreen
|
19
|
+
module Agent
|
20
|
+
module_function
|
21
|
+
|
22
|
+
def start
|
23
|
+
return if Sqreen.to_bool(ENV['SQREEN_DISABLE'])
|
24
|
+
|
25
|
+
Sqreen::Dependency::Detector.hook do
|
26
|
+
Sqreen.log.debug "[#{Process.pid}] Attaching to webserver"
|
27
|
+
Sqreen::WebServer.attach do
|
28
|
+
Sqreen.log.debug "[#{Process.pid}] Attached to webserver"
|
29
|
+
# TODO: maybe in dependency, not here, to separate concerns?
|
30
|
+
Sqreen::Dependency::Sentry.ignore_sqreen_exceptions
|
31
|
+
Sqreen::Dependency::NewRelic.ignore_sqreen_exceptions
|
32
|
+
Sqreen::Worker.start(Sqreen.framework)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -33,20 +33,20 @@ module Sqreen
|
|
33
33
|
FAILING = 'failing'.freeze
|
34
34
|
COUNT_CALLS = 'sqreen_call_counts'.freeze
|
35
35
|
|
36
|
-
def pre_with_count(inst,
|
37
|
-
ret = pre_without_count(inst,
|
36
|
+
def pre_with_count(inst, args, budget = nil, &block)
|
37
|
+
ret = pre_without_count(inst, args, budget, &block)
|
38
38
|
count_calls('pre')
|
39
39
|
ret
|
40
40
|
end
|
41
41
|
|
42
|
-
def post_with_count(rv, inst,
|
43
|
-
ret = post_without_count(rv, inst,
|
42
|
+
def post_with_count(rv, inst, args, budget = nil, &block)
|
43
|
+
ret = post_without_count(rv, inst, args, budget, &block)
|
44
44
|
count_calls('post')
|
45
45
|
ret
|
46
46
|
end
|
47
47
|
|
48
|
-
def failing_with_count(rv, inst,
|
49
|
-
ret = failing_without_count(rv, inst,
|
48
|
+
def failing_with_count(rv, inst, args, budget = nil, &block)
|
49
|
+
ret = failing_without_count(rv, inst, args, budget, &block)
|
50
50
|
count_calls('failing')
|
51
51
|
ret
|
52
52
|
end
|
data/lib/sqreen/conditionable.rb
CHANGED
@@ -25,22 +25,22 @@ module Sqreen
|
|
25
25
|
end
|
26
26
|
end
|
27
27
|
|
28
|
-
def pre_with_conditions(inst,
|
28
|
+
def pre_with_conditions(inst, args, budget = nil, &block)
|
29
29
|
eargs = [nil, framework, inst, args, @data, nil]
|
30
30
|
return nil if !pre_conditions.nil? && !pre_conditions.evaluate(*eargs)
|
31
|
-
pre_without_conditions(inst,
|
31
|
+
pre_without_conditions(inst, args, budget, &block)
|
32
32
|
end
|
33
33
|
|
34
|
-
def post_with_conditions(rv, inst,
|
34
|
+
def post_with_conditions(rv, inst, args, budget = nil, &block)
|
35
35
|
eargs = [nil, framework, inst, args, @data, rv]
|
36
36
|
return nil if !post_conditions.nil? && !post_conditions.evaluate(*eargs)
|
37
|
-
post_without_conditions(rv, inst,
|
37
|
+
post_without_conditions(rv, inst, args, budget, &block)
|
38
38
|
end
|
39
39
|
|
40
|
-
def failing_with_conditions(rv, inst,
|
40
|
+
def failing_with_conditions(rv, inst, args, budget = nil, &block)
|
41
41
|
eargs = [nil, framework, inst, args, @data, rv]
|
42
42
|
return nil if !failing_conditions.nil? && !failing_conditions.evaluate(*eargs)
|
43
|
-
failing_without_conditions(rv, inst,
|
43
|
+
failing_without_conditions(rv, inst, args, budget, &block)
|
44
44
|
end
|
45
45
|
|
46
46
|
protected
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# Copyright (c) 2015 Sqreen. All Rights Reserved.
|
2
|
+
# Please refer to our terms for more information: https://www.sqreen.io/terms.html
|
3
|
+
|
4
|
+
module Sqreen
|
5
|
+
module Dependency
|
6
|
+
def self.const_exist?(name)
|
7
|
+
resolve_const(name) && true
|
8
|
+
rescue NameError, ArgumentError
|
9
|
+
false
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.resolve_const(name)
|
13
|
+
raise ArgumentError if name.nil? || name.empty?
|
14
|
+
|
15
|
+
name.to_s.split('::').inject(Object) { |a, e| a.const_get(e) }
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# Copyright (c) 2015 Sqreen. All Rights Reserved.
|
2
|
+
# Please refer to our terms for more information: https://www.sqreen.io/terms.html
|
3
|
+
|
4
|
+
module Sqreen
|
5
|
+
module Dependency
|
6
|
+
class Callback
|
7
|
+
attr_reader :name
|
8
|
+
|
9
|
+
def initialize(name = nil, &block)
|
10
|
+
@name = name
|
11
|
+
@block = block
|
12
|
+
@disabled = false
|
13
|
+
end
|
14
|
+
|
15
|
+
def call(*args, &block)
|
16
|
+
Sqreen.log.debug "[#{Process.pid}] Callback #{@name} disabled:#{disabled?}"
|
17
|
+
return if @disabled
|
18
|
+
@block.call(*args, &block)
|
19
|
+
end
|
20
|
+
|
21
|
+
def disable
|
22
|
+
@disabled = true
|
23
|
+
end
|
24
|
+
|
25
|
+
def enable
|
26
|
+
@disabled = false
|
27
|
+
end
|
28
|
+
|
29
|
+
def disabled?
|
30
|
+
@disabled
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
# Copyright (c) 2015 Sqreen. All Rights Reserved.
|
2
|
+
# Please refer to our terms for more information: https://www.sqreen.io/terms.html
|
3
|
+
|
4
|
+
require 'sqreen/dependency/hook'
|
5
|
+
require 'sqreen/dependency/rails'
|
6
|
+
require 'sqreen/dependency/rack'
|
7
|
+
require 'sqreen/dependency/sentry'
|
8
|
+
require 'sqreen/dependency/new_relic'
|
9
|
+
|
10
|
+
module Sqreen
|
11
|
+
module Dependency
|
12
|
+
module Detector
|
13
|
+
module_function
|
14
|
+
|
15
|
+
def start_mode
|
16
|
+
if Sqreen::Dependency::Rails.server?
|
17
|
+
:rails
|
18
|
+
elsif Sqreen::Dependency::Rack.rackup?
|
19
|
+
:rackup
|
20
|
+
else
|
21
|
+
:default
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def hook(&block)
|
26
|
+
Sqreen.log.debug "[#{Process.pid}] Startup command: #{$0}"
|
27
|
+
|
28
|
+
# ensure middleware presence
|
29
|
+
|
30
|
+
ActiveSupport.on_load(:before_initialize, :yield => true) do
|
31
|
+
Sqreen::Dependency::Rails.insert_sqreen_middlewares
|
32
|
+
end if Sqreen::Dependency::Rails.required?
|
33
|
+
|
34
|
+
Sqreen::Dependency::Hook.add('Rack::Builder#to_app') do
|
35
|
+
after do
|
36
|
+
Sqreen::Dependency::Rails.inspect_middlewares
|
37
|
+
end
|
38
|
+
end if Sqreen::Dependency::Rails.required?
|
39
|
+
|
40
|
+
# ensure startup of thread in request handling processes
|
41
|
+
|
42
|
+
Sqreen::Dependency::Hook.add('Rack::Builder#to_app') do
|
43
|
+
after do |callback, *|
|
44
|
+
Sqreen.log.debug "[#{Process.pid}] Start mode #{Sqreen::Dependency::Detector.start_mode}"
|
45
|
+
if Sqreen::Dependency::Detector.start_mode == :rails || Sqreen::Dependency::Detector.start_mode == :rackup
|
46
|
+
|
47
|
+
Sqreen::Dependency::Rack.find_handler do |handler|
|
48
|
+
Sqreen::Dependency::Rack.on_run(handler) do
|
49
|
+
case handler.name
|
50
|
+
when 'Rack::Handler::Puma'
|
51
|
+
Sqreen::Dependency::Hook.add('Puma::Launcher#run') do
|
52
|
+
before do
|
53
|
+
# HACK: Puma master? hack falls apart when not preloading
|
54
|
+
# it would think master is not, triggering startup
|
55
|
+
Sqreen::WebServer.instance_eval { @master_pid = Process.pid }
|
56
|
+
block.call
|
57
|
+
# HACK: because to_app callback is disabled, so won't run again in fork
|
58
|
+
if Sqreen::WebServer.forking? && !Sqreen::WebServer.preload_app?
|
59
|
+
Sqreen::WebServer.after_fork { block.call }
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
Sqreen::Dependency::Hook['Puma::Launcher#run'].install
|
64
|
+
when 'Rack::Handler::PhusionPassenger'
|
65
|
+
# noop, passenger will start his own separate process
|
66
|
+
Sqreen.log.debug "[#{Process.pid}] Passenger will start in standalone process"
|
67
|
+
when 'Rack::Handler::Unicorn' # unicorn-rails
|
68
|
+
Sqreen::Dependency::Hook.add('Unicorn::HttpServer.new') do
|
69
|
+
before do
|
70
|
+
# BUG: detects single process...
|
71
|
+
end
|
72
|
+
end.install
|
73
|
+
else
|
74
|
+
block.call
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
else
|
79
|
+
block.call
|
80
|
+
end
|
81
|
+
|
82
|
+
# #to_app can be called multiple times, run callback once only
|
83
|
+
callback.disable
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
Sqreen::Dependency::Hook['Rack::Builder#to_app'].install
|
88
|
+
|
89
|
+
# Sqreen::Dependency::Hook.add('Rails::Server#start') do
|
90
|
+
# before { }
|
91
|
+
# end
|
92
|
+
# Sqreen::Dependency::Hook['Rails::Server#start'].install
|
93
|
+
# /!\ double instrument Rails < Rack => Rails.start_with -> Rails.start_without -> super -> Rack.start_with -> Rails.start_without
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
@@ -0,0 +1,102 @@
|
|
1
|
+
# Copyright (c) 2015 Sqreen. All Rights Reserved.
|
2
|
+
# Please refer to our terms for more information: https://www.sqreen.io/terms.html
|
3
|
+
|
4
|
+
require 'sqreen/dependency/callback'
|
5
|
+
require 'sqreen/dependency/hook_point'
|
6
|
+
|
7
|
+
module Sqreen
|
8
|
+
module Dependency
|
9
|
+
class Hook
|
10
|
+
@hooks = {}
|
11
|
+
|
12
|
+
def self.[](hook_point)
|
13
|
+
@hooks[hook_point] ||= new(hook_point)
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.add(hook_point, &block)
|
17
|
+
self[hook_point].add(&block)
|
18
|
+
end
|
19
|
+
|
20
|
+
attr_reader :point
|
21
|
+
|
22
|
+
def initialize(hook_point, dependency_test = nil)
|
23
|
+
@disabled = false
|
24
|
+
@point = hook_point.is_a?(HookPoint) ? hook_point : HookPoint.new(hook_point)
|
25
|
+
@before = []
|
26
|
+
@after = []
|
27
|
+
@raised = []
|
28
|
+
@dependency_test = dependency_test || Proc.new { point.exist? }
|
29
|
+
end
|
30
|
+
|
31
|
+
def dependency?
|
32
|
+
@dependency_test.call if @dependency_test
|
33
|
+
end
|
34
|
+
|
35
|
+
def add(&block)
|
36
|
+
tap { instance_eval(&block) }
|
37
|
+
end
|
38
|
+
|
39
|
+
def callback_name(whence, tag = nil)
|
40
|
+
"#{point}@#{whence}" << (tag ? ":#{tag}" : "")
|
41
|
+
end
|
42
|
+
|
43
|
+
def before(tag = nil, &block)
|
44
|
+
return @before if block.nil?
|
45
|
+
|
46
|
+
@before << Callback.new(callback_name(:before, tag), &block)
|
47
|
+
end
|
48
|
+
|
49
|
+
def after(tag = nil, &block)
|
50
|
+
return @after if block.nil?
|
51
|
+
|
52
|
+
@after << Callback.new(callback_name(:after, tag), &block)
|
53
|
+
end
|
54
|
+
|
55
|
+
def raised(tag = nil, &block)
|
56
|
+
return @raised if block.nil?
|
57
|
+
|
58
|
+
@raised << Callback.new(callback_name(:raised, tag), &block)
|
59
|
+
end
|
60
|
+
|
61
|
+
def depends_on(&block)
|
62
|
+
@dependency_test = block
|
63
|
+
end
|
64
|
+
|
65
|
+
def enable
|
66
|
+
@disabled = false
|
67
|
+
end
|
68
|
+
|
69
|
+
def disable
|
70
|
+
@disabled = true
|
71
|
+
end
|
72
|
+
|
73
|
+
def disabled?
|
74
|
+
@disabled
|
75
|
+
end
|
76
|
+
|
77
|
+
def install
|
78
|
+
unless point.exist?
|
79
|
+
Sqreen.log.debug "[#{Process.pid}] #{point} not found"
|
80
|
+
return
|
81
|
+
end
|
82
|
+
Sqreen.log.debug "[#{Process.pid}] Hook #{point}: installing"
|
83
|
+
|
84
|
+
point.install('sqreen_hook', &Sqreen::Dependency::Hook.wrapper(self))
|
85
|
+
end
|
86
|
+
|
87
|
+
def self.wrapper(hook)
|
88
|
+
# pass self to cbs
|
89
|
+
Proc.new do |*args, &block|
|
90
|
+
Sqreen.log.debug "[#{Process.pid}] Hook #{hook.point} disabled:#{hook.disabled?} caller:#{Kernel.caller[1].inspect}"
|
91
|
+
hook.before.each { |c| c.call(c, self, args) } unless hook.disabled?
|
92
|
+
begin
|
93
|
+
hook.point.apply(self, 'sqreen_hook', *args, &block)
|
94
|
+
rescue ::Exception => e # rubocop:disable Lint/RescueException
|
95
|
+
hook.raised.each { |c| c.call(c, self, e, args) } unless hook.disabled?
|
96
|
+
raise
|
97
|
+
end.tap { |v| hook.after.each { |c| c.call(c, self, v, args) } unless hook.disabled? }
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
@@ -0,0 +1,219 @@
|
|
1
|
+
# Copyright (c) 2015 Sqreen. All Rights Reserved.
|
2
|
+
# Please refer to our terms for more information: https://www.sqreen.io/terms.html
|
3
|
+
|
4
|
+
require 'sqreen/dependency'
|
5
|
+
|
6
|
+
module Sqreen
|
7
|
+
module Dependency
|
8
|
+
class HookPointError < StandardError; end
|
9
|
+
|
10
|
+
class HookPoint
|
11
|
+
def self.parse(hook_point)
|
12
|
+
klass_name, separator, method_name = hook_point.split(/(\#|\.)/, 2)
|
13
|
+
|
14
|
+
raise ArgumentError, hook_point if klass_name.nil? || separator.nil? || method_name.nil?
|
15
|
+
raise ArgumentError, hook_point unless ['.', '#'].include?(separator)
|
16
|
+
|
17
|
+
method_kind = separator == '.' ? :klass_method : :instance_method
|
18
|
+
|
19
|
+
[klass_name.to_sym, method_kind, method_name.to_sym]
|
20
|
+
end
|
21
|
+
|
22
|
+
attr_reader :klass_name, :method_kind, :method_name
|
23
|
+
|
24
|
+
def initialize(hook_point)
|
25
|
+
@klass_name, @method_kind, @method_name = Sqreen::Dependency::HookPoint.parse(hook_point)
|
26
|
+
end
|
27
|
+
|
28
|
+
def to_s
|
29
|
+
"#{@klass_name}#{@method_kind == :instance_method ? '#' : '.'}#{@method_name}"
|
30
|
+
end
|
31
|
+
|
32
|
+
def exist?
|
33
|
+
return false unless Sqreen::Dependency.const_exist?(@klass_name)
|
34
|
+
|
35
|
+
if klass_method?
|
36
|
+
(klass.methods + klass.protected_methods + klass.private_methods).include?(@method_name)
|
37
|
+
elsif instance_method?
|
38
|
+
(klass.instance_methods + klass.protected_instance_methods + klass.private_instance_methods).include?(@method_name)
|
39
|
+
else
|
40
|
+
raise HookPointError, 'unknown hook point kind'
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def klass
|
45
|
+
Sqreen::Dependency.resolve_const(@klass_name)
|
46
|
+
end
|
47
|
+
|
48
|
+
def klass_method?
|
49
|
+
@method_kind == :klass_method
|
50
|
+
end
|
51
|
+
|
52
|
+
def private_method?
|
53
|
+
if klass_method?
|
54
|
+
klass.private_methods.include?(@method_name)
|
55
|
+
elsif instance_method?
|
56
|
+
klass.private_instance_methods.include?(@method_name)
|
57
|
+
else
|
58
|
+
raise HookPointError, 'unknown hook point kind'
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def protected_method?
|
63
|
+
if klass_method?
|
64
|
+
klass.protected_methods.include?(@method_name)
|
65
|
+
elsif instance_method?
|
66
|
+
klass.protected_instance_methods.include?(@method_name)
|
67
|
+
else
|
68
|
+
raise HookPointError, 'unknown hook point kind'
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def instance_method?
|
73
|
+
@method_kind == :instance_method
|
74
|
+
end
|
75
|
+
|
76
|
+
def installed?(suffix)
|
77
|
+
if klass_method?
|
78
|
+
(klass.methods + klass.protected_methods + klass.private_methods).include?(:"#{method_name}_with_#{suffix}")
|
79
|
+
elsif instance_method?
|
80
|
+
(klass.instance_methods + klass.protected_instance_methods + klass.private_instance_methods).include?(:"#{method_name}_with_#{suffix}")
|
81
|
+
else
|
82
|
+
raise HookPointError, 'unknown hook point kind'
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def apply(obj, suffix, *args, &block)
|
87
|
+
obj.send("#{method_name}_without_#{suffix}", *args, &block)
|
88
|
+
end
|
89
|
+
|
90
|
+
def install(suffix, &block)
|
91
|
+
if installed?(suffix)
|
92
|
+
Sqreen.log.debug "[#{Process.pid}] #{self} already installed"
|
93
|
+
end
|
94
|
+
unless exist?
|
95
|
+
Sqreen.log.debug "[#{Process.pid}] #{self} hook point not found"
|
96
|
+
end
|
97
|
+
|
98
|
+
define(suffix, &block)
|
99
|
+
enable(suffix)
|
100
|
+
end
|
101
|
+
|
102
|
+
def uninstall(suffix)
|
103
|
+
disable(suffix)
|
104
|
+
remove(suffix)
|
105
|
+
end
|
106
|
+
|
107
|
+
def enable(suffix)
|
108
|
+
chain(suffix)
|
109
|
+
end
|
110
|
+
|
111
|
+
def disable(suffix)
|
112
|
+
unchain(suffix)
|
113
|
+
end
|
114
|
+
|
115
|
+
def disabled?(suffix)
|
116
|
+
!chained?(suffix)
|
117
|
+
end
|
118
|
+
|
119
|
+
private
|
120
|
+
|
121
|
+
def define(suffix, &block)
|
122
|
+
hook_point = self
|
123
|
+
method_name = @method_name
|
124
|
+
|
125
|
+
if klass_method?
|
126
|
+
klass.singleton_class.instance_eval do
|
127
|
+
if hook_point.protected_method?
|
128
|
+
private
|
129
|
+
elsif hook_point.protected_method?
|
130
|
+
protected
|
131
|
+
else
|
132
|
+
public
|
133
|
+
end
|
134
|
+
|
135
|
+
define_method(:"#{method_name}_with_#{suffix}", &block)
|
136
|
+
end
|
137
|
+
elsif instance_method?
|
138
|
+
klass.class_eval do
|
139
|
+
if hook_point.protected_method?
|
140
|
+
private
|
141
|
+
elsif hook_point.protected_method?
|
142
|
+
protected
|
143
|
+
else
|
144
|
+
public
|
145
|
+
end
|
146
|
+
|
147
|
+
define_method(:"#{method_name}_with_#{suffix}", &block)
|
148
|
+
end
|
149
|
+
else
|
150
|
+
raise HookPointError, 'unknown hook point kind'
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
def remove(suffix)
|
155
|
+
method_name = @method_name
|
156
|
+
|
157
|
+
if klass_method?
|
158
|
+
klass.singleton_class.instance_eval do
|
159
|
+
remove_method(:"#{method_name}_with_#{suffix}")
|
160
|
+
end
|
161
|
+
elsif instance_method?
|
162
|
+
klass.class_eval do
|
163
|
+
remove_method(:"#{method_name}_with_#{suffix}")
|
164
|
+
end
|
165
|
+
else
|
166
|
+
raise HookPointError, 'unknown hook point kind'
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
def chained?(suffix)
|
171
|
+
method_name = @method_name
|
172
|
+
|
173
|
+
if klass_method?
|
174
|
+
klass.singleton_class.instance_eval do
|
175
|
+
instance_method(:"#{method_name}").original_name == :"#{method_name}_with_#{suffix}"
|
176
|
+
end
|
177
|
+
elsif instance_method?
|
178
|
+
klass.class_eval do
|
179
|
+
instance_method(:"#{method_name}").original_name == :"#{method_name}_with_#{suffix}"
|
180
|
+
end
|
181
|
+
else
|
182
|
+
raise HookPointError, 'unknown hook point kind'
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
def chain(suffix)
|
187
|
+
method_name = @method_name
|
188
|
+
|
189
|
+
if klass_method?
|
190
|
+
klass.singleton_class.instance_eval do
|
191
|
+
alias_method :"#{method_name}_without_#{suffix}", :"#{method_name}"
|
192
|
+
alias_method :"#{method_name}", :"#{method_name}_with_#{suffix}"
|
193
|
+
end
|
194
|
+
elsif instance_method?
|
195
|
+
klass.class_eval do
|
196
|
+
alias_method :"#{method_name}_without_#{suffix}", :"#{method_name}"
|
197
|
+
alias_method :"#{method_name}", :"#{method_name}_with_#{suffix}"
|
198
|
+
end
|
199
|
+
else
|
200
|
+
raise HookPointError, 'unknown hook point kind'
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
def unchain(suffix)
|
205
|
+
method_name = @method_name
|
206
|
+
|
207
|
+
if klass_method?
|
208
|
+
klass.singleton_class.instance_eval do
|
209
|
+
alias_method :"#{method_name}", :"#{method_name}_without_#{suffix}"
|
210
|
+
end
|
211
|
+
elsif instance_method?
|
212
|
+
klass.class_eval do
|
213
|
+
alias_method :"#{method_name}", :"#{method_name}_without_#{suffix}"
|
214
|
+
end
|
215
|
+
end
|
216
|
+
end
|
217
|
+
end
|
218
|
+
end
|
219
|
+
end
|