Module: Backspin

Extended by:
RSpec::Mocks::ExampleMethods
Defined in:
lib/backspin/command.rb,
lib/backspin.rb,
lib/backspin/record.rb,
lib/backspin/command.rb,
lib/backspin/matcher.rb,
lib/backspin/version.rb,
lib/backspin/recorder.rb,
lib/backspin/command_diff.rb,
lib/backspin/configuration.rb,
lib/backspin/record_result.rb,
lib/backspin/command_result.rb

Overview

Define the Backspin::Capturer class for identification

Defined Under Namespace

Classes: Capturer, Command, CommandDiff, CommandResult, Configuration, Matcher, NoMoreRecordingsError, Record, RecordFormatError, RecordNotFoundError, RecordResult, Recorder, VerificationError

Constant Summary collapse

VERSION =
"0.7.1"

Class Method Summary collapse

Class Method Details

.capture(record_name, mode: :auto, matcher: nil, filter: nil, &block) ⇒ RecordResult

Captures all stdout/stderr output from a block

Parameters:

  • record_name (String)

    Name for the record file

  • mode (Symbol) (defaults to: :auto)

    Recording mode - :auto, :record, :verify, :playback

  • matcher (Proc, Hash) (defaults to: nil)

    Custom matcher for verification

  • filter (Proc) (defaults to: nil)

    Custom filter for recorded data

Returns:

Raises:

  • (ArgumentError)


158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
# File 'lib/backspin.rb', line 158

def capture(record_name, mode: :auto, matcher: nil, filter: nil, &block)
  raise ArgumentError, "record_name is required" if record_name.nil? || record_name.empty?
  raise ArgumentError, "block is required" unless block_given?

  record_path = Record.build_record_path(record_name)
  mode = determine_mode(mode, record_path)

  # Create or load the record based on mode
  record = if mode == :record
    Record.create(record_name)
  else
    Record.load_or_create(record_path)
  end

  # Create recorder with all needed context
  recorder = Recorder.new(record: record, mode: mode, matcher: matcher, filter: filter)

  # Execute the appropriate mode
  result = case mode
  when :record
    recorder.perform_capture_recording(&block)
  when :verify
    recorder.perform_capture_verification(&block)
  when :playback
    recorder.perform_capture_playback(&block)
  else
    raise ArgumentError, "Unknown mode: #{mode}"
  end

  # Check if we should raise on verification failure
  if configuration.raise_on_verification_failure && result.verified? == false
    error_message = "Backspin verification failed!\n"
    error_message += "Record: #{result.record.path}\n"
    error_message += result.error_message || "Output verification failed"

    # Include diff if available
    if result.diff
      error_message += "\n\nDiff:\n#{result.diff}"
    end

    raise VerificationError.new(error_message, result: result)
  end

  result
end

.configurationObject



47
48
49
50
51
# File 'lib/backspin.rb', line 47

def configuration
  return @configuration if @configuration

  @configuration = Configuration.new
end

.configure {|configuration| ... } ⇒ Object

Yields:



53
54
55
# File 'lib/backspin.rb', line 53

def configure
  yield(configuration)
end

.reset_configuration!Object



57
58
59
# File 'lib/backspin.rb', line 57

def reset_configuration!
  @configuration = Configuration.new
end

.run(record_name, mode: :auto, matcher: nil, filter: nil, &block) ⇒ RecordResult

Primary API - records on first run, verifies on subsequent runs

Parameters:

  • record_name (String)

    Name for the record file

  • mode (Symbol) (defaults to: :auto)

    Recording mode - :auto, :record, :verify, :playback

  • matcher (Proc, Hash) (defaults to: nil)

    Custom matcher for verification

    • Proc: ->(recorded, actual) { … } for full command matching

    • Hash: { stdout: ->(recorded, actual) { … }, stderr: ->(recorded, actual) { … } } for field-specific matching Only specified fields are checked - fields without matchers are ignored

    • Hash with :all key: { all: ->(recorded, actual) { … } } receives full command hashes Can be combined with field matchers - all specified matchers must pass

  • filter (Proc) (defaults to: nil)

    Custom filter for recorded data

Returns:

Raises:

  • (ArgumentError)


85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
# File 'lib/backspin.rb', line 85

def run(record_name, mode: :auto, matcher: nil, filter: nil, &block)
  raise ArgumentError, "record_name is required" if record_name.nil? || record_name.empty?
  raise ArgumentError, "block is required" unless block_given?

  record_path = Record.build_record_path(record_name)
  mode = determine_mode(mode, record_path)

  # Create or load the record based on mode
  record = if mode == :record
    Record.create(record_name)
  else
    Record.load_or_create(record_path)
  end

  # Create recorder with all needed context
  recorder = Recorder.new(record: record, mode: mode, matcher: matcher, filter: filter)

  # Execute the appropriate mode
  result = case mode
  when :record
    recorder.setup_recording_stubs(:capture3, :system)
    recorder.perform_recording(&block)
  when :verify
    recorder.perform_verification(&block)
  when :playback
    recorder.perform_playback(&block)
  else
    raise ArgumentError, "Unknown mode: #{mode}"
  end

  # Check if we should raise on verification failure
  if configuration.raise_on_verification_failure && result.verified? == false
    error_message = "Backspin verification failed!\n"
    error_message += "Record: #{result.record.path}\n"
    error_message += "\n#{result.error_message}" if result.error_message

    raise RSpec::Expectations::ExpectationNotMetError, error_message
  end

  result
end

.run!(record_name, mode: :auto, matcher: nil, filter: nil, &block) ⇒ RecordResult

Strict version of run that raises on verification failure

Parameters:

  • record_name (String)

    Name for the record file

  • mode (Symbol) (defaults to: :auto)

    Recording mode - :auto, :record, :verify, :playback

  • matcher (Proc, Hash) (defaults to: nil)

    Custom matcher for verification

  • filter (Proc) (defaults to: nil)

    Custom filter for recorded data

Returns:

Raises:

  • (RSpec::Expectations::ExpectationNotMetError)

    If verification fails



135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
# File 'lib/backspin.rb', line 135

def run!(record_name, mode: :auto, matcher: nil, filter: nil, &block)
  result = run(record_name, mode: mode, matcher: matcher, filter: filter, &block)

  if result.verified? == false
    error_message = "Backspin verification failed!\n"
    error_message += "Record: #{result.record.path}\n"

    # Use the error_message from the result which is now properly formatted
    error_message += "\n#{result.error_message}" if result.error_message

    raise RSpec::Expectations::ExpectationNotMetError, error_message
  end

  result
end

.scrub_text(text) ⇒ Object



61
62
63
64
65
66
67
68
69
70
71
# File 'lib/backspin.rb', line 61

def scrub_text(text)
  return text unless configuration.scrub_credentials && text

  scrubbed = text.dup
  configuration.credential_patterns.each do |pattern|
    scrubbed.gsub!(pattern) do |match|
      "*" * match.length
    end
  end
  scrubbed
end