appmap 0.73.0 → 0.76.0
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/CHANGELOG.md +31 -0
- data/lib/appmap/builtin_hooks/open3.yml +13 -0
- data/lib/appmap/builtin_hooks/ruby.yml +39 -0
- data/lib/appmap/config.rb +3 -4
- data/lib/appmap/cucumber.rb +1 -1
- data/lib/appmap/event.rb +23 -9
- data/lib/appmap/gem_hooks/actionview.yml +4 -0
- data/lib/appmap/gem_hooks/activesupport.yml +4 -0
- data/lib/appmap/handler.rb +38 -0
- data/lib/appmap/hook/method.rb +31 -23
- data/lib/appmap/hook.rb +13 -2
- data/lib/appmap/minitest.rb +1 -1
- data/lib/appmap/record.rb +1 -1
- data/lib/appmap/rspec.rb +1 -1
- data/lib/appmap/trace.rb +32 -0
- data/lib/appmap/util.rb +1 -9
- data/lib/appmap/version.rb +1 -1
- data/spec/display_string_spec.rb +40 -0
- data/spec/hook_spec.rb +1 -1
- data/spec/rails_recording_spec.rb +1 -1
- data/spec/record_net_http_spec.rb +1 -1
- data/test/gem_test.rb +1 -1
- metadata +6 -3
- data/lib/appmap/builtin_hooks/marshal.yml +0 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 15371b6980bcc95640c4d579c323da11db85509c0f50110c318da0d9cc04f189
|
4
|
+
data.tar.gz: 03a4e889edcfaf15629a7e9662f230df18b3b1123c86ce463edf4ba03c9e7280
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a1bc1b230b3e946400acbc3d1bc8ee87508973ce594ca488c17f2d39d1280346959e2c5acb5c9d3f6cd62627b61764f5cd0d96ef60639c645337df2ac850409b
|
7
|
+
data.tar.gz: e0bb0223a99795cedc38470d49dae428a720f0638674dc4e04b26d15aa085286d51c42aacc1ee490ff713122711728af9df1064adcb66a6dff7ccb89292b72a5
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,34 @@
|
|
1
|
+
# [0.76.0](https://github.com/applandinc/appmap-ruby/compare/v0.75.0...v0.76.0) (2022-03-19)
|
2
|
+
|
3
|
+
|
4
|
+
### Features
|
5
|
+
|
6
|
+
* Autoload hook handlers ([4cc0e70](https://github.com/applandinc/appmap-ruby/commit/4cc0e7003a8c37d3b6c8c8bbc68cffac0335b878))
|
7
|
+
|
8
|
+
# [0.75.0](https://github.com/applandinc/appmap-ruby/compare/v0.74.0...v0.75.0) (2022-03-17)
|
9
|
+
|
10
|
+
|
11
|
+
### Features
|
12
|
+
|
13
|
+
* Apply label deserialize.safe to ActiveSupport.run_load_hooks ([1f67f9b](https://github.com/applandinc/appmap-ruby/commit/1f67f9b260503772cba6824ef746f903def14323))
|
14
|
+
* Print stacks if requested by env var ([72ef911](https://github.com/applandinc/appmap-ruby/commit/72ef9116d3248467632762ce63303a54bed998e9))
|
15
|
+
|
16
|
+
# [0.74.0](https://github.com/applandinc/appmap-ruby/compare/v0.73.0...v0.74.0) (2022-03-14)
|
17
|
+
|
18
|
+
|
19
|
+
### Bug Fixes
|
20
|
+
|
21
|
+
* Apply special case hook handling to Kernel and instance_eval ([25823ff](https://github.com/applandinc/appmap-ruby/commit/25823ff0fb86beff3edc64da251a125ee198ef40))
|
22
|
+
* Only apply a method hook to a class that defines the method ([ede2236](https://github.com/applandinc/appmap-ruby/commit/ede22364bfcbf324e8db3aa6d64d5b032f36ace2))
|
23
|
+
* Optimize/improve string-ification of values ([c9b6cdb](https://github.com/applandinc/appmap-ruby/commit/c9b6cdb72dfc55cc3a166eda470eba19093e9090))
|
24
|
+
|
25
|
+
|
26
|
+
### Features
|
27
|
+
|
28
|
+
* Improve hook performance by using bind_call ([e09fce9](https://github.com/applandinc/appmap-ruby/commit/e09fce9f5b3c0b18bc3b81083c1523df6a6932db))
|
29
|
+
* Label system.exec, string.pack, string.html_safe ([963c6dd](https://github.com/applandinc/appmap-ruby/commit/963c6ddfa0f607ad219ae8829cfb383b0d5988d0))
|
30
|
+
* Log initiation of each builtin hook ([902a736](https://github.com/applandinc/appmap-ruby/commit/902a7360d17c6b49de97f34643c733e8c47c294d))
|
31
|
+
|
1
32
|
# [0.73.0](https://github.com/applandinc/appmap-ruby/compare/v0.72.5...v0.73.0) (2022-03-07)
|
2
33
|
|
3
34
|
|
@@ -0,0 +1,39 @@
|
|
1
|
+
- methods:
|
2
|
+
- Marshal#load
|
3
|
+
- Marshal#restore
|
4
|
+
require_name: ruby
|
5
|
+
label: deserialize.unsafe
|
6
|
+
- method: Marshal#dump
|
7
|
+
require_name: ruby
|
8
|
+
label: serialize
|
9
|
+
- method: String#pack
|
10
|
+
require_name: ruby
|
11
|
+
label: string.pack
|
12
|
+
- methods:
|
13
|
+
- String#unpack
|
14
|
+
- String#unpack1
|
15
|
+
require_name: ruby
|
16
|
+
label: string.unpack
|
17
|
+
#- methods:
|
18
|
+
# TODO: eval does not happen in the right context, and therefore any new constants
|
19
|
+
# which are defined are placed on the wrong module/class.
|
20
|
+
# - Kernel#eval
|
21
|
+
# - Binding#eval
|
22
|
+
# - BasicObject#instance_eval
|
23
|
+
# These methods cannot be hooked as far as I can tell.
|
24
|
+
# Why? When calling one of these functions, the context at the point of
|
25
|
+
# definition is used. It's not possible to bind class_eval to a new context.
|
26
|
+
# - Module#class_eval
|
27
|
+
# - Module#module_eval
|
28
|
+
# require_name: ruby
|
29
|
+
# label: lang.eval
|
30
|
+
- methods:
|
31
|
+
- IO#popen
|
32
|
+
- Kernel#exec
|
33
|
+
- Kernel#spawn
|
34
|
+
- Kernel#syscall
|
35
|
+
- Kernel#system
|
36
|
+
- Process#exec
|
37
|
+
- Process#spawn
|
38
|
+
require_name: ruby
|
39
|
+
label: system.exec
|
data/lib/appmap/config.rb
CHANGED
@@ -4,8 +4,7 @@ require 'pathname'
|
|
4
4
|
require 'set'
|
5
5
|
require 'yaml'
|
6
6
|
require 'appmap/util'
|
7
|
-
require 'appmap/handler
|
8
|
-
require 'appmap/handler/rails/template'
|
7
|
+
require 'appmap/handler'
|
9
8
|
require 'appmap/service/guesser'
|
10
9
|
require 'appmap/swagger/configuration'
|
11
10
|
require 'appmap/depends/configuration'
|
@@ -206,8 +205,8 @@ module AppMap
|
|
206
205
|
}.compact
|
207
206
|
|
208
207
|
handler_class = hook_decl['handler_class']
|
209
|
-
options[:handler_class] =
|
210
|
-
|
208
|
+
options[:handler_class] = Handler.find(handler_class) if handler_class
|
209
|
+
|
211
210
|
package_hooks(methods, **options)
|
212
211
|
end
|
213
212
|
|
data/lib/appmap/cucumber.rb
CHANGED
@@ -51,7 +51,7 @@ module AppMap
|
|
51
51
|
appmap['metadata'] = update_metadata(scenario, appmap['metadata'])
|
52
52
|
scenario_filename = AppMap::Util.scenario_filename(appmap['metadata']['name'])
|
53
53
|
|
54
|
-
AppMap::Util.write_appmap(File.join(APPMAP_OUTPUT_DIR, scenario_filename),
|
54
|
+
AppMap::Util.write_appmap(File.join(APPMAP_OUTPUT_DIR, scenario_filename), appmap)
|
55
55
|
end
|
56
56
|
|
57
57
|
def enabled?
|
data/lib/appmap/event.rb
CHANGED
@@ -20,7 +20,9 @@ module AppMap
|
|
20
20
|
MethodEventStruct = Struct.new(:id, :event, :thread_id)
|
21
21
|
|
22
22
|
class MethodEvent < MethodEventStruct
|
23
|
-
|
23
|
+
MAX_ARRAY_ENUMERATION = 10
|
24
|
+
MAX_HASH_ENUMERATION = 10
|
25
|
+
MAX_STRING_LENGTH = 100
|
24
26
|
|
25
27
|
class << self
|
26
28
|
def build_from_invocation(event_type, event:)
|
@@ -48,14 +50,14 @@ module AppMap
|
|
48
50
|
end
|
49
51
|
|
50
52
|
start = Time.now
|
51
|
-
value_string = custom_display_string(value) || default_display_string(value)
|
53
|
+
value_string, final = custom_display_string(value) || default_display_string(value)
|
52
54
|
|
53
55
|
if @times
|
54
56
|
elapsed = Time.now - start
|
55
57
|
@times[best_class_name(value)] += elapsed
|
56
58
|
end
|
57
59
|
|
58
|
-
encode_display_string(value_string)
|
60
|
+
final ? value_string : encode_display_string(value_string)
|
59
61
|
end
|
60
62
|
|
61
63
|
def object_properties(hash_like)
|
@@ -80,21 +82,33 @@ module AppMap
|
|
80
82
|
end
|
81
83
|
|
82
84
|
def encode_display_string(value)
|
83
|
-
(value||'')[0...
|
85
|
+
(value||'')[0...MAX_STRING_LENGTH].encode('utf-8', invalid: :replace, undef: :replace, replace: '_')
|
84
86
|
end
|
85
87
|
|
86
88
|
def custom_display_string(value)
|
87
89
|
case value
|
88
90
|
when NilClass, TrueClass, FalseClass, Numeric, Time, Date
|
89
|
-
value.to_s
|
91
|
+
[ value.to_s, true ]
|
92
|
+
when Symbol
|
93
|
+
[ ":#{value}", true ]
|
90
94
|
when String
|
91
|
-
value[0...
|
95
|
+
result = value[0...MAX_STRING_LENGTH].encode('utf-8', invalid: :replace, undef: :replace, replace: '_')
|
96
|
+
result << " (...#{value.length - MAX_STRING_LENGTH} more characters)" if value.length > MAX_STRING_LENGTH
|
97
|
+
[ result, true ]
|
98
|
+
when Array
|
99
|
+
result = value[0...MAX_ARRAY_ENUMERATION].map{|v| display_string(v)}.join(', ')
|
100
|
+
result << " (...#{value.length - MAX_ARRAY_ENUMERATION} more items)" if value.length > MAX_ARRAY_ENUMERATION
|
101
|
+
[ [ '[', result, ']' ].join, true ]
|
102
|
+
when Hash
|
103
|
+
result = value.keys[0...MAX_HASH_ENUMERATION].map{|key| "#{display_string(key)}=>#{display_string(value[key])}"}.join(', ')
|
104
|
+
result << " (...#{value.size - MAX_HASH_ENUMERATION} more entries)" if value.size > MAX_HASH_ENUMERATION
|
105
|
+
[ [ '{', result, '}' ].join, true ]
|
92
106
|
when File
|
93
|
-
"#{value.class}[path=#{value.path}]"
|
107
|
+
[ "#{value.class}[path=#{value.path}]", true ]
|
94
108
|
when Net::HTTP
|
95
|
-
"#{value.class}[#{value.address}:#{value.port}]"
|
109
|
+
[ "#{value.class}[#{value.address}:#{value.port}]", true ]
|
96
110
|
when Net::HTTPGenericRequest
|
97
|
-
"#{value.class}[#{value.method} #{value.path}]"
|
111
|
+
[ "#{value.class}[#{value.method} #{value.path}]", true ]
|
98
112
|
end
|
99
113
|
rescue StandardError
|
100
114
|
nil
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'active_support/inflector/methods'
|
4
|
+
|
5
|
+
module AppMap
|
6
|
+
# Specific hook handler classes and general related utilities.
|
7
|
+
module Handler
|
8
|
+
# Try to find handler module with a given name.
|
9
|
+
#
|
10
|
+
# If the module is not loaded, tries to require the appropriate file
|
11
|
+
# using the usual conventions, eg. `Acme::Handler::AppMap` will try
|
12
|
+
# to require `acme/handler/app_map`, then `acme/handler` and
|
13
|
+
# finally `acme`. Raises NameError if the module could not be loaded
|
14
|
+
# this way.
|
15
|
+
def self.find(name)
|
16
|
+
begin
|
17
|
+
return Object.const_get name
|
18
|
+
rescue NameError
|
19
|
+
try_load ActiveSupport::Inflector.underscore name
|
20
|
+
end
|
21
|
+
Object.const_get name
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.try_load(fname)
|
25
|
+
fname = fname.sub %r{^app_map/}, 'appmap/'
|
26
|
+
fname = fname.split '/'
|
27
|
+
until fname.empty?
|
28
|
+
begin
|
29
|
+
require fname.join '/'
|
30
|
+
return
|
31
|
+
rescue LoadError
|
32
|
+
# pass
|
33
|
+
end
|
34
|
+
fname.pop
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
data/lib/appmap/hook/method.rb
CHANGED
@@ -69,28 +69,24 @@ module AppMap
|
|
69
69
|
after_hook = self.method(:after_hook)
|
70
70
|
with_disabled_hook = self.method(:with_disabled_hook)
|
71
71
|
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
hook_method.bind(self).call({}, &block)
|
84
|
-
end
|
72
|
+
is_array_containing_empty_hash = ->(obj) {
|
73
|
+
obj.is_a?(Array) && obj.length == 1 && obj[0].is_a?(Hash) && obj[0].size == 0
|
74
|
+
}
|
75
|
+
|
76
|
+
call_instance_method = lambda do |receiver, args, &block|
|
77
|
+
# https://github.com/applandinc/appmap-ruby/issues/153
|
78
|
+
if NEW_RUBY && is_array_containing_empty_hash.(args) && hook_method.arity == 1
|
79
|
+
hook_method.bind_call(receiver, {}, &block)
|
80
|
+
else
|
81
|
+
if NEW_RUBY
|
82
|
+
hook_method.bind_call(receiver, *args, &block)
|
85
83
|
else
|
86
|
-
|
87
|
-
hook_method.bind_call(self, *args, &block)
|
88
|
-
else
|
89
|
-
hook_method.bind(self).call(*args, &block)
|
90
|
-
end
|
84
|
+
hook_method.bind(receiver).call(*args, &block)
|
91
85
|
end
|
92
|
-
|
86
|
+
end
|
87
|
+
end
|
93
88
|
|
89
|
+
hook_method_def = Proc.new do |*args, &block|
|
94
90
|
# We may not have gotten the class for the method during
|
95
91
|
# initialization (e.g. for a singleton method on an embedded
|
96
92
|
# struct), so make sure we have it now.
|
@@ -102,7 +98,9 @@ module AppMap
|
|
102
98
|
|
103
99
|
enabled = true if AppMap.tracing.enabled? && !reentrant && !disabled_by_shallow_flag.call
|
104
100
|
|
105
|
-
|
101
|
+
enabled = false if %i[instance_eval instance_exec].member?(hook_method.name) && args.empty?
|
102
|
+
|
103
|
+
return call_instance_method.call(self, args, &block) unless enabled
|
106
104
|
|
107
105
|
call_event, start_time = with_disabled_hook.call do
|
108
106
|
before_hook.call(self, defined_class, args)
|
@@ -110,7 +108,7 @@ module AppMap
|
|
110
108
|
return_value = nil
|
111
109
|
exception = nil
|
112
110
|
begin
|
113
|
-
return_value = call_instance_method.call
|
111
|
+
return_value = call_instance_method.call(self, args, &block)
|
114
112
|
rescue
|
115
113
|
exception = $ERROR_INFO
|
116
114
|
raise
|
@@ -125,8 +123,18 @@ module AppMap
|
|
125
123
|
hook_method_parameters = hook_method.parameters.dup.freeze
|
126
124
|
SIGNATURES[[ hook_class, hook_method.name ]] = hook_method_parameters
|
127
125
|
|
128
|
-
|
129
|
-
|
126
|
+
# irb(main):001:0> Kernel.public_instance_method(:system)
|
127
|
+
# (irb):1:in `public_instance_method': method `system' for module `Kernel' is private (NameError)
|
128
|
+
if hook_class == Kernel
|
129
|
+
hook_class.define_method_with_arity(hook_method.name, hook_method.arity, hook_method_def)
|
130
|
+
else
|
131
|
+
hook_class.ancestors.find { |cls| cls.method_defined?(hook_method.name, false) }.tap do |cls|
|
132
|
+
if cls
|
133
|
+
cls.define_method_with_arity(hook_method.name, hook_method.arity, hook_method_def)
|
134
|
+
else
|
135
|
+
warn "#{hook_method.name} not found on #{hook_class}"
|
136
|
+
end
|
137
|
+
end
|
130
138
|
end
|
131
139
|
end
|
132
140
|
|
data/lib/appmap/hook.rb
CHANGED
@@ -105,8 +105,14 @@ module AppMap
|
|
105
105
|
|
106
106
|
Array(hook.method_names).each do |method_name|
|
107
107
|
method_name = method_name.to_sym
|
108
|
-
|
109
|
-
|
108
|
+
|
109
|
+
warn "AppMap: Initiating hook for builtin #{class_name} #{method_name}" if LOG
|
110
|
+
|
111
|
+
begin
|
112
|
+
base_cls = Object.const_get class_name
|
113
|
+
rescue NameError
|
114
|
+
next
|
115
|
+
end
|
110
116
|
|
111
117
|
hook_method = lambda do |entry|
|
112
118
|
cls, method = entry
|
@@ -116,6 +122,11 @@ module AppMap
|
|
116
122
|
end
|
117
123
|
|
118
124
|
methods = []
|
125
|
+
# irb(main):001:0> Kernel.public_instance_method(:system)
|
126
|
+
# (irb):1:in `public_instance_method': method `system' for module `Kernel' is private (NameError)
|
127
|
+
if base_cls == Kernel
|
128
|
+
methods << [ base_cls, base_cls.instance_method(method_name) ] rescue nil
|
129
|
+
end
|
119
130
|
methods << [ base_cls, base_cls.public_instance_method(method_name) ] rescue nil
|
120
131
|
methods << [ base_cls, base_cls.protected_instance_method(method_name) ] rescue nil
|
121
132
|
if base_cls.respond_to?(:singleton_class)
|
data/lib/appmap/minitest.rb
CHANGED
@@ -120,7 +120,7 @@ module AppMap
|
|
120
120
|
}.compact
|
121
121
|
fname = AppMap::Util.scenario_filename(name)
|
122
122
|
|
123
|
-
AppMap::Util.write_appmap(File.join(APPMAP_OUTPUT_DIR, fname),
|
123
|
+
AppMap::Util.write_appmap(File.join(APPMAP_OUTPUT_DIR, fname), appmap)
|
124
124
|
end
|
125
125
|
|
126
126
|
def enabled?
|
data/lib/appmap/record.rb
CHANGED
data/lib/appmap/rspec.rb
CHANGED
@@ -205,7 +205,7 @@ module AppMap
|
|
205
205
|
}.compact
|
206
206
|
fname = AppMap::Util.scenario_filename(name)
|
207
207
|
|
208
|
-
AppMap::Util.write_appmap(File.join(APPMAP_OUTPUT_DIR, fname),
|
208
|
+
AppMap::Util.write_appmap(File.join(APPMAP_OUTPUT_DIR, fname), appmap)
|
209
209
|
end
|
210
210
|
|
211
211
|
def enabled?
|
data/lib/appmap/trace.rb
CHANGED
@@ -84,12 +84,43 @@ module AppMap
|
|
84
84
|
end
|
85
85
|
end
|
86
86
|
|
87
|
+
class StackPrinter
|
88
|
+
class << self
|
89
|
+
def enabled?
|
90
|
+
ENV['APPMAP_PRINT_STACKS'] == 'true'
|
91
|
+
end
|
92
|
+
|
93
|
+
def depth
|
94
|
+
(ENV['APPMAP_STACK_DEPTH'] || 20).to_i
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def initialize
|
99
|
+
@@stacks ||= Hash.new
|
100
|
+
end
|
101
|
+
|
102
|
+
def record(event)
|
103
|
+
stack = caller.select { |line| !line.index('/lib/appmap/') }[0...StackPrinter.depth].join("\n ")
|
104
|
+
stack_hash = Digest::SHA256.hexdigest(stack)
|
105
|
+
unless @@stacks[stack_hash]
|
106
|
+
@@stacks[stack_hash] = stack
|
107
|
+
puts
|
108
|
+
puts 'Event: ' + event.to_h.map { |k, v| [ "#{k}: #{v}" ] }.join(", ")
|
109
|
+
puts ' ' + stack
|
110
|
+
puts
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
87
115
|
class Tracer
|
116
|
+
attr_accessor :stacks
|
117
|
+
|
88
118
|
# Records the events which happen in a program.
|
89
119
|
def initialize
|
90
120
|
@events = []
|
91
121
|
@last_package_for_thread = {}
|
92
122
|
@methods = Set.new
|
123
|
+
@stack_printer = StackPrinter.new if StackPrinter.enabled?
|
93
124
|
@enabled = false
|
94
125
|
end
|
95
126
|
|
@@ -112,6 +143,7 @@ module AppMap
|
|
112
143
|
def record_event(event, package: nil, defined_class: nil, method: nil)
|
113
144
|
return unless @enabled
|
114
145
|
|
146
|
+
@stack_printer.record(event) if @stack_printer
|
115
147
|
@last_package_for_thread[Thread.current.object_id] = package if package
|
116
148
|
@events << event
|
117
149
|
static = event.static if event.respond_to?(:static)
|
data/lib/appmap/util.rb
CHANGED
@@ -21,14 +21,6 @@ module AppMap
|
|
21
21
|
WHITE = "\e[37m"
|
22
22
|
|
23
23
|
class << self
|
24
|
-
def class_from_string(fq_class, must: true)
|
25
|
-
fq_class.split('::').inject(Object) do |mod, class_name|
|
26
|
-
mod.const_get(class_name)
|
27
|
-
end
|
28
|
-
rescue NameError
|
29
|
-
raise if must
|
30
|
-
end
|
31
|
-
|
32
24
|
def parse_function_name(name)
|
33
25
|
package_tokens = name.split('/')
|
34
26
|
|
@@ -171,7 +163,7 @@ module AppMap
|
|
171
163
|
mode = File::RDWR | File::CREAT | File::EXCL
|
172
164
|
::Dir::Tmpname.create([ 'appmap_', '.json' ]) do |tmpname|
|
173
165
|
tempfile = File.open(tmpname, mode)
|
174
|
-
tempfile.write(appmap)
|
166
|
+
tempfile.write(JSON.generate(appmap))
|
175
167
|
tempfile.close
|
176
168
|
# Atomically move the tempfile into place.
|
177
169
|
FileUtils.mv tempfile.path, filename
|
data/lib/appmap/version.rb
CHANGED
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
require 'appmap/event'
|
5
|
+
|
6
|
+
include AppMap
|
7
|
+
|
8
|
+
describe 'display_string' do
|
9
|
+
def display_string(value)
|
10
|
+
Event::MethodEvent.display_string value
|
11
|
+
end
|
12
|
+
|
13
|
+
def compare_display_string(value, expected)
|
14
|
+
expect(display_string(value)).to eq(expected)
|
15
|
+
end
|
16
|
+
|
17
|
+
context 'for a' do
|
18
|
+
it 'String' do
|
19
|
+
compare_display_string 'foo', 'foo'
|
20
|
+
end
|
21
|
+
it 'long String' do
|
22
|
+
compare_display_string 'foo' * 100, 'foo' * 33 + 'f (...200 more characters)'
|
23
|
+
end
|
24
|
+
it 'Array' do
|
25
|
+
compare_display_string([ 1, 'my', :bar, [ 2, 3 ], { 4 => 5 } ], '[1, my, :bar, [2, 3], {4=>5}]')
|
26
|
+
end
|
27
|
+
it 'large Array' do
|
28
|
+
compare_display_string 50.times.map { |i| i }, '[0, 1, 2, 3, 4, 5, 6, 7, 8, 9 (...40 more items)]'
|
29
|
+
end
|
30
|
+
it 'large Hash' do
|
31
|
+
compare_display_string(50.times.map { |i| [ i*2, i*2+1] }.to_h, '{0=>1, 2=>3, 4=>5, 6=>7, 8=>9, 10=>11, 12=>13, 14=>15, 16=>17, 18=>19 (...40 more entries)}')
|
32
|
+
end
|
33
|
+
it 'Hash' do
|
34
|
+
compare_display_string({ 1 => 2, 'my' => 'neighbor', bar: :baz, ary: [ 1, 2 ]}, '{1=>2, my=>neighbor, :bar=>:baz, :ary=>[1, 2]}')
|
35
|
+
end
|
36
|
+
it 'big Hash' do
|
37
|
+
compare_display_string(50.times.map { |i| [ i*2, i*2+1] }.to_h, '{0=>1, 2=>3, 4=>5, 6=>7, 8=>9, 10=>11, 12=>13, 14=>15, 16=>17, 18=>19 (...40 more entries)}')
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
data/spec/hook_spec.rb
CHANGED
data/test/gem_test.rb
CHANGED
@@ -24,7 +24,7 @@ class GemTest < Minitest::Test
|
|
24
24
|
appmap_file = 'tmp/appmap/minitest/Parser_parser.appmap.json'
|
25
25
|
appmap = JSON.parse(File.read(appmap_file))
|
26
26
|
events = appmap['events']
|
27
|
-
assert_equal
|
27
|
+
assert_equal 6, events.size
|
28
28
|
assert_equal 'call', events.first['event']
|
29
29
|
assert_equal 'default_parser', events.first['method_id']
|
30
30
|
assert_match /\lib\/parser\/base\.rb$/, events.first['path']
|
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.
|
4
|
+
version: 0.76.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: 2022-03-
|
11
|
+
date: 2022-03-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -339,10 +339,11 @@ files:
|
|
339
339
|
- lib/appmap/agent.rb
|
340
340
|
- lib/appmap/builtin_hooks/json.yml
|
341
341
|
- lib/appmap/builtin_hooks/logger.yml
|
342
|
-
- lib/appmap/builtin_hooks/marshal.yml
|
343
342
|
- lib/appmap/builtin_hooks/net/http.yml
|
343
|
+
- lib/appmap/builtin_hooks/open3.yml
|
344
344
|
- lib/appmap/builtin_hooks/openssl.yml
|
345
345
|
- lib/appmap/builtin_hooks/psych.yml
|
346
|
+
- lib/appmap/builtin_hooks/ruby.yml
|
346
347
|
- lib/appmap/class_map.rb
|
347
348
|
- lib/appmap/command/agent_setup/init.rb
|
348
349
|
- lib/appmap/command/agent_setup/status.rb
|
@@ -373,6 +374,7 @@ files:
|
|
373
374
|
- lib/appmap/gem_hooks/resque.yml
|
374
375
|
- lib/appmap/gem_hooks/sidekiq.yml
|
375
376
|
- lib/appmap/gem_hooks/sprockets.yml
|
377
|
+
- lib/appmap/handler.rb
|
376
378
|
- lib/appmap/handler/function.rb
|
377
379
|
- lib/appmap/handler/net_http.rb
|
378
380
|
- lib/appmap/handler/rails/request_handler.rb
|
@@ -409,6 +411,7 @@ files:
|
|
409
411
|
- spec/config_spec.rb
|
410
412
|
- spec/depends/api_spec.rb
|
411
413
|
- spec/depends/spec_helper.rb
|
414
|
+
- spec/display_string_spec.rb
|
412
415
|
- spec/fixtures/config/incomplete_config.yml
|
413
416
|
- spec/fixtures/config/invalid_config.yml
|
414
417
|
- spec/fixtures/config/invalid_yaml_config.yml
|