Module: RSpecTracer::Configuration

Included in:
RSpecTracer
Defined in:
lib/rspec_tracer/configuration.rb

Overview

The user-facing configuration DSL. Mixed into ‘RSpecTracer` itself, so calls inside a `.rspec-tracer` (or `~/.rspec-tracer`) file appear against the top-level module:

The DSL methods are technically ‘private` in Ruby; the `configure` block uses Docile to expose them as if public. Calling them outside a `.rspec-tracer` file raises `InvalidUsageError`. The configuration loader allowlist enforces this gate (see ALLOWED_CONFIGURER).

See also:

rubocop:disable Metrics/ModuleLength

Examples:

A typical ‘.rspec-tracer`

RSpecTracer.configure do
  project_name 'My App'
  track_files 'config/locales/**/*.yml', 'db/schema.rb', 'Gemfile.lock'
  track_env   'AUTH_TOKEN', 'DATABASE_URL', 'RAILS_*'
  track_rails_defaults

  storage_backend :sqlite
  remote_cache_backend :s3, bucket: 'my-bucket', prefix: 'rspec-tracer'

  add_filter '/vendor/'
  add_coverage_filter %w[/spec/ /test/]
end

Defined Under Namespace

Modules: DslTypoSuggester Classes: InvalidUsageError

Constant Summary collapse

ALLOWED_CONFIGURER =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

Internal constant.

%w[
  lib/rspec_tracer/load_default_config.rb
  lib/rspec_tracer/load_global_config.rb
  lib/rspec_tracer/load_local_config.rb
].freeze
DEFAULT_CACHE_DIR =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

Internal constant.

'rspec_tracer_cache'
DEFAULT_COVERAGE_DIR =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

Internal constant.

'rspec_tracer_coverage'
DEFAULT_REPORT_DIR =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

Internal constant.

'rspec_tracer_report'
DEFAULT_LOCK_FILE =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

Internal constant.

'rspec_tracer.lock'
DEFAULT_STORAGE_BACKEND =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

Internal constant.

:json
STORAGE_BACKEND_NAMES =

:sqlite opt-in: MRI >= 3.2 only (sqlite3 2.x gem requirement). Kept closed so typos raise early.

%i[json sqlite].freeze
STORAGE_BACKEND_OPT_KEYS =

Keys allowed in ‘storage_backend`’s opts hash. ‘:serializer` is accepted only for the :json backend (see validate_storage_opts!).

%i[serializer].freeze
STORAGE_BACKEND_SERIALIZERS =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

Internal constant.

%i[json msgpack].freeze
DEFAULT_COVERAGE_MODES =

Default Ruby ‘Coverage` modes when the user has not called the `coverage_modes` DSL. Matches bare `Coverage.start` semantics so legacy configs continue to emit lines-only `coverage.json` shape.

%i[lines].freeze
COVERAGE_MODES =

Allowed Ruby ‘Coverage` modes accepted by the `coverage_modes` DSL. The set tracks Ruby 3.1+ `Coverage.start` keyword args. `coverage.json` ships the lines-only `Array<Integer|nil>` shape per file regardless — branches / methods / oneshot_lines / eval data is collected by Ruby but the user-facing artifact stays on the documented 1.x shape (see UPGRADING `#SimpleCov branch coverage now works` for SimpleCov interop).

%i[lines branches methods oneshot_lines eval].freeze
DEFAULT_CACHE_RETENTION_LOCAL_COUNT =

Per-save retention on the local cache’s run-id directories. 5 keeps enough history for rollback debugging without letting the cache grow unbounded (issue #20). 0 opts out entirely.

5
DEFAULT_CACHE_SIZE_WARN_PER_FILE_MB =

Size budgets (MiB). Warn at save time when any single cache file exceeds the per-file threshold or when the cache total exceeds the aggregate threshold. Surfaces dependency.json ballooning past the few-MB range while the user can still act on them. Set to 0 to disable either individually.

50
DEFAULT_CACHE_SIZE_WARN_TOTAL_MB =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

Internal constant.

500
LOG_LEVEL =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

Internal constant.

{
  off: 0,
  debug: 1,
  info: 2,
  warn: 3,
  error: 4
}.freeze

Instance Method Summary collapse

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(name, *args, **kwargs) ⇒ Object

Catches typos in ‘.rspec-tracer` config files. When the user mistypes a DSL name (e.g. `track_files_glob` for `track_files`), bare `NoMethodError` puts a Ruby backtrace in their face. This surface raises `InvalidUsageError` with a stdlib `DidYouMean` suggestion when the typo is close to a known DSL method; otherwise it falls through to NoMethodError so internal respond_to? probes / non-DSL undefined-method usage retains standard Ruby semantics.

Raises:



1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
# File 'lib/rspec_tracer/configuration.rb', line 1413

def method_missing(name, *args, **kwargs, &)
  return super if name.to_s.end_with?('=')

  candidates = RSpecTracer::Configuration::DslTypoSuggester.candidates
  suggestion = candidates.empty? ? nil : RSpecTracer::Configuration::DslTypoSuggester.nearest(name.to_s, candidates)
  return super if suggestion.nil?

  raise InvalidUsageError,
        "unknown .rspec-tracer DSL method #{name.inspect}; did you mean #{suggestion.inspect}?"
end

Instance Method Details

#configureObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Internal method on the tracer pipeline.

Raises:



117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
# File 'lib/rspec_tracer/configuration.rb', line 117

def configure(&)
  # Scan the full caller chain (not just the immediate two frames):
  # MRI / JRuby place the load_*_config.rb loader at depth 2, but
  # TruffleRuby's `load` interposes an extra runtime frame, pushing
  # the loader past the 2-frame window and tripping the InvalidUsage
  # raise. Path-suffix match against the well-known loader filenames
  # keeps the gate safe regardless of stack depth - user code would
  # have to copy one of those filenames verbatim into a path it
  # `load`s to get a false positive, which we treat as wilful.
  configurers = caller_locations(1).map(&:path)
  invalid = configurers.none? do |configurer|
    ALLOWED_CONFIGURER.any? do |allowed_configurer|
      configurer.end_with?(allowed_configurer)
    end
  end

  raise InvalidUsageError, 'You must define configurations in a .rspec-tracer file' if invalid

  RSpecTracer::Configuration.module_exec do
    RSpecTracer::Configuration.private_instance_methods(false).each do |method_name|
      alias_method :"_#{method_name}", method_name

      # Forward `**kwargs` too so DSL methods can accept Ruby 3+
      # keyword args (e.g. `track_rails_defaults except: [:views]`,
      # `storage_backend :json, serializer: :msgpack`). Earlier
      # forms of this wrapper forwarded `*args, &block` only and
      # silently stripped kwargs.
      define_method method_name do |*args, **kwargs, &block|
        send(:"_#{method_name}", *args, **kwargs, &block)
      end
    end
  end

  Docile.dsl_eval(self, &)
end

#respond_to_missing?(name, include_private = false) ⇒ Boolean

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Internal method on the tracer pipeline.

Returns:

  • (Boolean)


1426
1427
1428
# File 'lib/rspec_tracer/configuration.rb', line 1426

def respond_to_missing?(name, include_private = false)
  super
end