appmap 0.77.1 → 0.77.4
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 +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
|