Class: Lutaml::Xsd::DependencyGrapher
- Inherits:
-
Object
- Object
- Lutaml::Xsd::DependencyGrapher
- Defined in:
- lib/lutaml/xsd/dependency_grapher.rb
Overview
Analyzes and graphs type dependencies in schema repositories Provides functionality to find what types a type depends on and what depends on it
Instance Attribute Summary collapse
-
#repository ⇒ Object
readonly
Returns the value of attribute repository.
Instance Method Summary collapse
-
#dependencies(qname, depth: 3) ⇒ Hash
Find all dependencies of a type (what it depends on).
-
#dependents(qname) ⇒ Hash
Find all dependents of a type (what depends on it).
-
#initialize(repository) ⇒ DependencyGrapher
constructor
A new instance of DependencyGrapher.
-
#to_dot(graph) ⇒ String
Generate DOT format (Graphviz).
-
#to_mermaid(graph) ⇒ String
Generate Mermaid diagram format.
-
#to_text(graph, direction: "both") ⇒ String
Generate text format.
Constructor Details
#initialize(repository) ⇒ DependencyGrapher
Returns a new instance of DependencyGrapher.
10 11 12 13 |
# File 'lib/lutaml/xsd/dependency_grapher.rb', line 10 def initialize(repository) @repository = repository @type_index = repository.instance_variable_get(:@type_index) end |
Instance Attribute Details
#repository ⇒ Object (readonly)
Returns the value of attribute repository.
8 9 10 |
# File 'lib/lutaml/xsd/dependency_grapher.rb', line 8 def repository @repository end |
Instance Method Details
#dependencies(qname, depth: 3) ⇒ Hash
Find all dependencies of a type (what it depends on)
19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
# File 'lib/lutaml/xsd/dependency_grapher.rb', line 19 def dependencies(qname, depth: 3) result = repository.find_type(qname) unless result.resolved? return { resolved: false, error: result., qname: qname, } end graph = { resolved: true, root: qname, namespace: result.namespace, type_category: result.definition.class.name.split("::").last, dependencies: {}, } visited = Set.new collect_dependencies(result.definition, graph[:dependencies], depth, 0, visited) graph end |
#dependents(qname) ⇒ Hash
Find all dependents of a type (what depends on it)
47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 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 |
# File 'lib/lutaml/xsd/dependency_grapher.rb', line 47 def dependents(qname) result = repository.find_type(qname) unless result.resolved? return { resolved: false, error: result., qname: qname, } end target_clark_key = build_clark_key(result.namespace, result.local_name) dependents_list = [] all_types = @type_index.all all_types.each do |clark_key, type_info| next if clark_key == target_clark_key definition = type_info[:definition] deps = extract_type_references(definition) # Check if this type references our target next unless deps.any? do |dep| matches_target?(dep, result.namespace, result.local_name) end dependents_list << { qname: build_qname(type_info[:namespace], type_info[:definition].name), namespace: type_info[:namespace], local_name: type_info[:definition].name, type_category: type_info[:type].to_s, schema_file: File.basename(type_info[:schema_file]), } end { resolved: true, target: qname, namespace: result.namespace, dependents: dependents_list, count: dependents_list.size, } end |
#to_dot(graph) ⇒ String
Generate DOT format (Graphviz)
131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 |
# File 'lib/lutaml/xsd/dependency_grapher.rb', line 131 def to_dot(graph) return "digraph {\n error [label=\"Error: #{graph[:error]}\"];\n}" unless graph[:resolved] lines = ["digraph dependencies {"] lines << " rankdir=LR;" lines << " node [shape=box, style=rounded];" lines << "" node_id = 0 node_map = {} # Create root node root_id = "n#{node_id}" node_map[graph[:root]] = root_id lines << " #{root_id} [label=\"#{escape_dot(graph[:root])}\", style=\"rounded,filled\", fillcolor=\"#e1f5ff\"];" node_id += 1 # Add dependencies graph[:dependencies].each do |dep_name, dep_info| dep_id = node_map[dep_name] || "n#{node_id}" node_map[dep_name] = dep_id node_id += 1 unless node_map[dep_name] lines << " #{dep_id} [label=\"#{escape_dot(dep_name)}\"];" lines << " #{root_id} -> #{dep_id};" # Add nested dependencies if dep_info[:dependencies] add_dot_dependencies(dep_info[:dependencies], dep_id, lines, node_map, node_id) end end lines << "}" lines.join("\n") end |
#to_mermaid(graph) ⇒ String
Generate Mermaid diagram format
95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 |
# File 'lib/lutaml/xsd/dependency_grapher.rb', line 95 def to_mermaid(graph) return "graph TD\n error[Error: #{graph[:error]}]" unless graph[:resolved] lines = ["graph TD"] node_id = 0 node_map = {} # Create root node root_id = "n#{node_id}" node_map[graph[:root]] = root_id lines << " #{root_id}[\"#{escape_mermaid(graph[:root])}\"]" lines << " style #{root_id} fill:#e1f5ff,stroke:#01579b,stroke-width:2px" node_id += 1 # Add dependencies graph[:dependencies].each do |dep_name, dep_info| dep_id = node_map[dep_name] || "n#{node_id}" node_map[dep_name] = dep_id node_id += 1 unless node_map[dep_name] lines << " #{dep_id}[\"#{escape_mermaid(dep_name)}\"]" lines << " #{root_id} --> #{dep_id}" # Add nested dependencies if dep_info[:dependencies] add_mermaid_dependencies(dep_info[:dependencies], dep_id, lines, node_map, node_id) end end lines.join("\n") end |
#to_text(graph, direction: "both") ⇒ String
Generate text format
172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 |
# File 'lib/lutaml/xsd/dependency_grapher.rb', line 172 def to_text(graph, direction: "both") return "Error: #{graph[:error]}" unless graph[:resolved] lines = [] lines << "Type: #{graph[:root]}" lines << "Namespace: #{graph[:namespace]}" lines << "Category: #{graph[:type_category]}" lines << "" if %w[both down].include?(direction) lines << "Dependencies (what this type depends on):" if graph[:dependencies].empty? lines << " (none)" else add_text_dependencies(graph[:dependencies], lines, " ") end end lines.join("\n") end |