Class: TreeHaver::Backends::Psych::Node
- Inherits:
-
Object
- Object
- TreeHaver::Backends::Psych::Node
- Includes:
- Comparable, Enumerable
- Defined in:
- lib/tree_haver/backends/psych.rb
Overview
Psych node wrapper
Wraps Psych::Nodes::* classes to provide TreeHaver::Node-compatible interface.
Psych node types:
-
Stream: Root container
-
Document: YAML document (multiple per stream possible)
-
Mapping: Hash/object
-
Sequence: Array/list
-
Scalar: Primitive value (string, number, boolean, null)
-
Alias: YAML anchor reference
Instance Attribute Summary collapse
-
#inner_node ⇒ ::Psych::Nodes::Node
readonly
The underlying Psych node.
-
#source ⇒ String
readonly
The original source.
Instance Method Summary collapse
-
#<=>(other) ⇒ Integer?
Comparison for sorting.
-
#alias? ⇒ Boolean
Psych-specific: Check if this is an alias.
-
#anchor ⇒ String?
Psych-specific: Get the anchor name for Alias/anchored nodes.
-
#child(index) ⇒ Node?
Get child by index.
-
#child_count ⇒ Integer
Get the number of children.
-
#children ⇒ Array<Node>
Get child nodes.
-
#each {|Node| ... } ⇒ Enumerator?
Iterate over child nodes.
-
#end_byte ⇒ Integer
Get end byte offset.
-
#end_line ⇒ Integer
Get the 1-based line number where this node ends.
-
#end_point ⇒ Point
Get end point (row, column).
-
#first_child ⇒ Node?
Get the first child node.
-
#has_error? ⇒ Boolean
Check if the node or any descendant has an error.
-
#initialize(node, source, lines = nil) ⇒ Node
constructor
Create a new node wrapper.
-
#inspect ⇒ String
Human-readable representation.
-
#mapping? ⇒ Boolean
Psych-specific: Check if this is a mapping (hash).
-
#mapping_entries ⇒ Array<Array(Node, Node)>
Psych-specific: Get mapping entries as key-value pairs.
-
#missing? ⇒ Boolean
Check if this is a missing node.
-
#named? ⇒ Boolean
(also: #structural?)
Check if this is a named (structural) node.
-
#next_sibling ⇒ void
Get the next sibling.
-
#parent ⇒ void
Get the parent node.
-
#prev_sibling ⇒ void
Get the previous sibling.
-
#scalar? ⇒ Boolean
Psych-specific: Check if this is a scalar (primitive).
-
#sequence? ⇒ Boolean
Psych-specific: Check if this is a sequence (array).
-
#source_position ⇒ Hash{Symbol => Integer}
Get position information as a hash.
-
#start_byte ⇒ Integer
Get start byte offset.
-
#start_line ⇒ Integer
Get the 1-based line number where this node starts.
-
#start_point ⇒ Point
Get start point (row, column).
-
#tag ⇒ String?
Psych-specific: Get the tag for tagged nodes.
-
#text ⇒ String
Get the text content of this node.
-
#type ⇒ String
(also: #kind)
Get the node type as a string.
-
#value ⇒ String?
Psych-specific: Get the scalar value.
Constructor Details
#initialize(node, source, lines = nil) ⇒ Node
Create a new node wrapper
247 248 249 250 251 |
# File 'lib/tree_haver/backends/psych.rb', line 247 def initialize(node, source, lines = nil) @inner_node = node @source = source @lines = lines || source.lines end |
Instance Attribute Details
#inner_node ⇒ ::Psych::Nodes::Node (readonly)
Returns The underlying Psych node.
237 238 239 |
# File 'lib/tree_haver/backends/psych.rb', line 237 def inner_node @inner_node end |
#source ⇒ String (readonly)
Returns The original source.
240 241 242 |
# File 'lib/tree_haver/backends/psych.rb', line 240 def source @source end |
Instance Method Details
#<=>(other) ⇒ Integer?
Comparison for sorting
438 439 440 441 442 443 |
# File 'lib/tree_haver/backends/psych.rb', line 438 def <=>(other) return unless other.respond_to?(:start_byte) cmp = start_byte <=> other.start_byte return cmp unless cmp&.zero? end_byte <=> other.end_byte end |
#alias? ⇒ Boolean
Psych-specific: Check if this is an alias
519 520 521 |
# File 'lib/tree_haver/backends/psych.rb', line 519 def alias? @inner_node.is_a?(::Psych::Nodes::Alias) end |
#anchor ⇒ String?
Psych-specific: Get the anchor name for Alias/anchored nodes
477 478 479 |
# File 'lib/tree_haver/backends/psych.rb', line 477 def anchor @inner_node.anchor if @inner_node.respond_to?(:anchor) end |
#child(index) ⇒ Node?
Get child by index
318 319 320 |
# File 'lib/tree_haver/backends/psych.rb', line 318 def child(index) children[index] end |
#child_count ⇒ Integer
Get the number of children
310 311 312 |
# File 'lib/tree_haver/backends/psych.rb', line 310 def child_count children.size end |
#children ⇒ Array<Node>
Get child nodes
292 293 294 295 296 |
# File 'lib/tree_haver/backends/psych.rb', line 292 def children return [] unless @inner_node.respond_to?(:children) && @inner_node.children @inner_node.children.map { |child| Node.new(child, @source, @lines) } end |
#each {|Node| ... } ⇒ Enumerator?
Iterate over child nodes
302 303 304 305 |
# File 'lib/tree_haver/backends/psych.rb', line 302 def each(&block) return to_enum(__method__) unless block children.each(&block) end |
#end_byte ⇒ Integer
Get end byte offset
338 339 340 341 342 343 344 |
# File 'lib/tree_haver/backends/psych.rb', line 338 def end_byte return start_byte + text.bytesize unless @inner_node.respond_to?(:end_line) line = @inner_node.end_line || 0 col = @inner_node.end_column || 0 calculate_byte_offset(line, col) end |
#end_line ⇒ Integer
Get the 1-based line number where this node ends
377 378 379 380 |
# File 'lib/tree_haver/backends/psych.rb', line 377 def end_line row = end_point.row row + 1 end |
#end_point ⇒ Point
Get end point (row, column)
358 359 360 361 362 |
# File 'lib/tree_haver/backends/psych.rb', line 358 def end_point row = (@inner_node.respond_to?(:end_line) ? @inner_node.end_line : 0) || 0 col = (@inner_node.respond_to?(:end_column) ? @inner_node.end_column : 0) || 0 Point.new(row, col) end |
#first_child ⇒ Node?
Get the first child node
400 401 402 |
# File 'lib/tree_haver/backends/psych.rb', line 400 def first_child children.first end |
#has_error? ⇒ Boolean
Check if the node or any descendant has an error
Psych raises on errors rather than embedding them.
421 422 423 |
# File 'lib/tree_haver/backends/psych.rb', line 421 def has_error? false end |
#inspect ⇒ String
Returns human-readable representation.
446 447 448 |
# File 'lib/tree_haver/backends/psych.rb', line 446 def inspect "#<TreeHaver::Backends::Psych::Node type=#{type} children=#{child_count}>" end |
#mapping? ⇒ Boolean
Psych-specific: Check if this is a mapping (hash)
498 499 500 |
# File 'lib/tree_haver/backends/psych.rb', line 498 def mapping? @inner_node.is_a?(::Psych::Nodes::Mapping) end |
#mapping_entries ⇒ Array<Array(Node, Node)>
Psych-specific: Get mapping entries as key-value pairs
For Mapping nodes, children alternate key, value, key, value…
528 529 530 531 532 533 534 535 536 |
# File 'lib/tree_haver/backends/psych.rb', line 528 def mapping_entries return [] unless mapping? pairs = [] children.each_slice(2) do |key, val| pairs << [key, val] if key && val end pairs end |
#missing? ⇒ Boolean
Check if this is a missing node
Psych doesn’t have missing nodes.
430 431 432 |
# File 'lib/tree_haver/backends/psych.rb', line 430 def missing? false end |
#named? ⇒ Boolean Also known as: structural?
Check if this is a named (structural) node
All Psych nodes are structural.
409 410 411 |
# File 'lib/tree_haver/backends/psych.rb', line 409 def named? true end |
#next_sibling ⇒ void
This method returns an undefined value.
Get the next sibling
454 455 456 |
# File 'lib/tree_haver/backends/psych.rb', line 454 def next_sibling raise NotImplementedError, "Psych backend does not support sibling navigation" end |
#parent ⇒ void
This method returns an undefined value.
Get the parent node
470 471 472 |
# File 'lib/tree_haver/backends/psych.rb', line 470 def parent raise NotImplementedError, "Psych backend does not support parent navigation" end |
#prev_sibling ⇒ void
This method returns an undefined value.
Get the previous sibling
462 463 464 |
# File 'lib/tree_haver/backends/psych.rb', line 462 def prev_sibling raise NotImplementedError, "Psych backend does not support sibling navigation" end |
#scalar? ⇒ Boolean
Psych-specific: Check if this is a scalar (primitive)
512 513 514 |
# File 'lib/tree_haver/backends/psych.rb', line 512 def scalar? @inner_node.is_a?(::Psych::Nodes::Scalar) end |
#sequence? ⇒ Boolean
Psych-specific: Check if this is a sequence (array)
505 506 507 |
# File 'lib/tree_haver/backends/psych.rb', line 505 def sequence? @inner_node.is_a?(::Psych::Nodes::Sequence) end |
#source_position ⇒ Hash{Symbol => Integer}
Get position information as a hash
Returns a hash with 1-based line numbers and 0-based columns. Compatible with *-merge gems’ FileAnalysisBase.
388 389 390 391 392 393 394 395 |
# File 'lib/tree_haver/backends/psych.rb', line 388 def source_position { start_line: start_line, end_line: end_line, start_column: start_point.column, end_column: end_point.column, } end |
#start_byte ⇒ Integer
Get start byte offset
Psych doesn’t provide byte offsets directly, so we calculate from line/column.
327 328 329 330 331 332 333 |
# File 'lib/tree_haver/backends/psych.rb', line 327 def start_byte return 0 unless @inner_node.respond_to?(:start_line) line = @inner_node.start_line || 0 col = @inner_node.start_column || 0 calculate_byte_offset(line, col) end |
#start_line ⇒ Integer
Get the 1-based line number where this node starts
Psych provides 0-based line numbers, so we add 1.
369 370 371 372 |
# File 'lib/tree_haver/backends/psych.rb', line 369 def start_line row = start_point.row row + 1 end |
#start_point ⇒ Point
Get start point (row, column)
349 350 351 352 353 |
# File 'lib/tree_haver/backends/psych.rb', line 349 def start_point row = (@inner_node.respond_to?(:start_line) ? @inner_node.start_line : 0) || 0 col = (@inner_node.respond_to?(:start_column) ? @inner_node.start_column : 0) || 0 Point.new(row, col) end |
#tag ⇒ String?
Psych-specific: Get the tag for tagged nodes
484 485 486 |
# File 'lib/tree_haver/backends/psych.rb', line 484 def tag @inner_node.tag if @inner_node.respond_to?(:tag) end |
#text ⇒ String
Get the text content of this node
For Scalar nodes, returns the value. For containers, returns the source text spanning the node’s location.
277 278 279 280 281 282 283 284 285 286 287 |
# File 'lib/tree_haver/backends/psych.rb', line 277 def text case @inner_node when ::Psych::Nodes::Scalar @inner_node.value.to_s when ::Psych::Nodes::Alias "*#{@inner_node.anchor}" else # For container nodes, extract from source using location extract_text_from_location end end |
#type ⇒ String Also known as: kind
Get the node type as a string
Maps Psych class names to lowercase type strings:
-
Psych::Nodes::Stream → “stream”
-
Psych::Nodes::Document → “document”
-
Psych::Nodes::Mapping → “mapping”
-
Psych::Nodes::Sequence → “sequence”
-
Psych::Nodes::Scalar → “scalar”
-
Psych::Nodes::Alias → “alias”
264 265 266 |
# File 'lib/tree_haver/backends/psych.rb', line 264 def type @inner_node.class.name.split("::").last.downcase end |
#value ⇒ String?
Psych-specific: Get the scalar value
491 492 493 |
# File 'lib/tree_haver/backends/psych.rb', line 491 def value @inner_node.value if @inner_node.respond_to?(:value) end |