appmap 0.68.2 → 0.70.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7e87a42863f68312980ff6e9689b74489b147b283854463abbf1e2cf6be4fe29
4
- data.tar.gz: 0d5a7e86d9cea6ba154e6bc1ceb920fcba978074afd4351663832946d0ab0f30
3
+ metadata.gz: d65574736497b9626d5d45bedee98bf5b4e810dada23199cb3b6857928c609a7
4
+ data.tar.gz: d90ebdbb5978d36a9fa78aab06df63578645d600dc26e8a3c3e78e5a9c3f198d
5
5
  SHA512:
6
- metadata.gz: bc509802c9b69cca4cc88560b23b0d56e6c72f852e21dc414f5732e6e4cbfe8867b7dcfa132673e2a647f072bcafbe0086e2cbc15b2280eb3b5e3fcaef2db577
7
- data.tar.gz: e48934b5719439fa61970e7d239b163c6f42c0e9f5bd7c4a7959f73b62ff9e610fb967b124698129c96271a124d8288e9069e073f1cdeeffc53060270cf30c26
6
+ metadata.gz: e6645bda09b9fb033825c4230518322b537b013d96ec5c76de25736729a10d2338fd3361481901c804472c23f68552f5f6822d487dbd935ab8c45b67810b4a7a
7
+ data.tar.gz: a831e8748e982cf7ebb65f0a3bc0a9209a7e8b1991b85716d4fc43898685749304eeb5450b5e84a4657187b95f38b05c936a49b35ad18e30e8070110ddccf7ee
data/CHANGELOG.md CHANGED
@@ -1,3 +1,32 @@
1
+ ## [0.70.2](https://github.com/applandinc/appmap-ruby/compare/v0.70.1...v0.70.2) (2022-01-12)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * switch to activesupport's deep_dup implementation ([7715f28](https://github.com/applandinc/appmap-ruby/commit/7715f28285fbdabdb4c8d652fb9ac31eb8d86eab))
7
+
8
+ ## [0.70.1](https://github.com/applandinc/appmap-ruby/compare/v0.70.0...v0.70.1) (2021-12-10)
9
+
10
+
11
+ ### Bug Fixes
12
+
13
+ * Use require_name as the default package 'path' for builtins ([bcb4367](https://github.com/applandinc/appmap-ruby/commit/bcb4367811992c924c76950a22d11ddc3057c1ee))
14
+
15
+ # [0.70.0](https://github.com/applandinc/appmap-ruby/compare/v0.69.0...v0.70.0) (2021-12-08)
16
+
17
+
18
+ ### Features
19
+
20
+ * Hook protected methods ([a3722b5](https://github.com/applandinc/appmap-ruby/commit/a3722b504b8e5b8c032988b586b13bdd071fe577))
21
+ * Report sub-packages for nested folders ([dce709b](https://github.com/applandinc/appmap-ruby/commit/dce709b077fd64fc2b34f9abb30a65db529f824b))
22
+
23
+ # [0.69.0](https://github.com/applandinc/appmap-ruby/compare/v0.68.2...v0.69.0) (2021-12-01)
24
+
25
+
26
+ ### Features
27
+
28
+ * Add labels for job creation and canceling ([644fafe](https://github.com/applandinc/appmap-ruby/commit/644fafe7f0eab626a9e0a52243ad4faf052a883a))
29
+
1
30
  ## [0.68.2](https://github.com/applandinc/appmap-ruby/compare/v0.68.1...v0.68.2) (2021-11-25)
2
31
 
3
32
 
data/config-schema.yml CHANGED
@@ -45,13 +45,25 @@ properties:
45
45
  type: object
46
46
  additionalProperties: false
47
47
  properties:
48
- package:
48
+ method:
49
49
  type: string
50
- class:
51
- type: string
52
- function:
50
+ label:
53
51
  type: string
52
+ methods:
53
+ type: array
54
+ items:
55
+ type: string
54
56
  labels:
55
57
  type: array
56
58
  items:
57
59
  type: string
60
+ require_name:
61
+ type: string
62
+ gem:
63
+ type: string
64
+ path:
65
+ type: string
66
+ builtin:
67
+ type: boolean
68
+ force:
69
+ type: boolean
@@ -76,24 +76,39 @@ module AppMap
76
76
  methods.each do |method|
77
77
  add_function root, method
78
78
  end
79
- root.children.map(&:to_h)
79
+
80
+ collapse_package = lambda do |package|
81
+ return unless package.type == 'package'
82
+
83
+ while package.children.length == 1 && package.children.all? { |child| child.type == 'package' }
84
+ child = package.children[0]
85
+ package.children.clear
86
+ child.children.each { |child| package.children << child }
87
+ package.name = [ package.name, child.name ].join('/')
88
+ end
89
+ package.tap do
90
+ package.children.map(&collapse_package)
91
+ end
92
+ end
93
+
94
+ root.children.map(&collapse_package).map(&:to_h)
80
95
  end
81
96
 
82
97
  protected
83
98
 
84
99
  def add_function(root, method)
85
- object_infos = [
86
- {
87
- name: method.package,
88
- type: 'package'
89
- }
90
- ]
91
- object_infos += method.class_name.split('::').map do |name|
92
- {
93
- name: name,
94
- type: 'class'
95
- }
96
- end
100
+ object_infos = \
101
+ method.package.split('/').map do |name|
102
+ {
103
+ name: name,
104
+ type: 'package'
105
+ }
106
+ end + method.class_name.split('::').map do |name|
107
+ {
108
+ name: name,
109
+ type: 'class'
110
+ }
111
+ end
97
112
  function_info = {
98
113
  name: method.name,
99
114
  type: 'function',
data/lib/appmap/config.rb CHANGED
@@ -44,6 +44,21 @@ module AppMap
44
44
  shallow
45
45
  end
46
46
 
47
+ # Clones this package into a sub-package, if needed.
48
+ # For example, suppose the appmap.yml specifies package `app/models`. If some code in
49
+ # `app/models/dao/user.rb` is mapped, it will be associated with a sub-package
50
+ # `app/models/dao`.
51
+ def subpackage(location, config)
52
+ return self if gem
53
+
54
+ path = location.split('/')[0...-1].join('/')
55
+ clone.tap do |pkg|
56
+ pkg.name = path
57
+ pkg.path = path
58
+ config.packages << pkg
59
+ end
60
+ end
61
+
47
62
  class << self
48
63
  # Builds a package for a path, such as `app/models` in a Rails app. Generally corresponds to a `path:` entry
49
64
  # in appmap.yml. Also used for mapping specific methods via TargetMethods.
@@ -148,7 +163,7 @@ module AppMap
148
163
  def package_hooks(methods, path: nil, gem: nil, force: false, builtin: false, handler_class: nil, require_name: nil)
149
164
  Array(methods).map do |method|
150
165
  package = if builtin
151
- Package.build_from_builtin(path, require_name: require_name, labels: method.labels, shallow: false)
166
+ Package.build_from_builtin(path || require_name, require_name: require_name, labels: method.labels, shallow: false)
152
167
  elsif gem
153
168
  Package.build_from_gem(gem, require_name: require_name, labels: method.labels, shallow: false, force: force, optional: true)
154
169
  elsif path
@@ -191,7 +206,7 @@ module AppMap
191
206
  }.compact
192
207
 
193
208
  handler_class = hook_decl['handler_class']
194
- options[:handler_class] = Util::class_from_string(handler_class) if handler_class
209
+ options[:handler_class] = Util.class_from_string(handler_class) if handler_class
195
210
 
196
211
  package_hooks(methods, **options)
197
212
  end
@@ -215,7 +230,7 @@ module AppMap
215
230
  builtin = hook_decl['builtin']
216
231
 
217
232
  package_options = {}
218
- package_options[:labels] = Array(labels).map(&:to_s) if labels if labels
233
+ package_options[:labels] = Array(labels).map(&:to_s) if labels
219
234
  package_options[:require_name] = req
220
235
  package_options[:require_name] ||= package if builtin
221
236
  tm = TargetMethods.new(functions, Package.build_from_path(package, **package_options))
@@ -449,13 +464,17 @@ module AppMap
449
464
  return unless location_file
450
465
 
451
466
  location_file = AppMap::Util.normalize_path(location_file)
452
- config
453
- .packages
454
- .select { |pkg| pkg.path }
455
- .find do |pkg|
456
- (location_file.index(pkg.path) == 0) &&
457
- !pkg.exclude.find { |p| location_file.index(p) }
458
- end
467
+
468
+ pkg = config
469
+ .packages
470
+ .select { |pkg| pkg.path }
471
+ .select do |pkg|
472
+ (location_file.index(pkg.path) == 0) &&
473
+ !pkg.exclude.find { |p| location_file.index(p) }
474
+ end
475
+ .min { |a, b| b.path <=> a.path } # Longest matching package first
476
+
477
+ pkg.subpackage(location_file, config) if pkg
459
478
  end
460
479
  end
461
480
 
@@ -0,0 +1,2 @@
1
+ - method: ActiveJob::Cancel#cancel
2
+ label: job.cancel
@@ -0,0 +1,2 @@
1
+ - method: ActiveJob::Enqueuing#enqueue
2
+ label: job.create
@@ -0,0 +1,4 @@
1
+ - method: Resque::Job.create
2
+ label: job.create
3
+ - method: Resque::Job.destroy
4
+ label: job.cancel
@@ -0,0 +1,4 @@
1
+ - method: Sidekiq::Client#push
2
+ label: job.create
3
+ - method: Sidekiq::Job#delete
4
+ label: job.cancel
data/lib/appmap/hook.rb CHANGED
@@ -7,8 +7,10 @@ module AppMap
7
7
  LOG = (ENV['APPMAP_DEBUG'] == 'true' || ENV['DEBUG'] == 'true')
8
8
  LOG_HOOK = (ENV['DEBUG_HOOK'] == 'true')
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
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
10
+ OBJECT_INSTANCE_METHODS = %i[! != !~ <=> == === =~ __id__ __send__ class clone define_singleton_method display dup
11
+ 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
12
+ OBJECT_STATIC_METHODS = %i[! != !~ < <= <=> == === =~ > >= __id__ __send__ alias_method allocate ancestors attr
13
+ 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
12
14
  SLOW_PACKAGE_THRESHOLD = 0.05
13
15
 
14
16
  @unbound_method_arity = ::UnboundMethod.instance_method(:arity)
@@ -29,7 +31,7 @@ module AppMap
29
31
  def already_hooked?(method)
30
32
  # After a method is defined, the statement "module_function <the-method>" can convert that method
31
33
  # into a module (class) method. The method is hooked first when it's defined, then AppMap will attempt to
32
- # hook it again when it's redefined as a module method. So we check the method source location - if it's
34
+ # hook it again when it's redefined as a module method. So we check the method source location - if it's
33
35
  # part of the AppMap source tree, we ignore it.
34
36
  method.source_location && method.source_location[0].index(__dir__) == 0
35
37
  end
@@ -63,7 +65,7 @@ module AppMap
63
65
  @notrace_paths = Set.new
64
66
  # Locations that have already been visited.
65
67
  @trace_locations = Set.new
66
- @module_load_times = Hash.new {|memo,k| memo[k] = 0}
68
+ @module_load_times = Hash.new { |memo, k| memo[k] = 0 }
67
69
  @slow_packages = Set.new
68
70
 
69
71
  if ENV['APPMAP_PROFILE_HOOK'] == 'true'
@@ -90,18 +92,20 @@ module AppMap
90
92
  end
91
93
 
92
94
  # hook_builtins builds hooks for code that is built in to the Ruby standard library.
93
- # No TracePoint events are emitted for builtins, so a separate hooking mechanism is needed.
95
+ # No TracePoint events are emitted for builtins, so a separate hooking mechanism is needed.
94
96
  def hook_builtins
95
97
  return unless self.class.hook_builtins?
96
98
 
97
99
  hook_loaded_code = lambda do |hooks_by_class, builtin|
98
100
  hooks_by_class.each do |class_name, hooks|
99
101
  Array(hooks).each do |hook|
100
- require hook.package.require_name if builtin && hook.package.require_name && hook.package.require_name != 'ruby'
102
+ if builtin && hook.package.require_name && hook.package.require_name != 'ruby'
103
+ require hook.package.require_name
104
+ end
101
105
 
102
106
  Array(hook.method_names).each do |method_name|
103
107
  method_name = method_name.to_sym
104
- base_cls = Util::class_from_string(class_name, must: false)
108
+ base_cls = Util.class_from_string(class_name, must: false)
105
109
  next unless base_cls
106
110
 
107
111
  hook_method = lambda do |entry|
@@ -113,8 +117,10 @@ module AppMap
113
117
 
114
118
  methods = []
115
119
  methods << [ base_cls, base_cls.public_instance_method(method_name) ] rescue nil
120
+ methods << [ base_cls, base_cls.protected_instance_method(method_name) ] rescue nil
116
121
  if base_cls.respond_to?(:singleton_class)
117
122
  methods << [ base_cls.singleton_class, base_cls.singleton_class.public_instance_method(method_name) ] rescue nil
123
+ methods << [ base_cls.singleton_class, base_cls.singleton_class.protected_instance_method(method_name) ] rescue nil
118
124
  end
119
125
  methods.compact!
120
126
  if methods.empty?
@@ -144,19 +150,19 @@ module AppMap
144
150
 
145
151
  path = trace_point.path
146
152
  enabled = !@notrace_paths.member?(path) && config.path_enabled?(path)
147
- if !enabled
148
- warn "Not hooking - path is not enabled" if Hook::LOG || Hook::LOG_HOOK
153
+ unless enabled
154
+ warn 'Not hooking - path is not enabled' if Hook::LOG || Hook::LOG_HOOK
149
155
  @notrace_paths << path
150
156
  return
151
157
  end
152
158
 
153
159
  cls = trace_point.self
154
160
 
155
- instance_methods = cls.public_instance_methods(false) - OBJECT_INSTANCE_METHODS
161
+ instance_methods = cls.public_instance_methods(false) + cls.protected_instance_methods(false) - OBJECT_INSTANCE_METHODS
156
162
  # NoMethodError: private method `singleton_class' called for Rack::MiniProfiler:Class
157
163
  class_methods = begin
158
164
  if cls.respond_to?(:singleton_class)
159
- cls.singleton_class.public_instance_methods(false) - instance_methods - OBJECT_STATIC_METHODS
165
+ cls.singleton_class.public_instance_methods(false) + cls.singleton_class.protected_instance_methods(false) - instance_methods - OBJECT_STATIC_METHODS
160
166
  else
161
167
  []
162
168
  end
@@ -172,12 +178,13 @@ module AppMap
172
178
 
173
179
  next if method_id == :call
174
180
 
175
- method = begin
176
- hook_cls.public_instance_method(method_id)
177
- rescue NameError
178
- warn "AppMap: Method #{hook_cls} #{method.name} is not accessible" if LOG
179
- next
180
- end
181
+ method = \
182
+ begin
183
+ hook_cls.instance_method(method_id)
184
+ rescue NameError
185
+ warn "AppMap: Method #{hook_cls} #{fn} is not accessible: #{$!}" if LOG
186
+ next
187
+ end
181
188
 
182
189
  next if self.class.already_hooked?(method)
183
190
 
data/lib/appmap/util.rb CHANGED
@@ -195,8 +195,7 @@ module AppMap
195
195
  end
196
196
 
197
197
  def deep_dup(hash)
198
- # This is a simple way to avoid the need for deep_dup from activesupport.
199
- Marshal.load(Marshal.dump(hash))
198
+ hash.deep_dup
200
199
  end
201
200
 
202
201
  def blank?(obj)
@@ -3,7 +3,7 @@
3
3
  module AppMap
4
4
  URL = 'https://github.com/applandinc/appmap-ruby'
5
5
 
6
- VERSION = '0.68.2'
6
+ VERSION = '0.70.2'
7
7
 
8
8
  APPMAP_FORMAT_VERSION = '1.5.1'
9
9
 
data/lib/appmap.rb CHANGED
@@ -20,6 +20,13 @@
20
20
  # - appmap/swagger (Rake task)
21
21
  # - appmap/depends (Rake task)
22
22
 
23
+ begin
24
+ require 'active_support'
25
+ require 'active_support/core_ext'
26
+ rescue NameError
27
+ warn 'active_support is not available. AppMap execution will continue optimistically without it...'
28
+ end
29
+
23
30
  require 'appmap/version'
24
31
  require 'appmap/agent'
25
32
 
@@ -60,11 +67,11 @@ lambda do
60
67
  if defined?(::Rails)
61
68
  require 'appmap/railtie'
62
69
  end
63
-
70
+
64
71
  if defined?(::RSpec)
65
72
  require 'appmap/rspec'
66
73
  end
67
-
74
+
68
75
  if defined?(::Minitest)
69
76
  require 'appmap/minitest'
70
77
  end
@@ -73,7 +80,7 @@ lambda do
73
80
  require 'appmap/swagger'
74
81
  require 'appmap/depends'
75
82
  end
76
-
83
+
77
84
  end.call unless ENV['APPMAP_AUTOREQUIRE'] == 'false'
78
85
 
79
86
  AppMap.initialize_configuration if ENV['APPMAP'] == 'true' && ENV['APPMAP_INITIALIZE'] != 'false'
@@ -16,7 +16,7 @@ describe 'AppMap::ClassMap' do
16
16
  end
17
17
 
18
18
  def ruby_method(method)
19
- AppMap::Trace::RubyMethod.new AppMap::Config::Package.new, method.receiver.class.name, method, false
19
+ AppMap::Trace::RubyMethod.new AppMap::Config::Package.new('pkg'), method.receiver.class.name, method, false
20
20
  end
21
21
 
22
22
  def dig_map(map, depth)
@@ -0,0 +1,7 @@
1
+ module PkgA
2
+ class A
3
+ def self.hello
4
+ 'hello'
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ class ProtectedMethod
4
+ def call_protected
5
+ protected_method
6
+ end
7
+
8
+ def to_s
9
+ 'Protected Method fixture'
10
+ end
11
+
12
+ class << self
13
+ def call_protected
14
+ protected_method
15
+ end
16
+
17
+ protected
18
+
19
+ def protected_method
20
+ 'self.protected'
21
+ end
22
+ end
23
+
24
+ protected
25
+
26
+ def protected_method
27
+ 'protected'
28
+ end
29
+ end
@@ -0,0 +1,7 @@
1
+ require_relative 'pkg_a/a'
2
+
3
+ module SubPackages
4
+ def self.invoke_a
5
+ PkgA::A.hello
6
+ end
7
+ end
data/spec/hook_spec.rb CHANGED
@@ -9,7 +9,7 @@ require 'diffy'
9
9
  # empty. This make some of the expected YAML below easier to
10
10
  # understand.
11
11
  module ShowYamlNulls
12
- def visit_NilClass(o)
12
+ def visit_NilClass(_o)
13
13
  @emitter.scalar('null', nil, 'tag:yaml.org,2002:null', true, false, Psych::Nodes::Scalar::ANY)
14
14
  end
15
15
  end
@@ -18,10 +18,10 @@ Psych::Visitors::YAMLTree.prepend(ShowYamlNulls)
18
18
  describe 'AppMap class Hooking', docker: false do
19
19
  include_context 'collect events'
20
20
 
21
- def invoke_test_file(file, setup: nil, &block)
21
+ def invoke_test_file(file, setup: nil, packages: nil)
22
22
  AppMap.configuration = nil
23
- package = AppMap::Config::Package.build_from_path(file)
24
- config = AppMap::Config.new('hook_spec', packages: [ package ])
23
+ packages ||= [ AppMap::Config::Package.build_from_path(file) ]
24
+ config = AppMap::Config.new('hook_spec', packages: packages)
25
25
  AppMap.configuration = config
26
26
  tracer = nil
27
27
  AppMap::Hook.new(config).enable do
@@ -153,7 +153,7 @@ describe 'AppMap class Hooking', docker: false do
153
153
  class_map = AppMap.class_map(tracer.event_methods).to_yaml
154
154
  expect(Diffy::Diff.new(<<~YAML, class_map).to_s).to eq('')
155
155
  ---
156
- - :name: spec/fixtures/hook/labels.rb
156
+ - :name: spec/fixtures/hook
157
157
  :type: package
158
158
  :children:
159
159
  - :name: ClassWithLabel
@@ -166,7 +166,41 @@ describe 'AppMap class Hooking', docker: false do
166
166
  :labels:
167
167
  - has-fn-label
168
168
  :comment: "# @label has-fn-label\\n"
169
- YAML
169
+ YAML
170
+ end
171
+
172
+ it 'reports sub-folders as distinct packages' do
173
+ _, tracer = invoke_test_file 'spec/fixtures/hook/sub_packages.rb',
174
+ packages: [ AppMap::Config::Package.build_from_path('spec/fixtures/hook') ] do
175
+ SubPackages.invoke_a
176
+ end
177
+ class_map = AppMap.class_map(tracer.event_methods).to_yaml
178
+ expect(Diffy::Diff.new(<<~YAML, class_map).to_s).to eq('')
179
+ ---
180
+ - :name: spec/fixtures/hook
181
+ :type: package
182
+ :children:
183
+ - :name: SubPackages
184
+ :type: class
185
+ :children:
186
+ - :name: invoke_a
187
+ :type: function
188
+ :location: spec/fixtures/hook/sub_packages.rb:4
189
+ :static: true
190
+ - :name: pkg_a
191
+ :type: package
192
+ :children:
193
+ - :name: PkgA
194
+ :type: class
195
+ :children:
196
+ - :name: A
197
+ :type: class
198
+ :children:
199
+ - :name: hello
200
+ :type: function
201
+ :location: spec/fixtures/hook/pkg_a/a.rb:3
202
+ :static: true
203
+ YAML
170
204
  end
171
205
 
172
206
  it 'hooks an instance method that takes no arguments' do
@@ -210,7 +244,7 @@ describe 'AppMap class Hooking', docker: false do
210
244
  class_map = AppMap.class_map(tracer.event_methods).to_yaml
211
245
  expect(Diffy::Diff.new(<<~YAML, class_map).to_s).to eq('')
212
246
  ---
213
- - :name: spec/fixtures/hook/instance_method.rb
247
+ - :name: spec/fixtures/hook
214
248
  :type: package
215
249
  :children:
216
250
  - :name: InstanceMethod
@@ -243,6 +277,92 @@ describe 'AppMap class Hooking', docker: false do
243
277
  end
244
278
  end
245
279
 
280
+ it 'records protected instance methods' do
281
+ events_yaml = <<~YAML
282
+ ---
283
+ - :id: 1
284
+ :event: :call
285
+ :defined_class: ProtectedMethod
286
+ :method_id: call_protected
287
+ :path: spec/fixtures/hook/protected_method.rb
288
+ :lineno: 4
289
+ :static: false
290
+ :parameters: []
291
+ :receiver:
292
+ :class: ProtectedMethod
293
+ :value: Protected Method fixture
294
+ - :id: 2
295
+ :event: :call
296
+ :defined_class: ProtectedMethod
297
+ :method_id: protected_method
298
+ :path: spec/fixtures/hook/protected_method.rb
299
+ :lineno: 26
300
+ :static: false
301
+ :parameters: []
302
+ :receiver:
303
+ :class: ProtectedMethod
304
+ :value: Protected Method fixture
305
+ - :id: 3
306
+ :event: :return
307
+ :parent_id: 2
308
+ :return_value:
309
+ :class: String
310
+ :value: protected
311
+ - :id: 4
312
+ :event: :return
313
+ :parent_id: 1
314
+ :return_value:
315
+ :class: String
316
+ :value: protected
317
+ YAML
318
+ test_hook_behavior 'spec/fixtures/hook/protected_method.rb', events_yaml do
319
+ expect(ProtectedMethod.new.call_protected).to eq('protected')
320
+ end
321
+ end
322
+
323
+ it 'records protected singleton (static) methods' do
324
+ events_yaml = <<~YAML
325
+ ---
326
+ - :id: 1
327
+ :event: :call
328
+ :defined_class: ProtectedMethod
329
+ :method_id: call_protected
330
+ :path: spec/fixtures/hook/protected_method.rb
331
+ :lineno: 13
332
+ :static: true
333
+ :parameters: []
334
+ :receiver:
335
+ :class: Class
336
+ :value: ProtectedMethod
337
+ - :id: 2
338
+ :event: :call
339
+ :defined_class: ProtectedMethod
340
+ :method_id: protected_method
341
+ :path: spec/fixtures/hook/protected_method.rb
342
+ :lineno: 19
343
+ :static: true
344
+ :parameters: []
345
+ :receiver:
346
+ :class: Class
347
+ :value: ProtectedMethod
348
+ - :id: 3
349
+ :event: :return
350
+ :parent_id: 2
351
+ :return_value:
352
+ :class: String
353
+ :value: self.protected
354
+ - :id: 4
355
+ :event: :return
356
+ :parent_id: 1
357
+ :return_value:
358
+ :class: String
359
+ :value: self.protected
360
+ YAML
361
+ test_hook_behavior 'spec/fixtures/hook/protected_method.rb', events_yaml do
362
+ expect(ProtectedMethod.call_protected).to eq('self.protected')
363
+ end
364
+ end
365
+
246
366
  it 'hooks an instance method that takes an argument' do
247
367
  events_yaml = <<~YAML
248
368
  ---
@@ -483,7 +603,6 @@ describe 'AppMap class Hooking', docker: false do
483
603
  end
484
604
  end
485
605
 
486
-
487
606
  it 'hooks an included method' do
488
607
  events_yaml = <<~YAML
489
608
  ---
@@ -607,11 +726,9 @@ describe 'AppMap class Hooking', docker: false do
607
726
  :lineno: 9
608
727
  YAML
609
728
  test_hook_behavior 'spec/fixtures/hook/exception_method.rb', events_yaml do
610
- begin
611
- ExceptionMethod.new.raise_exception
612
- rescue
613
- # don't let the exception fail the test
614
- end
729
+ ExceptionMethod.new.raise_exception
730
+ rescue
731
+ # don't let the exception fail the test
615
732
  end
616
733
  end
617
734
 
@@ -639,16 +756,13 @@ describe 'AppMap class Hooking', docker: false do
639
756
  :lineno: 59
640
757
  YAML
641
758
  test_hook_behavior 'spec/fixtures/hook/exception_method.rb', events_yaml do
642
- begin
643
- ExceptionMethod.new.raise_illegal_utf8_message
644
- rescue
645
- # don't let the exception fail the test
646
- end
759
+ ExceptionMethod.new.raise_illegal_utf8_message
760
+ rescue
761
+ # don't let the exception fail the test
647
762
  end
648
763
  end
649
764
 
650
765
  context 'string conversions works for the receiver when' do
651
-
652
766
  it 'is missing #to_s' do
653
767
  events_yaml = <<~YAML
654
768
  ---
@@ -979,7 +1093,7 @@ describe 'AppMap class Hooking', docker: false do
979
1093
  end
980
1094
  end
981
1095
 
982
- it "preserves the arity of hooked methods" do
1096
+ it 'preserves the arity of hooked methods' do
983
1097
  invoke_test_file 'spec/fixtures/hook/instance_method.rb' do
984
1098
  expect(InstanceMethod.instance_method(:say_echo).arity).to be(1)
985
1099
  expect(InstanceMethod.new.method(:say_echo).arity).to be(1)
@@ -157,31 +157,31 @@ describe 'Rails' do
157
157
  )
158
158
 
159
159
  expect(appmap['classMap']).to include hash_including(
160
- 'name' => 'app/views',
160
+ 'name' => 'app',
161
161
  'children' => include(hash_including(
162
- 'name' => 'app_views_users_index_html_haml',
162
+ 'name' => 'views',
163
163
  'children' => include(hash_including(
164
- 'name' => 'render',
165
- 'type' => 'function',
166
- 'location' => 'app/views/users/index.html.haml',
167
- 'static' => true,
168
- 'labels' => [ 'mvc.template' ]
169
- ))
170
- ))
171
- )
164
+ 'name' => 'app_views_users_index_html_haml',
165
+ 'children' => include(hash_including(
166
+ 'name' => 'render',
167
+ 'type' => 'function',
168
+ 'location' => 'app/views/users/index.html.haml',
169
+ 'static' => true,
170
+ 'labels' => [ 'mvc.template' ]
171
+ )))))))
172
172
  expect(appmap['classMap']).to include hash_including(
173
- 'name' => 'app/views',
173
+ 'name' => 'app',
174
174
  'children' => include(hash_including(
175
- 'name' => 'app_views_layouts_application_html_haml',
175
+ 'name' => 'views',
176
176
  'children' => include(hash_including(
177
- 'name' => 'render',
178
- 'type' => 'function',
179
- 'location' => 'app/views/layouts/application.html.haml',
180
- 'static' => true,
181
- 'labels' => [ 'mvc.template' ]
182
- ))
183
- ))
184
- )
177
+ 'name' => 'app_views_layouts_application_html_haml',
178
+ 'children' => include(hash_including(
179
+ 'name' => 'render',
180
+ 'type' => 'function',
181
+ 'location' => 'app/views/layouts/application.html.haml',
182
+ 'static' => true,
183
+ 'labels' => [ 'mvc.template' ]
184
+ )))))))
185
185
  end
