Class: Psych::Merge::FileAnalysis
- Inherits:
-
Object
- Object
- Psych::Merge::FileAnalysis
- Includes:
- Ast::Merge::FileAnalyzable
- Defined in:
- lib/psych/merge/file_analysis.rb
Overview
Analyzes YAML file structure, extracting statements, comments, and freeze blocks.
This is the main analysis class that prepares YAML content for merging.
Constant Summary collapse
- DEFAULT_FREEZE_TOKEN =
Default freeze token for identifying freeze blocks
"psych-merge"
Instance Attribute Summary collapse
-
#ast ⇒ Psych::Nodes::Stream?
readonly
Parsed AST.
-
#comment_tracker ⇒ CommentTracker
readonly
Comment tracker for this file.
-
#errors ⇒ Array
readonly
Parse errors if any.
Instance Method Summary collapse
-
#fallthrough_node?(value) ⇒ Boolean
Override to detect Psych nodes for signature generator fallthrough.
-
#freeze_block_at(line_num) ⇒ FreezeNode?
Get the freeze block containing the given line.
-
#in_freeze_block?(line_num) ⇒ Boolean
Check if a line is within a freeze block.
-
#initialize(source, freeze_token: DEFAULT_FREEZE_TOKEN, signature_generator: nil, **options) ⇒ FileAnalysis
constructor
Initialize file analysis.
-
#root_mapping_entries ⇒ Array<Array(NodeWrapper, NodeWrapper)>
Get mapping entries from the root document.
-
#root_node ⇒ NodeWrapper?
Get the root node of the first document.
-
#valid? ⇒ Boolean
Check if parse was successful.
Constructor Details
#initialize(source, freeze_token: DEFAULT_FREEZE_TOKEN, signature_generator: nil, **options) ⇒ FileAnalysis
Initialize file analysis
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
# File 'lib/psych/merge/file_analysis.rb', line 34 def initialize(source, freeze_token: DEFAULT_FREEZE_TOKEN, signature_generator: nil, **) @source = source @lines = source.lines.map(&:chomp) @freeze_token = freeze_token @signature_generator = signature_generator @errors = [] # **options captures any additional parameters (e.g., node_typing) for forward compatibility # Initialize comment tracking @comment_tracker = CommentTracker.new(source) # Parse the YAML DebugLogger.time("FileAnalysis#parse_yaml") { parse_yaml } # Extract freeze blocks and integrate with nodes @freeze_blocks = extract_freeze_blocks @statements = integrate_nodes_and_freeze_blocks DebugLogger.debug("FileAnalysis initialized", { signature_generator: signature_generator ? "custom" : "default", statements_count: @statements.size, freeze_blocks: @freeze_blocks.size, valid: valid?, }) end |
Instance Attribute Details
#ast ⇒ Psych::Nodes::Stream? (readonly)
Returns Parsed AST.
23 24 25 |
# File 'lib/psych/merge/file_analysis.rb', line 23 def ast @ast end |
#comment_tracker ⇒ CommentTracker (readonly)
Returns Comment tracker for this file.
20 21 22 |
# File 'lib/psych/merge/file_analysis.rb', line 20 def comment_tracker @comment_tracker end |
#errors ⇒ Array (readonly)
Returns Parse errors if any.
26 27 28 |
# File 'lib/psych/merge/file_analysis.rb', line 26 def errors @errors end |
Instance Method Details
#fallthrough_node?(value) ⇒ Boolean
Override to detect Psych nodes for signature generator fallthrough
99 100 101 |
# File 'lib/psych/merge/file_analysis.rb', line 99 def fallthrough_node?(value) value.is_a?(NodeWrapper) || value.is_a?(Ast::Merge::FreezeNodeBase) || value.is_a?(MappingEntry) || super end |
#freeze_block_at(line_num) ⇒ FreezeNode?
Get the freeze block containing the given line.
NOTE: This method intentionally does NOT call super or use the base
freeze_blocks method. The base implementation derives freeze blocks from
statements.select { |n| n.is_a?(Freezable) }, but during initialization
@freeze_blocks is extracted BEFORE @statements is populated (see
integrate_nodes_and_freeze_blocks). This method is called during that
integration process, so we must use @freeze_blocks directly.
92 93 94 |
# File 'lib/psych/merge/file_analysis.rb', line 92 def freeze_block_at(line_num) @freeze_blocks.find { |fb| fb.location.cover?(line_num) } end |
#in_freeze_block?(line_num) ⇒ Boolean
Check if a line is within a freeze block.
NOTE: This method intentionally does NOT call super or use the base
freeze_blocks method. The base implementation derives freeze blocks from
statements.select { |n| n.is_a?(Freezable) }, but during initialization
@freeze_blocks is extracted BEFORE @statements is populated (see
integrate_nodes_and_freeze_blocks). This method is called during that
integration process, so we must use @freeze_blocks directly.
77 78 79 |
# File 'lib/psych/merge/file_analysis.rb', line 77 def in_freeze_block?(line_num) @freeze_blocks.any? { |fb| fb.location.cover?(line_num) } end |
#root_mapping_entries ⇒ Array<Array(NodeWrapper, NodeWrapper)>
Get mapping entries from the root document
105 106 107 108 109 110 111 112 113 114 115 116 |
# File 'lib/psych/merge/file_analysis.rb', line 105 def root_mapping_entries return [] unless valid? && @ast.children&.any? doc = @ast.children.first return [] unless doc.is_a?(::Psych::Nodes::Document) root = doc.children&.first return [] unless root.is_a?(::Psych::Nodes::Mapping) root_wrapper = NodeWrapper.new(root, lines: @lines) root_wrapper.mapping_entries(comment_tracker: @comment_tracker) end |
#root_node ⇒ NodeWrapper?
Get the root node of the first document
120 121 122 123 124 125 126 127 128 129 130 |
# File 'lib/psych/merge/file_analysis.rb', line 120 def root_node return unless valid? && @ast.children&.any? doc = @ast.children.first return unless doc.is_a?(::Psych::Nodes::Document) root = doc.children&.first return unless root NodeWrapper.new(root, lines: @lines) end |
#valid? ⇒ Boolean
Check if parse was successful
62 63 64 |
# File 'lib/psych/merge/file_analysis.rb', line 62 def valid? @errors.empty? && !@ast.nil? end |