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
271 272 273 274 275 |
# File 'lib/tree_haver/backends/psych.rb', line 271 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.
261 262 263 |
# File 'lib/tree_haver/backends/psych.rb', line 261 def inner_node @inner_node end |
#source ⇒ String (readonly)
Returns The original source.
264 265 266 |
# File 'lib/tree_haver/backends/psych.rb', line 264 def source @source end |
Instance Method Details
#<=>(other) ⇒ Integer?
Comparison for sorting
462 463 464 465 466 467 |
# File 'lib/tree_haver/backends/psych.rb', line 462 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
543 544 545 |
# File 'lib/tree_haver/backends/psych.rb', line 543 def alias? @inner_node.is_a?(::Psych::Nodes::Alias) end |
#anchor ⇒ String?
Psych-specific: Get the anchor name for Alias/anchored nodes
501 502 503 |
# File 'lib/tree_haver/backends/psych.rb', line 501 def anchor @inner_node.anchor if @inner_node.respond_to?(:anchor) end |
#child(index) ⇒ Node?
Get child by index
342 343 344 |
# File 'lib/tree_haver/backends/psych.rb', line 342 def child(index) children[index] end |
#child_count ⇒ Integer
Get the number of children
334 335 336 |
# File 'lib/tree_haver/backends/psych.rb', line 334 def child_count children.size end |
#children ⇒ Array<Node>
Get child nodes
316 317 318 319 320 |
# File 'lib/tree_haver/backends/psych.rb', line 316 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
326 327 328 329 |
# File 'lib/tree_haver/backends/psych.rb', line 326 def each(&block) return to_enum(__method__) unless block children.each(&block) end |
#end_byte ⇒ Integer
Get end byte offset
362 363 364 365 366 367 368 |
# File 'lib/tree_haver/backends/psych.rb', line 362 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
401 402 403 404 |
# File 'lib/tree_haver/backends/psych.rb', line 401 def end_line row = end_point.row row + 1 end |
#end_point ⇒ Point
Get end point (row, column)
382 383 384 385 386 |
# File 'lib/tree_haver/backends/psych.rb', line 382 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
424 425 426 |
# File 'lib/tree_haver/backends/psych.rb', line 424 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.
445 446 447 |
# File 'lib/tree_haver/backends/psych.rb', line 445 def has_error? false end |
#inspect ⇒ String
Returns human-readable representation.
470 471 472 |
# File 'lib/tree_haver/backends/psych.rb', line 470 def inspect "#<TreeHaver::Backends::Psych::Node type=#{type} children=#{child_count}>" end |
#mapping? ⇒ Boolean
Psych-specific: Check if this is a mapping (hash)
522 523 524 |
# File 'lib/tree_haver/backends/psych.rb', line 522 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…
552 553 554 555 556 557 558 559 560 |
# File 'lib/tree_haver/backends/psych.rb', line 552 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.
454 455 456 |
# File 'lib/tree_haver/backends/psych.rb', line 454 def missing? false end |
#named? ⇒ Boolean Also known as: structural?
Check if this is a named (structural) node
All Psych nodes are structural.
433 434 435 |
# File 'lib/tree_haver/backends/psych.rb', line 433 def named? true end |
#next_sibling ⇒ void
This method returns an undefined value.
Get the next sibling
478 479 480 |
# File 'lib/tree_haver/backends/psych.rb', line 478 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
494 495 496 |
# File 'lib/tree_haver/backends/psych.rb', line 494 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
486 487 488 |
# File 'lib/tree_haver/backends/psych.rb', line 486 def prev_sibling raise NotImplementedError, "Psych backend does not support sibling navigation" end |
#scalar? ⇒ Boolean
Psych-specific: Check if this is a scalar (primitive)
536 537 538 |
# File 'lib/tree_haver/backends/psych.rb', line 536 def scalar? @inner_node.is_a?(::Psych::Nodes::Scalar) end |
#sequence? ⇒ Boolean
Psych-specific: Check if this is a sequence (array)
529 530 531 |
# File 'lib/tree_haver/backends/psych.rb', line 529 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.
412 413 414 415 416 417 418 419 |
# File 'lib/tree_haver/backends/psych.rb', line 412 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.
351 352 353 354 355 356 357 |
# File 'lib/tree_haver/backends/psych.rb', line 351 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.
393 394 395 396 |
# File 'lib/tree_haver/backends/psych.rb', line 393 def start_line row = start_point.row row + 1 end |
#start_point ⇒ Point
Get start point (row, column)
373 374 375 376 377 |
# File 'lib/tree_haver/backends/psych.rb', line 373 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
508 509 510 |
# File 'lib/tree_haver/backends/psych.rb', line 508 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.
301 302 303 304 305 306 307 308 309 310 311 |
# File 'lib/tree_haver/backends/psych.rb', line 301 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”
288 289 290 |
# File 'lib/tree_haver/backends/psych.rb', line 288 def type @inner_node.class.name.split("::").last.downcase end |
#value ⇒ String?
Psych-specific: Get the scalar value
515 516 517 |
# File 'lib/tree_haver/backends/psych.rb', line 515 def value @inner_node.value if @inner_node.respond_to?(:value) end |