appmap 0.31.0 → 0.34.2
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/.gitignore +1 -1
- data/.rbenv-gemsets +1 -0
- data/CHANGELOG.md +22 -0
- data/README.md +38 -4
- data/Rakefile +10 -3
- data/appmap.gemspec +5 -0
- data/ext/appmap/appmap.c +26 -0
- data/ext/appmap/extconf.rb +6 -0
- data/lib/appmap.rb +23 -10
- data/lib/appmap/class_map.rb +13 -7
- data/lib/appmap/config.rb +54 -30
- data/lib/appmap/cucumber.rb +19 -2
- data/lib/appmap/event.rb +25 -16
- data/lib/appmap/hook.rb +52 -77
- data/lib/appmap/hook/method.rb +103 -0
- data/lib/appmap/open.rb +57 -0
- data/lib/appmap/rails/action_handler.rb +7 -7
- data/lib/appmap/rails/sql_handler.rb +10 -8
- data/lib/appmap/rspec.rb +1 -1
- data/lib/appmap/trace.rb +7 -7
- data/lib/appmap/util.rb +19 -0
- data/lib/appmap/version.rb +1 -1
- data/spec/abstract_controller4_base_spec.rb +1 -1
- data/spec/abstract_controller_base_spec.rb +9 -2
- data/spec/fixtures/hook/instance_method.rb +4 -0
- data/spec/fixtures/hook/singleton_method.rb +21 -12
- data/spec/hook_spec.rb +140 -44
- data/spec/open_spec.rb +19 -0
- data/spec/record_sql_rails_pg_spec.rb +56 -33
- data/test/cli_test.rb +12 -2
- data/test/fixtures/openssl_recorder/Gemfile +3 -0
- data/test/fixtures/openssl_recorder/appmap.yml +3 -0
- data/{spec/fixtures/hook/openssl_sign.rb → test/fixtures/openssl_recorder/lib/openssl_cert_sign.rb} +11 -4
- data/test/fixtures/openssl_recorder/lib/openssl_encrypt.rb +34 -0
- data/test/fixtures/openssl_recorder/lib/openssl_key_sign.rb +28 -0
- data/test/openssl_test.rb +203 -0
- data/test/test_helper.rb +1 -0
- metadata +58 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 81605d2c95140e963991e04af89235ee903cce0e3a86b2477f0f80961704e2d6
|
4
|
+
data.tar.gz: 7e526d9ffbc559bb3968b8a973dcd757147676d17a5028f737192fd8956d1b43
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6a34ba2662d48a7e0083e16d6abe4693b57711f9ac0020da6631ca6c40172aeb8f3ef734edd504cec00f2f437742e45fc0cf631b425cb960c9d51239556bc461
|
7
|
+
data.tar.gz: 156f126aac6f63e819c175d6b4d481679cbced9184007871c12fb174f187198afd8e7788befc4ab0ff35b10293e1e163eee25a985b35bd93853c03aa8268d192
|
data/.gitignore
CHANGED
data/.rbenv-gemsets
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
appmap-ruby
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,25 @@
|
|
1
|
+
# v0.34.2
|
2
|
+
* Add an extension that gets the name of the owner of a singleton method without calling
|
3
|
+
any methods that may have been redefined (e.g. `#to_s` or `.name`).
|
4
|
+
|
5
|
+
# v0.34.1
|
6
|
+
* Ensure that capturing events doesn't change the behavior of a hooked method that uses
|
7
|
+
`Time.now`. For example, if a test expects that `Time.now` will be called a certain
|
8
|
+
number of times by a hooked method, that expectation will now be met.
|
9
|
+
* Make sure `appmap/cucumber` requires `appmap`.
|
10
|
+
|
11
|
+
# v0.34.0
|
12
|
+
|
13
|
+
* Records builtin security and I/O methods from `OpenSSL`, `Net`, and `IO`.
|
14
|
+
|
15
|
+
# v0.33.0
|
16
|
+
|
17
|
+
* Added command `AppMap.open` to open an AppMap in the browser.
|
18
|
+
|
19
|
+
# v0.32.0
|
20
|
+
|
21
|
+
* Removes un-necessary fields from `return` events.
|
22
|
+
|
1
23
|
# v0.31.0
|
2
24
|
|
3
25
|
* Add the ability to hook methods by default, and optionally add labels to them in the
|
data/README.md
CHANGED
@@ -33,7 +33,7 @@ There are several ways to record AppMaps of your Ruby program using the `appmap`
|
|
33
33
|
|
34
34
|
Once you have recorded some AppMaps (for example, by running RSpec tests), you use the `appland upload` command
|
35
35
|
to upload them to the AppLand server. This command, and some others, is provided
|
36
|
-
by the [AppLand CLI](https://github.com/applandinc/appland-cli/releases)
|
36
|
+
by the [AppLand CLI](https://github.com/applandinc/appland-cli/releases).
|
37
37
|
Then, on the [AppLand website](https://app.land), you can
|
38
38
|
visualize the design of your code and share links with collaborators.
|
39
39
|
|
@@ -87,12 +87,25 @@ Each entry in the `packages` list is a YAML object which has the following keys:
|
|
87
87
|
|
88
88
|
To record RSpec tests, follow these additional steps:
|
89
89
|
|
90
|
-
1) Require `appmap/rspec` in your `spec_helper.rb
|
90
|
+
1) Require `appmap/rspec` in your `spec_helper.rb` before any other classes are loaded.
|
91
91
|
|
92
92
|
```ruby
|
93
93
|
require 'appmap/rspec'
|
94
94
|
```
|
95
95
|
|
96
|
+
Note that `spec_helper.rb` in a Rails project typically loads the application's classes this way:
|
97
|
+
|
98
|
+
```ruby
|
99
|
+
require File.expand_path("../../config/environment", __FILE__)
|
100
|
+
```
|
101
|
+
|
102
|
+
and `appmap/rspec` must be required before this:
|
103
|
+
|
104
|
+
```ruby
|
105
|
+
require 'appmap/rspec'
|
106
|
+
require File.expand_path("../../config/environment", __FILE__)
|
107
|
+
```
|
108
|
+
|
96
109
|
2) *Optional* Add `feature: '<feature name>'` and `feature_group: '<feature group name>'` annotations to your
|
97
110
|
examples.
|
98
111
|
|
@@ -136,6 +149,19 @@ To record Minitest tests, follow these additional steps:
|
|
136
149
|
require 'appmap/minitest'
|
137
150
|
```
|
138
151
|
|
152
|
+
Note that `test_helper.rb` in a Rails project typically loads the application's classes this way:
|
153
|
+
|
154
|
+
```ruby
|
155
|
+
require_relative '../config/environment'
|
156
|
+
```
|
157
|
+
|
158
|
+
and `appmap/rspec` must be required before this:
|
159
|
+
|
160
|
+
```ruby
|
161
|
+
require 'appmap/rspec'
|
162
|
+
require_relative '../config/environment'
|
163
|
+
```
|
164
|
+
|
139
165
|
2) Run the tests with the environment variable `APPMAP=true`:
|
140
166
|
|
141
167
|
```sh-session
|
@@ -159,6 +185,8 @@ To record Cucumber tests, follow these additional steps:
|
|
159
185
|
require 'appmap/cucumber'
|
160
186
|
```
|
161
187
|
|
188
|
+
Be sure to require it before `config/environment` is required.
|
189
|
+
|
162
190
|
2) Create an `Around` hook in `support/hooks.rb` to record the scenario:
|
163
191
|
|
164
192
|
|
@@ -239,7 +267,13 @@ $ bundle config local.appmap $(pwd)
|
|
239
267
|
Run the tests via `rake`:
|
240
268
|
```
|
241
269
|
$ bundle exec rake test
|
242
|
-
```
|
270
|
+
```
|
271
|
+
|
272
|
+
The `test` target will build the native extension first, then run the tests. If you need
|
273
|
+
to build the extension separately, run
|
274
|
+
```
|
275
|
+
$ bundle exec rake compile
|
276
|
+
```
|
243
277
|
|
244
278
|
## Using fixture apps
|
245
279
|
|
@@ -258,7 +292,7 @@ resources such as a PostgreSQL database.
|
|
258
292
|
To build the fixture container images, first run:
|
259
293
|
|
260
294
|
```sh-session
|
261
|
-
$ bundle exec rake fixtures:all
|
295
|
+
$ bundle exec rake build:fixtures:all
|
262
296
|
```
|
263
297
|
|
264
298
|
This will build the `appmap.gem`, along with a Docker image for each fixture app.
|
data/Rakefile
CHANGED
@@ -6,6 +6,13 @@ require 'rdoc/task'
|
|
6
6
|
|
7
7
|
require 'open3'
|
8
8
|
|
9
|
+
require "rake/extensiontask"
|
10
|
+
|
11
|
+
desc 'build the native extension'
|
12
|
+
Rake::ExtensionTask.new("appmap") do |ext|
|
13
|
+
ext.lib_dir = "lib/appmap"
|
14
|
+
end
|
15
|
+
|
9
16
|
namespace 'gem' do
|
10
17
|
require 'bundler/gem_tasks'
|
11
18
|
end
|
@@ -104,7 +111,7 @@ end
|
|
104
111
|
namespace :spec do
|
105
112
|
RUBY_VERSIONS.each do |ruby_version|
|
106
113
|
desc ruby_version
|
107
|
-
task ruby_version, [:specs] => ["build:fixtures:#{ruby_version}:all"] do |_, task_args|
|
114
|
+
task ruby_version, [:specs] => ["compile", "build:fixtures:#{ruby_version}:all"] do |_, task_args|
|
108
115
|
run_specs(ruby_version, task_args)
|
109
116
|
end.tap do|t|
|
110
117
|
desc "Run all specs"
|
@@ -119,13 +126,13 @@ Rake::RDocTask.new do |rd|
|
|
119
126
|
rd.title = 'AppMap'
|
120
127
|
end
|
121
128
|
|
122
|
-
Rake::TestTask.new(:
|
129
|
+
Rake::TestTask.new(minitest: 'compile') do |t|
|
123
130
|
t.libs << 'test'
|
124
131
|
t.libs << 'lib'
|
125
132
|
t.test_files = FileList['test/*_test.rb']
|
126
133
|
end
|
127
134
|
|
128
|
-
task spec:
|
135
|
+
task spec: %i[spec:all]
|
129
136
|
|
130
137
|
task test: %i[spec:all minitest]
|
131
138
|
|
data/appmap.gemspec
CHANGED
@@ -18,6 +18,8 @@ Gem::Specification.new do |spec|
|
|
18
18
|
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
19
19
|
spec.files = `git ls-files --no-deleted`.split("
|
20
20
|
")
|
21
|
+
spec.extensions << "ext/appmap/extconf.rb"
|
22
|
+
|
21
23
|
spec.bindir = 'exe'
|
22
24
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
23
25
|
spec.require_paths = ['lib']
|
@@ -26,6 +28,7 @@ Gem::Specification.new do |spec|
|
|
26
28
|
spec.add_dependency 'faraday'
|
27
29
|
spec.add_dependency 'gli'
|
28
30
|
spec.add_dependency 'parser'
|
31
|
+
spec.add_dependency 'rack'
|
29
32
|
|
30
33
|
spec.add_development_dependency 'bundler', '~> 1.16'
|
31
34
|
spec.add_development_dependency 'minitest', '~> 5.0'
|
@@ -33,6 +36,7 @@ Gem::Specification.new do |spec|
|
|
33
36
|
spec.add_development_dependency 'rake', '>= 12.3.3'
|
34
37
|
spec.add_development_dependency 'rdoc'
|
35
38
|
spec.add_development_dependency 'rubocop'
|
39
|
+
spec.add_development_dependency "rake-compiler"
|
36
40
|
|
37
41
|
# Testing
|
38
42
|
spec.add_development_dependency 'climate_control'
|
@@ -41,4 +45,5 @@ Gem::Specification.new do |spec|
|
|
41
45
|
spec.add_development_dependency 'rspec'
|
42
46
|
spec.add_development_dependency 'selenium-webdriver'
|
43
47
|
spec.add_development_dependency 'webdrivers', '~> 4.0'
|
48
|
+
spec.add_development_dependency 'timecop'
|
44
49
|
end
|
data/ext/appmap/appmap.c
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
#include <ruby.h>
|
2
|
+
#include <ruby/intern.h>
|
3
|
+
|
4
|
+
// Seems like CLASS_OR_MODULE_P should really be in a header file in
|
5
|
+
// the ruby source -- it's in object.c and duplicated in eval.c. In
|
6
|
+
// the future, we'll fail if it does get moved to a header.
|
7
|
+
#define CLASS_OR_MODULE_P(obj) \
|
8
|
+
(!SPECIAL_CONST_P(obj) && \
|
9
|
+
(BUILTIN_TYPE(obj) == T_CLASS || BUILTIN_TYPE(obj) == T_MODULE))
|
10
|
+
|
11
|
+
static VALUE singleton_method_owner_name(VALUE klass, VALUE method)
|
12
|
+
{
|
13
|
+
VALUE owner = rb_funcall(method, rb_intern("owner"), 0);
|
14
|
+
VALUE attached = rb_ivar_get(owner, rb_intern("__attached__"));
|
15
|
+
if (!CLASS_OR_MODULE_P(attached)) {
|
16
|
+
attached = rb_funcall(attached, rb_intern("class"), 0);
|
17
|
+
}
|
18
|
+
return rb_mod_name(attached);
|
19
|
+
}
|
20
|
+
|
21
|
+
void Init_appmap() {
|
22
|
+
VALUE appmap = rb_define_module("AppMap");
|
23
|
+
VALUE hook = rb_define_class_under(appmap, "Hook", rb_cObject);
|
24
|
+
|
25
|
+
rb_define_singleton_method(hook, "singleton_method_owner_name", singleton_method_owner_name, 1);
|
26
|
+
}
|
data/lib/appmap.rb
CHANGED
@@ -13,19 +13,24 @@ require 'appmap/config'
|
|
13
13
|
require 'appmap/trace'
|
14
14
|
require 'appmap/class_map'
|
15
15
|
require 'appmap/metadata'
|
16
|
+
require 'appmap/util'
|
17
|
+
require 'appmap/open'
|
18
|
+
|
19
|
+
# load extension
|
20
|
+
require 'appmap/appmap'
|
16
21
|
|
17
22
|
module AppMap
|
18
23
|
class << self
|
19
24
|
@configuration = nil
|
20
25
|
@configuration_file_path = nil
|
21
26
|
|
22
|
-
#
|
27
|
+
# Gets the configuration. If there is no configuration, the default
|
23
28
|
# configuration is initialized.
|
24
29
|
def configuration
|
25
|
-
@configuration ||=
|
30
|
+
@configuration ||= initialize
|
26
31
|
end
|
27
32
|
|
28
|
-
#
|
33
|
+
# Sets the configuration. This is only expected to happen once per
|
29
34
|
# Ruby process.
|
30
35
|
def configuration=(config)
|
31
36
|
warn 'AppMap is already configured' if @configuration && config
|
@@ -33,22 +38,24 @@ module AppMap
|
|
33
38
|
@configuration = config
|
34
39
|
end
|
35
40
|
|
36
|
-
#
|
41
|
+
# Configures AppMap for recording. Default behavior is to configure from "appmap.yml".
|
37
42
|
# This method also activates the code hooks which record function calls as trace events.
|
38
43
|
# Call this function before the program code is loaded by the Ruby VM, otherwise
|
39
44
|
# the load events won't be seen and the hooks won't activate.
|
40
45
|
def initialize(config_file_path = 'appmap.yml')
|
41
46
|
warn "Configuring AppMap from path #{config_file_path}"
|
42
|
-
|
43
|
-
|
47
|
+
Config.load_from_file(config_file_path).tap do |configuration|
|
48
|
+
self.configuration = configuration
|
49
|
+
Hook.new(configuration).enable
|
50
|
+
end
|
44
51
|
end
|
45
52
|
|
46
|
-
#
|
53
|
+
# Used to start tracing, stop tracing, and record events.
|
47
54
|
def tracing
|
48
55
|
@tracing ||= Trace::Tracing.new
|
49
56
|
end
|
50
57
|
|
51
|
-
#
|
58
|
+
# Records the events which occur while processing a block,
|
52
59
|
# and returns an AppMap as a Hash.
|
53
60
|
def record
|
54
61
|
tracer = tracing.trace
|
@@ -69,12 +76,18 @@ module AppMap
|
|
69
76
|
}
|
70
77
|
end
|
71
78
|
|
72
|
-
#
|
79
|
+
# Uploads an AppMap to the AppLand website and displays it.
|
80
|
+
def open(appmap = nil, &block)
|
81
|
+
appmap ||= AppMap.record(&block)
|
82
|
+
AppMap::Open.new(appmap).perform
|
83
|
+
end
|
84
|
+
|
85
|
+
# Builds a class map from a config and a list of Ruby methods.
|
73
86
|
def class_map(methods)
|
74
87
|
ClassMap.build_from_methods(configuration, methods)
|
75
88
|
end
|
76
89
|
|
77
|
-
#
|
90
|
+
# Returns default metadata detected from the Ruby system and from the
|
78
91
|
# filesystem.
|
79
92
|
def detect_metadata
|
80
93
|
@metadata ||= Metadata.detect.freeze
|
data/lib/appmap/class_map.rb
CHANGED
@@ -61,7 +61,7 @@ module AppMap
|
|
61
61
|
location: location,
|
62
62
|
static: static,
|
63
63
|
labels: labels
|
64
|
-
}.delete_if {|k,v| v.nil?}
|
64
|
+
}.delete_if { |k,v| v.nil? || v == [] }
|
65
65
|
end
|
66
66
|
end
|
67
67
|
end
|
@@ -80,10 +80,6 @@ module AppMap
|
|
80
80
|
protected
|
81
81
|
|
82
82
|
def add_function(root, package, method)
|
83
|
-
location = method.source_location
|
84
|
-
location_file, lineno = location
|
85
|
-
location_file = location_file[Dir.pwd.length + 1..-1] if location_file.index(Dir.pwd) == 0
|
86
|
-
|
87
83
|
static = method.static
|
88
84
|
|
89
85
|
object_infos = [
|
@@ -101,12 +97,22 @@ module AppMap
|
|
101
97
|
function_info = {
|
102
98
|
name: method.name,
|
103
99
|
type: 'function',
|
104
|
-
location: [ location_file, lineno ].join(':'),
|
105
100
|
static: static
|
106
101
|
}
|
102
|
+
location = method.source_location
|
103
|
+
|
104
|
+
function_info[:location] = \
|
105
|
+
if location
|
106
|
+
location_file, lineno = location
|
107
|
+
location_file = location_file[Dir.pwd.length + 1..-1] if location_file.index(Dir.pwd) == 0
|
108
|
+
[ location_file, lineno ].join(':')
|
109
|
+
else
|
110
|
+
[ method.defined_class, static ? '.' : '#', method.name ].join
|
111
|
+
end
|
112
|
+
|
107
113
|
function_info[:labels] = package.labels if package.labels
|
108
114
|
object_infos << function_info
|
109
|
-
|
115
|
+
|
110
116
|
parent = root
|
111
117
|
object_infos.each do |info|
|
112
118
|
parent = find_or_create parent.children, info do
|
data/lib/appmap/config.rb
CHANGED
@@ -1,33 +1,54 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module AppMap
|
4
|
-
|
5
|
-
|
6
|
-
|
4
|
+
class Config
|
5
|
+
Package = Struct.new(:path, :package_name, :exclude, :labels) do
|
6
|
+
def initialize(path, package_name: nil, exclude: [], labels: [])
|
7
|
+
super path, package_name, exclude, labels
|
8
|
+
end
|
9
|
+
|
10
|
+
def to_h
|
11
|
+
{
|
12
|
+
path: path,
|
13
|
+
package_name: package_name,
|
14
|
+
exclude: exclude.blank? ? nil : exclude,
|
15
|
+
labels: labels.blank? ? nil : labels
|
16
|
+
}.compact
|
17
|
+
end
|
7
18
|
end
|
8
|
-
|
9
|
-
|
10
|
-
{
|
11
|
-
path: path,
|
12
|
-
exclude: exclude.blank? ? nil : exclude,
|
13
|
-
labels: labels.blank? ? nil : labels
|
14
|
-
}.compact
|
19
|
+
|
20
|
+
Hook = Struct.new(:method_names, :package) do
|
15
21
|
end
|
16
|
-
end
|
17
22
|
|
18
|
-
|
23
|
+
OPENSSL_PACKAGE = Package.new('openssl', package_name: 'openssl', labels: %w[security crypto])
|
24
|
+
|
19
25
|
# Methods that should always be hooked, with their containing
|
20
26
|
# package and labels that should be applied to them.
|
21
27
|
HOOKED_METHODS = {
|
22
|
-
'ActiveSupport::SecurityUtils' =>
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
28
|
+
'ActiveSupport::SecurityUtils' => Hook.new(:secure_compare, Package.new('active_support', package_name: 'active_support', labels: %w[security crypto]))
|
29
|
+
}.freeze
|
30
|
+
|
31
|
+
BUILTIN_METHODS = {
|
32
|
+
'OpenSSL::PKey::PKey' => Hook.new(:sign, OPENSSL_PACKAGE),
|
33
|
+
'Digest::Instance' => Hook.new(:digest, OPENSSL_PACKAGE),
|
34
|
+
'OpenSSL::X509::Request' => Hook.new(%i[sign verify], OPENSSL_PACKAGE),
|
35
|
+
'OpenSSL::PKCS5' => Hook.new(%i[pbkdf2_hmac_sha1 pbkdf2_hmac], OPENSSL_PACKAGE),
|
36
|
+
'OpenSSL::Cipher' => Hook.new(%i[encrypt decrypt final], OPENSSL_PACKAGE),
|
37
|
+
'OpenSSL::X509::Certificate' => Hook.new(:sign, OPENSSL_PACKAGE),
|
38
|
+
'Logger' => Hook.new(:add, Package.new('logger', labels: %w[log io])),
|
39
|
+
'Net::HTTP' => Hook.new(:request, Package.new('net/http', package_name: 'net/http', labels: %w[http io])),
|
40
|
+
'Net::SMTP' => Hook.new(:send, Package.new('net/smtp', package_name: 'net/smtp', labels: %w[smtp email io])),
|
41
|
+
'Net::POP3' => Hook.new(:mails, Package.new('net/pop3', package_name: 'net/pop', labels: %w[pop pop3 email io])),
|
42
|
+
'Net::IMAP' => Hook.new(:send_command, Package.new('net/imap', package_name: 'net/imap', labels: %w[imap email io])),
|
43
|
+
'IO' => Hook.new(%i[read write open close], Package.new('io', labels: %w[io])),
|
44
|
+
'Marshal' => Hook.new(%i[dump load], Package.new('marshal', labels: %w[serialization marshal])),
|
45
|
+
'Psych' => Hook.new(%i[dump dump_stream load load_stream parse parse_stream], Package.new('yaml', package_name: 'psych', labels: %w[serialization yaml])),
|
46
|
+
'JSON::Ext::Parser' => Hook.new(:parse, Package.new('json', package_name: 'json', labels: %w[serialization json])),
|
47
|
+
'JSON::Ext::Generator::State' => Hook.new(:generate, Package.new('json', package_name: 'json', labels: %w[serialization json]))
|
48
|
+
}.freeze
|
29
49
|
|
30
50
|
attr_reader :name, :packages
|
51
|
+
|
31
52
|
def initialize(name, packages = [])
|
32
53
|
@name = name
|
33
54
|
@packages = packages
|
@@ -43,7 +64,7 @@ module AppMap
|
|
43
64
|
# Loads configuration from a Hash.
|
44
65
|
def load(config_data)
|
45
66
|
packages = (config_data['packages'] || []).map do |package|
|
46
|
-
Package.new(package['path'], package['exclude'] || [])
|
67
|
+
Package.new(package['path'], exclude: package['exclude'] || [])
|
47
68
|
end
|
48
69
|
Config.new config_data['name'], packages
|
49
70
|
end
|
@@ -57,14 +78,14 @@ module AppMap
|
|
57
78
|
end
|
58
79
|
|
59
80
|
def package_for_method(method)
|
81
|
+
defined_class, _, method_name = ::AppMap::Hook.qualify_method_name(method)
|
82
|
+
package = find_package(defined_class, method_name)
|
83
|
+
return package if package
|
84
|
+
|
60
85
|
location = method.source_location
|
61
86
|
location_file, = location
|
62
87
|
return unless location_file
|
63
88
|
|
64
|
-
defined_class,_,method_name = Hook.qualify_method_name(method)
|
65
|
-
hooked_method = find_hooked_method(defined_class, method_name)
|
66
|
-
return hooked_method if hooked_method
|
67
|
-
|
68
89
|
location_file = location_file[Dir.pwd.length + 1..-1] if location_file.index(Dir.pwd) == 0
|
69
90
|
packages.find do |pkg|
|
70
91
|
(location_file.index(pkg.path) == 0) &&
|
@@ -77,15 +98,18 @@ module AppMap
|
|
77
98
|
end
|
78
99
|
|
79
100
|
def always_hook?(defined_class, method_name)
|
80
|
-
!!
|
101
|
+
!!find_package(defined_class, method_name)
|
81
102
|
end
|
82
103
|
|
83
|
-
def
|
84
|
-
|
104
|
+
def find_package(defined_class, method_name)
|
105
|
+
hook = find_hook(defined_class)
|
106
|
+
return nil unless hook
|
107
|
+
|
108
|
+
Array(hook.method_names).include?(method_name) ? hook.package : nil
|
85
109
|
end
|
86
|
-
|
87
|
-
def
|
88
|
-
HOOKED_METHODS[defined_class] ||
|
110
|
+
|
111
|
+
def find_hook(defined_class)
|
112
|
+
HOOKED_METHODS[defined_class] || BUILTIN_METHODS[defined_class]
|
89
113
|
end
|
90
114
|
end
|
91
115
|
end
|