appmap 0.77.1 → 0.77.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +0 -7
- data/CHANGELOG.md +21 -0
- data/Rakefile +29 -3
- data/lib/appmap/config.rb +9 -1
- data/lib/appmap/handler/function.rb +8 -8
- data/lib/appmap/handler/net_http.rb +19 -18
- data/lib/appmap/handler/rails/request_handler.rb +3 -4
- data/lib/appmap/handler/rails/template.rb +68 -62
- data/lib/appmap/hook/method/ruby2.rb +56 -0
- data/lib/appmap/hook/method/ruby3.rb +56 -0
- data/lib/appmap/hook/method.rb +42 -98
- data/lib/appmap/hook.rb +2 -2
- data/lib/appmap/swagger/rake_tasks.rb +6 -1
- data/lib/appmap/version.rb +1 -1
- data/spec/fixtures/rails7_users_app/.dockerignore +1 -0
- data/spec/fixtures/rails7_users_app/.gitattributes +7 -0
- data/spec/fixtures/rails7_users_app/.gitignore +31 -0
- data/spec/fixtures/rails7_users_app/.rspec +1 -0
- data/spec/fixtures/rails7_users_app/.ruby-version +1 -0
- data/spec/fixtures/rails7_users_app/Dockerfile +30 -0
- data/spec/fixtures/rails7_users_app/Dockerfile.pg +3 -0
- data/spec/fixtures/rails7_users_app/Gemfile +99 -0
- data/spec/fixtures/rails7_users_app/README.md +24 -0
- data/spec/fixtures/rails7_users_app/Rakefile +6 -0
- data/spec/fixtures/rails7_users_app/app/assets/config/manifest.js +4 -0
- data/spec/fixtures/rails7_users_app/app/assets/images/.keep +0 -0
- data/spec/fixtures/rails7_users_app/app/assets/stylesheets/application.css +15 -0
- data/spec/fixtures/rails7_users_app/app/channels/application_cable/channel.rb +4 -0
- data/spec/fixtures/rails7_users_app/app/channels/application_cable/connection.rb +4 -0
- data/spec/fixtures/rails7_users_app/app/controllers/application_controller.rb +2 -0
- data/spec/fixtures/rails7_users_app/app/controllers/concerns/.keep +0 -0
- data/spec/fixtures/rails7_users_app/app/helpers/application_helper.rb +2 -0
- data/spec/fixtures/rails7_users_app/app/javascript/application.js +3 -0
- data/spec/fixtures/rails7_users_app/app/javascript/controllers/application.js +9 -0
- data/spec/fixtures/rails7_users_app/app/javascript/controllers/hello_controller.js +7 -0
- data/spec/fixtures/rails7_users_app/app/javascript/controllers/index.js +11 -0
- data/spec/fixtures/rails7_users_app/app/jobs/application_job.rb +7 -0
- data/spec/fixtures/rails7_users_app/app/mailers/application_mailer.rb +4 -0
- data/spec/fixtures/rails7_users_app/app/models/application_record.rb +3 -0
- data/spec/fixtures/rails7_users_app/app/models/concerns/.keep +0 -0
- data/spec/fixtures/rails7_users_app/app/models/instance.rb +7 -0
- data/spec/fixtures/rails7_users_app/app/models/instructor.rb +7 -0
- data/spec/fixtures/rails7_users_app/app/views/layouts/application.html.erb +16 -0
- data/spec/fixtures/rails7_users_app/app/views/layouts/mailer.html.erb +13 -0
- data/spec/fixtures/rails7_users_app/app/views/layouts/mailer.text.erb +1 -0
- data/spec/fixtures/rails7_users_app/appmap.yml +3 -0
- data/spec/fixtures/rails7_users_app/bin/bundle +114 -0
- data/spec/fixtures/rails7_users_app/bin/importmap +4 -0
- data/spec/fixtures/rails7_users_app/bin/rails +4 -0
- data/spec/fixtures/rails7_users_app/bin/rake +4 -0
- data/spec/fixtures/rails7_users_app/bin/setup +33 -0
- data/spec/fixtures/rails7_users_app/config/application.rb +22 -0
- data/spec/fixtures/rails7_users_app/config/boot.rb +4 -0
- data/spec/fixtures/rails7_users_app/config/cable.yml +10 -0
- data/spec/fixtures/rails7_users_app/config/credentials.yml.enc +1 -0
- data/spec/fixtures/rails7_users_app/config/database.yml +86 -0
- data/spec/fixtures/rails7_users_app/config/environment.rb +5 -0
- data/spec/fixtures/rails7_users_app/config/environments/development.rb +70 -0
- data/spec/fixtures/rails7_users_app/config/environments/production.rb +93 -0
- data/spec/fixtures/rails7_users_app/config/environments/test.rb +60 -0
- data/spec/fixtures/rails7_users_app/config/importmap.rb +7 -0
- data/spec/fixtures/rails7_users_app/config/initializers/assets.rb +12 -0
- data/spec/fixtures/rails7_users_app/config/initializers/content_security_policy.rb +26 -0
- data/spec/fixtures/rails7_users_app/config/initializers/filter_parameter_logging.rb +8 -0
- data/spec/fixtures/rails7_users_app/config/initializers/inflections.rb +16 -0
- data/spec/fixtures/rails7_users_app/config/initializers/permissions_policy.rb +11 -0
- data/spec/fixtures/rails7_users_app/config/locales/en.yml +33 -0
- data/spec/fixtures/rails7_users_app/config/puma.rb +43 -0
- data/spec/fixtures/rails7_users_app/config/routes.rb +6 -0
- data/spec/fixtures/rails7_users_app/config/storage.yml +34 -0
- data/spec/fixtures/rails7_users_app/config.ru +6 -0
- data/spec/fixtures/rails7_users_app/create_app +31 -0
- data/spec/fixtures/rails7_users_app/db/migrate/20220328093141_create_instances.rb +8 -0
- data/spec/fixtures/rails7_users_app/db/migrate/20220328093154_create_instructors.rb +8 -0
- data/spec/fixtures/rails7_users_app/db/schema.rb +27 -0
- data/spec/fixtures/rails7_users_app/db/seeds.rb +7 -0
- data/spec/fixtures/rails7_users_app/docker-compose.yml +31 -0
- data/spec/fixtures/rails7_users_app/lib/assets/.keep +0 -0
- data/spec/fixtures/rails7_users_app/lib/tasks/.keep +0 -0
- data/spec/fixtures/rails7_users_app/log/.keep +0 -0
- data/spec/fixtures/rails7_users_app/public/404.html +67 -0
- data/spec/fixtures/rails7_users_app/public/422.html +67 -0
- data/spec/fixtures/rails7_users_app/public/500.html +66 -0
- data/spec/fixtures/rails7_users_app/public/apple-touch-icon-precomposed.png +0 -0
- data/spec/fixtures/rails7_users_app/public/apple-touch-icon.png +0 -0
- data/spec/fixtures/rails7_users_app/public/favicon.ico +0 -0
- data/spec/fixtures/rails7_users_app/public/robots.txt +1 -0
- data/spec/fixtures/rails7_users_app/storage/.keep +0 -0
- data/spec/fixtures/rails7_users_app/test/application_system_test_case.rb +5 -0
- data/spec/fixtures/rails7_users_app/test/channels/application_cable/connection_test.rb +11 -0
- data/spec/fixtures/rails7_users_app/test/controllers/.keep +0 -0
- data/spec/fixtures/rails7_users_app/test/fixtures/files/.keep +0 -0
- data/spec/fixtures/rails7_users_app/test/fixtures/instances.yml +11 -0
- data/spec/fixtures/rails7_users_app/test/fixtures/instructors.yml +11 -0
- data/spec/fixtures/rails7_users_app/test/helpers/.keep +0 -0
- data/spec/fixtures/rails7_users_app/test/integration/.keep +0 -0
- data/spec/fixtures/rails7_users_app/test/mailers/.keep +0 -0
- data/spec/fixtures/rails7_users_app/test/models/.keep +0 -0
- data/spec/fixtures/rails7_users_app/test/models/instance_test.rb +6 -0
- data/spec/fixtures/rails7_users_app/test/models/instructor_test.rb +7 -0
- data/spec/fixtures/rails7_users_app/test/system/.keep +0 -0
- data/spec/fixtures/rails7_users_app/test/test_helper.rb +13 -0
- data/spec/hook_spec.rb +2 -2
- data/spec/rails_recording_spec.rb +6 -4
- data/spec/rails_spec_helper.rb +7 -0
- data/spec/rails_test_spec.rb +45 -0
- data/spec/swagger/swagger_spec.rb +2 -2
- metadata +93 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4a3775abc9bff6d949fa377e2da5121414500735c37d9c5b9d6f03a7a2ae31a7
|
4
|
+
data.tar.gz: 7254e2e5c3f25f431cdb25e8d0512d55a155afd8b64647b255b3a8223b663f3f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cf54fd237e40750eff85fb4723651a747ba6e69214ea04acae1a95964a09e4a800ea1de31dbc4f7dec7d26c585ef7fb9167a3e97eb36e9b0c14003240696d6d6
|
7
|
+
data.tar.gz: 81f413c5e21379b145a99f9882db9faea3d27e75ef56df7a8a928ce0b74f141c26025300cf0449fbf00128eb4991d99c94316f4fb522c5bd25042fb6ad2cfff3
|
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,24 @@
|
|
1
|
+
## [0.77.4](https://github.com/applandinc/appmap-ruby/compare/v0.77.3...v0.77.4) (2022-04-04)
|
2
|
+
|
3
|
+
|
4
|
+
### Bug Fixes
|
5
|
+
|
6
|
+
* Update Rails request handler to the new hook architecture ([595b39a](https://github.com/applandinc/appmap-ruby/commit/595b39abb030c1dcf85c83e4717c25d4c5177d4d))
|
7
|
+
|
8
|
+
## [0.77.3](https://github.com/applandinc/appmap-ruby/compare/v0.77.2...v0.77.3) (2022-03-29)
|
9
|
+
|
10
|
+
|
11
|
+
### Bug Fixes
|
12
|
+
|
13
|
+
* Rescue exceptions when calling Class#to_s ([f59f2f6](https://github.com/applandinc/appmap-ruby/commit/f59f2f6b39664ff050486c88ff1b859ca0db48d8))
|
14
|
+
|
15
|
+
## [0.77.2](https://github.com/applandinc/appmap-ruby/compare/v0.77.1...v0.77.2) (2022-03-25)
|
16
|
+
|
17
|
+
|
18
|
+
### Bug Fixes
|
19
|
+
|
20
|
+
* Pass the proper openapi-template arg ([05cbfde](https://github.com/applandinc/appmap-ruby/commit/05cbfdebdf80e3df2105a943ad892d5a7df614d7))
|
21
|
+
|
1
22
|
## [0.77.1](https://github.com/applandinc/appmap-ruby/compare/v0.77.0...v0.77.1) (2022-03-24)
|
2
23
|
|
3
24
|
|
data/Rakefile
CHANGED
@@ -2,6 +2,21 @@ $: << File.join(__dir__, 'lib')
|
|
2
2
|
require 'appmap/version'
|
3
3
|
GEM_VERSION = AppMap::VERSION
|
4
4
|
|
5
|
+
# Make sure the local version is not behind the one on
|
6
|
+
# rubygems.org (it's ok if they're the same).
|
7
|
+
#
|
8
|
+
# If it is behind, the fixture images won't get updated with the gem
|
9
|
+
# built from the local source, so you'll wind up testing the rubygems
|
10
|
+
# version instead.
|
11
|
+
unless ENV['SKIP_VERSION_CHECK']
|
12
|
+
require 'json'
|
13
|
+
require 'net/http'
|
14
|
+
rubygems_version = JSON.parse(Net::HTTP.get(URI.parse('https://rubygems.org/api/v1/gems/appmap.json')))['version']
|
15
|
+
if Gem::Version.new(GEM_VERSION) < Gem::Version.new(rubygems_version)
|
16
|
+
raise "#{GEM_VERSION} < #{rubygems_version}. Rebase to avoid build issues."
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
5
20
|
require 'rake/testtask'
|
6
21
|
require 'rdoc/task'
|
7
22
|
|
@@ -24,7 +39,7 @@ RUBY_VERSIONS=%w[2.6 2.7 3.0 3.1].select do |version|
|
|
24
39
|
|
25
40
|
false
|
26
41
|
end
|
27
|
-
FIXTURE_APPS
|
42
|
+
FIXTURE_APPS=[:rack_users_app, :rails6_users_app, :rails5_users_app, :rails7_users_app => {:ruby_version => '>= 2.7'}]
|
28
43
|
|
29
44
|
def run_cmd(*cmd)
|
30
45
|
$stderr.puts "Running: #{cmd}"
|
@@ -83,7 +98,17 @@ namespace :build do
|
|
83
98
|
RUBY_VERSIONS.each do |ruby_version|
|
84
99
|
namespace ruby_version do
|
85
100
|
desc "build:fixtures:#{ruby_version}"
|
86
|
-
FIXTURE_APPS.each do |
|
101
|
+
FIXTURE_APPS.each do |app_spec|
|
102
|
+
app = if app_spec.instance_of?(Hash)
|
103
|
+
app_spec = app_spec.flatten
|
104
|
+
version_rqt = Gem::Requirement.create(app_spec[1][:ruby_version])
|
105
|
+
next unless version_rqt =~ (Gem::Version.new(ruby_version))
|
106
|
+
app = app_spec[0]
|
107
|
+
else
|
108
|
+
app = app_spec
|
109
|
+
end.to_s
|
110
|
+
|
111
|
+
|
87
112
|
desc app
|
88
113
|
task app => ["base:#{ruby_version}"] do
|
89
114
|
build_app_image(app, ruby_version)
|
@@ -109,12 +134,13 @@ def run_specs(ruby_version, task_args)
|
|
109
134
|
# description), because it's not intended to be invoked directly
|
110
135
|
RSpec::Core::RakeTask.new("rspec_#{ruby_version}", [:specs]) do |task, args|
|
111
136
|
task.exclude_pattern = 'spec/fixtures/**/*_spec.rb'
|
137
|
+
task.rspec_opts = '-f doc'
|
112
138
|
if args.count > 0
|
113
139
|
# There doesn't appear to be a value for +pattern+ that will
|
114
140
|
# cause it to be ignored. Setting it to '' or +nil+ causes an
|
115
141
|
# empty argument to get passed to rspec, which confuses it.
|
116
142
|
task.pattern = 'never match this'
|
117
|
-
task.rspec_opts
|
143
|
+
task.rspec_opts += " " + args.to_a.join(' ')
|
118
144
|
end
|
119
145
|
end
|
120
146
|
|
data/lib/appmap/config.rb
CHANGED
@@ -450,7 +450,15 @@ module AppMap
|
|
450
450
|
|
451
451
|
# Hook a method which is specified by class and method name.
|
452
452
|
def package_for_code_object
|
453
|
-
class_name =
|
453
|
+
class_name = begin
|
454
|
+
cls.to_s.index('#<Class:') == 0 ? cls.to_s['#<Class:'.length...-1] : cls.name
|
455
|
+
rescue
|
456
|
+
# Calling #to_s on some Rails classes
|
457
|
+
# (e.g. those generated to represent
|
458
|
+
# associations) will raise an exception. Fall
|
459
|
+
# back to using the class name.
|
460
|
+
cls.name
|
461
|
+
end
|
454
462
|
Array(config.gem_hooks[class_name])
|
455
463
|
.find { |hook| hook.include_method?(method.name) }
|
456
464
|
&.package
|
@@ -1,18 +1,18 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'appmap/event'
|
4
|
+
require 'appmap/hook/method'
|
4
5
|
|
5
6
|
module AppMap
|
6
7
|
module Handler
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
8
|
+
# Base handler class, will emit method call and return events.
|
9
|
+
class Function < Hook::Method
|
10
|
+
def handle_call(receiver, args)
|
11
|
+
AppMap::Event::MethodCall.build_from_invocation(defined_class, hook_method, receiver, args)
|
12
|
+
end
|
12
13
|
|
13
|
-
|
14
|
-
|
15
|
-
end
|
14
|
+
def handle_return(call_event_id, elapsed, return_value, exception)
|
15
|
+
AppMap::Event::MethodReturn.build_from_invocation(call_event_id, return_value, exception, elapsed: elapsed)
|
16
16
|
end
|
17
17
|
end
|
18
18
|
end
|
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'appmap/event'
|
4
|
+
require 'appmap/hook/method'
|
4
5
|
require 'appmap/util'
|
5
6
|
require 'rack'
|
6
7
|
|
@@ -81,29 +82,29 @@ module AppMap
|
|
81
82
|
end
|
82
83
|
end
|
83
84
|
|
84
|
-
class
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
85
|
+
# Handler class for HTTP requests.
|
86
|
+
# Emits HTTP request events instead of method calls.
|
87
|
+
class NetHTTP < Hook::Method
|
88
|
+
def self.copy_headers(obj)
|
89
|
+
{}.tap do |headers|
|
90
|
+
obj.each_header do |key, value|
|
91
|
+
key = key.split('-').map(&:capitalize).join('-')
|
92
|
+
headers[key] = value
|
92
93
|
end
|
93
94
|
end
|
95
|
+
end
|
94
96
|
|
95
|
-
|
96
|
-
|
97
|
-
|
97
|
+
def handle_call(receiver, args)
|
98
|
+
# request will call itself again in a start block if it's not already started.
|
99
|
+
return unless receiver.started?
|
98
100
|
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
101
|
+
http = receiver
|
102
|
+
request = args.first
|
103
|
+
HTTPClientRequest.new(http, request)
|
104
|
+
end
|
103
105
|
|
104
|
-
|
105
|
-
|
106
|
-
end
|
106
|
+
def handle_return(call_event_id, elapsed, return_value, exception)
|
107
|
+
HTTPClientResponse.new(return_value, call_event_id, elapsed)
|
107
108
|
end
|
108
109
|
end
|
109
110
|
end
|
@@ -100,15 +100,14 @@ module AppMap
|
|
100
100
|
|
101
101
|
protected
|
102
102
|
|
103
|
-
def before_hook(receiver,
|
103
|
+
def before_hook(receiver, *)
|
104
104
|
call_event = HTTPServerRequest.new(receiver.request)
|
105
105
|
# http_server_request events are i/o and do not require a package name.
|
106
106
|
AppMap.tracing.record_event call_event, defined_class: defined_class, method: hook_method
|
107
|
-
|
107
|
+
call_event
|
108
108
|
end
|
109
109
|
|
110
|
-
def after_hook(receiver, call_event,
|
111
|
-
elapsed = TIME_NOW.call - start_time
|
110
|
+
def after_hook(receiver, call_event, elapsed, *)
|
112
111
|
return_event = HTTPServerResponse.new receiver.response, call_event.id, elapsed
|
113
112
|
AppMap.tracing.record_event return_event
|
114
113
|
end
|
@@ -1,5 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'appmap/handler/function'
|
3
4
|
require 'appmap/event'
|
4
5
|
|
5
6
|
module AppMap
|
@@ -9,7 +10,7 @@ module AppMap
|
|
9
10
|
LOG = (ENV['APPMAP_TEMPLATE_DEBUG'] == 'true' || ENV['DEBUG'] == 'true')
|
10
11
|
|
11
12
|
# All the code which is touched by the AppMap is recorded in the classMap.
|
12
|
-
# This duck-typed 'method' is used to represent a view template as a package,
|
13
|
+
# This duck-typed 'method' is used to represent a view template as a package,
|
13
14
|
# class, and method in the classMap.
|
14
15
|
# The class name is generated from the template path. The package name is
|
15
16
|
# 'app/views', and the method name is 'render'. The source location of the method
|
@@ -41,31 +42,31 @@ module AppMap
|
|
41
42
|
def package
|
42
43
|
'app/views'
|
43
44
|
end
|
44
|
-
|
45
|
+
|
45
46
|
def name
|
46
47
|
'render'
|
47
48
|
end
|
48
|
-
|
49
|
+
|
49
50
|
def source_location
|
50
51
|
path
|
51
52
|
end
|
52
|
-
|
53
|
+
|
53
54
|
def static
|
54
55
|
true
|
55
56
|
end
|
56
|
-
|
57
|
+
|
57
58
|
def comment
|
58
59
|
nil
|
59
60
|
end
|
60
|
-
|
61
|
+
|
61
62
|
def labels
|
62
63
|
[ 'mvc.template' ]
|
63
64
|
end
|
64
65
|
end
|
65
|
-
|
66
|
+
|
66
67
|
# TemplateCall is a type of function call which is specialized to view template rendering. Since
|
67
68
|
# there isn't really a perfect method in Rails to hook, this one is synthesized from the available
|
68
|
-
# information.
|
69
|
+
# information.
|
69
70
|
class TemplateCall < AppMap::Event::MethodEvent
|
70
71
|
# This is basically the +self+ parameter.
|
71
72
|
attr_reader :render_instance
|
@@ -75,19 +76,19 @@ module AppMap
|
|
75
76
|
attr_accessor :ready
|
76
77
|
|
77
78
|
alias ready? ready
|
78
|
-
|
79
|
+
|
79
80
|
def initialize(render_instance)
|
80
81
|
super :call
|
81
|
-
|
82
|
+
|
82
83
|
AppMap::Event::MethodEvent.build_from_invocation(:call, event: self)
|
83
84
|
@ready = false
|
84
85
|
@render_instance = render_instance
|
85
86
|
end
|
86
|
-
|
87
|
+
|
87
88
|
def static?
|
88
89
|
true
|
89
90
|
end
|
90
|
-
|
91
|
+
|
91
92
|
def to_h
|
92
93
|
super.tap do |h|
|
93
94
|
h[:defined_class] = path ? path.parameterize.underscore : 'inline_template'
|
@@ -103,71 +104,76 @@ module AppMap
|
|
103
104
|
end.compact
|
104
105
|
end
|
105
106
|
end
|
106
|
-
|
107
|
+
|
107
108
|
TEMPLATE_RENDERER = 'appmap.handler.rails.template.renderer'
|
108
109
|
|
109
110
|
# Hooks the ActionView::Resolver methods +find_all+, +find_all_anywhere+. The resolver is used
|
110
111
|
# during template rendering to lookup the template file path from parameters such as the
|
111
112
|
# template name, prefix, and partial (boolean).
|
112
|
-
class ResolverHandler
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
name, prefix, partial = args
|
117
|
-
warn "Resolver: #{{ name: name, prefix: prefix, partial: partial }}" if LOG
|
118
|
-
|
119
|
-
AppMap::Handler::Function.handle_call(defined_class, hook_method, receiver, args)
|
120
|
-
end
|
113
|
+
class ResolverHandler < AppMap::Handler::Function
|
114
|
+
def handle_call(receiver, args)
|
115
|
+
name, prefix, partial = args
|
116
|
+
warn "Resolver: #{{ name: name, prefix: prefix, partial: partial }}" if LOG
|
121
117
|
|
122
|
-
|
123
|
-
|
124
|
-
# template will be recorded in the classMap.
|
125
|
-
def handle_return(call_event_id, elapsed, return_value, exception)
|
126
|
-
renderer = Array(Thread.current[TEMPLATE_RENDERER]).last
|
127
|
-
path_obj = Array(return_value).first
|
128
|
-
|
129
|
-
warn "Resolver return: #{path_obj}" if LOG
|
130
|
-
|
131
|
-
if path_obj
|
132
|
-
path = if path_obj.respond_to?(:identifier) && path_obj.inspect.index('#<')
|
133
|
-
path_obj.identifier
|
134
|
-
else
|
135
|
-
path_obj.inspect
|
136
|
-
end
|
137
|
-
path = path[Dir.pwd.length + 1..-1] if path.index(Dir.pwd) == 0
|
138
|
-
AppMap.tracing.record_method(TemplateMethod.new(path))
|
139
|
-
renderer.path ||= path if renderer
|
140
|
-
end
|
118
|
+
super
|
119
|
+
end
|
141
120
|
|
142
|
-
|
143
|
-
|
121
|
+
# When the resolver returns, look to see if there is template rendering underway.
|
122
|
+
# If so, populate the template path. In all cases, add a TemplateMethod so that the
|
123
|
+
# template will be recorded in the classMap.
|
124
|
+
def handle_return(call_event_id, elapsed, return_value, exception)
|
125
|
+
renderer = Array(Thread.current[TEMPLATE_RENDERER]).last
|
126
|
+
path_obj = Array(return_value).first
|
127
|
+
|
128
|
+
warn "Resolver return: #{path_obj}" if LOG
|
129
|
+
|
130
|
+
record_template_path renderer, path_obj
|
131
|
+
|
132
|
+
super
|
133
|
+
end
|
134
|
+
|
135
|
+
def record_template_path(renderer, path_obj)
|
136
|
+
return unless path_obj
|
137
|
+
|
138
|
+
path = path_from_obj path_obj
|
139
|
+
AppMap.tracing.record_method(TemplateMethod.new(path))
|
140
|
+
renderer.path ||= path if renderer
|
141
|
+
end
|
142
|
+
|
143
|
+
def path_from_obj(path_obj)
|
144
|
+
path =
|
145
|
+
if path_obj.respond_to?(:identifier) && path_obj.inspect.index('#<')
|
146
|
+
path_obj.identifier
|
147
|
+
else
|
148
|
+
path_obj.inspect
|
149
|
+
end
|
150
|
+
path = path[Dir.pwd.length + 1..] if path.index(Dir.pwd) == 0
|
151
|
+
path
|
144
152
|
end
|
145
153
|
end
|
146
154
|
|
147
155
|
# Hooks the ActionView::Renderer method +render+. This method is used by Rails to perform
|
148
156
|
# template rendering. The TemplateCall event which is emitted by this handler has a
|
149
|
-
# +path+ parameter, which is nil until it's filled in by a ResolverHandler.
|
150
|
-
class RenderHandler
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
warn "Renderer: #{options}" if LOG
|
157
|
-
|
158
|
-
TemplateCall.new(receiver).tap do |call|
|
159
|
-
Thread.current[TEMPLATE_RENDERER] ||= []
|
160
|
-
Thread.current[TEMPLATE_RENDERER] << call
|
161
|
-
end
|
162
|
-
end
|
163
|
-
|
164
|
-
def handle_return(call_event_id, elapsed, return_value, exception)
|
165
|
-
template_call = Array(Thread.current[TEMPLATE_RENDERER]).pop
|
166
|
-
template_call.ready = true
|
157
|
+
# +path+ parameter, which is nil until it's filled in by a ResolverHandler.
|
158
|
+
class RenderHandler < AppMap::Hook::Method
|
159
|
+
def handle_call(receiver, args)
|
160
|
+
# context, options
|
161
|
+
_, options = args
|
162
|
+
|
163
|
+
warn "Renderer: #{options}" if LOG
|
167
164
|
|
168
|
-
|
165
|
+
TemplateCall.new(receiver).tap do |call|
|
166
|
+
Thread.current[TEMPLATE_RENDERER] ||= []
|
167
|
+
Thread.current[TEMPLATE_RENDERER] << call
|
169
168
|
end
|
170
169
|
end
|
170
|
+
|
171
|
+
def handle_return(call_event_id, elapsed, _return_value, _exception)
|
172
|
+
template_call = Array(Thread.current[TEMPLATE_RENDERER]).pop
|
173
|
+
template_call.ready = true
|
174
|
+
|
175
|
+
AppMap::Event::MethodReturnIgnoreValue.build_from_invocation(call_event_id, elapsed: elapsed)
|
176
|
+
end
|
171
177
|
end
|
172
178
|
end
|
173
179
|
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
def ruby2_keywords(*); end unless respond_to?(:ruby2_keywords, true)
|
4
|
+
|
5
|
+
module AppMap
|
6
|
+
class Hook
|
7
|
+
# Delegation methods for Ruby 2.
|
8
|
+
# cf. https://eregon.me/blog/2019/11/10/the-delegation-challenge-of-ruby27.html
|
9
|
+
class Method
|
10
|
+
ruby2_keywords def call(receiver, *args, &block)
|
11
|
+
return do_call(receiver, *args, &block) unless trace?
|
12
|
+
|
13
|
+
call_event = with_disabled_hook { before_hook receiver, *args }
|
14
|
+
trace_call call_event, receiver, *args, &block
|
15
|
+
end
|
16
|
+
|
17
|
+
protected
|
18
|
+
|
19
|
+
def before_hook(receiver, *args)
|
20
|
+
call_event = handle_call(receiver, args)
|
21
|
+
if call_event
|
22
|
+
AppMap.tracing.record_event \
|
23
|
+
call_event,
|
24
|
+
package: hook_package,
|
25
|
+
defined_class: defined_class,
|
26
|
+
method: hook_method
|
27
|
+
end
|
28
|
+
call_event
|
29
|
+
end
|
30
|
+
|
31
|
+
ruby2_keywords def do_call(receiver, *args, &block)
|
32
|
+
hook_method.bind(receiver).call(*args, &block)
|
33
|
+
end
|
34
|
+
|
35
|
+
ruby2_keywords def trace_call(call_event, receiver, *args, &block)
|
36
|
+
start_time = gettime
|
37
|
+
begin
|
38
|
+
return_value = do_call(receiver, *args, &block)
|
39
|
+
rescue # rubocop:disable Style/RescueStandardError
|
40
|
+
exception = $ERROR_INFO
|
41
|
+
raise
|
42
|
+
ensure
|
43
|
+
with_disabled_hook { after_hook receiver, call_event, gettime - start_time, return_value, exception } \
|
44
|
+
if call_event
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def hook_method_def
|
49
|
+
this = self
|
50
|
+
proc { |*args, &block| this.call self, *args, &block }.tap do |hook|
|
51
|
+
hook.ruby2_keywords if hook.respond_to? :ruby2_keywords
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AppMap
|
4
|
+
class Hook
|
5
|
+
# Delegation methods for Ruby 3.
|
6
|
+
class Method
|
7
|
+
def call(receiver, *args, **kwargs, &block)
|
8
|
+
return do_call(receiver, *args, **kwargs, &block) unless trace?
|
9
|
+
|
10
|
+
call_event = with_disabled_hook { before_hook receiver, *args, **kwargs }
|
11
|
+
trace_call call_event, receiver, *args, **kwargs, &block
|
12
|
+
end
|
13
|
+
|
14
|
+
protected
|
15
|
+
|
16
|
+
def before_hook(receiver, *args, **kwargs)
|
17
|
+
args = [*args, kwargs] if !kwargs.empty? || keyrest?
|
18
|
+
call_event = handle_call(receiver, args)
|
19
|
+
if call_event
|
20
|
+
AppMap.tracing.record_event \
|
21
|
+
call_event,
|
22
|
+
package: hook_package,
|
23
|
+
defined_class: defined_class,
|
24
|
+
method: hook_method
|
25
|
+
end
|
26
|
+
call_event
|
27
|
+
end
|
28
|
+
|
29
|
+
def keyrest?
|
30
|
+
@keyrest ||= parameters.map(&:last).include? :keyrest
|
31
|
+
end
|
32
|
+
|
33
|
+
def do_call(receiver, *args, **kwargs, &block)
|
34
|
+
hook_method.bind_call(receiver, *args, **kwargs, &block)
|
35
|
+
end
|
36
|
+
|
37
|
+
def trace_call(call_event, receiver, *args, **kwargs, &block)
|
38
|
+
start_time = gettime
|
39
|
+
begin
|
40
|
+
return_value = do_call(receiver, *args, **kwargs, &block)
|
41
|
+
rescue # rubocop:disable Style/RescueStandardError
|
42
|
+
exception = $ERROR_INFO
|
43
|
+
raise
|
44
|
+
ensure
|
45
|
+
with_disabled_hook { after_hook receiver, call_event, gettime - start_time, return_value, exception } \
|
46
|
+
if call_event
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def hook_method_def
|
51
|
+
this = self
|
52
|
+
proc { |*args, **kwargs, &block| this.call self, *args, **kwargs, &block }
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|