diff options
| author | Paul Buetow <paul@buetow.org> | 2026-03-01 23:37:42 +0200 |
|---|---|---|
| committer | Paul Buetow <paul@buetow.org> | 2026-03-01 23:37:42 +0200 |
| commit | 211e3650387bd299bfcc6d21b7230323e45217c2 (patch) | |
| tree | fa0a8ba47074f3286a88db7256812ade3adf4dcf | |
| parent | 1ef38a857c895e5f970d219ba6802b2627801620 (diff) | |
refactor: defer Options parsing — add explicit Options.parse! method
Parsing ARGV at module eval time (during require) is fragile: it runs
before the application is ready, can pick up test-runner flags, and
bleeds stale values across repeated configure calls in tests.
Move the OptionParser setup and ARGV slicing into Options.parse!. The
module body now only sets safe defaults. parse! resets to defaults
before each parse so state cannot accumulate across calls.
Call Options.parse! once at the top of configure() in dsl.rb so all
entry points (scripts, Rake tasks) still receive parsed options without
any caller needing to know about the details.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
| -rw-r--r-- | lib/dsl.rb | 4 | ||||
| -rw-r--r-- | lib/options.rb | 47 |
2 files changed, 33 insertions, 18 deletions
@@ -71,6 +71,10 @@ module RCM end def configure(reset: false, &block) + # Parse ARGV each time configure is called so that scripts which call + # configure multiple times (or test suites that reset state) always + # start with a fresh, consistent option set. + RCM::Options.parse! RCM::DSL.new(reset) do |rcm| rcm.info('Configuring...') rcm.instance_eval(&block) diff --git a/lib/options.rb b/lib/options.rb index 6ce2479..41a6a50 100644 --- a/lib/options.rb +++ b/lib/options.rb @@ -4,30 +4,41 @@ module RCM # Command line options, supports both Rake mode (args after --) # and standalone mode (direct args). Unknown options are ignored # so that test runners and other tools can pass their own flags. + # + # Defaults are set at module load time. Call Options.parse! once at + # the application entry point to overlay them with actual ARGV values. + # Tests that never call parse! safely get the default values. module Options @@options = { debug: false, dry: false, hosts: [] } - parser = OptionParser.new do |opts| - opts.banner = 'Usage: rake [task] -- [options] OR ruby config.rb [options]' - opts.on('-v', '--[no-]debug', 'debug output') { |v| @@options[:debug] = v } - opts.on('-d', '--dry', 'dry mode') { |v| @@options[:dry] = v } - opts.on('--hosts HOSTS', 'comma-separated list of target hostnames') do |v| - @@options[:hosts] = v.split(',').map(&:strip) + # Parse ARGV and update @@options. Resets to defaults before each + # parse so stale values cannot accumulate across repeated calls + # (e.g. between test cases). + def self.parse! + @@options = { debug: false, dry: false, hosts: [] } + + parser = OptionParser.new do |opts| + opts.banner = 'Usage: rake [task] -- [options] OR ruby config.rb [options]' + opts.on('-v', '--[no-]debug', 'debug output') { |v| @@options[:debug] = v } + opts.on('-d', '--dry', 'dry mode') { |v| @@options[:dry] = v } + opts.on('--hosts HOSTS', 'comma-separated list of target hostnames') do |v| + @@options[:hosts] = v.split(',').map(&:strip) + end end - end - # Rake passes args after '--'; standalone scripts pass args directly. - args = if ARGV.include?('--') - ARGV.slice_before('--').to_a.last.drop(1) - else - ARGV.dup - end + # Rake passes args after '--'; standalone scripts pass args directly. + args = if ARGV.include?('--') + ARGV.slice_before('--').to_a.last.drop(1) + else + ARGV.dup + end - # Ignore unknown options (e.g. from test runners or other tools) - begin - parser.parse!(args) - rescue OptionParser::InvalidOption - retry + # Ignore unknown options (e.g. flags from test runners or rake itself). + begin + parser.parse!(args) + rescue OptionParser::InvalidOption + retry + end end def option(key) |
