class Node
Represents a node in the object graph with usage information.
Definitions
attr_accessor :object
Signature
-
attribute
Object The object this node represents.
attr_accessor :usage
Signature
-
attribute
Usage The memory usage of this object (not including children).
attr_accessor :parent
Signature
-
attribute
Node | Nil The parent node (nil for root).
attr_accessor :children
Signature
-
attribute
Hash(String, Node) | Nil Child nodes reachable from this object (hash of reference => node).
attr_accessor :reference
Signature
-
attribute
String | Nil The reference to the parent object (nil for root).
def add(child)
Add a child node to this node.
Signature
-
parameter
childNode The child node to add.
-
returns
self Returns self for chaining.
Implementation
def add(child)
@children ||= {}
# Use the reference as the key, or a fallback if not found:
key = child.reference || "(#{@children.size})"
@children[key] = child
return self
end
def total_usage
Compute total usage including all children.
Implementation
def total_usage
unless @total_usage
@total_usage = Usage.new(@usage.size, @usage.count)
@children&.each_value do |child|
child_total = child.total_usage
@total_usage.add!(child_total)
end
end
return @total_usage
end
def find_reference(child)
Find how this node references a child object.
Signature
-
parameter
childObject The child object to find.
-
returns
String | Nil A human-readable description of the reference, or nil if not found.
Implementation
def find_reference(child)
# Check instance variables:
@object.instance_variables.each do |ivar|
value = @object.instance_variable_get(ivar)
if value.equal?(child)
return ivar.to_s
end
end
# Check array elements:
if @object.is_a?(Array)
@object.each_with_index do |element, index|
if element.equal?(child)
return "[#{index}]"
end
end
end
# Check hash keys and values:
if @object.is_a?(Hash)
@object.each do |key, value|
if value.equal?(child)
return "[#{key.inspect}]"
end
if key.equal?(child)
return "(key: #{key.inspect})"
end
end
end
# Check struct members:
if @object.is_a?(Struct)
@object.each_pair do |member, value|
if value.equal?(child)
return ".#{member}"
end
end
end
# Could not determine the reference:
return nil
end
def path
Get the path string from root to this node (cached).
Signature
-
returns
String | Nil The formatted path string, or nil if no graph available.
Implementation
def path
unless @path
# Build object path from root to this node:
object_path = []
current = self
while current
object_path.unshift(current)
current = current.parent
end
# Format the path:
parts = ["#<#{object_path.first.object.class}:0x%016x>" % (object_path.first.object.object_id << 1)]
# Append each reference in the path:
(1...object_path.size).each do |i|
parent_node = object_path[i - 1]
child_node = object_path[i]
parts << (parent_node.find_reference(child_node.object) || "<??>")
end
@path = parts.join
end
return @path
end
def as_json(*)
Convert this node to a JSON-compatible hash.
Signature
-
parameter
optionsHash Options for JSON serialization.
-
returns
Hash A hash representation of this node.
Implementation
def as_json(*)
json = {
path: path,
object: {
class: @object.class.name,
object_id: @object.object_id
},
usage: @usage.as_json,
}
if @children&.any?
json[:total_usage] = total_usage.as_json
json[:children] = @children.transform_values(&:as_json)
end
return json
end
def to_json(...)
Convert this node to a JSON string.
Signature
-
parameter
optionsHash Options for JSON serialization.
-
returns
String A JSON string representation of this node.
Implementation
def to_json(...)
as_json.to_json(...)
end