vistual_call 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 254b90d7ec0cbe6c4c202202beaf927acab31c4a8ebdf38c566affefde719513
4
+ data.tar.gz: bb2dabaf7f79a194341c6757a0e94e48e66695460b6f47333595d6ce6aa47f2a
5
+ SHA512:
6
+ metadata.gz: 7ddce952a828984266dd861a20bce14942ec483b9e5a2edd864fe93fb47c3e04cdad8f835cd59a5b11f4bb0d84fffe925be8b77e3de5d7c63261cd31e3584669
7
+ data.tar.gz: 11179df1c70d10ab271c4754e1986e09d4c7cc49887bca333ccc10a9880f83c808db525d6462418d0c83e57240960a821b691f5a15a080c44ee8b9b11d0fc6e5
data/.DS_Store ADDED
Binary file
data/Gemfile ADDED
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ source "https://rubygems.org"
4
+
5
+ # Specify your gem's dependencies in vistual_call.gemspec
6
+ gemspec
7
+
8
+ gem "rake", "~> 13.0"
data/Gemfile.lock ADDED
@@ -0,0 +1,19 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ vistual_call (0.2.0)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ rake (13.0.6)
10
+
11
+ PLATFORMS
12
+ arm64-darwin-21
13
+
14
+ DEPENDENCIES
15
+ rake (~> 13.0)
16
+ vistual_call!
17
+
18
+ BUNDLED WITH
19
+ 2.4.12
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2023 Mark24
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,76 @@
1
+ # VistualCall
2
+
3
+ VistualCall is a gem to help you trace your code and export beautiful vistual call graph.
4
+
5
+ # Introduction
6
+
7
+ ## Dependency
8
+
9
+ 1. Graphviz
10
+
11
+ You need to install [Graphviz](https://graphviz.org/) by yourself.
12
+
13
+ Go to install [graphviz](https://graphviz.org/download/).
14
+
15
+ ## Usage
16
+
17
+ ### 1. Install gem
18
+
19
+ `gem install vistual_call`
20
+
21
+ ### 2. Only the method needs to be wrapped.
22
+
23
+
24
+ ```ruby
25
+ require 'vistual_call'
26
+
27
+ def call_c
28
+ end
29
+
30
+ def call_b
31
+ call_c
32
+ end
33
+
34
+ def call_a
35
+ call_b
36
+ end
37
+
38
+ VistualCall.trace do
39
+ call_a # enter call
40
+ end
41
+ ```
42
+
43
+ ![example](./example/example.png)
44
+
45
+ The method after each node is call order number. This will help your understand the order of the function call.
46
+
47
+ ## 3. More information
48
+
49
+ ## configuration
50
+
51
+ ```ruby
52
+ # you can pass options
53
+ VistualCall.trace(options) do
54
+ # run your code here...
55
+ end
56
+ ```
57
+
58
+ Options:
59
+
60
+ | name | type | required | explain | example |
61
+ | ---- | ---- | ---- | ---- | ---- |
62
+ | label | String | true | 标题 | Hello |
63
+ | labelloc | Symbol | false | 标题位置: :top :bottom :center | :top |
64
+ | labeljust | Symbol | false | 标题对齐位置 :left, :center, :right | :center |
65
+ | direction | Symbol| false | 绘制方向,依次是 :TB(从上到下),:LR(从左到右,默认方式),:BT(从下到上),:RL(从右到左) | :LR |
66
+ | format | String | false | 输出图片格式,查看 [graphviz 支持输出格式](https://graphviz.org/docs/outputs/) 'png'、'svg' | 默认 'png' |
67
+ | output | String | false | 导出图片绝对路径 | 默认家目录下 `vistual_call_result.png` |
68
+ | theme | Symbol | false | 配色主题 :sky, :lemon | 默认 :sky |
69
+ | show_dot | boolean | false | 展示 dot 内容 | 默认 false |
70
+ | show_order_number | boolean | false | 输出调用序号 | 默认 true |
71
+ | jump_list | Array(String) | false | 跳过节点,默认 ["Kernel#class", "Kernel#frozen?"] | - |
72
+ | heightlight_match | Regex | false | 默认高亮匹配 label, 默认 /method_missing/ | /method_missing/ |
73
+
74
+ ## LICENSE
75
+
76
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ task default: %i[]
Binary file
data/example/sample.rb ADDED
@@ -0,0 +1,16 @@
1
+ require_relative "../lib/vistual_call"
2
+
3
+ def call_c
4
+ end
5
+
6
+ def call_b
7
+ call_c
8
+ end
9
+
10
+ def call_a
11
+ call_b
12
+ end
13
+
14
+ VistualCall.trace(title: "Hellow", show_dot: true) do
15
+ call_a # enter call
16
+ end
Binary file
@@ -0,0 +1,8 @@
1
+ require "sinatra"
2
+ require_relative "../lib/vistual_call"
3
+
4
+ VistualCall.trace do
5
+ get "/" do
6
+ "hello"
7
+ end
8
+ end
@@ -0,0 +1,298 @@
1
+ require "set"
2
+ require "tempfile"
3
+ require "yaml"
4
+ require_relative "./tracer"
5
+
6
+ module VistualCall
7
+ # Output config
8
+ DEFAULT_OUTPUT_FORMAT = "png"
9
+ DEFAULT_OUTPUT = "vistual_call_result.png"
10
+ DEFAULT_OUTPUT_PATH = File.join(Dir.home, DEFAULT_OUTPUT)
11
+
12
+ # Jump Node
13
+ DEFAULT_JUMP_NODE = %w[Kernel#class Kernel#frozen?]
14
+
15
+ # Hightlight Label
16
+ HIGHT_LIGHT_REGEX = /method_missing/
17
+
18
+ # Core
19
+ DIRECTIONS = %w[TB LR BT RL]
20
+ LABEL_LOC = %w[top bottom center]
21
+ LABEL_JUST = %w[left right center]
22
+
23
+ class Graph
24
+ @@custer_count = 0
25
+ attr_accessor :call_tree_root
26
+
27
+ def self.root
28
+ File.expand_path("../../", __dir__)
29
+ end
30
+
31
+ def initialize(options = {})
32
+ @label = options.fetch(:label, nil)
33
+ @labelloc = options.fetch(:labelloc, :top).to_s
34
+ if !LABEL_LOC.include?(@labelloc)
35
+ raise VistualCallError("labelloc must in #{LABEL_LOC}")
36
+ end
37
+ @labeljust = options.fetch(:labeljust, :center).to_s
38
+ if !LABEL_JUST.include?(@labeljust)
39
+ raise VistualCallError("labeljust must in #{LABEL_JUST}")
40
+ end
41
+ @margin = options[:margin] || "5"
42
+ # display config
43
+ @direction = options.fetch(:direction, :LR).to_s
44
+ if !DIRECTIONS.include?(@direction)
45
+ raise VistualCallError("direction must in #{DIRECTIONS}")
46
+ end
47
+ @format = options.fetch(:format, DEFAULT_OUTPUT_FORMAT)
48
+ @output = File.expand_path(options.fetch(:output, DEFAULT_OUTPUT_PATH))
49
+
50
+ @show_dot = options.fetch(:show_dot, false)
51
+ @show_order_number = options.fetch(:show_order_number, true)
52
+
53
+ # node graph config
54
+ @jump_list = options.fetch(:jump_list, DEFAULT_JUMP_NODE)
55
+ @heightlight_match = options.fetch(:heightlight_match, HIGHT_LIGHT_REGEX)
56
+
57
+ # theme
58
+ @theme_name = options.fetch(:theme, :sky).to_s
59
+ @theme_config =
60
+ YAML.load_file(File.join(self.class.root, "theme.yml"), aliases: true)
61
+ @theme =
62
+ @theme_config[@theme_name] || @theme_config[@theme_config["use_theme"]]
63
+ @node_attrs = @theme["node_attrs"]
64
+ @edge_attrs = @theme["edge_attrs"]
65
+ @node_waring_attrs = @theme["node_warn_attrs"]
66
+
67
+ # working cache
68
+ @tracer = Tracer.new
69
+
70
+ @call_tree_root = nil
71
+ @call_tree_hashmap = nil
72
+
73
+ @label_hashmap = {}
74
+ @cache_graph_nodes_set = Set.new
75
+ @cache_graph_edges = []
76
+ end
77
+
78
+ def get_call_tree_root
79
+ @call_tree_root = @tracer.call_tree_root
80
+ end
81
+
82
+ def get_call_tree_hashmap
83
+ @call_tree_hashmap = @tracer.call_tree_hashmap
84
+ end
85
+
86
+ def track(&block)
87
+ @tracer.track(&block)
88
+ end
89
+
90
+ def get_graph_node_id(node)
91
+ label_name = node.method_name
92
+ if !@label_hashmap.key?(label_name)
93
+ @label_hashmap[label_name] = node.node_id
94
+ end
95
+ return @label_hashmap[label_name]
96
+ end
97
+
98
+ def collect_graph_nodes_edges(node)
99
+ return if node == nil
100
+ return if @jump_list.include?(node.method_name)
101
+
102
+ graph_node_id = get_graph_node_id(node)
103
+
104
+ # build node
105
+ @cache_graph_nodes_set.add(graph_node_id)
106
+
107
+ # buid edges
108
+ if node.parent_node_id
109
+ parent_node = @call_tree_hashmap[node.parent_node_id]
110
+ parent_graph_node_id = get_graph_node_id(parent_node)
111
+ @cache_graph_edges.push([parent_graph_node_id, graph_node_id])
112
+ end
113
+
114
+ # Make recurse call
115
+ if node.children.size > 0
116
+ node.children.each do |one_child_node|
117
+ collect_graph_nodes_edges(one_child_node)
118
+ end
119
+ end
120
+ end
121
+
122
+ def create_or_set(obj, key, value)
123
+ obj[key] = [] if !obj.key?(key)
124
+ obj[key].push(value)
125
+ end
126
+
127
+ def collect_group_cluster
128
+ @cluster_group = {}
129
+ @label_hashmap.keys.each do |label_name|
130
+ if label_name.count("::") == 0
131
+ create_or_set(@cluster_group, "_single", @label_hashmap[label_name])
132
+ else
133
+ module_name = label_name.split("#")
134
+ module_name.pop
135
+ module_name = module_name.join("#")
136
+ create_or_set(@cluster_group, module_name, @label_hashmap[label_name])
137
+ end
138
+ end
139
+ end
140
+
141
+ def get_dot_config_string(hashmap = nil)
142
+ return if !hashmap
143
+ config = hashmap.keys.map { |key| "#{key}=\"#{hashmap[key]}\"" }.join(",")
144
+ return "[#{config}]"
145
+ end
146
+
147
+ def merge_config(*configs)
148
+ new_config = {}
149
+ configs.each { |conf| new_config = new_config.merge(conf) }
150
+ return new_config
151
+ end
152
+
153
+ def get_label_text(node)
154
+ result = "#{node.defined_class}##{node.method_id}"
155
+ result << " (#{node.node_id})" if @show_order_number
156
+ return result
157
+ end
158
+
159
+ def dot_node_format(node_id)
160
+ if node_id == StartNodeID
161
+ return("node#{node_id}#{get_dot_config_string({ label: "Start" })}")
162
+ end
163
+
164
+ node = @call_tree_hashmap[node_id]
165
+
166
+ config = { label: get_label_text(node) }
167
+ config = merge_config(config, @node_waring_attrs) if @heightlight_match =~
168
+ node.method_name
169
+
170
+ return("node#{node_id}#{get_dot_config_string(config)}")
171
+ end
172
+
173
+ def generate_node_text(graph_node_id)
174
+ return dot_node_format(graph_node_id) + ";\n"
175
+ end
176
+
177
+ def generate_cluster(module_name, graph_ids)
178
+ @@custer_count += 1
179
+
180
+ cluster_style_config = @theme.dig("cluster", "style") || nil
181
+ cluster_style_config_text =
182
+ cluster_style_config && "style=\"#{cluster_style_config}\";"
183
+
184
+ cluster_color_config = @theme.dig("cluster", "color") || nil
185
+ cluster_color_config_text =
186
+ cluster_color_config && "color=\"#{cluster_color_config}\";"
187
+
188
+ cluster_node_config = @theme.dig("cluster_node") || nil
189
+ cluster_node_config_text =
190
+ cluster_node_config &&
191
+ "node#{get_dot_config_string(cluster_node_config)};"
192
+
193
+ template = <<-CLUSTER
194
+ subgraph cluster_#{@@custer_count} {
195
+ label="#{module_name}";
196
+ #{cluster_style_config_text}
197
+ #{cluster_color_config_text}
198
+ #{cluster_node_config_text}
199
+
200
+ #{graph_ids.map { |graph_node_id| generate_node_text(graph_node_id) }.join("")}
201
+ }
202
+ CLUSTER
203
+
204
+ return template
205
+ end
206
+
207
+ def render_nodes_and_clusters()
208
+ content = ""
209
+ @cluster_group.keys.each do |key|
210
+ if key == "_single"
211
+ graph_node_ids = @cluster_group[key]
212
+
213
+ graph_node_ids.each do |graph_node_id|
214
+ content << generate_node_text(graph_node_id)
215
+ end
216
+ else
217
+ module_name = key
218
+ module_graph_node_ids = @cluster_group[key]
219
+
220
+ content << generate_cluster(module_name, module_graph_node_ids)
221
+ end
222
+ end
223
+
224
+ return content
225
+ end
226
+
227
+ def dot_edge_format(edge)
228
+ parent_id, child_id = edge
229
+ return("node#{parent_id} -> node#{child_id}")
230
+ end
231
+
232
+ def render_edges
233
+ @cache_graph_edges.map { |edge| dot_edge_format(edge) }.join("\n")
234
+ end
235
+
236
+ def render_graph_config
237
+ @theme.dig("graph") &&
238
+ "graph #{get_dot_config_string(@theme.dig("graph"))}"
239
+ end
240
+
241
+ def render_node_config
242
+ @node_attrs && "node #{get_dot_config_string(@node_attrs)};"
243
+ end
244
+
245
+ def render_edge_config
246
+ @edge_attrs && "edge #{get_dot_config_string(@edge_attrs)};"
247
+ end
248
+
249
+ def render_meta_info
250
+ meta_info = ["rankdir=#{@direction};"]
251
+ meta_info << "margin=#{@margin};" if @margin
252
+ meta_info << "label=\"#{@label}\";" if @label
253
+ meta_info << "labelloc=\"#{@labelloc}\";" if @labelloc
254
+ meta_info << "labeljust=\"#{@labeljust}\";" if @labeljust
255
+
256
+ meta_info.join("\n")
257
+ end
258
+ def generate_dot_template
259
+ dot_template = <<-DOT
260
+ digraph "virtual_call_graph"{
261
+
262
+ #{render_meta_info}
263
+ #{render_graph_config}
264
+ #{render_node_config}
265
+ #{render_edge_config}
266
+
267
+ #{render_nodes_and_clusters}
268
+
269
+ #{render_edges}
270
+
271
+ }
272
+ DOT
273
+
274
+ return dot_template
275
+ end
276
+
277
+ def create_dot_file(content)
278
+ dot_file_path = nil
279
+ dot_file = Tempfile.new("vistual_call")
280
+ dot_file_path = dot_file.path
281
+ dot_file.write content
282
+ dot_file.close
283
+ return dot_file_path
284
+ end
285
+
286
+ def output
287
+ get_call_tree_root()
288
+ get_call_tree_hashmap()
289
+
290
+ collect_graph_nodes_edges(@call_tree_root)
291
+ collect_group_cluster()
292
+ content = generate_dot_template()
293
+ dot_file_path = create_dot_file(content)
294
+ system("cat #{dot_file_path}") if @show_dot
295
+ system("dot #{dot_file_path} -T #{@format} -o '#{@output}'")
296
+ end
297
+ end
298
+ end
@@ -0,0 +1,39 @@
1
+ require_relative "./method_node"
2
+
3
+ module VistualCall
4
+ class MethodCallTree
5
+ attr_accessor :call_stack, :memo
6
+ def initialize
7
+ @call_stack = []
8
+ @memo = {}
9
+
10
+ root = BasicNode.new
11
+ @call_stack.push(root)
12
+ memo_it(root.node_id, root)
13
+ end
14
+
15
+ def memo_it(node_id, payload)
16
+ @memo[node_id] = payload unless @memo.key?(node_id)
17
+ return @memo[node_id]
18
+ end
19
+
20
+ def dispatch_call(method_info)
21
+ # Memo: 构建树的call、return 不应该被跳过、修改,来保持对应关系,可以还原起调用树。过滤工作应该在消费数据的层面
22
+ node = MethodNode.new(method_info)
23
+ node_id = node.node_id
24
+ memo_it(node_id, node)
25
+
26
+ @call_stack.push(node)
27
+ end
28
+
29
+ def dispatch_return(method_info = {})
30
+ match_call_method = @call_stack.pop
31
+
32
+ match_call_method_parent = @call_stack.last
33
+ if match_call_method_parent
34
+ match_call_method.parent_node_id = match_call_method_parent.node_id
35
+ match_call_method_parent.add_child(match_call_method)
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,48 @@
1
+ module VistualCall
2
+ StartNodeID = 1
3
+
4
+ class BasicNode
5
+ attr_accessor :node_id, :method_name, :parent_node_id, :children
6
+ def initialize(method_name = nil)
7
+ @node_id = StartNodeID
8
+ @method_name = method_name || "Start"
9
+ @parent_node_id = nil
10
+ @children = []
11
+ end
12
+
13
+ def add_child(child)
14
+ @children << child
15
+ end
16
+ end
17
+
18
+ class MethodNode
19
+ @@instance_count = StartNodeID
20
+
21
+ def self.instance_count
22
+ @@instance_count
23
+ end
24
+
25
+ def self.get_method_name(node_info)
26
+ "#{node_info.defined_class}##{node_info.method_id}"
27
+ end
28
+
29
+ attr_accessor :node_id, :method_name, :parent_node_id, :children
30
+ def initialize(method_info)
31
+ @@instance_count += 1
32
+ @node_id = @@instance_count
33
+ @parent_node_id = nil
34
+
35
+ # Must copy TracePointer information, because TracePointer cannot access outside.
36
+ %i[path event lineno method_id defined_class parameters].each do |attr|
37
+ instance_variable_set("@#{attr}", method_info.send(attr))
38
+ self.class.send(:attr_accessor, attr)
39
+ end
40
+ @method_name = self.class.get_method_name(self)
41
+ @children = []
42
+ end
43
+
44
+ def add_child(child)
45
+ @children << child
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,29 @@
1
+ require_relative "./method_call_tree"
2
+
3
+ module VistualCall
4
+ class Tracer
5
+ attr_accessor :call_tree
6
+ def initialize(options = {})
7
+ @events = %i[call return]
8
+ @call_tree = MethodCallTree.new
9
+
10
+ @trace_point =
11
+ TracePoint.new(*@events) do |tp|
12
+ # TODO: stop & disable situations
13
+ @call_tree.send("dispatch_#{tp.event}", tp)
14
+ end
15
+ end
16
+
17
+ def track(&block)
18
+ @trace_point.enable { block.call }
19
+ end
20
+
21
+ def call_tree_root
22
+ @call_tree.call_stack.first || nil
23
+ end
24
+
25
+ def call_tree_hashmap
26
+ @call_tree.memo || {}
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module VistualCall
4
+ VERSION = "1.0.0"
5
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "vistual_call/version"
4
+ require_relative "./vistual_call/graph"
5
+
6
+ module VistualCall
7
+ class VistualCallError < StandardError
8
+ end
9
+
10
+ class << self
11
+ def trace(options = {})
12
+ unless block_given?
13
+ puts "Block required!"
14
+ return
15
+ end
16
+
17
+ proxy = ::VistualCall::Graph.new(options)
18
+ proxy.track { yield }
19
+ proxy.output
20
+ end
21
+ end
22
+ end
data/read_yaml.rb ADDED
@@ -0,0 +1,6 @@
1
+ require "yaml"
2
+ require "json"
3
+
4
+ data = YAML.load_file("./theme.yml", aliases: true)
5
+
6
+ puts JSON.pretty_generate(data)
@@ -0,0 +1,4 @@
1
+ module VistualCall
2
+ VERSION: String
3
+ # See the writing guide of rbs: https://github.com/ruby/rbs#guides
4
+ end
data/theme.yml ADDED
@@ -0,0 +1,86 @@
1
+ # Setting your theme
2
+ use_theme: "sky"
3
+
4
+
5
+ # Theme basic settings
6
+ basic_node: &basic_node
7
+ fontname: "wqy-microhei"
8
+ shape: "box"
9
+ peripheries: 1
10
+ style: "rounded, filled"
11
+
12
+ # Theme list
13
+ lemon:
14
+ name: "柠檬黄主题"
15
+
16
+ # 说明
17
+ # color 非填充是边框色、填充就是节点背景色
18
+ # fontcolor 是文字颜色
19
+
20
+ # 画布属性
21
+ graph:
22
+ bgcolor: "#eff1f3" # 全局背景
23
+
24
+ # 节点
25
+ node_attrs: &lemon_node
26
+ <<: *basic_node
27
+ color: "#696773"
28
+ fontcolor: "#fcfcfc"
29
+
30
+ # 高亮节点
31
+ node_warn_attrs:
32
+ <<: *basic_node
33
+ fontcolor: "#ffffff"
34
+ color: "#f19b97"
35
+
36
+ # 边
37
+ edge_attrs:
38
+ color: "#696773"
39
+
40
+ # 子图容器
41
+ cluster:
42
+ style: "filled"
43
+ color: "#e3efd7"
44
+
45
+ # 子图节点
46
+ cluster_node:
47
+ color: "#f4b184"
48
+ fontcolor: "#ffffff"
49
+
50
+
51
+ sky:
52
+ name: "天真蓝主题"
53
+
54
+ # 说明
55
+ # color 非填充是边框色、填充就是节点背景色
56
+ # fontcolor 是文字颜色
57
+
58
+ # 画布背景
59
+ graph:
60
+ bgcolor: "#ffffff" # 全局背景
61
+
62
+ # 节点
63
+ node_attrs:
64
+ <<: *basic_node
65
+ color: "#deeaf6"
66
+ fontcolor: "#000000"
67
+
68
+ # 高亮节点
69
+ node_warn_attrs:
70
+ <<: *basic_node
71
+ fontcolor: "#000000"
72
+ color: "#ffda65"
73
+
74
+ # 边
75
+ edge_attrs:
76
+ color: "#021d57"
77
+
78
+ # 子图
79
+ cluster:
80
+ style: "filled"
81
+ color: "#deeaf6"
82
+
83
+ # 子图节点
84
+ cluster_node:
85
+ color: "#5a9ad7"
86
+ fontcolor: "#ffffff"
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "lib/vistual_call/version"
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "vistual_call"
7
+ spec.version = VistualCall::VERSION
8
+ spec.authors = ["Mark24"]
9
+ spec.email = ["mark.zhangyoung@qq.com"]
10
+
11
+ spec.summary = "Export vistual call graph"
12
+ spec.description = "Make export vistual call graph easy to use."
13
+ spec.homepage = "https://github.com/Mark24Code/vistual_call"
14
+ spec.required_ruby_version = ">= 2.6.0"
15
+
16
+ spec.metadata["homepage_uri"] = spec.homepage
17
+ spec.metadata[
18
+ "source_code_uri"
19
+ ] = "https://github.com/Mark24Code/vistual_call"
20
+ spec.metadata["changelog_uri"] = "https://github.com/Mark24Code/vistual_call"
21
+
22
+ # Specify which files should be added to the gem when it is released.
23
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
24
+ spec.files =
25
+ Dir.chdir(__dir__) do
26
+ `git ls-files -z`.split("\x0")
27
+ .reject do |f|
28
+ (File.expand_path(f) == __FILE__) ||
29
+ f.start_with?(
30
+ *%w[bin/ test/ spec/ features/ .git .circleci appveyor]
31
+ )
32
+ end
33
+ end
34
+ spec.bindir = "exe"
35
+ spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
36
+ spec.require_paths = ["lib"]
37
+ spec.licenses = ["MIT"]
38
+
39
+ # Uncomment to register a new dependency of your gem
40
+ # spec.add_dependency "example-gem", "~> 1.0"
41
+
42
+ # For more information and examples about making a new gem, check out our
43
+ # guide at: https://bundler.io/guides/creating_gem.html
44
+ end
metadata ADDED
@@ -0,0 +1,66 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: vistual_call
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Mark24
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2023-04-24 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: Make export vistual call graph easy to use.
14
+ email:
15
+ - mark.zhangyoung@qq.com
16
+ executables: []
17
+ extensions: []
18
+ extra_rdoc_files: []
19
+ files:
20
+ - ".DS_Store"
21
+ - Gemfile
22
+ - Gemfile.lock
23
+ - LICENSE.txt
24
+ - README.md
25
+ - Rakefile
26
+ - example/example.png
27
+ - example/sample.rb
28
+ - example/sinatra.png
29
+ - example/sinatra.rb
30
+ - lib/vistual_call.rb
31
+ - lib/vistual_call/graph.rb
32
+ - lib/vistual_call/method_call_tree.rb
33
+ - lib/vistual_call/method_node.rb
34
+ - lib/vistual_call/tracer.rb
35
+ - lib/vistual_call/version.rb
36
+ - read_yaml.rb
37
+ - sig/vistual_call.rbs
38
+ - theme.yml
39
+ - vistual_call.gemspec
40
+ homepage: https://github.com/Mark24Code/vistual_call
41
+ licenses:
42
+ - MIT
43
+ metadata:
44
+ homepage_uri: https://github.com/Mark24Code/vistual_call
45
+ source_code_uri: https://github.com/Mark24Code/vistual_call
46
+ changelog_uri: https://github.com/Mark24Code/vistual_call
47
+ post_install_message:
48
+ rdoc_options: []
49
+ require_paths:
50
+ - lib
51
+ required_ruby_version: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ version: 2.6.0
56
+ required_rubygems_version: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: '0'
61
+ requirements: []
62
+ rubygems_version: 3.4.12
63
+ signing_key:
64
+ specification_version: 4
65
+ summary: Export vistual call graph
66
+ test_files: []