Class: Ast::Merge::Recipe::Config
- Defined in:
- lib/ast/merge/recipe/config.rb
Overview
Loads and represents a merge recipe from YAML configuration.
A recipe extends Preset with:
- Optional template file specification
- Optional target file patterns
- Injection point configuration
- when_missing behavior
File-oriented recipes provide a template path and targets for on-disk execution via Runner#run. Content-oriented recipes may omit both and be executed in memory via Runner#run_content.
Instance Attribute Summary collapse
-
#injection ⇒ Hash
readonly
Injection point / partial target configuration.
-
#steps ⇒ Array<Hash>
readonly
Normalized execution steps.
-
#targets ⇒ Array<String>
readonly
Glob patterns for target files.
-
#template_path ⇒ String?
readonly
Path to template file (relative to recipe or absolute).
-
#when_missing ⇒ Symbol
readonly
Behavior when the partial target is not found (:skip, :append, :prepend, :add).
Attributes inherited from Preset
#description, #freeze_token, #merge_config, #name, #parser, #parser_explicit, #preset_path
Class Method Summary collapse
-
.load(path) ⇒ Config
Load a recipe from a YAML file.
Instance Method Summary collapse
-
#content_recipe? ⇒ Boolean
Whether this recipe expects caller-provided content.
-
#execution_steps ⇒ Array<Hash>
Explicit steps or a synthesized legacy-compatible step.
-
#expand_targets(base_dir: nil) ⇒ Array<String>
Expand target globs to actual file paths.
-
#explicit_steps? ⇒ Boolean
Whether this recipe uses explicit step execution.
-
#file_recipe? ⇒ Boolean
Whether this recipe can be executed against files on disk.
-
#finder_query ⇒ Hash
Build an InjectionPointFinder query from the injection config.
-
#initialize(config, preset_path: nil, recipe_path: nil) ⇒ Config
constructor
Create a recipe from a hash (parsed YAML or programmatic).
- #key_path_partial_target? ⇒ Boolean
- #navigable_partial_target? ⇒ Boolean
-
#partial_target ⇒ Hash?
Get the normalized partial-target contract for this recipe.
-
#partial_target_kind ⇒ Symbol?
The normalized target selector kind.
-
#recipe_path ⇒ Object
Alias for compatibility - recipe_path points to the same file as preset_path.
-
#replace_mode? ⇒ Boolean
Whether to use replace mode (template replaces section entirely).
-
#template_absolute_path(base_dir: nil) ⇒ String
Get the absolute path to the template file.
Methods inherited from Preset
#add_missing, #add_missing?, #match_refiner, #node_typing, #normalize_whitespace, #parser_explicit?, #preference, #rehydrate_link_references, #script_loader, #signature_generator, #to_h
Constructor Details
#initialize(config, preset_path: nil, recipe_path: nil) ⇒ Config
Create a recipe from a hash (parsed YAML or programmatic).
94 95 96 97 98 99 100 101 102 103 104 105 |
# File 'lib/ast/merge/recipe/config.rb', line 94 def initialize(config, preset_path: nil, recipe_path: nil) # Support both preset_path and recipe_path for backward compatibility effective_path = preset_path || recipe_path super(config, preset_path: effective_path) @template_path = config['template'] @targets = Array(config.fetch('targets', default_targets_for(@template_path))) @when_missing = (config['when_missing'] || 'skip').to_sym validate_top_level_step_contract!(config) @injection = parse_injection(config['injection'] || {}) @steps = parse_steps(config['steps']) end |
Instance Attribute Details
#injection ⇒ Hash (readonly)
Returns Injection point / partial target configuration.
62 63 64 |
# File 'lib/ast/merge/recipe/config.rb', line 62 def injection @injection end |
#steps ⇒ Array<Hash> (readonly)
Returns Normalized execution steps.
68 69 70 |
# File 'lib/ast/merge/recipe/config.rb', line 68 def steps @steps end |
#targets ⇒ Array<String> (readonly)
Returns Glob patterns for target files.
59 60 61 |
# File 'lib/ast/merge/recipe/config.rb', line 59 def targets @targets end |
#template_path ⇒ String? (readonly)
Returns Path to template file (relative to recipe or absolute).
56 57 58 |
# File 'lib/ast/merge/recipe/config.rb', line 56 def template_path @template_path end |
#when_missing ⇒ Symbol (readonly)
Returns Behavior when the partial target is not found (:skip, :append, :prepend, :add).
65 66 67 |
# File 'lib/ast/merge/recipe/config.rb', line 65 def when_missing @when_missing end |
Class Method Details
.load(path) ⇒ Config
Load a recipe from a YAML file.
81 82 83 84 85 86 |
# File 'lib/ast/merge/recipe/config.rb', line 81 def load(path) raise ArgumentError, "Recipe file not found: #{path}" unless File.exist?(path) yaml = YAML.safe_load_file(path, permitted_classes: [Regexp, Symbol]) new(yaml, preset_path: path) end |
Instance Method Details
#content_recipe? ⇒ Boolean
Returns Whether this recipe expects caller-provided content.
234 235 236 |
# File 'lib/ast/merge/recipe/config.rb', line 234 def content_recipe? !file_recipe? end |
#execution_steps ⇒ Array<Hash>
Returns Explicit steps or a synthesized legacy-compatible step.
215 216 217 218 219 |
# File 'lib/ast/merge/recipe/config.rb', line 215 def execution_steps return steps unless steps.empty? [legacy_implicit_step] end |
#expand_targets(base_dir: nil) ⇒ Array<String>
Expand target globs to actual file paths.
123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 |
# File 'lib/ast/merge/recipe/config.rb', line 123 def (base_dir: nil) return [] if targets.empty? base = base_dir || (preset_path ? File.dirname(preset_path) : Dir.pwd) targets.flat_map do |pattern| if File.absolute_path?(pattern) Dir.glob(pattern) else # Expand and normalize to remove .. segments = File.(pattern, base) Dir.glob() end end.uniq.sort end |
#explicit_steps? ⇒ Boolean
Returns Whether this recipe uses explicit step execution.
210 211 212 |
# File 'lib/ast/merge/recipe/config.rb', line 210 def explicit_steps? !@steps.empty? end |
#file_recipe? ⇒ Boolean
Returns Whether this recipe can be executed against files on disk.
229 230 231 |
# File 'lib/ast/merge/recipe/config.rb', line 229 def file_recipe? !template_path.nil? end |
#finder_query ⇒ Hash
Build an InjectionPointFinder query from the injection config.
142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 |
# File 'lib/ast/merge/recipe/config.rb', line 142 def finder_query return {} unless navigable_partial_target? anchor = injection[:anchor] || {} boundary = injection[:boundary] || {} query = { type: anchor[:type], text: anchor[:text], position: injection[:position] || :replace, boundary_type: boundary[:type], boundary_text: boundary[:text] } # Support tree-depth based boundary detection # same_or_shallower: true means "end at next sibling (same tree level or above)" query[:boundary_same_or_shallower] = true if boundary[:same_or_shallower] query.compact end |
#key_path_partial_target? ⇒ Boolean
205 206 207 |
# File 'lib/ast/merge/recipe/config.rb', line 205 def key_path_partial_target? partial_target_kind == :key_path end |
#navigable_partial_target? ⇒ Boolean
200 201 202 |
# File 'lib/ast/merge/recipe/config.rb', line 200 def navigable_partial_target? partial_target_kind == :navigable end |
#partial_target ⇒ Hash?
Get the normalized partial-target contract for this recipe.
This is the shared shape used by the stock runner to dispatch between parser families without baking parser-specific YAML parsing logic into the runner itself.
170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 |
# File 'lib/ast/merge/recipe/config.rb', line 170 def partial_target return if explicit_steps? case partial_target_kind when :navigable { kind: :navigable, anchor: injection[:anchor], position: injection[:position] || :replace, boundary: injection[:boundary] }.compact when :key_path { kind: :key_path, key_path: injection[:key_path] } end end |
#partial_target_kind ⇒ Symbol?
Returns The normalized target selector kind.
190 191 192 193 194 195 196 197 |
# File 'lib/ast/merge/recipe/config.rb', line 190 def partial_target_kind return if explicit_steps? return :key_path if injection[:key_path] return :navigable if injection[:anchor] nil end |
#recipe_path ⇒ Object
Alias for compatibility - recipe_path points to the same file as preset_path
71 72 73 |
# File 'lib/ast/merge/recipe/config.rb', line 71 def recipe_path preset_path end |
#replace_mode? ⇒ Boolean
Whether to use replace mode (template replaces section entirely).
224 225 226 |
# File 'lib/ast/merge/recipe/config.rb', line 224 def replace_mode? merge_config[:replace_mode] == true end |
#template_absolute_path(base_dir: nil) ⇒ String
Get the absolute path to the template file.
111 112 113 114 115 116 117 |
# File 'lib/ast/merge/recipe/config.rb', line 111 def template_absolute_path(base_dir: nil) return if @template_path.nil? return @template_path if File.absolute_path?(@template_path) base = base_dir || (preset_path ? File.dirname(preset_path) : Dir.pwd) File.(@template_path, base) end |