source_route 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +2 -1
- data/examples/study_callback.rb +1 -1
- data/lib/source_route.rb +16 -29
- data/lib/source_route/config.rb +123 -0
- data/lib/source_route/formats/html.rb +7 -7
- data/lib/source_route/formats/html_semantic.slim +12 -12
- data/lib/source_route/generate_result.rb +9 -80
- data/lib/source_route/proxy.rb +36 -0
- data/lib/source_route/tp_filter.rb +7 -6
- data/lib/source_route/tp_result.rb +12 -34
- data/lib/source_route/tp_result_chain.rb +0 -14
- data/lib/source_route/version.rb +1 -1
- data/test/source_route/config_test.rb +86 -0
- data/test/source_route/proxy_test.rb +10 -0
- data/test/source_route/tp_filter_test.rb +12 -6
- data/test/source_route_test.rb +39 -39
- metadata +8 -5
- data/lib/source_route/wrapper.rb +0 -112
- data/test/source_route/wrapper_test.rb +0 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c2fa5c78d22ad8c809c220b45e5d7940fdbe9f84
|
4
|
+
data.tar.gz: f9ff7bcf3f5cb8e116b3dc0023a677aa2e434677
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d13bafaf3a17ffdc98aeb9491d2cf15c3f05dc140bacc769f4a82a45fbd5143df729b0e1097e63a3939a0330f388ac01d4da1c6fcd6a6a5c06c79d9d57a26286
|
7
|
+
data.tar.gz: 2d4c883291edd2c76e33ae293a99e4046b066fbd3b5194f69ef2fae2504cc685adc0ee786d4dea71f3abc93d9e09c4cf327edd109ac6e1158adfb277fd0dd623
|
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# SourceRoute
|
2
2
|
|
3
|
-
|
3
|
+
Trace ruby code
|
4
4
|
|
5
5
|
## Dependency
|
6
6
|
|
@@ -40,6 +40,7 @@ you will get a different trace file.
|
|
40
40
|
SourceRoute.enable do
|
41
41
|
method_id :wanted_method_name
|
42
42
|
full_feature
|
43
|
+
filename 'tmp/capture_wanted.html'
|
43
44
|
end
|
44
45
|
.... # here is your code
|
45
46
|
....
|
data/examples/study_callback.rb
CHANGED
@@ -5,7 +5,7 @@ require 'source_route'
|
|
5
5
|
SourceRoute.enable do
|
6
6
|
method_id 'base_decorate', 'prepare_decorate'
|
7
7
|
defined_class 'ActiveSupport::Callbacks', 'House', 'Filters'
|
8
|
-
|
8
|
+
filename = 'trace_callback.html'
|
9
9
|
full_feature 10
|
10
10
|
end
|
11
11
|
|
data/lib/source_route.rb
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
require 'ostruct'
|
2
|
-
require 'logger'
|
3
2
|
require 'singleton'
|
4
3
|
require 'forwardable'
|
5
4
|
require 'oj'
|
@@ -7,7 +6,8 @@ require 'awesome_print'
|
|
7
6
|
|
8
7
|
require "source_route/core_ext"
|
9
8
|
require "source_route/version"
|
10
|
-
require "source_route/
|
9
|
+
require "source_route/config"
|
10
|
+
require "source_route/proxy"
|
11
11
|
require "source_route/jsonify"
|
12
12
|
require "source_route/generate_result"
|
13
13
|
require "source_route/tp_result"
|
@@ -18,7 +18,7 @@ require 'source_route/json_overrides/activerecord_associations_association'
|
|
18
18
|
begin
|
19
19
|
if Rails
|
20
20
|
ActiveSupport.on_load(:after_initialize, yield: true) do
|
21
|
-
# make it respond to to_s.
|
21
|
+
# make it respond to to_s. In rails source, almost all of its methods are removed, including to_s.
|
22
22
|
module ActiveSupport
|
23
23
|
class OptionMerger
|
24
24
|
def to_s
|
@@ -35,51 +35,38 @@ end
|
|
35
35
|
module SourceRoute
|
36
36
|
extend self
|
37
37
|
|
38
|
-
def
|
39
|
-
@@
|
38
|
+
def proxy
|
39
|
+
@@proxy ||= Proxy.instance
|
40
40
|
end
|
41
41
|
|
42
42
|
def reset
|
43
|
-
|
43
|
+
proxy.reset
|
44
44
|
end
|
45
45
|
|
46
46
|
def disable
|
47
|
-
|
47
|
+
proxy.tp.disable
|
48
48
|
end
|
49
49
|
|
50
50
|
def enable(match = nil, &block)
|
51
|
-
|
51
|
+
proxy.reset
|
52
52
|
|
53
|
-
|
54
|
-
wrapper.condition.method_id(match)
|
55
|
-
wrapper.condition.defined_class(match)
|
56
|
-
end
|
57
|
-
|
58
|
-
wrapper.condition.instance_eval(&block) if block_given?
|
53
|
+
proxy.config = BlockConfigParser.new.run(match, &block)
|
59
54
|
|
60
|
-
|
55
|
+
proxy.trace
|
61
56
|
end
|
62
57
|
|
63
58
|
def trace(opt, &block)
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
wrapper.condition.send(k, v)
|
68
|
-
end
|
69
|
-
|
70
|
-
wrapper.trace
|
59
|
+
proxy.reset
|
60
|
+
proxy.config = ParamsConfigParser.run(opt)
|
61
|
+
proxy.trace
|
71
62
|
yield
|
72
|
-
|
73
|
-
SourceRoute.output_html if
|
63
|
+
proxy.tp.disable
|
64
|
+
SourceRoute.output_html if proxy.config.output_format == :html
|
74
65
|
end
|
75
66
|
|
76
67
|
def output_html
|
77
68
|
SourceRoute.disable
|
78
|
-
SourceRoute::Formats::Html.slim_render(
|
79
|
-
end
|
80
|
-
|
81
|
-
# Not implement yet
|
82
|
-
class Logger < Logger
|
69
|
+
SourceRoute::Formats::Html.slim_render(proxy)
|
83
70
|
end
|
84
71
|
|
85
72
|
module Formats
|
@@ -0,0 +1,123 @@
|
|
1
|
+
module SourceRoute
|
2
|
+
TP_FILTER = [:defined_class, :method_id, :path, :lineno].freeze
|
3
|
+
TP_FILTER_METHODS = (TP_FILTER + TP_FILTER.map { |tpf| "#{tpf}_not".to_sym }).freeze
|
4
|
+
|
5
|
+
class Config
|
6
|
+
|
7
|
+
DIRECT_ATTRS = [:event, :full_feature, :debug,
|
8
|
+
:output_format, :show_additional_attrs,
|
9
|
+
:filename, :include_local_var, :include_instance_var,
|
10
|
+
:import_return_to_call
|
11
|
+
]
|
12
|
+
|
13
|
+
attr_accessor *DIRECT_ATTRS
|
14
|
+
attr_accessor :negatives, :positives
|
15
|
+
|
16
|
+
def initialize
|
17
|
+
@event = [:call]
|
18
|
+
@output_format = :test
|
19
|
+
@positives = {}
|
20
|
+
@negatives = {}
|
21
|
+
end
|
22
|
+
|
23
|
+
# mutable method
|
24
|
+
def formulize
|
25
|
+
symbolize_output_format
|
26
|
+
event_becomes_array
|
27
|
+
self
|
28
|
+
end
|
29
|
+
|
30
|
+
def symbolize_output_format
|
31
|
+
self.output_format = output_format.to_sym if output_format.respond_to? :to_sym
|
32
|
+
end
|
33
|
+
|
34
|
+
def event_becomes_array
|
35
|
+
self.event = Array(event).map(&:to_sym)
|
36
|
+
end
|
37
|
+
|
38
|
+
def has_call_and_return_event
|
39
|
+
event.include? :return and event.include? :call
|
40
|
+
end
|
41
|
+
end # END Config
|
42
|
+
|
43
|
+
class BlockConfigParser
|
44
|
+
attr_accessor :ret_params
|
45
|
+
|
46
|
+
def initialize
|
47
|
+
@ret_params = {}
|
48
|
+
end
|
49
|
+
|
50
|
+
def run(match_str = nil, &block)
|
51
|
+
unless match_str.nil?
|
52
|
+
ret_params[:defined_class] = match_str
|
53
|
+
ret_params[:method_id] = match_str
|
54
|
+
end
|
55
|
+
instance_eval(&block) if block_given?
|
56
|
+
ParamsConfigParser.run(@ret_params)
|
57
|
+
end
|
58
|
+
|
59
|
+
Config::DIRECT_ATTRS.each do |attr|
|
60
|
+
define_method attr do |v=true|
|
61
|
+
ret_params[attr] = v
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
# override
|
66
|
+
[:event, :show_additional_attrs].each do |attr|
|
67
|
+
define_method attr do |*v|
|
68
|
+
ret_params[attr] = v unless v == []
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
# override
|
73
|
+
def output_format(data = nil, &block)
|
74
|
+
ret_params[:output_format] = block_given? ? block : data
|
75
|
+
end
|
76
|
+
|
77
|
+
TP_FILTER_METHODS.each do |m|
|
78
|
+
define_method m do |*v|
|
79
|
+
ret_params[m] = v
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
end # END BlockConfigParser
|
84
|
+
|
85
|
+
module ParamsConfigParser
|
86
|
+
extend self
|
87
|
+
|
88
|
+
TP_FILTER.each do |m|
|
89
|
+
define_method m do |v|
|
90
|
+
@config.positives[m] = Array(v).flatten.map(&:to_s).join('|')
|
91
|
+
end
|
92
|
+
|
93
|
+
define_method "#{m}_not" do |*v|
|
94
|
+
@config.negatives[m] = Array(v).flatten.map(&:to_s).join('|')
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def run(params)
|
99
|
+
@config = Config.new
|
100
|
+
params.each do |k, v|
|
101
|
+
@config.send("#{k}=", v) if Config::DIRECT_ATTRS.include? k.to_sym
|
102
|
+
send(k, v) if (TP_FILTER_METHODS + [:full_feature]).include? k.to_sym
|
103
|
+
end
|
104
|
+
@config.formulize
|
105
|
+
end
|
106
|
+
|
107
|
+
# todo. value equal 10 may not be a good params
|
108
|
+
def full_feature(value=true)
|
109
|
+
return unless value
|
110
|
+
@config.formulize
|
111
|
+
@config.event = (@config.event + [:call, :return]).uniq
|
112
|
+
@config.import_return_to_call = true
|
113
|
+
@config.show_additional_attrs = [:path, :lineno]
|
114
|
+
# JSON serialize trigger many problems when handle complicated object(in rails?)
|
115
|
+
# a Back Door to open more data. but be care it could trigger weird crash when Jsonify these vars
|
116
|
+
if value == 10
|
117
|
+
@config.include_instance_var = true
|
118
|
+
@config.include_local_var = true
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end # END ParamsConfigParser
|
122
|
+
|
123
|
+
end
|
@@ -5,19 +5,19 @@ module SourceRoute
|
|
5
5
|
module Formats
|
6
6
|
module Html
|
7
7
|
|
8
|
-
def self.slim_render(
|
9
|
-
|
8
|
+
def self.slim_render(proxy)
|
9
|
+
|
10
10
|
template_path = File.expand_path "../html_semantic.slim", __FILE__
|
11
11
|
slim_template = Slim::Template.new(template_path, pretty: true)
|
12
12
|
|
13
|
-
filename =
|
13
|
+
filename = proxy.config.filename || "#{Time.now.strftime('%H')}-source-route.html"
|
14
14
|
|
15
|
-
if
|
16
|
-
|
17
|
-
|
15
|
+
if proxy.config.import_return_to_call and proxy.config.has_call_and_return_event
|
16
|
+
proxy.result_builder.import_return_value_to_call_chain
|
17
|
+
proxy.result_builder.treeize_call_chain
|
18
18
|
end
|
19
19
|
# TODO: any exception triggered in render method will be absorb totally, how to fix it?
|
20
|
-
html_output_str = slim_template.render(
|
20
|
+
html_output_str = slim_template.render(proxy.result_builder)
|
21
21
|
File.open(filename, 'w') do |f|
|
22
22
|
f << html_output_str
|
23
23
|
end
|
@@ -4,12 +4,12 @@ html
|
|
4
4
|
title Source Route Result
|
5
5
|
link rel="stylesheet" href="https://cdn.rawgit.com/Urigo/angular-spinkit/master/build/angular-spinkit.min.css"
|
6
6
|
link rel="stylesheet" href="https://cdn.rawgit.com/mohsen1/json-formatter/master/dist/json-formatter.css"
|
7
|
-
link rel="stylesheet" href="http://oss.maxcdn.com/semantic-ui/2.
|
7
|
+
link rel="stylesheet" href="http://oss.maxcdn.com/semantic-ui/2.1.4/semantic.min.css"
|
8
8
|
|
9
9
|
script async=true src="http://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.10.0/lodash.js"
|
10
10
|
script src="http://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.4/jquery.min.js"
|
11
|
-
script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.
|
12
|
-
script async=true src="http://oss.maxcdn.com/semantic-ui/2.
|
11
|
+
script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.6/angular.min.js"
|
12
|
+
script async=true src="http://oss.maxcdn.com/semantic-ui/2.1.4/semantic.min.js"
|
13
13
|
|
14
14
|
css:
|
15
15
|
.call-level-0 {}
|
@@ -42,7 +42,7 @@ html
|
|
42
42
|
.right.menu
|
43
43
|
.item
|
44
44
|
span Trace Count
|
45
|
-
.ui.teal.pointing.
|
45
|
+
.ui.teal.left.pointing.label(ng-bind="currentCounter()")
|
46
46
|
|
47
47
|
.ui.container
|
48
48
|
.row
|
@@ -57,11 +57,11 @@ html
|
|
57
57
|
/ workaround for return_value is 'false' and return_value always to be string when existed
|
58
58
|
.meta(ng-if="trace.hasOwnProperty('return_value')")
|
59
59
|
i.icon.pointing.right.small
|
60
|
-
json-formatter(open="1" json="::trace.return_value")
|
60
|
+
json-formatter(open="1" json="::trace.return_value" style="display: inline-block")
|
61
61
|
.description
|
62
62
|
.ui.vertical.buttons.basic
|
63
63
|
button.ui.labeled.icon.button(ng-show="::containsDetail(trace)" ng-click="showMoreDetail = !showMoreDetail")
|
64
|
-
i.
|
64
|
+
i.browser.icon
|
65
65
|
span Details
|
66
66
|
button.ui.labeled.icon.button(ng-if="::hasChild()" ng-click="toggleChild()" ng-class="{loading: togglingChild}")
|
67
67
|
i.icon.angle.down(ng-show="trace.childOpened")
|
@@ -71,20 +71,20 @@ html
|
|
71
71
|
|
72
72
|
.details.right.floated(ng-if="showMoreDetail")
|
73
73
|
.ui.segments(style="border-color: blue")
|
74
|
+
.ui.segment(ng-if="::trace.params_var")
|
75
|
+
.ui.teal.right.ribbon.label Parameters
|
76
|
+
json-formatter(open="1" json="::trace.params_var")
|
74
77
|
.ui.segment(ng-if="::trace.hasOwnProperty('return_value')")
|
75
78
|
.ui.grey.right.ribbon.label Return Value
|
76
79
|
json-formatter(json="::trace.return_value")
|
77
80
|
.ui.segment(ng-if="::containsOtherAttrs(trace)")
|
78
|
-
.ui.orange.right.ribbon.label Trace
|
81
|
+
.ui.orange.right.ribbon.label Trace Attributes
|
79
82
|
json-formatter(open="1" json="::plusTraceAttrs[trace.order_id]")
|
80
|
-
.ui.segment(ng-if="::trace.params_var")
|
81
|
-
.ui.teal.right.ribbon.label Params Var
|
82
|
-
json-formatter(open="1" json="::trace.params_var")
|
83
83
|
.ui.segment(ng-if="::trace.local_var")
|
84
|
-
.ui.teal.right.ribbon.label Local
|
84
|
+
.ui.teal.right.ribbon.label Local Variables
|
85
85
|
json-formatter(open="1" json="::trace.local_var")
|
86
86
|
.ui.segment(ng-if="::trace.instance_var")
|
87
|
-
.ui.blue.right.ribbon.label Instance
|
87
|
+
.ui.blue.right.ribbon.label Instance Variables
|
88
88
|
json-formatter(open="1" json="::trace.instance_var")
|
89
89
|
|
90
90
|
script src="https://cdn.rawgit.com/Urigo/angular-spinkit/master/build/angular-spinkit.min.js"
|
@@ -11,16 +11,7 @@ module SourceRoute
|
|
11
11
|
attr_reader :tp_result_chain, :tp_self_caches, :collected_data
|
12
12
|
|
13
13
|
extend Forwardable
|
14
|
-
|
15
|
-
def_delegators :@tp_result_chain, :import_return_value_to_call_chain, :treeize_call_chain, :call_chain, :return_chain, :parent_length_list
|
16
|
-
|
17
|
-
Config = Struct.new(:format, :show_additional_attrs,
|
18
|
-
:include_local_var, :include_instance_var,
|
19
|
-
:filename, :import_return_to_call) do
|
20
|
-
def initialize(f=:test, s=[], ilr=false, iiv=false)
|
21
|
-
super(f, s, ilr, iiv)
|
22
|
-
end
|
23
|
-
end
|
14
|
+
def_delegators :@tp_result_chain, :import_return_value_to_call_chain, :treeize_call_chain
|
24
15
|
|
25
16
|
# see event description in TracePoint API Doc
|
26
17
|
DEFAULT_ATTRS = {
|
@@ -39,22 +30,17 @@ module SourceRoute
|
|
39
30
|
thread_end: [:defined_class, :method_id]
|
40
31
|
}
|
41
32
|
|
42
|
-
def initialize(
|
43
|
-
@
|
44
|
-
|
45
|
-
@config = @wrapper.condition.result_config
|
46
|
-
|
33
|
+
def initialize(proxy)
|
34
|
+
@proxy = proxy
|
47
35
|
@tp_result_chain = TpResultChain.new
|
48
|
-
|
49
36
|
@tp_self_caches = []
|
50
|
-
@wanted_attributes = {}
|
51
37
|
end
|
52
38
|
|
53
39
|
# it cached and only calculate once for one trace point block round
|
54
40
|
def self.wanted_attributes(eve)
|
55
41
|
event = eve.to_sym
|
56
42
|
@wanted_attributes.fetch event do
|
57
|
-
attrs = DEFAULT_ATTRS[event] + Array(SourceRoute.
|
43
|
+
attrs = DEFAULT_ATTRS[event] + Array(SourceRoute.proxy.config.show_additional_attrs)
|
58
44
|
attrs.push(:event)
|
59
45
|
@wanted_attributes[event] = attrs.uniq
|
60
46
|
@wanted_attributes[event]
|
@@ -66,21 +52,18 @@ module SourceRoute
|
|
66
52
|
end
|
67
53
|
|
68
54
|
def output(tp_ins)
|
69
|
-
format = @config.
|
70
|
-
format = format.to_sym if format.respond_to? :to_sym
|
55
|
+
format = @proxy.config.output_format
|
71
56
|
|
72
57
|
assign_tp_self_caches(tp_ins)
|
73
58
|
# we cant call method on tp_ins outside of track block,
|
74
59
|
# so we have to run it immediately
|
75
|
-
|
76
60
|
@collected_data = TpResult.new(tp_ins)
|
77
|
-
|
78
61
|
case format
|
79
62
|
when :console
|
80
63
|
console_put(tp_ins)
|
81
64
|
when :html
|
82
|
-
# we cant generate html right now becase the tp
|
83
|
-
# so we
|
65
|
+
# we cant generate html right now becase the tp callback is still in process
|
66
|
+
# so we gather data into array
|
84
67
|
@tp_result_chain.push(TpResult.new(tp_ins))
|
85
68
|
when :silence, :none
|
86
69
|
# do nothing at now
|
@@ -92,26 +75,10 @@ module SourceRoute
|
|
92
75
|
format.call(tp_ins)
|
93
76
|
else
|
94
77
|
klass = "SourceRoute::Formats::#{format.to_s.capitalize}"
|
95
|
-
::SourceRoute.const_get(klass).render(self, tp_ins)
|
78
|
+
::SourceRoute.const_get(klass).render(self, tp_ins, @collected_data)
|
96
79
|
end
|
97
80
|
end
|
98
81
|
|
99
|
-
# def build(trace_point_instance)
|
100
|
-
# TpResult.new(trace_point_instance)
|
101
|
-
# # tp_result.collect_self
|
102
|
-
|
103
|
-
# # @tp = trace_point_instance
|
104
|
-
# # collect_tp_data
|
105
|
-
# # collect_tp_self # NEED more check. Does TracePoint support self for all events?
|
106
|
-
# # collect_local_var_data if @config[:include_local_var]
|
107
|
-
# # collect_instance_var_data if @config[:include_instance_var]
|
108
|
-
# # @collected_data
|
109
|
-
# end
|
110
|
-
|
111
|
-
# def collect_tp_result
|
112
|
-
# tp_result = TpResult.new(tp)
|
113
|
-
# end
|
114
|
-
|
115
82
|
# include? will evaluate @tp.self, if @tp.self is AR::Relation, it could cause problems
|
116
83
|
# So that's why I use object_id as replace
|
117
84
|
def assign_tp_self_caches(tp_ins)
|
@@ -121,7 +88,7 @@ module SourceRoute
|
|
121
88
|
end
|
122
89
|
|
123
90
|
def jsonify_events
|
124
|
-
Oj.dump(@
|
91
|
+
Oj.dump(@proxy.config.event.map(&:to_s))
|
125
92
|
end
|
126
93
|
|
127
94
|
def jsonify_tp_result_chain
|
@@ -138,44 +105,6 @@ module SourceRoute
|
|
138
105
|
|
139
106
|
private
|
140
107
|
|
141
|
-
# def collect_tp_data
|
142
|
-
# tp_data = wanted_attributes(@tp.event).inject({}) do |memo, key|
|
143
|
-
# memo[key.to_sym] = @tp.send(key) if @tp.respond_to?(key)
|
144
|
-
# memo
|
145
|
-
# end
|
146
|
-
# @collected_data = TpResult.new(tp_data)
|
147
|
-
# puts @collected_data.inspect if @wrapper.condition.is_debug?
|
148
|
-
# end
|
149
|
-
|
150
|
-
# def collect_tp_self(tp)
|
151
|
-
# unless tp_self_caches.find { |tp_cache| tp_cache.object_id.equal? tp.self.object_id }
|
152
|
-
# tp_self_caches.push tp.self
|
153
|
-
# end
|
154
|
-
# @collected_data[:tp_self_refer] = tp_self_caches.map(&:__id__).index(tp.self.__id__)
|
155
|
-
# end
|
156
|
-
|
157
|
-
# def collect_local_var_data
|
158
|
-
# local_var_hash = {}
|
159
|
-
# # Warn: @tp.binding.eval('local_variables') =! @tp.binding.send('local_variables')
|
160
|
-
# @tp.binding.eval('local_variables').each do |v|
|
161
|
-
# # I need rememeber why i need source_route_display
|
162
|
-
# local_var_hash[v] = @tp.binding.local_variable_get(v).source_route_display
|
163
|
-
# end
|
164
|
-
# if local_var_hash != {}
|
165
|
-
# @collected_data.merge!(local_var: local_var_hash)
|
166
|
-
# end
|
167
|
-
# end
|
168
|
-
|
169
|
-
# def collect_instance_var_data
|
170
|
-
# instance_var_hash = {}
|
171
|
-
# @tp.self.instance_variables.each do |key|
|
172
|
-
# instance_var_hash[key] = @tp.self.instance_variable_get(key).source_route_display
|
173
|
-
# end
|
174
|
-
# if instance_var_hash != {}
|
175
|
-
# @collected_data.merge!(instance_var: instance_var_hash)
|
176
|
-
# end
|
177
|
-
# end
|
178
|
-
|
179
108
|
def console_put(tp)
|
180
109
|
ret = []
|
181
110
|
ret << "#{collected_data.defined_class.inspect}##{collected_data.method_id}"
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module SourceRoute
|
2
|
+
|
3
|
+
class Proxy # todo Rename it to Proxy
|
4
|
+
include Singleton
|
5
|
+
|
6
|
+
attr_accessor :config, :tp, :result_builder
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
reset
|
10
|
+
end
|
11
|
+
|
12
|
+
def reset
|
13
|
+
@tp.disable if defined? @tp
|
14
|
+
@config = Config.new
|
15
|
+
# only init once, so its @collected_data seems not useful
|
16
|
+
@result_builder = GenerateResult.new(self)
|
17
|
+
GenerateResult.clear_wanted_attributes
|
18
|
+
self
|
19
|
+
end
|
20
|
+
|
21
|
+
def trace
|
22
|
+
tp_filter = TpFilter.new(config)
|
23
|
+
track = TracePoint.new(*config.event) do |tp|
|
24
|
+
next if tp_filter.block_it?(tp)
|
25
|
+
@result_builder.output(tp)
|
26
|
+
end
|
27
|
+
track.enable
|
28
|
+
self.tp = track
|
29
|
+
end
|
30
|
+
|
31
|
+
def tp_result_chain
|
32
|
+
result_builder.tp_result_chain
|
33
|
+
end
|
34
|
+
end # END Proxy
|
35
|
+
|
36
|
+
end
|
@@ -1,26 +1,27 @@
|
|
1
1
|
module SourceRoute
|
2
2
|
|
3
3
|
class TpFilter
|
4
|
+
attr_accessor :cond
|
4
5
|
def initialize(condition)
|
5
|
-
@
|
6
|
+
@cond = condition
|
6
7
|
end
|
7
8
|
|
8
9
|
# to improve performance, we didnt assign tp as instance variable
|
9
10
|
def block_it?(tp)
|
10
11
|
return true if negative_check(tp)
|
11
|
-
return false if
|
12
|
+
return false if positives_check(tp)
|
12
13
|
true
|
13
14
|
end
|
14
15
|
|
15
16
|
def negative_check(tp)
|
16
|
-
|
17
|
+
cond.negatives.any? do |method_key, value|
|
17
18
|
tp.send(method_key).to_s =~ Regexp.new(value)
|
18
19
|
end
|
19
20
|
end
|
20
21
|
|
21
|
-
def
|
22
|
-
return true if
|
23
|
-
|
22
|
+
def positives_check(tp)
|
23
|
+
return true if cond.positives == {}
|
24
|
+
cond.positives.any? do |method_key, value|
|
24
25
|
tp.send(method_key).to_s =~ Regexp.new(value)
|
25
26
|
end
|
26
27
|
end
|
@@ -10,19 +10,18 @@ module SourceRoute
|
|
10
10
|
INNER_ATTRS = [:local_var, :instance_var, :params_var].freeze
|
11
11
|
attr_accessor *INNER_ATTRS
|
12
12
|
|
13
|
-
# customized attrs
|
13
|
+
# customized attrs for build html output
|
14
14
|
CUSTOM_ATTRS = [:order_id, :parent_ids, :direct_child_order_ids,
|
15
15
|
:has_return_value, :parent_length, :tp_self_refer].freeze
|
16
16
|
attr_accessor *CUSTOM_ATTRS
|
17
17
|
|
18
|
-
# extend Forwardable
|
19
|
-
# def_delegators :@ret_data, :[], :merge, :merge!, :reject, :has_key?, :values, :[]=
|
20
|
-
|
21
18
|
# The tricky part is
|
22
|
-
#
|
19
|
+
# can't call method on @tp_ins outside trace block finished
|
20
|
+
# it could be a security limitation in ruby TracePoint object
|
21
|
+
# so collect_required_data can only run once and immediately
|
23
22
|
def initialize(tp_ins)
|
24
|
-
@tp_ins = tp_ins
|
25
|
-
collect_required_data
|
23
|
+
@tp_ins = tp_ins
|
24
|
+
collect_required_data
|
26
25
|
end
|
27
26
|
|
28
27
|
def found_opposite
|
@@ -57,16 +56,13 @@ module SourceRoute
|
|
57
56
|
call_tp.instance_var = instance_var unless instance_var.nil?
|
58
57
|
end
|
59
58
|
|
60
|
-
# to_hash
|
61
|
-
# why we need wrapper?
|
62
|
-
# it's nonsense
|
63
59
|
def to_hash
|
64
60
|
stringify
|
65
61
|
ret_hash = GenerateResult.wanted_attributes(event).inject({}) do |memo, k|
|
66
62
|
memo[k.to_s] = send(k)
|
67
63
|
memo
|
68
64
|
end
|
69
|
-
if SourceRoute.
|
65
|
+
if SourceRoute.proxy.config.event.include?(:return)
|
70
66
|
ret_hash['return_value'] = return_value.nil? ? return_value.inspect : return_value
|
71
67
|
end
|
72
68
|
(INNER_ATTRS + CUSTOM_ATTRS).each do |k|
|
@@ -75,16 +71,7 @@ module SourceRoute
|
|
75
71
|
ret_hash
|
76
72
|
end
|
77
73
|
|
78
|
-
#
|
79
|
-
# # why dup it?
|
80
|
-
# # dup_core = ret_data.dup
|
81
|
-
# # to_s is safer than inspect
|
82
|
-
# # ex: inspect on ActiveRecord_Relation may crash
|
83
|
-
# ret_data[:defined_class] = ret_data[:defined_class].to_s if ret_data.has_key?(:defined_class)
|
84
|
-
# ret_data[:return_value] = ret_data[:return_value].source_route_display if ret_data.has_key?(:return_value)
|
85
|
-
# end
|
86
|
-
|
87
|
-
# this is a mutable method
|
74
|
+
# todo: this is a mutable method
|
88
75
|
# not a good solution.
|
89
76
|
# we should use it on the return hash of method to_hash
|
90
77
|
def stringify
|
@@ -109,30 +96,21 @@ module SourceRoute
|
|
109
96
|
get_attrs
|
110
97
|
get_self_refer
|
111
98
|
|
112
|
-
get_local_or_params_var if SourceRoute.
|
113
|
-
get_instance_var if SourceRoute.
|
99
|
+
get_local_or_params_var if SourceRoute.proxy.config.include_local_var
|
100
|
+
get_instance_var if SourceRoute.proxy.config.include_instance_var and return_event?
|
114
101
|
self
|
115
102
|
end
|
116
103
|
|
117
|
-
# Becare. we cal @tp_ins.event here
|
118
|
-
# but in stringify method we jsut call event
|
119
104
|
def get_attrs
|
120
|
-
|
121
|
-
@tp_ins.event).each do |key|
|
105
|
+
GenerateResult.wanted_attributes(@tp_ins.event).each do |key|
|
122
106
|
if @tp_ins.respond_to?(key)
|
123
107
|
send("#{key}=", @tp_ins.send(key))
|
124
108
|
end
|
125
109
|
end
|
126
110
|
end
|
127
111
|
|
128
|
-
# def get_additional_attributes
|
129
|
-
# [:order_id, :parent_ids, :direct_child_order_ids, :parent_length].each do |k|
|
130
|
-
# @ret_data[k] = send(k) unless send(k).nil?
|
131
|
-
# end
|
132
|
-
# end
|
133
|
-
|
134
112
|
def get_self_refer
|
135
|
-
self.tp_self_refer = SourceRoute.
|
113
|
+
self.tp_self_refer = SourceRoute.proxy.result_builder.tp_self_caches
|
136
114
|
.map(&:__id__).index(@tp_ins.self.__id__)
|
137
115
|
end
|
138
116
|
|
@@ -56,20 +56,6 @@ module SourceRoute
|
|
56
56
|
call_chain.map { |tp| tp.parent_length }.uniq.sort
|
57
57
|
end
|
58
58
|
|
59
|
-
# def deep_cloned
|
60
|
-
# chain.map { |r| r.clone }
|
61
|
-
# end
|
62
|
-
|
63
|
-
# def stringify
|
64
|
-
# deep_cloned.map do |tr|
|
65
|
-
# # to_s is safer than inspect
|
66
|
-
# # ex: inspect on ActiveRecord_Relation may crash
|
67
|
-
# # should moved to tr object
|
68
|
-
# tr.stringify
|
69
|
-
# tr
|
70
|
-
# end
|
71
|
-
# end
|
72
|
-
|
73
59
|
private
|
74
60
|
def init_order_id_and_parent_ids
|
75
61
|
each_with_index do |tpr, index|
|
data/lib/source_route/version.rb
CHANGED
@@ -0,0 +1,86 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
module SourceRoute
|
4
|
+
class ConfigTest < Minitest::Test
|
5
|
+
|
6
|
+
def test_tp_filter_methods
|
7
|
+
assert TP_FILTER_METHODS.include?(:defined_class_not)
|
8
|
+
assert TP_FILTER_METHODS.include?(:method_id_not)
|
9
|
+
assert TP_FILTER_METHODS.include?(:path)
|
10
|
+
assert TP_FILTER_METHODS.frozen?
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_block_parser
|
14
|
+
block_parser = BlockConfigParser.new
|
15
|
+
config = block_parser.run do
|
16
|
+
event :call, 'c_call'
|
17
|
+
method_id_not :exception_method_name
|
18
|
+
defined_class 'ActiveRecord::Callback'
|
19
|
+
output_format 'silence'
|
20
|
+
end
|
21
|
+
assert_equal [:call, :c_call], config.event
|
22
|
+
assert_equal 'exception_method_name', config.negatives[:method_id]
|
23
|
+
assert_equal 'ActiveRecord::Callback', config.positives[:defined_class]
|
24
|
+
assert_equal :silence, config.output_format
|
25
|
+
end
|
26
|
+
|
27
|
+
def test_block_parser_with_full_feature
|
28
|
+
block_parser = BlockConfigParser.new
|
29
|
+
config = block_parser.run do
|
30
|
+
event :call, 'c_call'
|
31
|
+
path 'your_rails_application_root_dir_name'
|
32
|
+
filename 'trial.html'
|
33
|
+
full_feature 10
|
34
|
+
end
|
35
|
+
assert_equal 3, config.event.size
|
36
|
+
assert_includes config.event, :return
|
37
|
+
assert config.import_return_to_call
|
38
|
+
assert 'trial.html', config.filename
|
39
|
+
assert_includes config.positives[:path], 'root_dir'
|
40
|
+
end
|
41
|
+
|
42
|
+
def test_block_parser_with_params
|
43
|
+
block_parser = BlockConfigParser.new
|
44
|
+
config = block_parser.run 'wanted' do
|
45
|
+
end
|
46
|
+
assert_equal 'wanted', config.positives[:defined_class]
|
47
|
+
assert_equal 'wanted', config.positives[:method_id]
|
48
|
+
end
|
49
|
+
|
50
|
+
def test_block_parser_without_block
|
51
|
+
block_parser = BlockConfigParser.new
|
52
|
+
config = block_parser.run 'ActiveSupport'
|
53
|
+
assert_equal 'ActiveSupport', config.positives[:defined_class]
|
54
|
+
end
|
55
|
+
|
56
|
+
def test_full_feature_of_params_parser
|
57
|
+
params = {output_format: 'html', event: :c_call,
|
58
|
+
defined_class: 'ActiveRecord::Base',
|
59
|
+
method_id_not: ['initialize', 'nonsense']
|
60
|
+
}
|
61
|
+
config = ParamsConfigParser.run(params)
|
62
|
+
assert_equal :html, config.output_format
|
63
|
+
assert_equal [:c_call], config.event
|
64
|
+
assert_equal 'ActiveRecord::Base', config.positives[:defined_class]
|
65
|
+
assert_equal 'initialize|nonsense', config.negatives[:method_id]
|
66
|
+
end
|
67
|
+
|
68
|
+
def test_default_value_of_config
|
69
|
+
params = {defined_class: [:Rack, :ActiveRecord]}
|
70
|
+
config = ParamsConfigParser.run(params)
|
71
|
+
assert_equal :test, config.output_format
|
72
|
+
assert_equal [:call], config.event
|
73
|
+
assert_equal 'Rack|ActiveRecord', config.positives[:defined_class]
|
74
|
+
end
|
75
|
+
|
76
|
+
def test_config_formulize
|
77
|
+
config = Config.new
|
78
|
+
config.output_format = 'html'
|
79
|
+
config.event = ['return', :call]
|
80
|
+
config.formulize
|
81
|
+
assert_equal :html, config.output_format
|
82
|
+
assert_equal [:return, :call], config.event
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
@@ -14,39 +14,45 @@ module SourceRoute
|
|
14
14
|
@warden_tp = FakeTp.new(:auth, Warden, 6)
|
15
15
|
@user_tp = FakeTp.new(:new, User, 8)
|
16
16
|
@tps = [@devise_tp, @warden_tp, @user_tp]
|
17
|
-
|
17
|
+
super
|
18
18
|
end
|
19
19
|
|
20
20
|
def test_filter_method_not_auth
|
21
|
-
cond =
|
21
|
+
cond = Config.new
|
22
|
+
cond.negatives[:method_id] = 'auth'
|
22
23
|
@tp_filter = TpFilter.new(cond)
|
23
24
|
filtered = @tps.reject { |tp| @tp_filter.block_it?(tp) }
|
24
25
|
assert_equal [@user_tp], filtered
|
25
26
|
end
|
26
27
|
|
27
28
|
def test_filter_class_is_admin
|
28
|
-
cond =
|
29
|
+
cond = Config.new
|
30
|
+
cond.positives[:defined_class] = 'Admin'
|
29
31
|
@tp_filter = TpFilter.new(cond)
|
30
32
|
filtered = @tps.reject { |tp| @tp_filter.block_it?(tp) }
|
31
33
|
assert_equal [], filtered
|
32
34
|
end
|
33
35
|
|
34
36
|
def test_filter_method_is_auth
|
35
|
-
cond =
|
37
|
+
cond = Config.new
|
38
|
+
cond.positives[:method_id] = 'auth'
|
36
39
|
@tp_filter = TpFilter.new(cond)
|
37
40
|
filtered = @tps.reject { |tp| @tp_filter.block_it?(tp) }
|
38
41
|
assert_equal [@devise_tp, @warden_tp], filtered
|
39
42
|
end
|
40
43
|
|
41
44
|
def test_filter_method_is_new_class_is_devise
|
42
|
-
cond =
|
45
|
+
cond = Config.new
|
46
|
+
cond.positives[:defined_class] = 'Devise'
|
47
|
+
cond.positives[:method_id] = 'new'
|
43
48
|
@tp_filter = TpFilter.new(cond)
|
44
49
|
filtered = @tps.reject { |tp| @tp_filter.block_it?(tp) }
|
45
50
|
assert_equal [@devise_tp, @user_tp], filtered
|
46
51
|
end
|
47
52
|
|
48
53
|
def test_filter_class_is_devise_or_warden
|
49
|
-
cond =
|
54
|
+
cond = Config.new
|
55
|
+
cond.positives[:defined_class] = 'Warden|User'
|
50
56
|
@tp_filter = TpFilter.new(cond)
|
51
57
|
filtered = @tps.reject { |tp| @tp_filter.block_it?(tp) }
|
52
58
|
assert_equal [@warden_tp, @user_tp], filtered
|
data/test/source_route_test.rb
CHANGED
@@ -3,7 +3,7 @@ require 'test_helper'
|
|
3
3
|
class SourceRouteTest < Minitest::Test
|
4
4
|
|
5
5
|
def setup
|
6
|
-
@
|
6
|
+
@proxy = SourceRoute::Proxy.instance
|
7
7
|
super
|
8
8
|
end
|
9
9
|
|
@@ -13,9 +13,9 @@ class SourceRouteTest < Minitest::Test
|
|
13
13
|
end
|
14
14
|
|
15
15
|
def test_enable_return_true
|
16
|
-
@source_route = SourceRoute.enable
|
16
|
+
@source_route = SourceRoute.enable 'nnnonsense'
|
17
17
|
assert @source_route
|
18
|
-
assert_equal @
|
18
|
+
assert_equal @proxy, SourceRoute.proxy
|
19
19
|
end
|
20
20
|
|
21
21
|
def test_catch_call_event
|
@@ -26,24 +26,24 @@ class SourceRouteTest < Minitest::Test
|
|
26
26
|
end
|
27
27
|
SampleApp.new.nonsense
|
28
28
|
|
29
|
-
assert @
|
29
|
+
assert @proxy.tp
|
30
30
|
end
|
31
31
|
|
32
32
|
def test_show_addtional_attrs
|
33
33
|
SourceRoute.enable 'nonsense' do
|
34
|
-
|
34
|
+
show_additional_attrs :path
|
35
35
|
full_feature
|
36
36
|
end
|
37
37
|
SampleApp.new.nonsense
|
38
38
|
|
39
|
-
assert_includes @
|
39
|
+
assert_includes @proxy.tp_result_chain.first.path, 'test'
|
40
40
|
end
|
41
41
|
|
42
42
|
def test_match_class_name_by_first_parameter
|
43
43
|
@source_route = SourceRoute.enable 'SampleApp'
|
44
44
|
SampleApp.new.nonsense
|
45
45
|
|
46
|
-
assert @
|
46
|
+
assert @proxy.tp_result_chain.size > 0
|
47
47
|
end
|
48
48
|
|
49
49
|
def test_not_match
|
@@ -52,7 +52,7 @@ class SourceRouteTest < Minitest::Test
|
|
52
52
|
method_id_not 'nonsense'
|
53
53
|
end
|
54
54
|
SampleApp.new.nonsense
|
55
|
-
refute_includes @
|
55
|
+
refute_includes @proxy.tp_result_chain.map(&:method_id).flatten, 'nonsense'
|
56
56
|
end
|
57
57
|
|
58
58
|
def test_match_multiple_class_name
|
@@ -61,8 +61,8 @@ class SourceRouteTest < Minitest::Test
|
|
61
61
|
end
|
62
62
|
|
63
63
|
SampleApp.new.nonsense
|
64
|
-
assert @
|
65
|
-
assert_equal SampleApp, @
|
64
|
+
assert @proxy.tp_result_chain.size > 0
|
65
|
+
assert_equal SampleApp, @proxy.tp_result_chain.last.defined_class
|
66
66
|
end
|
67
67
|
|
68
68
|
def test_source_route_with_one_parameter
|
@@ -71,19 +71,19 @@ class SourceRouteTest < Minitest::Test
|
|
71
71
|
end
|
72
72
|
SampleApp.new.nonsense
|
73
73
|
|
74
|
-
ret_tp = @
|
74
|
+
ret_tp = @proxy.tp_result_chain.last
|
75
75
|
assert_equal SampleApp, ret_tp.defined_class
|
76
76
|
end
|
77
77
|
|
78
|
-
def
|
78
|
+
def test_proxy_reset
|
79
79
|
SourceRoute.enable 'nonsense'
|
80
80
|
SampleApp.new.nonsense
|
81
|
-
assert_equal 1, @
|
81
|
+
assert_equal 1, @proxy.tp_result_chain.size
|
82
82
|
|
83
83
|
SourceRoute.reset
|
84
84
|
SampleApp.new.nonsense
|
85
85
|
|
86
|
-
assert_equal 0, @
|
86
|
+
assert_equal 0, @proxy.tp_result_chain.size
|
87
87
|
end
|
88
88
|
|
89
89
|
def test_source_route_with_block
|
@@ -96,7 +96,7 @@ class SourceRouteTest < Minitest::Test
|
|
96
96
|
end
|
97
97
|
SampleApp.new.nonsense
|
98
98
|
|
99
|
-
assert_equal 0, @
|
99
|
+
assert_equal 0, @proxy.tp_result_chain.size
|
100
100
|
assert_equal 1, paths.size
|
101
101
|
assert_includes paths.first, 'sample_app'
|
102
102
|
end
|
@@ -104,14 +104,14 @@ class SourceRouteTest < Minitest::Test
|
|
104
104
|
def test_trace_with_c_call
|
105
105
|
SourceRoute.trace(event: :c_call) { 'abc'.upcase }
|
106
106
|
|
107
|
-
assert_equal 2, @
|
107
|
+
assert_equal 2, @proxy.tp_result_chain.size
|
108
108
|
end
|
109
109
|
|
110
110
|
def test_trace_with_full_feature
|
111
111
|
SourceRoute.trace method_id: 'nonsense', full_feature: 10 do
|
112
112
|
SampleApp.new.nonsense
|
113
113
|
end
|
114
|
-
first_result = @
|
114
|
+
first_result = @proxy.tp_result_chain.first
|
115
115
|
assert_equal first_result.tp_self_refer, 0
|
116
116
|
end
|
117
117
|
|
@@ -119,25 +119,25 @@ class SourceRouteTest < Minitest::Test
|
|
119
119
|
# SourceRoute.trace method_id: 'nonsense', full_feature: true do
|
120
120
|
# SampleApp.new.nonsense
|
121
121
|
# end
|
122
|
-
# assert_equal 1, @
|
123
|
-
# assert @
|
122
|
+
# assert_equal 1, @proxy.tp_self_caches.size
|
123
|
+
# assert @proxy.tp_self_caches.first.is_a? SampleApp
|
124
124
|
# end
|
125
125
|
|
126
126
|
def test_stringify_tp_result_chain_only
|
127
127
|
SourceRoute.trace method_id: 'nonsense', full_feature: true do
|
128
128
|
SampleApp.new.nonsense
|
129
129
|
end
|
130
|
-
origin_tp_result_chain = @
|
131
|
-
assert @
|
132
|
-
assert_equal origin_tp_result_chain, @
|
130
|
+
origin_tp_result_chain = @proxy.tp_result_chain
|
131
|
+
assert @proxy.tp_result_chain.first.stringify.defined_class.is_a? String
|
132
|
+
assert_equal origin_tp_result_chain, @proxy.tp_result_chain
|
133
133
|
end
|
134
134
|
|
135
135
|
def test_trace_without_first_hash_option
|
136
136
|
SourceRoute.trace output_format: :test do
|
137
137
|
SampleApp.new.nonsense
|
138
138
|
end
|
139
|
-
assert @
|
140
|
-
refute @
|
139
|
+
assert @proxy.tp_result_chain.size > 0
|
140
|
+
refute @proxy.tp.enabled?
|
141
141
|
end
|
142
142
|
|
143
143
|
def test_trace_two_events
|
@@ -145,44 +145,44 @@ class SourceRouteTest < Minitest::Test
|
|
145
145
|
event :call, :return
|
146
146
|
end
|
147
147
|
SampleApp.new.nonsense
|
148
|
-
assert_equal 2, @
|
148
|
+
assert_equal 2, @proxy.tp_result_chain.size
|
149
149
|
end
|
150
150
|
|
151
151
|
# but local var didnt displayed
|
152
152
|
def test_show_local_variables
|
153
153
|
SourceRoute.enable 'nonsense_with_params' do
|
154
|
-
|
154
|
+
include_local_var true
|
155
155
|
output_format :console
|
156
156
|
end
|
157
157
|
|
158
158
|
SampleApp.new.nonsense_with_params(88)
|
159
159
|
|
160
|
-
ret_value = @
|
160
|
+
ret_value = @proxy.tp_result_chain.last
|
161
161
|
end
|
162
162
|
|
163
163
|
def test_track_local_var_when_event_is_return
|
164
164
|
SourceRoute.enable 'nonsense_with_params' do
|
165
165
|
event :return
|
166
|
-
|
166
|
+
include_local_var true
|
167
167
|
end
|
168
168
|
|
169
169
|
SampleApp.new.nonsense_with_params(88)
|
170
|
-
assert_equal 1, @
|
170
|
+
assert_equal 1, @proxy.tp_result_chain.size
|
171
171
|
|
172
|
-
ret_value_for_return_event = @
|
172
|
+
ret_value_for_return_event = @proxy.tp_result_chain.last
|
173
173
|
assert_equal 88, ret_value_for_return_event.local_var[:param1]
|
174
174
|
assert_equal 5, ret_value_for_return_event.local_var[:param2]
|
175
175
|
end
|
176
176
|
|
177
177
|
def test_show_instance_vars_only
|
178
178
|
SourceRoute.enable 'nonsense' do
|
179
|
-
|
179
|
+
include_instance_var true
|
180
180
|
event :call, :return
|
181
181
|
end
|
182
182
|
SampleApp.new('ins sure').nonsense_with_instance_var
|
183
183
|
|
184
|
-
assert_equal 4, @
|
185
|
-
ret_value = @
|
184
|
+
assert_equal 4, @proxy.tp_result_chain.size
|
185
|
+
ret_value = @proxy.tp_result_chain.pop
|
186
186
|
|
187
187
|
assert_equal 'ins sure', ret_value.instance_var[:@sample]
|
188
188
|
end
|
@@ -192,8 +192,8 @@ class SourceRouteTest < Minitest::Test
|
|
192
192
|
full_feature 10
|
193
193
|
end
|
194
194
|
SampleApp.new('cool stuff').init_cool_app
|
195
|
-
@
|
196
|
-
assert @
|
195
|
+
@proxy.tp_result_chain.import_return_value_to_call_chain
|
196
|
+
assert @proxy.tp_result_chain.call_chain[0].return_value, 'call results should contain return_value'
|
197
197
|
end
|
198
198
|
|
199
199
|
def test_order_call_sequence
|
@@ -202,8 +202,8 @@ class SourceRouteTest < Minitest::Test
|
|
202
202
|
end
|
203
203
|
SampleApp.new.nonsense_with_instance_var
|
204
204
|
|
205
|
-
@
|
206
|
-
call_results = @
|
205
|
+
@proxy.tp_result_chain.treeize_call_chain
|
206
|
+
call_results = @proxy.result_builder.tp_result_chain.call_chain
|
207
207
|
|
208
208
|
nonsense_call_tp = call_results.find { |tp| tp.method_id == :nonsense }
|
209
209
|
nonsense_with_instance_var_call_tp = call_results.find do |tp|
|
@@ -211,7 +211,7 @@ class SourceRouteTest < Minitest::Test
|
|
211
211
|
end
|
212
212
|
assert_equal [nonsense_with_instance_var_call_tp.order_id], nonsense_call_tp.parent_ids
|
213
213
|
assert_equal 1, nonsense_call_tp.parent_length
|
214
|
-
assert_equal [0, 1], @
|
214
|
+
assert_equal [0, 1], @proxy.result_builder.tp_result_chain.parent_length_list
|
215
215
|
assert_equal [nonsense_call_tp.order_id], nonsense_with_instance_var_call_tp.direct_child_order_ids
|
216
216
|
end
|
217
217
|
|
@@ -221,7 +221,7 @@ class SourceRouteTest < Minitest::Test
|
|
221
221
|
defined_class 'SampleApp'
|
222
222
|
event :call, :return
|
223
223
|
full_feature 10
|
224
|
-
|
224
|
+
filename 'call_and_return_in_sample_app.html'
|
225
225
|
end
|
226
226
|
|
227
227
|
SampleApp.new.init_cool_app
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: source_route
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- raykin
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-09-
|
11
|
+
date: 2015-09-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: awesome_print
|
@@ -197,23 +197,25 @@ files:
|
|
197
197
|
- examples/show_task_trace_in_rails.rb
|
198
198
|
- examples/study_callback.rb
|
199
199
|
- lib/source_route.rb
|
200
|
+
- lib/source_route/config.rb
|
200
201
|
- lib/source_route/core_ext.rb
|
201
202
|
- lib/source_route/formats/html.rb
|
202
203
|
- lib/source_route/formats/html_semantic.slim
|
203
204
|
- lib/source_route/generate_result.rb
|
204
205
|
- lib/source_route/json_overrides/activerecord_associations_association.rb
|
205
206
|
- lib/source_route/jsonify.rb
|
207
|
+
- lib/source_route/proxy.rb
|
206
208
|
- lib/source_route/rails_plugins/source_track_middleware.rb
|
207
209
|
- lib/source_route/tp_filter.rb
|
208
210
|
- lib/source_route/tp_result.rb
|
209
211
|
- lib/source_route/tp_result_chain.rb
|
210
212
|
- lib/source_route/version.rb
|
211
|
-
- lib/source_route/wrapper.rb
|
212
213
|
- source_route.gemspec
|
213
214
|
- test/fake_app.rb
|
214
215
|
- test/sample_app.rb
|
216
|
+
- test/source_route/config_test.rb
|
217
|
+
- test/source_route/proxy_test.rb
|
215
218
|
- test/source_route/tp_filter_test.rb
|
216
|
-
- test/source_route/wrapper_test.rb
|
217
219
|
- test/source_route_test.rb
|
218
220
|
- test/test_helper.rb
|
219
221
|
homepage: http://github.com/raykin/source-route
|
@@ -243,8 +245,9 @@ summary: Wrapper of TracePoint.
|
|
243
245
|
test_files:
|
244
246
|
- test/fake_app.rb
|
245
247
|
- test/sample_app.rb
|
248
|
+
- test/source_route/config_test.rb
|
249
|
+
- test/source_route/proxy_test.rb
|
246
250
|
- test/source_route/tp_filter_test.rb
|
247
|
-
- test/source_route/wrapper_test.rb
|
248
251
|
- test/source_route_test.rb
|
249
252
|
- test/test_helper.rb
|
250
253
|
has_rdoc:
|
data/lib/source_route/wrapper.rb
DELETED
@@ -1,112 +0,0 @@
|
|
1
|
-
module SourceRoute
|
2
|
-
|
3
|
-
class Wrapper
|
4
|
-
include Singleton
|
5
|
-
|
6
|
-
TRACE_POINT_METHODS = [:defined_class, :method_id, :path, :lineno]
|
7
|
-
|
8
|
-
attr_accessor :condition, :tp, :result_builder
|
9
|
-
|
10
|
-
Condition = Struct.new(:events, :negatives, :positive, :result_config) do
|
11
|
-
def initialize(e=[:call], n={}, p={}, r=GenerateResult::Config.new)
|
12
|
-
@debug = false
|
13
|
-
super(e, n, p, r)
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
|
-
class Condition
|
18
|
-
|
19
|
-
TRACE_POINT_METHODS.each do |m|
|
20
|
-
define_method m do |*v|
|
21
|
-
positive[m] = v.flatten.map(&:to_s).join('|')
|
22
|
-
end
|
23
|
-
|
24
|
-
define_method "#{m}_not" do |*v|
|
25
|
-
negatives[m] = v.map(&:to_s).join('|')
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
def event(*v)
|
30
|
-
self.events = v.map(&:to_sym) unless v == []
|
31
|
-
end
|
32
|
-
|
33
|
-
def output_format(data = nil, &block)
|
34
|
-
result_config.format = block_given? ? block : data
|
35
|
-
end
|
36
|
-
|
37
|
-
def has_call_and_return_event
|
38
|
-
events.include? :return and events.include? :call
|
39
|
-
end
|
40
|
-
|
41
|
-
def full_feature(value=true)
|
42
|
-
return unless value
|
43
|
-
|
44
|
-
self.events = [:call, :return]
|
45
|
-
result_config.import_return_to_call = true
|
46
|
-
|
47
|
-
result_config.show_additional_attrs = [:path, :lineno]
|
48
|
-
# JSON serialize trigger many problems when handle complicated object
|
49
|
-
|
50
|
-
# a Back Door to open more data. but be care it could trigger weird crash when Jsonify these vars
|
51
|
-
if value == 10
|
52
|
-
result_config.include_instance_var = true
|
53
|
-
result_config.include_local_var = true
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
|
-
def debug(value=false)
|
58
|
-
@debug = value
|
59
|
-
end
|
60
|
-
|
61
|
-
def is_debug?
|
62
|
-
@debug
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
def initialize
|
67
|
-
reset
|
68
|
-
end
|
69
|
-
|
70
|
-
def reset
|
71
|
-
@tp.disable if defined? @tp
|
72
|
-
@condition = Condition.new
|
73
|
-
@result_builder = GenerateResult.new(self)
|
74
|
-
GenerateResult.clear_wanted_attributes
|
75
|
-
self
|
76
|
-
end
|
77
|
-
|
78
|
-
def trace
|
79
|
-
# dont wanna init it in tp block, cause tp block could run thousands of times in one cycle trace
|
80
|
-
|
81
|
-
tp_filter = TpFilter.new(condition)
|
82
|
-
|
83
|
-
track = TracePoint.new *condition.events do |tp|
|
84
|
-
|
85
|
-
next if tp_filter.block_it?(tp)
|
86
|
-
|
87
|
-
# immediate output trace point result
|
88
|
-
# here is confused. todo
|
89
|
-
# should move tp_result_chain to result generator
|
90
|
-
@result_builder.output(tp)
|
91
|
-
# if condition.result_config.format == :console
|
92
|
-
# ret_data = build_result.build(tp)
|
93
|
-
# @tp_result_chain.push(ret_data)
|
94
|
-
# build_result.output(tp)
|
95
|
-
# elsif condition.result_config.format.is_a? Proc
|
96
|
-
# build_result.output(tp)
|
97
|
-
# else
|
98
|
-
# # why not push the tp to result chain
|
99
|
-
# ret_data = build_result.build(tp)
|
100
|
-
# @tp_result_chain.push(ret_data)
|
101
|
-
# end
|
102
|
-
end
|
103
|
-
track.enable
|
104
|
-
self.tp = track
|
105
|
-
end
|
106
|
-
|
107
|
-
def tp_result_chain
|
108
|
-
result_builder.tp_result_chain
|
109
|
-
end
|
110
|
-
end # END Wrapper
|
111
|
-
|
112
|
-
end
|