appmap 0.68.0 → 0.70.0

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: 4d54229f9f87639b89c9388722e8e9ee30e327a39f9e4effe40739033229de5f
4
- data.tar.gz: 2a87b31d06444d8091f78ec00e0751b900f2068ee87003c945b3b6da3e58602d
3
+ metadata.gz: 64006e414b4b6cece101a113b5b5359c370b77b96761cfcb02818c07e621d8c5
4
+ data.tar.gz: e7ab888c17031adb8ae993dae863539b32359e967c706b2cc2b13f1f2bb11761
5
5
  SHA512:
6
- metadata.gz: 3a6efa5f3fbac309a6df73405f281deaaf4a577de3d22466e04e2a8587af59dc418e99c032387f5cf00d604da2d43cedfaa745f63589ae39f8edba685f9ab5b9
7
- data.tar.gz: 390d01607fcf6ae24852758a50f4f174b90c4d59f5b008c77c60108540a9d58c65917a36242ce495430fc7bfe38bdd58a4be050d106ebbb4c7ad6a3ea7d2104e
6
+ metadata.gz: e9b9fbf621b59dfb72875365d2c4485e174b4532b159d62854883e77fd741451f1e8ca4609b0a5323cccc562fcf31ead2ef19923bd3be3e6b0d5d28d5c188635
7
+ data.tar.gz: 4a079f0b5ae28e45a065187e0044446bdbef6a5a91df88f9072b71a825a18c86e3ba6eaf8dc54102b224eb16f3eae1ea0b9e3b8da3958b209bdd9f5d78d0ac50
data/CHANGELOG.md CHANGED
@@ -1,3 +1,32 @@
1
+ # [0.70.0](https://github.com/applandinc/appmap-ruby/compare/v0.69.0...v0.70.0) (2021-12-08)
2
+
3
+
4
+ ### Features
5
+
6
+ * Hook protected methods ([a3722b5](https://github.com/applandinc/appmap-ruby/commit/a3722b504b8e5b8c032988b586b13bdd071fe577))
7
+ * Report sub-packages for nested folders ([dce709b](https://github.com/applandinc/appmap-ruby/commit/dce709b077fd64fc2b34f9abb30a65db529f824b))
8
+
9
+ # [0.69.0](https://github.com/applandinc/appmap-ruby/compare/v0.68.2...v0.69.0) (2021-12-01)
10
+
11
+
12
+ ### Features
13
+
14
+ * Add labels for job creation and canceling ([644fafe](https://github.com/applandinc/appmap-ruby/commit/644fafe7f0eab626a9e0a52243ad4faf052a883a))
15
+
16
+ ## [0.68.2](https://github.com/applandinc/appmap-ruby/compare/v0.68.1...v0.68.2) (2021-11-25)
17
+
18
+
19
+ ### Bug Fixes
20
+
21
+ * Missing gems will no longer attempt to be hooked ([ac6cf26](https://github.com/applandinc/appmap-ruby/commit/ac6cf264897e492c73ba4b66233709eb4eaf7b36))
22
+
23
+ ## [0.68.1](https://github.com/applandinc/appmap-ruby/compare/v0.68.0...v0.68.1) (2021-11-12)
24
+
25
+
26
+ ### Bug Fixes
27
+
28
+ * Support new style of `functions` syntax in appmap.yml ([dca327c](https://github.com/applandinc/appmap-ruby/commit/dca327c98db1bddf849056995541306a5fc07eea))
29
+
1
30
  # [0.68.0](https://github.com/applandinc/appmap-ruby/compare/v0.67.1...v0.68.0) (2021-11-05)
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.
@@ -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))
@@ -366,7 +381,7 @@ module AppMap
366
381
  # hook config.
367
382
  declare_hook(hook_decl)
368
383
  end
369
- end
384
+ end.flatten
370
385
  end
371
386
 
372
387
  config_params[:packages] = \
@@ -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
@@ -226,7 +226,9 @@ module AppMap
226
226
  elsif ENV['DEBUG'] == 'true'
227
227
  warn msg
228
228
  end
229
- end
229
+
230
+ nil
231
+ end
230
232
 
231
233
  def ruby_minor_version
232
234
  @ruby_minor_version ||= RUBY_VERSION.split('.')[0..1].join('.').to_f
@@ -3,7 +3,7 @@
3
3
  module AppMap
4
4
  URL = 'https://github.com/applandinc/appmap-ruby'
5
5
 
6
- VERSION = '0.68.0'
6
+ VERSION = '0.70.0'
7
7
 
8
8
  APPMAP_FORMAT_VERSION = '1.5.1'
9
9
 
@@ -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)
data/spec/config_spec.rb CHANGED
@@ -11,6 +11,10 @@ describe AppMap::Config, docker: false do
11
11
  functions: [
12
12
  {
13
13
  name: 'pkg/cls#fn',
14
+ },
15
+ {
16
+ methods: ['cls#new_fn'],
17
+ path: 'pkg'
14
18
  }
15
19
  ]
16
20
  }.deep_stringify_keys!
@@ -64,6 +68,15 @@ describe AppMap::Config, docker: false do
64
68
  "fn"
65
69
  ]
66
70
  }
71
+ },
72
+ {
73
+ "cls": "cls",
74
+ "target_methods": {
75
+ "package": "pkg",
76
+ "method_names": [
77
+ "new_fn"
78
+ ]
79
+ }
67
80
  }
68
81
  ],
69
82
  "builtin_hooks": {
@@ -195,6 +208,12 @@ describe AppMap::Config, docker: false do
195
208
  "method_names": [
196
209
  "fn"
197
210
  ]
211
+ },
212
+ {
213
+ "package": "pkg",
214
+ "method_names": [
215
+ "new_fn"
216
+ ]
198
217
  }
199
218
  ],
200
219
  "ActiveSupport::Callbacks::CallbackSequence": [
@@ -224,6 +243,21 @@ describe AppMap::Config, docker: false do
224
243
  FIXTURE
225
244
  end
226
245
 
246
+ describe AppMap::Config::Package do
247
+ describe :build_from_gem do
248
+ let(:mock_rails) { double(logger: double(info: true)) }
249
+
250
+ before do
251
+ stub_const('Rails', mock_rails)
252
+ end
253
+
254
+ it 'does not return a truthy value on failure' do
255
+ result = AppMap::Config::Package.build_from_gem('some_missing_gem_name', optional: true)
256
+ expect(result).to_not be_truthy
257
+ end
258
+ end
259
+ end
260
+
227
261
  context do
228
262
  let(:warnings) { @warnings ||= [] }
229
263
  let(:warning) { warnings.join }
@@ -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.0
4
+ version: 0.70.0
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-05 00:00:00.000000000 Z
11
+ date: 2021-12-08 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