186
186
  end
187
187
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: appmap
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.68.2
4
+ version: 0.70.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kevin Gilpin
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-11-25 00:00:00.000000000 Z
11
+ date: 2022-01-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -3429,8 +3429,12 @@ files:
3429
3429
  - lib/appmap/event.rb
3430
3430
  - lib/appmap/gem_hooks/actionpack.yml
3431
3431
  - lib/appmap/gem_hooks/actionview.yml
3432
+ - lib/appmap/gem_hooks/activejob-cancel.yml
3433
+ - lib/appmap/gem_hooks/activejob.yml
3432
3434
  - lib/appmap/gem_hooks/activesupport.yml
3433
3435
  - lib/appmap/gem_hooks/cancancan.yml
3436
+ - lib/appmap/gem_hooks/resque.yml
3437
+ - lib/appmap/gem_hooks/sidekiq.yml
3434
3438
  - lib/appmap/handler/function.rb
3435
3439
  - lib/appmap/handler/net_http.rb
3436
3440
  - lib/appmap/handler/rails/request_handler.rb
@@ -3502,10 +3506,13 @@ files:
3502
3506
  - spec/fixtures/hook/kwargs.rb
3503
3507
  - spec/fixtures/hook/labels.rb
3504
3508
  - spec/fixtures/hook/method_named_call.rb
3509
+ - spec/fixtures/hook/pkg_a/a.rb
3510
+ - spec/fixtures/hook/protected_method.rb
3505
3511
  - spec/fixtures/hook/revoke_api_key.appmap.json
3506
3512
  - spec/fixtures/hook/singleton_method.rb
3507
3513
  - spec/fixtures/hook/spec/api_spec.rb
3508
3514
  - spec/fixtures/hook/spec/user_spec.rb
3515
+ - spec/fixtures/hook/sub_packages.rb
3509
3516
  - spec/fixtures/hook/user_page_scenario.appmap.json
3510
3517
  - spec/fixtures/rack_users_app/.dockerignore
3511
3518
  - spec/fixtures/rack_users_app/.gitignore