Class: Seams::CLI::Resolve
- Inherits:
-
Object
- Object
- Seams::CLI::Resolve
- Defined in:
- lib/seams/cli/resolve.rb
Overview
Implementation behind bin/seams resolve — gap-report 1.2 from
the 2026-05 framework feature-gap survey: the documented escape
hatch from seams' generators.
Three modes:
bin/seams resolve --eject <engine>/<file>
Marks a single host file as host-owned. The next regeneration
of the engine skips this file. The file already lives in the
host's working tree (seams generates "the code is in your
repo") — eject just prepends an explicit ownership header
and tells the engine generator to leave it alone.
bin/seams resolve --list-markers <engine>
Lists every `# seams:insertion-point ...` marker the engine
ships across all of its templated files. Helps the host
operator see which extension points are public contract
before writing a follow-up generator.
bin/seams resolve --list-ejected
Surveys engines/ for files marked with the eject header and
lists them. Useful for "what's diverged from the gem".
Returns true on success / false on failure. The caller (the
bin/seams shim) translates that into a non-zero exit code.
Several methods here legitimately return true/false to signal
success/failure but are command verbs (run_eject,
engine_present? is fine, fail_with etc). Rubocop's
PredicateMethod cop wants every bool-returning method renamed
with a trailing ?, but that's wrong for the run_* dispatchers
(they're imperative, not predicates). AbcSize / CyclomaticComplexity
likewise trigger on the run_* methods because CLI command
branches are inherently branchy. The cops are disabled at file
scope and the methods are kept linear and well-commented.
rubocop:disable Naming/PredicateMethod, Metrics/AbcSize, Metrics/CyclomaticComplexity
Constant Summary collapse
- DEFAULT_ENGINES_ROOT =
"engines"- EJECT_HEADER_PREFIX =
Header injected at the top of every ejected file. Position matters: future regenerations check the FIRST line of an existing destination file for this exact prefix.
"# seams:ejected from"- EJECT_HEADER_LINES =
lambda do |from| " \#{EJECT_HEADER_PREFIX} \#{from}\n # Re-running `bin/rails generate seams:\#{from.split(\".\").first}` will NOT overwrite this file.\n # To return to the gem version: delete this file and re-run the generator.\n HEADER\nend\n"
- INELIGIBLE_RELATIVE_PATTERNS =
Files at this list of relative paths under engines/
/ are NOT eject-eligible. See doc note in EjectAware module. [ %r{\Adb/migrate/}, # one-shot, host runs them %r{\Alib/[^/]+/engine\.rb\z}, # framework-managed boot file %r{\Alib/[^/]+/version\.rb\z}, # framework-managed version constant /\AGemfile\z/, # engine's own Gemfile %r{\A[^/]+\.gemspec\z}, # engine's gemspec /\ARakefile\z/ # engine's Rakefile (loads engine tasks) ].freeze
Instance Method Summary collapse
- #call ⇒ Object
-
#initialize(mode:, argument: nil, engines_root: DEFAULT_ENGINES_ROOT, output: $stdout, error: $stderr) ⇒ Resolve
constructor
A new instance of Resolve.
Constructor Details
#initialize(mode:, argument: nil, engines_root: DEFAULT_ENGINES_ROOT, output: $stdout, error: $stderr) ⇒ Resolve
Returns a new instance of Resolve.
73 74 75 76 77 78 79 |
# File 'lib/seams/cli/resolve.rb', line 73 def initialize(mode:, argument: nil, engines_root: DEFAULT_ENGINES_ROOT, output: $stdout, error: $stderr) @mode = mode @argument = argument @engines_root = engines_root @output = output @error = error end |
Instance Method Details
#call ⇒ Object
81 82 83 84 85 86 87 88 89 |
# File 'lib/seams/cli/resolve.rb', line 81 def call case @mode when :eject then run_eject when :list_markers then run_list_markers when :list_ejected then run_list_ejected else fail_with("unknown mode: #{@mode.inspect}") end end |