load_tracer 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +1 -1
- data/README.md +12 -0
- data/lib/load_tracer/formatter/default.rb +36 -0
- data/lib/load_tracer/formatter/dot.rb +65 -0
- data/lib/load_tracer/formatter/templates/default.dot.erb +6 -0
- data/lib/load_tracer/version.rb +1 -1
- data/lib/load_tracer.rb +33 -35
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 54faee11fca635fb5444d731ba08da06967dd8b26f6164282ae8fe748149840a
|
4
|
+
data.tar.gz: c759a241b21b3c04f34b83274a67abce0a6a3c3c56a6ec92df1c201848859872
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2c48aca3dbca0cafe40c9aedf1b97c37c9dd325b77fb6c1be41fa7804fb9625d46c8d375a97e1a7cc08ffd53c224ffc6eb994a76a3cfce52e41a0d11cdd09d34
|
7
|
+
data.tar.gz: 2b980c8f85959c33b4fc98eb3a7717a1e25ab1af8062ab285633003ec745de0ce9fa4340f3d5b91954a947994426c635b2175e8b1494ed600b787f58999acbf1
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -38,6 +38,18 @@ end
|
|
38
38
|
pp report
|
39
39
|
```
|
40
40
|
|
41
|
+
### dot format
|
42
|
+
|
43
|
+
```ruby
|
44
|
+
require 'load_tracer'
|
45
|
+
|
46
|
+
puts LoadTracer.trace(format: :dot) { require 'prime' }
|
47
|
+
```
|
48
|
+
|
49
|
+
```
|
50
|
+
ruby example.rb | dot -Tpng -o example.png | open example.png
|
51
|
+
```
|
52
|
+
|
41
53
|
## License
|
42
54
|
|
43
55
|
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
@@ -0,0 +1,36 @@
|
|
1
|
+
class LoadTracer
|
2
|
+
class DefaultFormatter
|
3
|
+
def self.export(dependencies:, reverse_dependencies:)
|
4
|
+
report = dependencies.map do |path, deps|
|
5
|
+
FileSpec.new(
|
6
|
+
name: File.basename(path),
|
7
|
+
path: path,
|
8
|
+
dependencies: deps,
|
9
|
+
reverse_dependencies: [],
|
10
|
+
)
|
11
|
+
end
|
12
|
+
|
13
|
+
reverse_dependencies.each do |path, rdeps|
|
14
|
+
fs = report.find { |fs| fs.path == path }
|
15
|
+
|
16
|
+
if fs.nil?
|
17
|
+
report << FileSpec.new(
|
18
|
+
name: File.basename(path),
|
19
|
+
path: path,
|
20
|
+
dependencies: [],
|
21
|
+
reverse_dependencies: rdeps,
|
22
|
+
)
|
23
|
+
else
|
24
|
+
fs.reverse_dependencies = rdeps
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
report.each do |fs|
|
29
|
+
fs.dependencies.sort!.uniq!
|
30
|
+
fs.reverse_dependencies.sort!.uniq!
|
31
|
+
end
|
32
|
+
|
33
|
+
report.sort_by(&:name)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
require 'erb'
|
2
|
+
require 'pathname'
|
3
|
+
|
4
|
+
class LoadTracer
|
5
|
+
class DotFormatter
|
6
|
+
def self.export(dependencies:)
|
7
|
+
new(dependencies: dependencies).export
|
8
|
+
end
|
9
|
+
|
10
|
+
def initialize(dependencies:)
|
11
|
+
@dependencies = dependencies
|
12
|
+
@template = File.read(File.expand_path('templates/default.dot.erb', __dir__))
|
13
|
+
end
|
14
|
+
|
15
|
+
def export
|
16
|
+
graph_data = ERB.new(@template, nil, '-').result(binding)
|
17
|
+
|
18
|
+
graph_data.lines.map(&:rstrip).join("\n")
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def graph_edges
|
24
|
+
@dependencies.flat_map do |from, deps|
|
25
|
+
label1 = File.basename(from)
|
26
|
+
|
27
|
+
deps.map do |to|
|
28
|
+
label2 = File.basename(to)
|
29
|
+
|
30
|
+
[
|
31
|
+
duplicated_label_names.include?(label1) ? node_label(from) : label1,
|
32
|
+
duplicated_label_names.include?(label2) ? node_label(to) : label2,
|
33
|
+
]
|
34
|
+
end
|
35
|
+
end.sort_by(&:first).uniq
|
36
|
+
end
|
37
|
+
|
38
|
+
def duplicated_label_names
|
39
|
+
return @_duplicate_names if @_duplicate_names
|
40
|
+
|
41
|
+
checked = Hash.new
|
42
|
+
@_duplicate_names = []
|
43
|
+
|
44
|
+
@dependencies.each do |from, deps|
|
45
|
+
label1 = File.basename(from)
|
46
|
+
@_duplicate_names << label1 if checked[label1]
|
47
|
+
checked[label1] = true
|
48
|
+
|
49
|
+
deps.each do |to|
|
50
|
+
label2 = File.basename(to)
|
51
|
+
|
52
|
+
@_duplicate_names << label2 if label1 == label2
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
@_duplicate_names.uniq!
|
57
|
+
@_duplicate_names
|
58
|
+
end
|
59
|
+
|
60
|
+
def node_label(absolute_path)
|
61
|
+
s, _, t = Pathname.new(absolute_path).ascend.take(3)
|
62
|
+
s.relative_path_from(t).to_s
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
data/lib/load_tracer/version.rb
CHANGED
data/lib/load_tracer.rb
CHANGED
@@ -1,25 +1,23 @@
|
|
1
1
|
require 'binding_of_caller'
|
2
|
+
require 'load_tracer/formatter/default'
|
3
|
+
require 'load_tracer/formatter/dot'
|
2
4
|
require 'load_tracer/version'
|
3
5
|
|
4
6
|
module Kernel
|
5
7
|
unless defined?(__original_require__)
|
6
8
|
alias __original_require__ require
|
7
|
-
private :__original_require__
|
8
9
|
end
|
9
10
|
|
10
11
|
unless defined?(__original_require_relative__)
|
11
12
|
alias __original_require_relative__ require_relative
|
12
|
-
private :__original_require_relative__
|
13
13
|
end
|
14
14
|
|
15
15
|
unless defined?(__original_load__)
|
16
16
|
alias __original_load__ load
|
17
|
-
private :__original_load__
|
18
17
|
end
|
19
18
|
|
20
19
|
unless defined?(__original_autoload__)
|
21
20
|
alias __original_autoload__ autoload
|
22
|
-
private :__original_autoload__
|
23
21
|
end
|
24
22
|
|
25
23
|
def require(feature)
|
@@ -44,63 +42,58 @@ class LoadTracer
|
|
44
42
|
|
45
43
|
LOAD_METHODS = %i(require require_relative load autoload)
|
46
44
|
|
47
|
-
def self.trace
|
45
|
+
def self.trace(format: nil)
|
48
46
|
instance = new
|
49
47
|
instance.tracer.enable { yield }
|
50
|
-
instance.report
|
48
|
+
instance.report(format: format)
|
51
49
|
end
|
52
50
|
|
53
51
|
def initialize
|
54
52
|
@dependencies = Hash.new { |hash, key| hash[key] = [] }
|
55
53
|
@reverse_dependencies = Hash.new { |hash, key| hash[key] = [] }
|
54
|
+
@not_found_features = []
|
56
55
|
end
|
57
56
|
|
58
57
|
def tracer
|
59
|
-
TracePoint.new(:
|
58
|
+
TracePoint.new(:return) do |tp|
|
60
59
|
next unless LOAD_METHODS.include?(tp.method_id)
|
61
60
|
next if tp.defined_class != ::Kernel
|
62
61
|
next if tp.path != __FILE__
|
63
62
|
|
64
63
|
case tp.event
|
65
|
-
when :
|
64
|
+
when :return
|
66
65
|
bl = caller_locations[1]
|
67
|
-
|
68
66
|
feature = get_feature(tp)
|
67
|
+
|
68
|
+
if bl.absolute_path.nil?
|
69
|
+
bl = find_caller_of_internal_library(feature)
|
70
|
+
end
|
71
|
+
|
69
72
|
path = find_path(feature) || find_path(File.expand_path(feature, File.dirname(bl.path)))
|
70
73
|
|
71
|
-
|
74
|
+
if path.nil?
|
75
|
+
@not_found_features << feature
|
76
|
+
next
|
77
|
+
end
|
72
78
|
|
73
|
-
@dependencies[bl.
|
74
|
-
@reverse_dependencies[path] << bl.
|
79
|
+
@dependencies[bl.absolute_path] << path
|
80
|
+
@reverse_dependencies[path] << bl.absolute_path
|
75
81
|
end
|
76
82
|
end
|
77
83
|
end
|
78
84
|
|
79
|
-
def report
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
+
def report(format:)
|
86
|
+
case format
|
87
|
+
when :dot
|
88
|
+
DotFormatter.export(
|
89
|
+
dependencies: @dependencies
|
90
|
+
)
|
91
|
+
else
|
92
|
+
DefaultFormatter.export(
|
93
|
+
dependencies: @dependencies,
|
94
|
+
reverse_dependencies: @reverse_dependencies
|
85
95
|
)
|
86
96
|
end
|
87
|
-
|
88
|
-
@reverse_dependencies.each do |path, rdeps|
|
89
|
-
fs = file_specs.find { |fs| fs.path == path }
|
90
|
-
|
91
|
-
if fs.nil?
|
92
|
-
file_specs << FileSpec.new(
|
93
|
-
name: File.basename(path),
|
94
|
-
path: path,
|
95
|
-
dependencies: [],
|
96
|
-
reverse_dependencies: rdeps
|
97
|
-
)
|
98
|
-
else
|
99
|
-
fs.reverse_dependencies = rdeps
|
100
|
-
end
|
101
|
-
end
|
102
|
-
|
103
|
-
file_specs
|
104
97
|
end
|
105
98
|
|
106
99
|
private
|
@@ -121,4 +114,9 @@ class LoadTracer
|
|
121
114
|
rescue LoadError
|
122
115
|
nil
|
123
116
|
end
|
117
|
+
|
118
|
+
def find_caller_of_internal_library(feature)
|
119
|
+
index = caller_locations.find_index { |bl| bl.base_label == feature && bl.path == '<internal:prelude>' }
|
120
|
+
caller_locations[index + 1]
|
121
|
+
end
|
124
122
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: load_tracer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Shuichi Tamayose
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-01
|
11
|
+
date: 2019-03-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: binding_of_caller
|
@@ -85,6 +85,9 @@ files:
|
|
85
85
|
- bin/console
|
86
86
|
- bin/setup
|
87
87
|
- lib/load_tracer.rb
|
88
|
+
- lib/load_tracer/formatter/default.rb
|
89
|
+
- lib/load_tracer/formatter/dot.rb
|
90
|
+
- lib/load_tracer/formatter/templates/default.dot.erb
|
88
91
|
- lib/load_tracer/version.rb
|
89
92
|
- load_tracer.gemspec
|
90
93
|
homepage: https://github.com/siman-man/load_tracer
|