source_route 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/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
|