callstacking-rails 0.1.2 → 0.1.3
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/LICENSE +621 -0
- data/README.md +49 -6
- data/app/assets/config/callstacking_rails_manifest.js +1 -0
- data/app/assets/stylesheets/{checkpoint → callstacking}/rails/application.css +0 -0
- data/app/controllers/{checkpoint → callstacking}/rails/application_controller.rb +1 -1
- data/app/helpers/{checkpoint → callstacking}/rails/application_helper.rb +1 -1
- data/app/jobs/{checkpoint → callstacking}/rails/application_job.rb +1 -1
- data/app/mailers/{checkpoint → callstacking}/rails/application_mailer.rb +1 -1
- data/app/models/{checkpoint → callstacking}/rails/application_record.rb +1 -1
- data/config/routes.rb +1 -1
- data/exe/callstacking-rails +32 -0
- data/lib/{checkpoint → callstacking}/rails/client/authenticate.rb +2 -1
- data/lib/{checkpoint → callstacking}/rails/client/base.rb +3 -3
- data/lib/{checkpoint → callstacking}/rails/client/trace.rb +3 -1
- data/lib/callstacking/rails/engine.rb +49 -0
- data/lib/{checkpoint → callstacking}/rails/env.rb +3 -1
- data/lib/callstacking/rails/instrument.rb +100 -0
- data/lib/callstacking/rails/loader.rb +29 -0
- data/lib/{checkpoint → callstacking}/rails/settings.rb +13 -5
- data/lib/callstacking/rails/setup.rb +115 -0
- data/lib/callstacking/rails/spans.rb +53 -0
- data/lib/callstacking/rails/trace.rb +126 -0
- data/lib/{checkpoint → callstacking}/rails/traces_helper.rb +20 -7
- data/lib/callstacking/rails/version.rb +5 -0
- data/lib/callstacking/rails.rb +7 -0
- metadata +32 -40
- data/MIT-LICENSE +0 -20
- data/app/assets/config/checkpoint_rails_manifest.js +0 -1
- data/app/controllers/checkpoint/rails/traces_controller.rb +0 -6
- data/lib/checkpoint/rails/engine.rb +0 -34
- data/lib/checkpoint/rails/setup.rb +0 -93
- data/lib/checkpoint/rails/traceable.rb +0 -210
- data/lib/checkpoint/rails/version.rb +0 -5
- data/lib/checkpoint/rails.rb +0 -7
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
#
|
1
|
+
# Callstacking::Rails
|
2
2
|
|
3
3
|
Callstacking is a rolling, checkpoint debugger for Rails. It records all of the critical method calls within your app, along with their important context (param/argument/return/local variable values).
|
4
4
|
|
@@ -17,13 +17,13 @@ For method returns ↳, the final values of the local variables will be listed w
|
|
17
17
|
|
18
18
|
Subsequent calls within a method are visibly nested.
|
19
19
|
|
20
|
-
|
20
|
+
Callstacking is a Rails engine that you mount within your Rails app.
|
21
21
|
|
22
22
|
Here's a sample debugging sessions recorded from a Jumpstart Rails based app I've been working on. This is a request for the main page ( https://smartk.id/ ).
|
23
23
|
|
24
24
|

|
25
25
|
|
26
|
-
|
26
|
+
Callstacking Rails records all of the critical method calls within your app, along with their important context (param/argument/return/local variable values).
|
27
27
|
|
28
28
|
All in a rolling panel, so that you can debug your call chains from any point in the stack.
|
29
29
|
|
@@ -42,11 +42,54 @@ And then execute:
|
|
42
42
|
```bash
|
43
43
|
$ bundle
|
44
44
|
```
|
45
|
+
|
46
|
+
Register an account at Callstacking.com
|
47
|
+
```bash
|
48
|
+
callstacking-rails register
|
49
|
+
```
|
50
|
+
|
51
|
+
Authenticate to your newly created account.
|
52
|
+
|
53
|
+
```bash
|
54
|
+
callstacking-rails setup
|
55
|
+
```
|
56
|
+
|
57
|
+
You're now ready to start tracing.
|
45
58
|
|
46
59
|
## Usage
|
47
|
-
|
60
|
+
Usage:
|
61
|
+
|
62
|
+
> callstacking-rails enable
|
63
|
+
|
64
|
+
Enables the callstacking tracing.
|
65
|
+
|
66
|
+
> callstacking-rails disable
|
67
|
+
|
68
|
+
Disables the callstacking tracing.
|
69
|
+
|
70
|
+
> callstacking-rails register
|
71
|
+
|
72
|
+
Opens a browser window to register as a callstacking.com user.
|
73
|
+
|
74
|
+
> callstacking-rails setup
|
75
|
+
|
76
|
+
Interactively prompts you for your callstacking.com username/password.
|
77
|
+
Stores auth details in `~/.callstacking`.
|
78
|
+
|
79
|
+
You can have multiple environments.
|
80
|
+
The default is `development`.
|
81
|
+
|
82
|
+
The `development:` section in the `~/.callstacking` config contains your credentials.
|
83
|
+
|
84
|
+
By setting the RAILS_ENV environment you can maintain multiple settings.
|
85
|
+
|
86
|
+
Questions? Create an issue: https://github.com/callstacking/callstacking-rails/issues
|
87
|
+
|
88
|
+
|
89
|
+
## Trace Output
|
90
|
+
When you open a page for your app, once the page has rendered, you will see an `<<` arrow on the right hand side.
|
48
91
|
|
49
|
-
Click the
|
92
|
+
Click the arrows, and observe the full callstack context.
|
50
93
|
|
51
94
|
## License
|
52
|
-
The gem is available as open source under the terms of the [
|
95
|
+
The gem is available as open source under the terms of the [GPLv3 License](https://www.gnu.org/licenses/gpl-3.0.en.html).
|
@@ -0,0 +1 @@
|
|
1
|
+
//= link_directory ../stylesheets/callstacking/rails .css
|
File without changes
|
data/config/routes.rb
CHANGED
@@ -0,0 +1,32 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "callstacking/rails/setup"
|
5
|
+
require "callstacking/rails/settings"
|
6
|
+
|
7
|
+
include Callstacking::Rails::Settings
|
8
|
+
|
9
|
+
action = ARGV[0]&.downcase&.strip
|
10
|
+
|
11
|
+
if action.nil?
|
12
|
+
Callstacking::Rails::Setup.instructions
|
13
|
+
exit!(1)
|
14
|
+
end
|
15
|
+
|
16
|
+
read_settings
|
17
|
+
|
18
|
+
case action
|
19
|
+
when 'register'
|
20
|
+
`open #{settings.url || Callstacking::Rails::Settings::PRODUCTION_URL}/users/sign_up`
|
21
|
+
|
22
|
+
when 'setup'
|
23
|
+
Callstacking::Rails::Setup.new.start
|
24
|
+
|
25
|
+
when 'enable'
|
26
|
+
Callstacking::Rails::Setup.new.enable_disable
|
27
|
+
puts "Callstacking tracing enabled (#{Callstacking::Rails::Env.environment})"
|
28
|
+
|
29
|
+
when 'disable'
|
30
|
+
Callstacking::Rails::Setup.new.enable_disable(enabled: false)
|
31
|
+
puts "Callstacking tracing disabled (#{Callstacking::Rails::Env.environment})"
|
32
|
+
end
|
@@ -1,14 +1,14 @@
|
|
1
1
|
require 'faraday'
|
2
2
|
require 'faraday/follow_redirects'
|
3
|
-
require "
|
3
|
+
require "callstacking/rails/settings"
|
4
4
|
|
5
|
-
module
|
5
|
+
module Callstacking
|
6
6
|
module Rails
|
7
7
|
module Client
|
8
8
|
class Error < StandardError; end
|
9
9
|
|
10
10
|
class Base
|
11
|
-
include
|
11
|
+
include Callstacking::Rails::Settings
|
12
12
|
|
13
13
|
def initialize
|
14
14
|
read_settings
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require "rails"
|
2
|
+
require "callstacking/rails/trace"
|
3
|
+
require "callstacking/rails/instrument"
|
4
|
+
require 'callstacking/rails/spans'
|
5
|
+
require "callstacking/rails/setup"
|
6
|
+
require "callstacking/rails/settings"
|
7
|
+
require "callstacking/rails/loader"
|
8
|
+
require "callstacking/rails/client/base"
|
9
|
+
require "callstacking/rails/client/authenticate"
|
10
|
+
require "callstacking/rails/client/trace"
|
11
|
+
require "callstacking/rails/traces_helper"
|
12
|
+
|
13
|
+
module Callstacking
|
14
|
+
module Rails
|
15
|
+
class Engine < ::Rails::Engine
|
16
|
+
include Settings
|
17
|
+
isolate_namespace Callstacking::Rails
|
18
|
+
|
19
|
+
read_settings
|
20
|
+
|
21
|
+
spans = Spans.new
|
22
|
+
trace = Trace.new(spans)
|
23
|
+
|
24
|
+
initializer "engine_name.assets.precompile" do |app|
|
25
|
+
app.config.assets.precompile << "checkpoint_rails_manifest.js"
|
26
|
+
end
|
27
|
+
|
28
|
+
initializer 'local_helper.action_controller' do
|
29
|
+
ActiveSupport.on_load :action_controller do
|
30
|
+
helper Callstacking::Rails::TracesHelper
|
31
|
+
include Callstacking::Rails::TracesHelper
|
32
|
+
end
|
33
|
+
|
34
|
+
Callstacking::Rails::Loader.new.on_load(spans) if enabled?
|
35
|
+
end
|
36
|
+
|
37
|
+
initializer :append_before_action do
|
38
|
+
ActionController::Base.send :after_action, :inject_hud
|
39
|
+
end
|
40
|
+
|
41
|
+
if enabled?
|
42
|
+
puts "Callstacking enabled (#{Callstacking::Rails::Env.environment})"
|
43
|
+
trace.tracing
|
44
|
+
else
|
45
|
+
puts "Callstacking disabled (#{Callstacking::Rails::Env.environment})"
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
require 'rails'
|
2
|
+
|
3
|
+
# https://stackoverflow.com/q/52932516
|
4
|
+
module Callstacking
|
5
|
+
module Rails
|
6
|
+
class Instrument
|
7
|
+
attr_accessor :spans, :klass
|
8
|
+
attr_reader :root
|
9
|
+
|
10
|
+
def initialize(spans, klass)
|
11
|
+
@spans = spans
|
12
|
+
@klass = klass
|
13
|
+
@root = Regexp.new(::Rails.root.to_s)
|
14
|
+
end
|
15
|
+
|
16
|
+
def instrument_method(method_name, application_level: true)
|
17
|
+
method_path = (klass.instance_method(method_name).source_location.first rescue nil) ||
|
18
|
+
(klass.method(method_name).source_location.first rescue nil)
|
19
|
+
|
20
|
+
# Application level method definitions
|
21
|
+
return unless method_path =~ root if application_level
|
22
|
+
|
23
|
+
tmp_module = find_or_initialize_module
|
24
|
+
|
25
|
+
return if tmp_module.instance_methods.include?(method_name) ||
|
26
|
+
tmp_module.singleton_methods.include?(method_name)
|
27
|
+
|
28
|
+
tmp_module.define_method(method_name) do |*args, &block|
|
29
|
+
method_name = __method__
|
30
|
+
|
31
|
+
path = method(__method__).super_method.source_location.first
|
32
|
+
line_no = method(__method__).super_method.source_location.last
|
33
|
+
|
34
|
+
p, l = caller.find { |c| c.to_s =~ /#{::Rails.root.to_s}/}&.split(':')
|
35
|
+
|
36
|
+
spans = tmp_module.instance_variable_get(:@spans)
|
37
|
+
klass = tmp_module.instance_variable_get(:@klass)
|
38
|
+
|
39
|
+
arguments = Callstacking::Rails::Instrument.arguments_for(method(__method__).super_method, args)
|
40
|
+
|
41
|
+
spans.call_entry(klass, method_name, arguments, p || path, l || line_no)
|
42
|
+
return_val = super(*args, &block)
|
43
|
+
spans.call_return(klass, method_name, p || path, l || line_no, return_val)
|
44
|
+
|
45
|
+
return_val
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def find_or_initialize_module
|
50
|
+
module_name = "#{klass.name.gsub('::', '')}Span"
|
51
|
+
module_index = klass.ancestors.map(&:to_s).index(module_name)
|
52
|
+
|
53
|
+
unless module_index
|
54
|
+
new_module = Object.const_set(module_name, Module.new)
|
55
|
+
|
56
|
+
new_module.instance_variable_set("@klass", klass)
|
57
|
+
new_module.instance_variable_set("@spans", spans)
|
58
|
+
|
59
|
+
klass.prepend new_module
|
60
|
+
klass.singleton_class.prepend new_module if klass.class == Module
|
61
|
+
|
62
|
+
return find_or_initialize_module
|
63
|
+
end
|
64
|
+
|
65
|
+
klass.ancestors[module_index]
|
66
|
+
end
|
67
|
+
|
68
|
+
def instrument_klass(application_level: true)
|
69
|
+
relevant = all_methods - filtered
|
70
|
+
relevant.each { |method| instrument_method(method, application_level: application_level) }
|
71
|
+
end
|
72
|
+
|
73
|
+
def self.arguments_for(m, args)
|
74
|
+
param_names = m.parameters&.map(&:last)
|
75
|
+
return {} if param_names.nil?
|
76
|
+
|
77
|
+
param_names.map.with_index do |param, index|
|
78
|
+
next if [:&, :*, :**].include?(param)
|
79
|
+
[param, args[index]]
|
80
|
+
end.compact.to_h
|
81
|
+
end
|
82
|
+
|
83
|
+
private
|
84
|
+
|
85
|
+
def all_methods
|
86
|
+
@all_methods ||= (klass.instance_methods +
|
87
|
+
klass.private_instance_methods(false) +
|
88
|
+
klass.protected_instance_methods(false) +
|
89
|
+
klass.methods +
|
90
|
+
klass.singleton_methods).uniq
|
91
|
+
end
|
92
|
+
|
93
|
+
def filtered
|
94
|
+
@filtered ||= (Object.instance_methods + Object.private_instance_methods +
|
95
|
+
Object.protected_instance_methods + Object.methods(false)).uniq
|
96
|
+
end
|
97
|
+
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require "rails"
|
2
|
+
|
3
|
+
module Callstacking
|
4
|
+
module Rails
|
5
|
+
class Loader
|
6
|
+
attr_accessor :loader, :root, :once
|
7
|
+
def initialize
|
8
|
+
@root = Regexp.new(::Rails.root.to_s)
|
9
|
+
end
|
10
|
+
|
11
|
+
def on_load(spans)
|
12
|
+
trace = TracePoint.new(:end) do |tp|
|
13
|
+
klass = tp.self
|
14
|
+
path = tp.path
|
15
|
+
|
16
|
+
Instrument.new(spans, klass).instrument_klass if path =~ root
|
17
|
+
end
|
18
|
+
|
19
|
+
trace.enable
|
20
|
+
|
21
|
+
Instrument.new(spans, ActionView::PartialRenderer).instrument_method(:render,
|
22
|
+
application_level: false)
|
23
|
+
|
24
|
+
Instrument.new(spans, ActionView::TemplateRenderer).instrument_method( :render,
|
25
|
+
application_level: false)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -1,8 +1,8 @@
|
|
1
1
|
require "active_support/concern"
|
2
2
|
require "active_support/core_ext/class/attribute_accessors"
|
3
|
-
require "
|
3
|
+
require "callstacking/rails/env"
|
4
4
|
|
5
|
-
module
|
5
|
+
module Callstacking
|
6
6
|
module Rails
|
7
7
|
module Settings
|
8
8
|
extend ActiveSupport::Concern
|
@@ -11,7 +11,7 @@ module Checkpoint
|
|
11
11
|
attr_accessor :settings
|
12
12
|
end
|
13
13
|
|
14
|
-
SETTINGS_FILE = "#{Dir.home}/.callstacking
|
14
|
+
SETTINGS_FILE = "#{Dir.home}/.callstacking"
|
15
15
|
PRODUCTION_URL = "https://callstacking.com"
|
16
16
|
|
17
17
|
def url
|
@@ -30,8 +30,16 @@ module Checkpoint
|
|
30
30
|
File.write(SETTINGS_FILE, new_settings.to_yaml)
|
31
31
|
end
|
32
32
|
|
33
|
+
def enabled?
|
34
|
+
settings[:enabled]
|
35
|
+
end
|
36
|
+
|
37
|
+
def disabled?
|
38
|
+
!enabled?
|
39
|
+
end
|
40
|
+
|
33
41
|
def read_settings
|
34
|
-
@@settings = @settings = complete_settings.dig(::
|
42
|
+
@@settings = @settings = complete_settings.dig(::Callstacking::Rails::Env.environment, :settings)
|
35
43
|
rescue StandardError => e
|
36
44
|
puts e.full_message
|
37
45
|
puts e.backtrace.join("\n")
|
@@ -39,7 +47,7 @@ module Checkpoint
|
|
39
47
|
end
|
40
48
|
|
41
49
|
def complete_settings
|
42
|
-
YAML.load(File.read(
|
50
|
+
YAML.load(File.read(SETTINGS_FILE)) rescue {}
|
43
51
|
end
|
44
52
|
end
|
45
53
|
end
|
@@ -0,0 +1,115 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
require "callstacking/rails/settings"
|
3
|
+
require "callstacking/rails/client/authenticate"
|
4
|
+
require "callstacking/rails/env"
|
5
|
+
|
6
|
+
module Callstacking
|
7
|
+
module Rails
|
8
|
+
class Setup
|
9
|
+
include ::Callstacking::Rails::Settings
|
10
|
+
extend ::Callstacking::Rails::Settings
|
11
|
+
|
12
|
+
attr_accessor :client
|
13
|
+
|
14
|
+
def initialize
|
15
|
+
read_settings
|
16
|
+
end
|
17
|
+
|
18
|
+
def client
|
19
|
+
@client = Callstacking::Rails::Client::Authenticate.new
|
20
|
+
end
|
21
|
+
|
22
|
+
def start
|
23
|
+
email = prompt("Enter email:")
|
24
|
+
password = prompt("Enter password:")
|
25
|
+
|
26
|
+
url = if Callstacking::Rails::Env.production? && ENV['CHECKPOINT_RAILS_LOCAL_TEST'].nil?
|
27
|
+
PRODUCTION_URL
|
28
|
+
else
|
29
|
+
prompt("Enter URL for #{Callstacking::Rails::Env.environment} API calls [#{PRODUCTION_URL}]:") || PRODUCTION_URL
|
30
|
+
end
|
31
|
+
|
32
|
+
save(email, password, url)
|
33
|
+
|
34
|
+
puts "Authentication successful."
|
35
|
+
puts "Settings saved to #{SETTINGS_FILE}"
|
36
|
+
rescue StandardError => e
|
37
|
+
puts "Problem authenticating: #{e.message}"
|
38
|
+
end
|
39
|
+
|
40
|
+
def enable_disable(enabled: true)
|
41
|
+
settings[:enabled] = enabled
|
42
|
+
|
43
|
+
props = { Callstacking::Rails::Env.environment => {
|
44
|
+
settings: settings
|
45
|
+
} }
|
46
|
+
|
47
|
+
write_settings(complete_settings.merge(props))
|
48
|
+
end
|
49
|
+
|
50
|
+
def prompt(label)
|
51
|
+
puts label
|
52
|
+
value = STDIN.gets.chomp
|
53
|
+
puts
|
54
|
+
|
55
|
+
return nil if value == ''
|
56
|
+
value
|
57
|
+
end
|
58
|
+
|
59
|
+
def token(email, password)
|
60
|
+
client.login(email, password)
|
61
|
+
end
|
62
|
+
|
63
|
+
def save(email, password, url)
|
64
|
+
props = { auth_token: '',
|
65
|
+
url: url,
|
66
|
+
enabled: true
|
67
|
+
}
|
68
|
+
|
69
|
+
props = { Callstacking::Rails::Env.environment => {
|
70
|
+
settings: props
|
71
|
+
} }
|
72
|
+
|
73
|
+
write_settings(complete_settings.merge(props))
|
74
|
+
|
75
|
+
props[Callstacking::Rails::Env.environment][:settings][:auth_token] = token(email, password)
|
76
|
+
|
77
|
+
write_settings(complete_settings.merge(props))
|
78
|
+
|
79
|
+
read_settings
|
80
|
+
end
|
81
|
+
|
82
|
+
def self.instructions
|
83
|
+
read_settings
|
84
|
+
puts "loading environment #{Callstacking::Rails::Env.environment}"
|
85
|
+
puts
|
86
|
+
puts "Usage: "
|
87
|
+
puts
|
88
|
+
puts " > callstacking-rails enable"
|
89
|
+
puts
|
90
|
+
puts " Enables the callstacking tracing."
|
91
|
+
puts
|
92
|
+
puts " > callstacking-rails disable"
|
93
|
+
puts
|
94
|
+
puts " Disables the callstacking tracing."
|
95
|
+
puts
|
96
|
+
puts " > callstacking-rails register"
|
97
|
+
puts
|
98
|
+
puts " Opens a browser window to register as a callstacking.com user."
|
99
|
+
puts
|
100
|
+
puts " > callstacking-rails setup"
|
101
|
+
puts
|
102
|
+
puts " Interactively prompts you for your callstacking.com username/password."
|
103
|
+
puts " Stores auth details in #{SETTINGS_FILE}"
|
104
|
+
puts
|
105
|
+
puts " You can have multiple environments."
|
106
|
+
puts " The default is #{Callstacking::Rails::Env::DEFAULT_ENVIRONMENT}."
|
107
|
+
puts
|
108
|
+
puts " The #{Callstacking::Rails::Env.environment}: section in the #{SETTINGS_FILE} contains your credentials."
|
109
|
+
puts " By setting the RAILS_ENV environment you can maintain multiple settings."
|
110
|
+
puts
|
111
|
+
puts "Questions? Create an issue: https://github.com/callstacking/callstacking-rails/issues"
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
module Callstacking
|
2
|
+
module Rails
|
3
|
+
class Spans
|
4
|
+
attr_accessor :order_num, :nesting_level, :previous_entry
|
5
|
+
attr_accessor :call_entry_callback, :call_return_callback
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@nesting_level = -1
|
9
|
+
@order_num = -1
|
10
|
+
@previous_entry = nil
|
11
|
+
end
|
12
|
+
|
13
|
+
def increment_order_num
|
14
|
+
@order_num+=1
|
15
|
+
@order_num
|
16
|
+
end
|
17
|
+
|
18
|
+
def increment_nesting_level
|
19
|
+
@nesting_level+=1
|
20
|
+
@nesting_level
|
21
|
+
end
|
22
|
+
|
23
|
+
def call_entry(klass, method_name, arguments, path, line_no)
|
24
|
+
@nesting_level+=1
|
25
|
+
@previous_entry = previous_event(klass, method_name)
|
26
|
+
@call_entry_callback.call(@nesting_level, increment_order_num, klass, method_name, arguments, path, line_no)
|
27
|
+
end
|
28
|
+
|
29
|
+
def call_return(klass, method_name, path, line_no, return_val)
|
30
|
+
@call_return_callback.call(coupled_callee(klass, method_name), @nesting_level,
|
31
|
+
increment_order_num, klass, method_name, path, line_no, return_val)
|
32
|
+
@nesting_level-=1
|
33
|
+
end
|
34
|
+
|
35
|
+
def on_call_entry(&block)
|
36
|
+
@call_entry_callback = block
|
37
|
+
end
|
38
|
+
|
39
|
+
def on_call_return(&block)
|
40
|
+
@call_return_callback = block
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
def previous_event(klass, method_name)
|
45
|
+
"#{klass}:#{method_name}"
|
46
|
+
end
|
47
|
+
|
48
|
+
def coupled_callee(klass, method_name)
|
49
|
+
previous_entry == previous_event(klass, method_name)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|