Module: RSpecTracer::CLI::SnapshotHelpers Private

Defined in:
lib/rspec_tracer/cli/snapshot_helpers.rb

Overview

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

Shared plumbing for the snapshot-reading sub-commands (Explain, BlastRadius): help-flag detection, backend-agnostic snapshot loading with uniform degradation messages, and String/Symbol- tolerant metadata lookups. Extracted so the two commands cannot drift apart on message wording or cache-shape tolerance.

Class Method Summary collapse

Class Method Details

.dig_meta(meta, *keys) ⇒ Object

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.

Look up a nested key from a Hash, tolerating both String and Symbol storage at each level. See fetch_meta for rationale.



90
91
92
93
94
95
96
# File 'lib/rspec_tracer/cli/snapshot_helpers.rb', line 90

def self.dig_meta(meta, *keys)
  keys.reduce(meta) do |acc, k|
    break nil if acc.nil? || !acc.is_a?(::Hash)

    acc[k] || acc[k.to_sym]
  end
end

.example_description(meta) ⇒ String?

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.

Returns the example's description, or nil when the meta is missing both description fields.

Parameters:

  • meta (Hash)

    one all_examples entry

Returns:

  • (String, nil)

    the example's description, or nil when the meta is missing both description fields



114
115
116
# File 'lib/rspec_tracer/cli/snapshot_helpers.rb', line 114

def self.example_description(meta)
  fetch_meta(meta, 'full_description', 'description')
end

.example_location(meta) ⇒ Array(Object, Object)

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.

The example's rerun location from persisted all_examples meta, preferring the rerun_* fields the reporter records.

Parameters:

  • meta (Hash)

    one all_examples entry

Returns:

  • (Array(Object, Object))

    [file, line]; either element may be nil when the meta is missing the field



104
105
106
107
108
109
# File 'lib/rspec_tracer/cli/snapshot_helpers.rb', line 104

def self.example_location(meta)
  [
    fetch_meta(meta, 'rerun_file_name', 'file_name'),
    fetch_meta(meta, 'rerun_line_number', 'line_number')
  ]
end

.fetch_meta(meta, *keys) ⇒ Object

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.

Look up a key from a Hash, tolerating both String and Symbol storage. Snapshot Hashes round-tripped through JSON yield String keys; the post-#182 msgpack serializer preserves Symbol keys end-to-end, so callers can't assume either shape.



77
78
79
80
81
82
83
84
85
86
# File 'lib/rspec_tracer/cli/snapshot_helpers.rb', line 77

def self.fetch_meta(meta, *keys)
  keys.each do |k|
    v = meta[k]
    return v unless v.nil?

    sym_value = meta[k.to_sym]
    return sym_value unless sym_value.nil?
  end
  nil
end

.filter_decisions_persisted?(backend) ⇒ 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.

Whether the backend persists the per-run filter decisions (filtered_examples / skipped_examples). JsonBackend does; SqliteBackend deliberately does not (its dispatch_read returns {} for those fields). Callers use this to attribute an empty decision set honestly: on a persisting backend it means "no decision was recorded for this id" (cold run, or the id was not part of the last run), NOT a backend limitation.

Parameters:

Returns:

  • (Boolean)


69
70
71
# File 'lib/rspec_tracer/cli/snapshot_helpers.rb', line 69

def self.filter_decisions_persisted?(backend)
  backend.is_a?(Storage::JsonBackend)
end

.help_requested?(args) ⇒ 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.

Returns true when the sub-command should print its help text instead of executing.

Parameters:

  • args (Array<String>)

    sub-command args (flags removed by the caller where applicable)

Returns:

  • (Boolean)

    true when the sub-command should print its help text instead of executing



23
24
25
# File 'lib/rspec_tracer/cli/snapshot_helpers.rb', line 23

def self.help_requested?(args)
  args.empty? || args.include?('-h') || args.include?('--help')
end

.load_snapshot(cache_path, command:, stderr:) ⇒ Array(Object, Object)?

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.

Resolve the persisted snapshot through the configured storage backend (Storage::Backend.build), so storage_backend :sqlite resolves the latest run from the meta table instead of the JsonBackend-only last_run.json.

Parameters:

  • cache_path (String)

    root cache directory

  • command (String)

    sub-command name used as the message prefix (e.g. explain, blast-radius)

  • stderr (IO)

Returns:

  • (Array(Object, Object), nil)

    [snapshot, backend] on success; nil (after printing a one-line explanation) when no run has been recorded yet or the cache schema is incompatible



40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
# File 'lib/rspec_tracer/cli/snapshot_helpers.rb', line 40

def self.load_snapshot(cache_path, command:, stderr:)
  backend = Storage::Backend.build(cache_path: cache_path, configuration: RSpecTracer)
  run_id = backend.last_run_id
  if run_id.nil? || run_id.to_s.empty?
    stderr.puts "#{command}: no cache yet at #{cache_path} -- run rspec first"
    return nil
  end

  snapshot = backend.load_graph(schema_version: Storage::Schema::CURRENT)
  if snapshot.nil?
    stderr.puts "#{command}: cache at #{cache_path} is incompatible with this rspec-tracer; " \
                'next rspec run is cold'
    return nil
  end

  [snapshot, backend]
end