summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2026-03-01 23:37:42 +0200
committerPaul Buetow <paul@buetow.org>2026-03-01 23:37:42 +0200
commit211e3650387bd299bfcc6d21b7230323e45217c2 (patch)
treefa0a8ba47074f3286a88db7256812ade3adf4dcf
parent1ef38a857c895e5f970d219ba6802b2627801620 (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.rb4
-rw-r--r--lib/options.rb47
2 files changed, 33 insertions, 18 deletions
diff --git a/lib/dsl.rb b/lib/dsl.rb
index d80c701..6185c98 100644
--- a/lib/dsl.rb
+++ b/lib/dsl.rb
@@ -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)