appmap 0.54.0 → 0.55.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +16 -10
- data/CHANGELOG.md +45 -0
- data/Rakefile +13 -4
- data/appmap.gemspec +1 -0
- data/lib/appmap.rb +6 -7
- data/lib/appmap/config.rb +1 -1
- data/lib/appmap/event.rb +32 -2
- data/lib/appmap/handler/net_http.rb +1 -1
- data/lib/appmap/handler/rails/template.rb +2 -1
- data/lib/appmap/hook.rb +35 -3
- data/lib/appmap/hook/method.rb +41 -28
- data/lib/appmap/trace.rb +2 -0
- data/lib/appmap/util.rb +18 -2
- data/lib/appmap/version.rb +1 -1
- data/release.sh +0 -1
- data/spec/fixtures/hook/kwargs.rb +11 -0
- data/spec/hook_spec.rb +10 -1
- data/spec/record_net_http_spec.rb +1 -0
- metadata +17 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: dfd518bd44a86f1270fe90e70c397e213763dd582260ace7c5a01898b94030d2
|
4
|
+
data.tar.gz: cf449bff5700a1bfd5efabda40ccd59c5281d595aa34ca551d6a3b4b1f89f5f8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1824e49817ccceca6571fb2cb6f4a3033fb4873bb184577ec3989af3d74d09aecbf7685f9ce9f7efeb2a43e811f9477b0cfc5c6f6778ba3ec8d141c37560112c
|
7
|
+
data.tar.gz: da796d7072dab9b505f6fe1220ae3987e0577be458dfb1253b3d4b860df41d7a4856640629dd300ebcb6588f350f4f55af2b867bf730d0a65e90788c0f2eeb0d
|
data/.travis.yml
CHANGED
@@ -1,5 +1,10 @@
|
|
1
1
|
language: ruby
|
2
2
|
|
3
|
+
rbenv:
|
4
|
+
- 2.5
|
5
|
+
- 2.6
|
6
|
+
- 2.7
|
7
|
+
|
3
8
|
addons:
|
4
9
|
apt:
|
5
10
|
packages:
|
@@ -29,28 +34,29 @@ before_install:
|
|
29
34
|
- |
|
30
35
|
nvm install --lts \
|
31
36
|
&& nvm use --lts
|
32
|
-
|
37
|
+
|
33
38
|
# GEM_ALTERNATIVE_NAME only needed for deployment
|
34
39
|
jobs:
|
35
40
|
include:
|
36
41
|
- stage: test
|
37
42
|
script:
|
43
|
+
- set -e
|
38
44
|
- mkdir tmp
|
39
|
-
-
|
45
|
+
- npm i -g yarn
|
46
|
+
- GEM_ALTERNATIVE_NAME='' bundle exec rake gem:build test
|
40
47
|
|
41
|
-
|
42
48
|
before_deploy:
|
43
49
|
- |
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
semantic-release-rubygem
|
50
|
+
npm i -g \
|
51
|
+
yarn \
|
52
|
+
semantic-release \
|
53
|
+
@semantic-release/git \
|
54
|
+
@semantic-release/changelog \
|
55
|
+
semantic-release-rubygem
|
51
56
|
|
52
57
|
deploy:
|
53
58
|
- provider: script
|
54
59
|
script: ./release.sh
|
55
60
|
on:
|
56
61
|
branch: master
|
62
|
+
condition: "$TRAVIS_RUBY_VERSION = 2.7"
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,48 @@
|
|
1
|
+
# [0.55.0](https://github.com/applandinc/appmap-ruby/compare/v0.54.4...v0.55.0) (2021-06-28)
|
2
|
+
|
3
|
+
|
4
|
+
### Bug Fixes
|
5
|
+
|
6
|
+
* Avoid calling == ([f30ed9f](https://github.com/applandinc/appmap-ruby/commit/f30ed9f309753252df35e372d925db3b914260d4))
|
7
|
+
* Log dynamic loading of appmap helpers at info level ([15dcd3c](https://github.com/applandinc/appmap-ruby/commit/15dcd3c913fa1c32aea034b28ddae59668efa217))
|
8
|
+
* Remove dynamic loading of rake and rspec helpers ([6790970](https://github.com/applandinc/appmap-ruby/commit/67909702f3c8a52081ef1e23a87c292908883334))
|
9
|
+
|
10
|
+
|
11
|
+
### Features
|
12
|
+
|
13
|
+
* APPMAP_PROFILE_DISPLAY_STRING and APPMAP_OBJECT_STRING ([3f5daa8](https://github.com/applandinc/appmap-ruby/commit/3f5daa890bfbfd39b7f825794d0c43da509b3201))
|
14
|
+
* Package name to require can be specified when hooking a gem ([fcc5eb6](https://github.com/applandinc/appmap-ruby/commit/fcc5eb691a0330444560eb4c2afe7fc3c4c8afa8))
|
15
|
+
* Profile packaging hooking ([c020a31](https://github.com/applandinc/appmap-ruby/commit/c020a312f4545348ec7cc302443269c57a7fc026))
|
16
|
+
|
17
|
+
## [0.54.4](https://github.com/applandinc/appmap-ruby/compare/v0.54.3...v0.54.4) (2021-06-27)
|
18
|
+
|
19
|
+
|
20
|
+
### Bug Fixes
|
21
|
+
|
22
|
+
* Only allow trace_end once per location ([10e48cf](https://github.com/applandinc/appmap-ruby/commit/10e48cf855907f9029479b4b7b63bc4d25d664ab))
|
23
|
+
|
24
|
+
## [0.54.3](https://github.com/applandinc/appmap-ruby/compare/v0.54.2...v0.54.3) (2021-06-25)
|
25
|
+
|
26
|
+
|
27
|
+
### Bug Fixes
|
28
|
+
|
29
|
+
* Get deployment working with packaging of NodeJS code ([733c5b8](https://github.com/applandinc/appmap-ruby/commit/733c5b85ec1a0c17ada81be524fa572f78f52500))
|
30
|
+
|
31
|
+
## [0.54.2](https://github.com/applandinc/appmap-ruby/compare/v0.54.1...v0.54.2) (2021-06-25)
|
32
|
+
|
33
|
+
|
34
|
+
### Bug Fixes
|
35
|
+
|
36
|
+
* Require appmap/railtie if Rails is defined ([66b4cbd](https://github.com/applandinc/appmap-ruby/commit/66b4cbd4d418695b0e69150d253dfd5a6f9096cf))
|
37
|
+
|
38
|
+
## [0.54.1](https://github.com/applandinc/appmap-ruby/compare/v0.54.0...v0.54.1) (2021-06-25)
|
39
|
+
|
40
|
+
|
41
|
+
### Bug Fixes
|
42
|
+
|
43
|
+
* Add missing imports and remove deprecation warnings ([f1cb087](https://github.com/applandinc/appmap-ruby/commit/f1cb087f80cad88093227ebf8b4a4cd574853667))
|
44
|
+
* Workaround Ruby bug in 2.7.3 with kwrest ([26e34ca](https://github.com/applandinc/appmap-ruby/commit/26e34ca421fdae6602b27fee5653c8fe26b3793b))
|
45
|
+
|
1
46
|
# [0.54.0](https://github.com/applandinc/appmap-ruby/compare/v0.53.0...v0.54.0) (2021-06-24)
|
2
47
|
|
3
48
|
|
data/Rakefile
CHANGED
@@ -6,8 +6,7 @@ require 'rake/testtask'
|
|
6
6
|
require 'rdoc/task'
|
7
7
|
|
8
8
|
require 'open3'
|
9
|
-
|
10
|
-
require "rake/extensiontask"
|
9
|
+
require 'rake/extensiontask'
|
11
10
|
|
12
11
|
desc 'build the native extension'
|
13
12
|
Rake::ExtensionTask.new("appmap") do |ext|
|
@@ -26,7 +25,7 @@ namespace 'gem' do
|
|
26
25
|
# ~/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/bundler-2.1.4/lib/bundler/gem_helper.rb:39:in `install'
|
27
26
|
def build_gem
|
28
27
|
# Ensure that NPM packages are installed before building.
|
29
|
-
sh('yarn install --prod'
|
28
|
+
sh('yarn install --prod')
|
30
29
|
|
31
30
|
default_build_gem
|
32
31
|
end
|
@@ -34,7 +33,17 @@ namespace 'gem' do
|
|
34
33
|
end
|
35
34
|
end
|
36
35
|
|
37
|
-
RUBY_VERSIONS=%w[2.5 2.6 2.7]
|
36
|
+
RUBY_VERSIONS=%w[2.5 2.6 2.7].select do |version|
|
37
|
+
travis_ruby_version = ENV['TRAVIS_RUBY_VERSION']
|
38
|
+
next true unless travis_ruby_version
|
39
|
+
|
40
|
+
if travis_ruby_version.index(version) == 0
|
41
|
+
warn "Testing Ruby version #{version}, since it matches TRAVIS_RUBY_VERSION=#{travis_ruby_version}"
|
42
|
+
next true
|
43
|
+
end
|
44
|
+
|
45
|
+
false
|
46
|
+
end
|
38
47
|
FIXTURE_APPS=%w[rack_users_app rails6_users_app rails5_users_app]
|
39
48
|
|
40
49
|
def run_cmd(*cmd)
|
data/appmap.gemspec
CHANGED
data/lib/appmap.rb
CHANGED
@@ -26,12 +26,11 @@ lambda do
|
|
26
26
|
Initializer = Struct.new(:class_name, :module_name, :gem_module_name)
|
27
27
|
|
28
28
|
INITIALIZERS = {
|
29
|
-
|
30
|
-
'
|
29
|
+
# In a Rails app, Rails is always defined by the time the other gems are loaded. Therefore, we
|
30
|
+
# don't try and trap the loading of Rails itself here.
|
31
|
+
# Emperically, Rake and RSpec are also defined before appmap is loaded whenever a Rake task or
|
32
|
+
# RSpec tests are being run. Therefore, the only hook we need here is Minitest.
|
31
33
|
'Minitest::Unit::TestCase' => Initializer.new('AppMap::Minitest', 'appmap/minitest', 'minitest'),
|
32
|
-
'Rake' => [
|
33
|
-
Initializer.new('AppMap::Swagger', 'appmap/swagger', 'rake')
|
34
|
-
]
|
35
34
|
}
|
36
35
|
|
37
36
|
TracePoint.new(:class) do |tp|
|
@@ -57,7 +56,7 @@ lambda do
|
|
57
56
|
end
|
58
57
|
end.enable
|
59
58
|
|
60
|
-
if defined?(::Rails
|
59
|
+
if defined?(::Rails)
|
61
60
|
require 'appmap/railtie'
|
62
61
|
end
|
63
62
|
|
@@ -68,7 +67,7 @@ lambda do
|
|
68
67
|
if defined?(::Minitest)
|
69
68
|
require 'appmap/minitest'
|
70
69
|
end
|
71
|
-
|
70
|
+
|
72
71
|
if defined?(::Rake)
|
73
72
|
require 'appmap/swagger'
|
74
73
|
end
|
data/lib/appmap/config.rb
CHANGED
@@ -343,7 +343,7 @@ module AppMap
|
|
343
343
|
shallow = package['shallow']
|
344
344
|
# shallow is true by default for gems
|
345
345
|
shallow = true if shallow.nil?
|
346
|
-
Package.build_from_gem(gem, exclude: package['exclude'] || [], shallow: shallow)
|
346
|
+
Package.build_from_gem(gem, package_name: package['package'], exclude: package['exclude'] || [], shallow: shallow)
|
347
347
|
else
|
348
348
|
Package.build_from_path(path, exclude: package['exclude'] || [], shallow: package['shallow'])
|
349
349
|
end
|
data/lib/appmap/event.rb
CHANGED
@@ -29,11 +29,31 @@ module AppMap
|
|
29
29
|
|
30
30
|
# Gets a display string for a value. This is not meant to be a machine deserializable value.
|
31
31
|
def display_string(value)
|
32
|
-
return nil
|
32
|
+
return nil if value.equal?(nil)
|
33
33
|
|
34
|
+
# With setting APPMAP_PROFILE_DISPLAY_STRING, stringifying this class is shown to take 9 seconds(!) of a 17 second test run.
|
35
|
+
return nil if best_class_name(value) == 'ActiveSupport::Callbacks::Filters::Environment'
|
36
|
+
|
37
|
+
if @times.nil? && ENV['APPMAP_PROFILE_DISPLAY_STRING'] == 'true'
|
38
|
+
@times = Hash.new {|memo,key| memo[key] = 0}
|
39
|
+
Thread.new do
|
40
|
+
sleep 0.5
|
41
|
+
while true
|
42
|
+
warn @times.to_a.sort{|a,b| b[1] <=> a[1]}[0..9].join("\n")
|
43
|
+
sleep 3
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
start = Time.now
|
34
49
|
value_string = custom_display_string(value) || default_display_string(value)
|
35
50
|
|
36
|
-
|
51
|
+
if @times
|
52
|
+
elapsed = Time.now - start
|
53
|
+
@times[best_class_name(value)] += elapsed
|
54
|
+
end
|
55
|
+
|
56
|
+
encode_dislay_string(value_string)
|
37
57
|
end
|
38
58
|
|
39
59
|
def object_properties(hash_like)
|
@@ -57,8 +77,16 @@ module AppMap
|
|
57
77
|
value_cls.name
|
58
78
|
end
|
59
79
|
|
80
|
+
def encode_dislay_string(value)
|
81
|
+
(value||'')[0...LIMIT].encode('utf-8', invalid: :replace, undef: :replace, replace: '_')
|
82
|
+
end
|
83
|
+
|
60
84
|
def custom_display_string(value)
|
61
85
|
case value
|
86
|
+
when NilClass, TrueClass, FalseClass, Numeric, Time, Date
|
87
|
+
value.to_s
|
88
|
+
when String
|
89
|
+
value[0...LIMIT].encode('utf-8', invalid: :replace, undef: :replace, replace: '_')
|
62
90
|
when File
|
63
91
|
"#{value.class}[path=#{value.path}]"
|
64
92
|
when Net::HTTP
|
@@ -71,6 +99,8 @@ module AppMap
|
|
71
99
|
end
|
72
100
|
|
73
101
|
def default_display_string(value)
|
102
|
+
return nil if ENV['APPMAP_OBJECT_STRING'] == 'false'
|
103
|
+
|
74
104
|
last_resort_string = lambda do
|
75
105
|
warn "AppMap encountered an error inspecting a #{value.class.name}: #{$!.message}"
|
76
106
|
'*Error inspecting variable*'
|
data/lib/appmap/hook.rb
CHANGED
@@ -9,6 +9,7 @@ module AppMap
|
|
9
9
|
|
10
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
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
|
12
|
+
SLOW_PACKAGE_THRESHOLD = 0.05
|
12
13
|
|
13
14
|
@unbound_method_arity = ::UnboundMethod.instance_method(:arity)
|
14
15
|
@method_arity = ::Method.instance_method(:arity)
|
@@ -37,8 +38,6 @@ module AppMap
|
|
37
38
|
def initialize(config)
|
38
39
|
@config = config
|
39
40
|
@trace_enabled = []
|
40
|
-
# Paths that are known to be non-tracing
|
41
|
-
@notrace_paths = Set.new
|
42
41
|
end
|
43
42
|
|
44
43
|
# Observe class loading and hook all methods which match the config.
|
@@ -47,6 +46,32 @@ module AppMap
|
|
47
46
|
|
48
47
|
hook_builtins
|
49
48
|
|
49
|
+
# Paths that are known to be non-tracing.
|
50
|
+
@notrace_paths = Set.new
|
51
|
+
# Locations that have already been visited.
|
52
|
+
@trace_locations = Set.new
|
53
|
+
@module_load_times = Hash.new {|memo,k| memo[k] = 0}
|
54
|
+
@slow_packages = Set.new
|
55
|
+
|
56
|
+
if ENV['APPMAP_PROFILE_HOOK'] == 'true'
|
57
|
+
Thread.new do
|
58
|
+
sleep 1
|
59
|
+
while true
|
60
|
+
@module_load_times
|
61
|
+
.keys
|
62
|
+
.select { |key| !@slow_packages.member?(key) }
|
63
|
+
.each do |key|
|
64
|
+
elapsed = @module_load_times[key]
|
65
|
+
if elapsed >= SLOW_PACKAGE_THRESHOLD
|
66
|
+
@slow_packages.add(key)
|
67
|
+
warn "AppMap: Package #{key} took #{@module_load_times[key]} seconds to hook"
|
68
|
+
end
|
69
|
+
end
|
70
|
+
sleep 5
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
50
75
|
@trace_end = TracePoint.new(:end, &method(:trace_end))
|
51
76
|
@trace_end.enable(&block)
|
52
77
|
end
|
@@ -100,7 +125,8 @@ module AppMap
|
|
100
125
|
|
101
126
|
def trace_end(trace_point)
|
102
127
|
location = trace_location(trace_point)
|
103
|
-
warn "Class or module ends at location #{
|
128
|
+
warn "Class or module ends at location #{location}" if Hook::LOG || Hook::LOG_HOOK
|
129
|
+
return unless @trace_locations.add?(location)
|
104
130
|
|
105
131
|
path = trace_point.path
|
106
132
|
enabled = !@notrace_paths.member?(path) && config.path_enabled?(path)
|
@@ -153,6 +179,7 @@ module AppMap
|
|
153
179
|
end
|
154
180
|
end
|
155
181
|
|
182
|
+
start = Time.now
|
156
183
|
instance_methods.each(&hook.(cls))
|
157
184
|
begin
|
158
185
|
# NoMethodError: private method `singleton_class' called for Rack::MiniProfiler:Class
|
@@ -162,6 +189,11 @@ module AppMap
|
|
162
189
|
# uninitialized constant Faraday::Connection
|
163
190
|
warn "NameError in #{__FILE__}: #{$!.message}"
|
164
191
|
end
|
192
|
+
elapsed = Time.now - start
|
193
|
+
if location.index(Bundler.bundle_path.to_s) == 0
|
194
|
+
package_tokens = location[Bundler.bundle_path.to_s.length + 1..-1].split('/')
|
195
|
+
@module_load_times[package_tokens[1]] += elapsed
|
196
|
+
end
|
165
197
|
end
|
166
198
|
end
|
167
199
|
end
|
data/lib/appmap/hook/method.rb
CHANGED
@@ -18,6 +18,8 @@ module AppMap
|
|
18
18
|
TIME_NOW = Time.method(:now)
|
19
19
|
private_constant :TIME_NOW
|
20
20
|
|
21
|
+
ARRAY_OF_EMPTY_HASH = [{}.freeze].freeze
|
22
|
+
|
21
23
|
def initialize(hook_package, hook_class, hook_method)
|
22
24
|
@hook_package = hook_package
|
23
25
|
@hook_class = hook_class
|
@@ -45,42 +47,53 @@ module AppMap
|
|
45
47
|
after_hook = self.method(:after_hook)
|
46
48
|
with_disabled_hook = self.method(:with_disabled_hook)
|
47
49
|
|
48
|
-
hook_method_def =
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
50
|
+
hook_method_def = Proc.new do |*args, &block|
|
51
|
+
instance_method = hook_method.bind(self).to_proc
|
52
|
+
|
53
|
+
is_array_containing_empty_hash = ->(obj) {
|
54
|
+
obj.is_a?(Array) && obj.length == 1 && obj[0].is_a?(Hash) && obj[0].size == 0
|
55
|
+
}
|
53
56
|
|
54
|
-
|
55
|
-
#
|
56
|
-
|
57
|
-
|
57
|
+
call_instance_method = -> {
|
58
|
+
# https://github.com/applandinc/appmap-ruby/issues/153
|
59
|
+
if Util.ruby_minor_version >= 2.7 && is_array_containing_empty_hash.(args) && hook_method.arity == 1
|
60
|
+
instance_method.call({}, &block)
|
61
|
+
else
|
62
|
+
instance_method.call(*args, &block)
|
63
|
+
end
|
64
|
+
}
|
58
65
|
|
59
|
-
|
60
|
-
|
61
|
-
|
66
|
+
# We may not have gotten the class for the method during
|
67
|
+
# initialization (e.g. for a singleton method on an embedded
|
68
|
+
# struct), so make sure we have it now.
|
69
|
+
defined_class, = Hook.qualify_method_name(hook_method) unless defined_class
|
62
70
|
|
63
|
-
|
71
|
+
reentrant = Thread.current[HOOK_DISABLE_KEY]
|
72
|
+
disabled_by_shallow_flag = \
|
73
|
+
-> { hook_package&.shallow? && AppMap.tracing.last_package_for_current_thread == hook_package }
|
64
74
|
|
65
|
-
|
75
|
+
enabled = true if AppMap.tracing.enabled? && !reentrant && !disabled_by_shallow_flag.call
|
66
76
|
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
77
|
+
return call_instance_method.call unless enabled
|
78
|
+
|
79
|
+
call_event, start_time = with_disabled_hook.call do
|
80
|
+
before_hook.call(self, defined_class, args)
|
81
|
+
end
|
82
|
+
return_value = nil
|
83
|
+
exception = nil
|
84
|
+
begin
|
85
|
+
return_value = call_instance_method.call
|
86
|
+
rescue
|
87
|
+
exception = $ERROR_INFO
|
88
|
+
raise
|
89
|
+
ensure
|
90
|
+
with_disabled_hook.call do
|
91
|
+
after_hook.call(self, call_event, start_time, return_value, exception) if call_event
|
81
92
|
end
|
82
93
|
end
|
83
94
|
end
|
95
|
+
hook_method_def = hook_method_def.ruby2_keywords if hook_method_def.respond_to?(:ruby2_keywords)
|
96
|
+
|
84
97
|
hook_class.define_method_with_arity(hook_method.name, hook_method.arity, hook_method_def)
|
85
98
|
end
|
86
99
|
|
data/lib/appmap/trace.rb
CHANGED
data/lib/appmap/util.rb
CHANGED
@@ -124,7 +124,7 @@ module AppMap
|
|
124
124
|
path = path.split('(.')[0]
|
125
125
|
tokens = path.split('/')
|
126
126
|
tokens.map do |token|
|
127
|
-
token.gsub
|
127
|
+
token.gsub(/^:(.*)/, '{\1}')
|
128
128
|
end.join('/')
|
129
129
|
end
|
130
130
|
|
@@ -154,6 +154,18 @@ module AppMap
|
|
154
154
|
word.split(/[\-_]/).map(&:capitalize).join
|
155
155
|
end
|
156
156
|
|
157
|
+
# https://api.rubyonrails.org/v6.1.3.2/classes/ActiveSupport/Inflector.html#method-i-underscore
|
158
|
+
def underscore(camel_cased_word)
|
159
|
+
return camel_cased_word unless /[A-Z-]|::/.match?(camel_cased_word)
|
160
|
+
word = camel_cased_word.to_s.gsub("::", "/")
|
161
|
+
# word.gsub!(inflections.acronyms_underscore_regex) { "#{$1 && '_' }#{$2.downcase}" }
|
162
|
+
word.gsub!(/([A-Z\d]+)([A-Z][a-z])/, '\1_\2')
|
163
|
+
word.gsub!(/([a-z\d])([A-Z])/, '\1_\2')
|
164
|
+
word.tr!("-", "_")
|
165
|
+
word.downcase!
|
166
|
+
word
|
167
|
+
end
|
168
|
+
|
157
169
|
def deep_dup(hash)
|
158
170
|
# This is a simple way to avoid the need for deep_dup from activesupport.
|
159
171
|
Marshal.load(Marshal.dump(hash))
|
@@ -173,11 +185,15 @@ module AppMap
|
|
173
185
|
|
174
186
|
def startup_message(msg)
|
175
187
|
if defined?(::Rails) && defined?(::Rails.logger) && ::Rails.logger
|
176
|
-
::Rails.logger.
|
188
|
+
::Rails.logger.info msg
|
177
189
|
elsif ENV['DEBUG'] == 'true'
|
178
190
|
warn msg
|
179
191
|
end
|
180
192
|
end
|
193
|
+
|
194
|
+
def ruby_minor_version
|
195
|
+
@ruby_minor_version ||= RUBY_VERSION.split('.')[0..1].join('.').to_f
|
196
|
+
end
|
181
197
|
end
|
182
198
|
end
|
183
199
|
end
|
data/lib/appmap/version.rb
CHANGED
data/release.sh
CHANGED
data/spec/hook_spec.rb
CHANGED
@@ -970,7 +970,7 @@ describe 'AppMap class Hooking', docker: false do
|
|
970
970
|
tz = ENV['TZ']
|
971
971
|
ENV['TZ'] = 'UTC'
|
972
972
|
Timecop.freeze(Time.utc('2020-01-01')) do
|
973
|
-
expect(Time).to receive(:now).
|
973
|
+
expect(Time).to receive(:now).at_least(3).times.and_call_original
|
974
974
|
expect(InstanceMethod.new.say_the_time).to be
|
975
975
|
end
|
976
976
|
ensure
|
@@ -985,4 +985,13 @@ describe 'AppMap class Hooking', docker: false do
|
|
985
985
|
expect(InstanceMethod.new.method(:say_echo).arity).to be(1)
|
986
986
|
end
|
987
987
|
end
|
988
|
+
|
989
|
+
describe 'kwargs handling' do
|
990
|
+
# https://github.com/applandinc/appmap-ruby/issues/153
|
991
|
+
it 'empty hash for **kwrest can be proxied as a regular function argument', github_issue: 153 do
|
992
|
+
invoke_test_file 'spec/fixtures/hook/kwargs.rb' do
|
993
|
+
expect(Kwargs.has_kwrest_calls_no_kwargs(nil, {})).to eq({})
|
994
|
+
end
|
995
|
+
end
|
996
|
+
end
|
988
997
|
end
|
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.55.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-06-
|
11
|
+
date: 2021-06-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -276,6 +276,20 @@ dependencies:
|
|
276
276
|
- - ">="
|
277
277
|
- !ruby/object:Gem::Version
|
278
278
|
version: '0'
|
279
|
+
- !ruby/object:Gem::Dependency
|
280
|
+
name: webrick
|
281
|
+
requirement: !ruby/object:Gem::Requirement
|
282
|
+
requirements:
|
283
|
+
- - ">="
|
284
|
+
- !ruby/object:Gem::Version
|
285
|
+
version: '0'
|
286
|
+
type: :development
|
287
|
+
prerelease: false
|
288
|
+
version_requirements: !ruby/object:Gem::Requirement
|
289
|
+
requirements:
|
290
|
+
- - ">="
|
291
|
+
- !ruby/object:Gem::Version
|
292
|
+
version: '0'
|
279
293
|
description:
|
280
294
|
email:
|
281
295
|
- kgilpin@gmail.com
|
@@ -364,6 +378,7 @@ files:
|
|
364
378
|
- spec/fixtures/hook/exception_method.rb
|
365
379
|
- spec/fixtures/hook/exclude.rb
|
366
380
|
- spec/fixtures/hook/instance_method.rb
|
381
|
+
- spec/fixtures/hook/kwargs.rb
|
367
382
|
- spec/fixtures/hook/labels.rb
|
368
383
|
- spec/fixtures/hook/method_named_call.rb
|
369
384
|
- spec/fixtures/hook/revoke_api_key.appmap.json
|