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| <<~HEADER #{EJECT_HEADER_PREFIX} #{from} # Re-running `bin/rails generate seams:#{from.split(".").first}` will NOT overwrite this file. # To return to the gem version: delete this file and re-run the generator. HEADER end
- INELIGIBLE_RELATIVE_PATTERNS =
Files at this list of relative paths under engines/<engine>/ 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 |