Module: Rigor::ModuleGraph::Viewer::Html
- Defined in:
- lib/rigor/module_graph/viewer/html.rb
Constant Summary collapse
- TEMPLATE_DIR =
File.("../templates", __dir__)
- TEMPLATE_PATH =
File.join(TEMPLATE_DIR, "viewer.html.erb")
- CSS_PATH =
File.join(TEMPLATE_DIR, "viewer.css")
- VIEWER_JS_PATH =
File.join(TEMPLATE_DIR, "viewer.js")
- CYTOSCAPE_JS_PATH =
File.join(TEMPLATE_DIR, "vendor", "cytoscape.min.js")
- CONSTANT_KINDS =
Node kinds that map to top-level Cytoscape nodes. Method / attribute nodes are out of scope for the graph viewer (they belong to the class diagram, not the dependency graph).
%w[class module].freeze
Class Method Summary collapse
-
.build_data(edges:, nodes:, path_mode:, open_with:) ⇒ Object
Builds the ‘edges:, options:` payload the inline init JS reads from `<script type=“application/json” id=“rmg-data”>`.
- .fully_qualified(node) ⇒ Object
- .path_for(path, mode) ⇒ Object
-
.render(edges:, nodes:, title:, subtitle: nil, path_mode: :relative, open_with: nil) ⇒ String
Complete HTML document.
-
.safe_json(value) ⇒ Object
JSON embedded in ‘<script>` must not contain `</` (would break out of the surrounding tag).
Class Method Details
.build_data(edges:, nodes:, path_mode:, open_with:) ⇒ Object
Builds the ‘edges:, options:` payload the inline init JS reads from `<script type=“application/json” id=“rmg-data”>`.
62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 |
# File 'lib/rigor/module_graph/viewer/html.rb', line 62 def build_data(edges:, nodes:, path_mode:, open_with:) = {} nodes.each do |node| next unless CONSTANT_KINDS.include?(node.kind) key = fully_qualified(node) # First definition wins; class re-opens still resolve # to one Cytoscape node, matching the dedup contract # in `Edge#dedup_key`. [key] ||= { # Cytoscape resolves `edge.source` / `edge.target` # against `node.data.id`, so the constant name has # to be the id (not just a display field). id: key, name: key, kind: node.kind, path: path_for(node.path, path_mode), line: node.line } end # Every edge endpoint becomes a node, even when the # constant has no definition in the analysed paths # (e.g. `ApplicationRecord` from a Rails gem). These # get the `external` kind so the styling can dim them. edges.flat_map { |e| [e.from, e.to] }.uniq.each do |name| [name] ||= { id: name, name: name, kind: "external" } end { nodes: .values.map { |n| { data: n } }, edges: edges.each_with_index.map do |edge, i| { data: { id: "e#{i}", source: edge.from, target: edge.to, kind: edge.kind, confidence: edge.confidence } } end, options: { open_with: open_with&.to_s } } end |
.fully_qualified(node) ⇒ Object
108 109 110 111 |
# File 'lib/rigor/module_graph/viewer/html.rb', line 108 def fully_qualified(node) owner = node.owner owner && !owner.empty? ? "#{owner}::#{node.name}" : node.name end |
.path_for(path, mode) ⇒ Object
113 114 115 116 117 118 119 120 |
# File 'lib/rigor/module_graph/viewer/html.rb', line 113 def path_for(path, mode) return nil if path.nil? || mode == :none case mode when :absolute then File.(path) when :relative then path end end |
.render(edges:, nodes:, title:, subtitle: nil, path_mode: :relative, open_with: nil) ⇒ String
Returns complete HTML document.
43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
# File 'lib/rigor/module_graph/viewer/html.rb', line 43 def render(edges:, nodes:, title:, subtitle: nil, path_mode: :relative, open_with: nil) data = build_data( edges: edges, nodes: nodes, path_mode: path_mode, open_with: open_with ) template = ERB.new(File.read(TEMPLATE_PATH), trim_mode: "-") template.result_with_hash( title: title, subtitle: subtitle, data_json: safe_json(data), css: File.read(CSS_PATH), cytoscape: File.read(CYTOSCAPE_JS_PATH), viewer: File.read(VIEWER_JS_PATH) ) end |
.safe_json(value) ⇒ Object
JSON embedded in ‘<script>` must not contain `</` (would break out of the surrounding tag). `JSON.generate` does not escape it by default; rewriting the literal pair `</` → `</` is the standard safety pass.
126 127 128 |
# File 'lib/rigor/module_graph/viewer/html.rb', line 126 def safe_json(value) JSON.generate(value).gsub("</", "<\\/") end |