appmap 0.45.0 → 0.48.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/.travis.yml +10 -0
- data/CHANGELOG.md +36 -0
- data/README.md +39 -27
- data/lib/appmap.rb +1 -2
- data/lib/appmap/class_map.rb +7 -15
- data/lib/appmap/config.rb +194 -96
- data/lib/appmap/event.rb +29 -28
- data/lib/appmap/handler/function.rb +1 -1
- data/lib/appmap/handler/rails/request_handler.rb +124 -0
- data/lib/appmap/handler/rails/sql_handler.rb +152 -0
- data/lib/appmap/handler/rails/template.rb +155 -0
- data/lib/appmap/hook.rb +109 -71
- data/lib/appmap/hook/method.rb +1 -1
- data/lib/appmap/railtie.rb +6 -28
- data/lib/appmap/trace.rb +46 -6
- data/lib/appmap/util.rb +18 -0
- data/lib/appmap/version.rb +2 -2
- data/package-lock.json +3 -3
- data/spec/abstract_controller_base_spec.rb +68 -9
- data/spec/class_map_spec.rb +3 -3
- data/spec/fixtures/rails5_users_app/config/application.rb +0 -2
- data/spec/fixtures/rails6_users_app/config/application.rb +0 -2
- data/spec/hook_spec.rb +11 -58
- data/spec/railtie_spec.rb +7 -11
- data/spec/util_spec.rb +18 -1
- metadata +5 -4
- data/lib/appmap/rails/request_handler.rb +0 -122
- data/lib/appmap/rails/sql_handler.rb +0 -150
data/lib/appmap/hook.rb
CHANGED
@@ -5,6 +5,7 @@ require 'English'
|
|
5
5
|
module AppMap
|
6
6
|
class Hook
|
7
7
|
LOG = (ENV['APPMAP_DEBUG'] == 'true' || ENV['DEBUG'] == 'true')
|
8
|
+
LOG_HOOK = (ENV['DEBUG_HOOK'] == 'true')
|
8
9
|
|
9
10
|
OBJECT_INSTANCE_METHODS = %i[! != !~ <=> == === =~ __id__ __send__ class clone define_singleton_method display dup enum_for eql? equal? extend freeze frozen? hash inspect instance_eval instance_exec instance_of? instance_variable_defined? instance_variable_get instance_variable_set instance_variables is_a? itself kind_of? method methods nil? object_id private_methods protected_methods public_method public_methods public_send remove_instance_variable respond_to? send singleton_class singleton_method singleton_methods taint tainted? tap then to_enum to_s to_h to_a trust untaint untrust untrusted? yield_self].freeze
|
10
11
|
OBJECT_STATIC_METHODS = %i[! != !~ < <= <=> == === =~ > >= __id__ __send__ alias_method allocate ancestors attr attr_accessor attr_reader attr_writer autoload autoload? class class_eval class_exec class_variable_defined? class_variable_get class_variable_set class_variables clone const_defined? const_get const_missing const_set constants define_method define_singleton_method deprecate_constant display dup enum_for eql? equal? extend freeze frozen? hash include include? included_modules inspect instance_eval instance_exec instance_method instance_methods instance_of? instance_variable_defined? instance_variable_get instance_variable_set instance_variables is_a? itself kind_of? method method_defined? methods module_eval module_exec name new nil? object_id prepend private_class_method private_constant private_instance_methods private_method_defined? private_methods protected_instance_methods protected_method_defined? protected_methods public_class_method public_constant public_instance_method public_instance_methods public_method public_method_defined? public_methods public_send remove_class_variable remove_instance_variable remove_method respond_to? send singleton_class singleton_class? singleton_method singleton_methods superclass taint tainted? tap then to_enum to_s trust undef_method untaint untrust untrusted? yield_self].freeze
|
@@ -35,73 +36,21 @@ module AppMap
|
|
35
36
|
|
36
37
|
def initialize(config)
|
37
38
|
@config = config
|
39
|
+
@trace_locations = []
|
40
|
+
# Paths that are known to be non-tracing
|
41
|
+
@notrace_paths = Set.new
|
38
42
|
end
|
39
43
|
|
40
44
|
# Observe class loading and hook all methods which match the config.
|
41
|
-
def enable
|
45
|
+
def enable(&block)
|
42
46
|
require 'appmap/hook/method'
|
43
47
|
|
44
48
|
hook_builtins
|
45
49
|
|
46
|
-
|
47
|
-
|
50
|
+
@trace_begin = TracePoint.new(:class, &method(:trace_class))
|
51
|
+
@trace_end = TracePoint.new(:end, &method(:trace_end))
|
48
52
|
|
49
|
-
|
50
|
-
# NoMethodError: private method `singleton_class' called for Rack::MiniProfiler:Class
|
51
|
-
class_methods = begin
|
52
|
-
if cls.respond_to?(:singleton_class)
|
53
|
-
cls.singleton_class.public_instance_methods(false) - instance_methods - OBJECT_STATIC_METHODS
|
54
|
-
else
|
55
|
-
[]
|
56
|
-
end
|
57
|
-
rescue NameError
|
58
|
-
[]
|
59
|
-
end
|
60
|
-
|
61
|
-
hook = lambda do |hook_cls|
|
62
|
-
lambda do |method_id|
|
63
|
-
# Don't try and trace the AppMap methods or there will be
|
64
|
-
# a stack overflow in the defined hook method.
|
65
|
-
return if (hook_cls&.name || '').split('::')[0] == AppMap.name
|
66
|
-
|
67
|
-
method = begin
|
68
|
-
hook_cls.public_instance_method(method_id)
|
69
|
-
rescue NameError
|
70
|
-
warn "AppMap: Method #{hook_cls} #{method.name} is not accessible" if LOG
|
71
|
-
return
|
72
|
-
end
|
73
|
-
|
74
|
-
warn "AppMap: Examining #{hook_cls} #{method.name}" if LOG
|
75
|
-
|
76
|
-
disasm = RubyVM::InstructionSequence.disasm(method)
|
77
|
-
# Skip methods that have no instruction sequence, as they are obviously trivial.
|
78
|
-
next unless disasm
|
79
|
-
|
80
|
-
next if config.never_hook?(method)
|
81
|
-
|
82
|
-
next unless \
|
83
|
-
config.always_hook?(hook_cls, method.name) ||
|
84
|
-
config.included_by_location?(method)
|
85
|
-
|
86
|
-
package = config.package_for_method(method)
|
87
|
-
|
88
|
-
hook_method = Hook::Method.new(package, hook_cls, method)
|
89
|
-
|
90
|
-
hook_method.activate
|
91
|
-
end
|
92
|
-
end
|
93
|
-
|
94
|
-
instance_methods.each(&hook.(cls))
|
95
|
-
# NoMethodError: private method `singleton_class' called for Rack::MiniProfiler:Class
|
96
|
-
begin
|
97
|
-
class_methods.each(&hook.(cls.singleton_class)) if cls.respond_to?(:singleton_class)
|
98
|
-
rescue NameError
|
99
|
-
# NameError:
|
100
|
-
# uninitialized constant Faraday::Connection
|
101
|
-
end
|
102
|
-
end
|
103
|
-
|
104
|
-
tp.enable(&block)
|
53
|
+
@trace_begin.enable(&block)
|
105
54
|
end
|
106
55
|
|
107
56
|
# hook_builtins builds hooks for code that is built in to the Ruby standard library.
|
@@ -115,30 +64,119 @@ module AppMap
|
|
115
64
|
end
|
116
65
|
end
|
117
66
|
|
118
|
-
config.
|
67
|
+
config.builtin_hooks.each do |class_name, hooks|
|
119
68
|
Array(hooks).each do |hook|
|
120
69
|
require hook.package.package_name if hook.package.package_name
|
121
70
|
Array(hook.method_names).each do |method_name|
|
122
71
|
method_name = method_name.to_sym
|
72
|
+
base_cls = class_from_string.(class_name)
|
123
73
|
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
cls.instance_method(method_name)
|
128
|
-
rescue NameError
|
129
|
-
cls.method(method_name) rescue nil
|
130
|
-
end
|
131
|
-
|
132
|
-
next if config.never_hook?(method)
|
74
|
+
hook_method = lambda do |entry|
|
75
|
+
cls, method = entry
|
76
|
+
return false if config.never_hook?(cls, method)
|
133
77
|
|
134
|
-
if method
|
135
78
|
Hook::Method.new(hook.package, cls, method).activate
|
79
|
+
end
|
80
|
+
|
81
|
+
methods = []
|
82
|
+
methods << [ base_cls, base_cls.public_instance_method(method_name) ] rescue nil
|
83
|
+
if base_cls.respond_to?(:singleton_class)
|
84
|
+
methods << [ base_cls.singleton_class, base_cls.singleton_class.public_instance_method(method_name) ] rescue nil
|
85
|
+
end
|
86
|
+
methods.compact!
|
87
|
+
if methods.empty?
|
88
|
+
warn "Method #{method_name} not found on #{base_cls.name}"
|
136
89
|
else
|
137
|
-
|
90
|
+
methods.each(&hook_method)
|
138
91
|
end
|
139
92
|
end
|
140
93
|
end
|
141
94
|
end
|
142
95
|
end
|
96
|
+
|
97
|
+
protected
|
98
|
+
|
99
|
+
def trace_class(trace_point)
|
100
|
+
path = trace_point.path
|
101
|
+
|
102
|
+
return if @notrace_paths.member?(path)
|
103
|
+
|
104
|
+
if config.path_enabled?(path)
|
105
|
+
location = trace_location(trace_point)
|
106
|
+
warn "Entering hook-enabled location #{location}" if Hook::LOG || Hook::LOG_HOOK
|
107
|
+
@trace_locations << location
|
108
|
+
unless @trace_end.enabled?
|
109
|
+
warn "Enabling hooking" if Hook::LOG || Hook::LOG_HOOK
|
110
|
+
@trace_end.enable
|
111
|
+
end
|
112
|
+
else
|
113
|
+
@notrace_paths << path
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
def trace_location(trace_point)
|
118
|
+
[ trace_point.path, trace_point.lineno ].join(':')
|
119
|
+
end
|
120
|
+
|
121
|
+
def trace_end(trace_point)
|
122
|
+
cls = trace_point.self
|
123
|
+
|
124
|
+
instance_methods = cls.public_instance_methods(false) - OBJECT_INSTANCE_METHODS
|
125
|
+
# NoMethodError: private method `singleton_class' called for Rack::MiniProfiler:Class
|
126
|
+
class_methods = begin
|
127
|
+
if cls.respond_to?(:singleton_class)
|
128
|
+
cls.singleton_class.public_instance_methods(false) - instance_methods - OBJECT_STATIC_METHODS
|
129
|
+
else
|
130
|
+
[]
|
131
|
+
end
|
132
|
+
rescue NameError
|
133
|
+
[]
|
134
|
+
end
|
135
|
+
|
136
|
+
hook = lambda do |hook_cls|
|
137
|
+
lambda do |method_id|
|
138
|
+
# Don't try and trace the AppMap methods or there will be
|
139
|
+
# a stack overflow in the defined hook method.
|
140
|
+
next if %w[Marshal AppMap ActiveSupport].member?((hook_cls&.name || '').split('::')[0])
|
141
|
+
|
142
|
+
next if method_id == :call
|
143
|
+
|
144
|
+
method = begin
|
145
|
+
hook_cls.public_instance_method(method_id)
|
146
|
+
rescue NameError
|
147
|
+
warn "AppMap: Method #{hook_cls} #{method.name} is not accessible" if LOG
|
148
|
+
next
|
149
|
+
end
|
150
|
+
|
151
|
+
warn "AppMap: Examining #{hook_cls} #{method.name}" if LOG
|
152
|
+
|
153
|
+
disasm = RubyVM::InstructionSequence.disasm(method)
|
154
|
+
# Skip methods that have no instruction sequence, as they are obviously trivial.
|
155
|
+
next unless disasm
|
156
|
+
|
157
|
+
package = config.lookup_package(hook_cls, method)
|
158
|
+
next unless package
|
159
|
+
|
160
|
+
Hook::Method.new(package, hook_cls, method).activate
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
instance_methods.each(&hook.(cls))
|
165
|
+
begin
|
166
|
+
# NoMethodError: private method `singleton_class' called for Rack::MiniProfiler:Class
|
167
|
+
class_methods.each(&hook.(cls.singleton_class)) if cls.respond_to?(:singleton_class)
|
168
|
+
rescue NameError
|
169
|
+
# NameError:
|
170
|
+
# uninitialized constant Faraday::Connection
|
171
|
+
warn "NameError in #{__FILE__}: #{$!.message}"
|
172
|
+
end
|
173
|
+
|
174
|
+
location = @trace_locations.pop
|
175
|
+
warn "Leaving hook-enabled location #{location}" if Hook::LOG || Hook::LOG_HOOK
|
176
|
+
if @trace_locations.empty?
|
177
|
+
warn "Disabling hooking" if Hook::LOG || Hook::LOG_HOOK
|
178
|
+
@trace_end.disable
|
179
|
+
end
|
180
|
+
end
|
143
181
|
end
|
144
182
|
end
|
data/lib/appmap/hook/method.rb
CHANGED
@@ -95,7 +95,7 @@ module AppMap
|
|
95
95
|
def after_hook(_receiver, call_event, start_time, return_value, exception)
|
96
96
|
elapsed = TIME_NOW.call - start_time
|
97
97
|
return_event = hook_package.handler_class.handle_return(call_event.id, elapsed, return_value, exception)
|
98
|
-
AppMap.tracing.record_event return_event
|
98
|
+
AppMap.tracing.record_event(return_event) if return_event
|
99
99
|
nil
|
100
100
|
end
|
101
101
|
|
data/lib/appmap/railtie.rb
CHANGED
@@ -3,37 +3,15 @@
|
|
3
3
|
module AppMap
|
4
4
|
# Railtie connects the AppMap recorder to Rails-specific features.
|
5
5
|
class Railtie < ::Rails::Railtie
|
6
|
-
config.appmap = ActiveSupport::OrderedOptions.new
|
7
|
-
|
8
6
|
# appmap.subscribe subscribes to ActiveSupport Notifications so that they can be recorded as
|
9
7
|
# AppMap events.
|
10
8
|
initializer 'appmap.subscribe' do |_| # params: app
|
11
|
-
require 'appmap/rails/sql_handler'
|
12
|
-
require 'appmap/rails/request_handler'
|
13
|
-
ActiveSupport::Notifications.subscribe 'sql.sequel', AppMap::Rails::SQLHandler.new
|
14
|
-
ActiveSupport::Notifications.subscribe 'sql.active_record', AppMap::Rails::SQLHandler.new
|
15
|
-
|
16
|
-
AppMap::Rails::RequestHandler::HookMethod.new.activate
|
17
|
-
end
|
18
|
-
|
19
|
-
# appmap.trace begins recording an AppMap trace and writes it to appmap.json.
|
20
|
-
# This behavior is only activated if the configuration setting app.config.appmap.enabled
|
21
|
-
# is truthy.
|
22
|
-
initializer 'appmap.trace', after: 'appmap.subscribe' do |app|
|
23
|
-
lambda do
|
24
|
-
return unless app.config.appmap.enabled
|
9
|
+
require 'appmap/handler/rails/sql_handler'
|
10
|
+
require 'appmap/handler/rails/request_handler'
|
11
|
+
ActiveSupport::Notifications.subscribe 'sql.sequel', AppMap::Handler::Rails::SQLHandler.new
|
12
|
+
ActiveSupport::Notifications.subscribe 'sql.active_record', AppMap::Handler::Rails::SQLHandler.new
|
25
13
|
|
26
|
-
|
27
|
-
require 'json'
|
28
|
-
AppMap::Command::Record.new(AppMap.configuration).perform do |version, metadata, class_map, events|
|
29
|
-
appmap = JSON.generate \
|
30
|
-
version: version,
|
31
|
-
metadata: metadata,
|
32
|
-
classMap: class_map,
|
33
|
-
events: events
|
34
|
-
File.open('appmap.json', 'w').write(appmap)
|
35
|
-
end
|
36
|
-
end.call
|
14
|
+
AppMap::Handler::Rails::RequestHandler::HookMethod.new.activate
|
37
15
|
end
|
38
16
|
end
|
39
|
-
end
|
17
|
+
end if ENV['APPMAP'] == 'true'
|
data/lib/appmap/trace.rb
CHANGED
@@ -2,14 +2,36 @@
|
|
2
2
|
|
3
3
|
module AppMap
|
4
4
|
module Trace
|
5
|
-
class
|
6
|
-
attr_reader :
|
5
|
+
class RubyMethod
|
6
|
+
attr_reader :class_name, :static
|
7
7
|
|
8
|
-
def initialize(package,
|
8
|
+
def initialize(package, class_name, method, static)
|
9
9
|
@package = package
|
10
|
-
@
|
10
|
+
@class_name = class_name
|
11
|
+
@method = method
|
11
12
|
@static = static
|
12
|
-
|
13
|
+
end
|
14
|
+
|
15
|
+
def source_location
|
16
|
+
@method.source_location
|
17
|
+
end
|
18
|
+
|
19
|
+
def comment
|
20
|
+
@method.comment
|
21
|
+
rescue MethodSource::SourceNotFoundError
|
22
|
+
nil
|
23
|
+
end
|
24
|
+
|
25
|
+
def package
|
26
|
+
@package.name
|
27
|
+
end
|
28
|
+
|
29
|
+
def name
|
30
|
+
@method.name
|
31
|
+
end
|
32
|
+
|
33
|
+
def labels
|
34
|
+
@package.labels
|
13
35
|
end
|
14
36
|
end
|
15
37
|
|
@@ -43,6 +65,12 @@ module AppMap
|
|
43
65
|
end
|
44
66
|
end
|
45
67
|
|
68
|
+
def record_method(method)
|
69
|
+
@tracers.each do |tracer|
|
70
|
+
tracer.record_method(method)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
46
74
|
def delete(tracer)
|
47
75
|
return unless @tracers.member?(tracer)
|
48
76
|
|
@@ -83,10 +111,22 @@ module AppMap
|
|
83
111
|
@last_package_for_thread[Thread.current.object_id] = package if package
|
84
112
|
@events << event
|
85
113
|
static = event.static if event.respond_to?(:static)
|
86
|
-
@methods << Trace::
|
114
|
+
@methods << Trace::RubyMethod.new(package, defined_class, method, static) \
|
87
115
|
if package && defined_class && method && (event.event == :call)
|
88
116
|
end
|
89
117
|
|
118
|
+
# +method+ should be duck-typed to respond to the following:
|
119
|
+
# * package
|
120
|
+
# * defined_class
|
121
|
+
# * name
|
122
|
+
# * static
|
123
|
+
# * comment
|
124
|
+
# * labels
|
125
|
+
# * source_location
|
126
|
+
def record_method(method)
|
127
|
+
@methods << method
|
128
|
+
end
|
129
|
+
|
90
130
|
# Gets the last package which was observed on the current thread.
|
91
131
|
def last_package_for_current_thread
|
92
132
|
@last_package_for_thread[Thread.current.object_id]
|
data/lib/appmap/util.rb
CHANGED
@@ -93,6 +93,24 @@ module AppMap
|
|
93
93
|
matching_headers.blank? ? nil : matching_headers
|
94
94
|
end
|
95
95
|
|
96
|
+
def normalize_path(path)
|
97
|
+
if path.index(Dir.pwd) == 0
|
98
|
+
path[Dir.pwd.length + 1..-1]
|
99
|
+
else
|
100
|
+
path
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
# Convert a Rails-style path from /org/:org_id(.:format)
|
105
|
+
# to Swagger-style paths like /org/{org_id}
|
106
|
+
def swaggerize_path(path)
|
107
|
+
path = path.split('(.')[0]
|
108
|
+
tokens = path.split('/')
|
109
|
+
tokens.map do |token|
|
110
|
+
token.gsub /^:(.*)/, '{\1}'
|
111
|
+
end.join('/')
|
112
|
+
end
|
113
|
+
|
96
114
|
# Atomically writes AppMap data to +filename+.
|
97
115
|
def write_appmap(filename, appmap)
|
98
116
|
require 'fileutils'
|
data/lib/appmap/version.rb
CHANGED
data/package-lock.json
CHANGED
@@ -551,9 +551,9 @@
|
|
551
551
|
}
|
552
552
|
},
|
553
553
|
"lodash": {
|
554
|
-
"version": "4.17.
|
555
|
-
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.
|
556
|
-
"integrity": "sha512-
|
554
|
+
"version": "4.17.21",
|
555
|
+
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
556
|
+
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
|
557
557
|
},
|
558
558
|
"longest": {
|
559
559
|
"version": "1.0.1",
|
@@ -42,7 +42,7 @@ describe 'Rails' do
|
|
42
42
|
hash_including(
|
43
43
|
'http_server_request' => hash_including(
|
44
44
|
'request_method' => 'POST',
|
45
|
-
'normalized_path_info' => '/api/users
|
45
|
+
'normalized_path_info' => '/api/users',
|
46
46
|
'path_info' => '/api/users'
|
47
47
|
),
|
48
48
|
'message' => include(
|
@@ -144,7 +144,49 @@ describe 'Rails' do
|
|
144
144
|
end
|
145
145
|
|
146
146
|
describe 'a UI route' do
|
147
|
-
describe 'rendering a page' do
|
147
|
+
describe 'rendering a page using a template file' do
|
148
|
+
let(:appmap_json_file) do
|
149
|
+
'UsersController_GET_users_lists_the_users.appmap.json'
|
150
|
+
end
|
151
|
+
|
152
|
+
it 'records the template file' do
|
153
|
+
expect(events).to include hash_including(
|
154
|
+
'event' => 'call',
|
155
|
+
'defined_class' => 'app_views_users_index_html_haml',
|
156
|
+
'method_id' => 'render',
|
157
|
+
'path' => 'app/views/users/index.html.haml'
|
158
|
+
)
|
159
|
+
|
160
|
+
expect(appmap['classMap']).to include hash_including(
|
161
|
+
'name' => 'app/views',
|
162
|
+
'children' => include(hash_including(
|
163
|
+
'name' => 'app_views_users_index_html_haml',
|
164
|
+
'children' => include(hash_including(
|
165
|
+
'name' => 'render',
|
166
|
+
'type' => 'function',
|
167
|
+
'location' => 'app/views/users/index.html.haml',
|
168
|
+
'static' => true,
|
169
|
+
'labels' => [ 'mvc.template' ]
|
170
|
+
))
|
171
|
+
))
|
172
|
+
)
|
173
|
+
expect(appmap['classMap']).to include hash_including(
|
174
|
+
'name' => 'app/views',
|
175
|
+
'children' => include(hash_including(
|
176
|
+
'name' => 'app_views_layouts_application_html_haml',
|
177
|
+
'children' => include(hash_including(
|
178
|
+
'name' => 'render',
|
179
|
+
'type' => 'function',
|
180
|
+
'location' => 'app/views/layouts/application.html.haml',
|
181
|
+
'static' => true,
|
182
|
+
'labels' => [ 'mvc.template' ]
|
183
|
+
))
|
184
|
+
))
|
185
|
+
)
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
describe 'rendering a page using a text template' do
|
148
190
|
let(:appmap_json_file) do
|
149
191
|
'UsersController_GET_users_login_shows_the_user.appmap.json'
|
150
192
|
end
|
@@ -155,7 +197,7 @@ describe 'Rails' do
|
|
155
197
|
'http_server_request' => {
|
156
198
|
'request_method' => 'GET',
|
157
199
|
'path_info' => '/users/alice',
|
158
|
-
'normalized_path_info' => '/users
|
200
|
+
'normalized_path_info' => '/users/{id}',
|
159
201
|
'headers' => {
|
160
202
|
'Host' => 'test.host',
|
161
203
|
'User-Agent' => 'Rails Testing'
|
@@ -165,19 +207,36 @@ describe 'Rails' do
|
|
165
207
|
)
|
166
208
|
end
|
167
209
|
|
210
|
+
it 'ignores the text template' do
|
211
|
+
expect(events).to_not include hash_including(
|
212
|
+
'event' => 'call',
|
213
|
+
'method_id' => 'render',
|
214
|
+
'render_template' => anything
|
215
|
+
)
|
216
|
+
|
217
|
+
expect(appmap['classMap']).to_not include hash_including(
|
218
|
+
'name' => 'views',
|
219
|
+
'children' => include(hash_including(
|
220
|
+
'name' => 'ViewTemplate',
|
221
|
+
'children' => include(hash_including(
|
222
|
+
'name' => 'render',
|
223
|
+
'type' => 'function',
|
224
|
+
'location' => 'text template'
|
225
|
+
))
|
226
|
+
))
|
227
|
+
)
|
228
|
+
end
|
229
|
+
|
168
230
|
it 'records and labels view rendering' do
|
169
231
|
expect(events).to include hash_including(
|
170
232
|
'event' => 'call',
|
171
233
|
'thread_id' => Numeric,
|
172
|
-
'defined_class' => '
|
173
|
-
'method_id' => 'render'
|
174
|
-
'path' => String,
|
175
|
-
'lineno' => Integer,
|
176
|
-
'static' => false
|
234
|
+
'defined_class' => 'inline_template',
|
235
|
+
'method_id' => 'render'
|
177
236
|
)
|
178
237
|
|
179
238
|
expect(appmap['classMap']).to include hash_including(
|
180
|
-
'name' => '
|
239
|
+
'name' => 'actionview',
|
181
240
|
'children' => include(hash_including(
|
182
241
|
'name' => 'ActionView',
|
183
242
|
'children' => include(hash_including(
|