Module: BareTest::IRBMode

Defined in:
lib/baretest/irb_mode.rb

Overview

For internal use only.

This module extends BareTest::Run if –interactive/-i is used

See BareTest::IRBMode::AssertionContext for some methods IRBMode adds to Assertion for use within the irb session.

Defined Under Namespace

Modules: IRBContext

Constant Summary collapse

RemoveGlobals =

:nodoc:

%w[
  $! $" $$ $& $' $* $+ $, $-0 $-F $-I $-K $-a $-d $-i $-l $-p $-v $-w $. $/
  $0 $: $; $< $= $> $? $@ $FS $NR $OFS $ORS $PID $RS $\\ $_ $` $~
  $ARGV $CHILD_STATUS $DEBUG $DEFAULT_INPUT $DEFAULT_OUTPUT $ERROR_INFO
  $ERROR_POSITION $FIELD_SEPARATOR $FILENAME $IGNORECASE $INPUT_LINE_NUMBER
  $INPUT_RECORD_SEPARATOR $KCODE $LAST_MATCH_INFO $LAST_PAREN_MATCH
  $LAST_READ_LINE $LOADED_FEATURES $LOAD_PATH $MATCH $OUTPUT_FIELD_SEPARATOR
  $OUTPUT_RECORD_SEPARATOR $POSTMATCH $PREMATCH $PROCESS_ID $PROGRAM_NAME
  $SAFE $VERBOSE $stderr $stdin $stdout
]

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.extended(by) ⇒ Object

Install the init handler



210
211
212
213
214
215
216
217
218
# File 'lib/baretest/irb_mode.rb', line 210

def self.extended(by) # :nodoc:
  by.init do
    require 'irb'
    require 'pp'
    require 'yaml'
    IRB.setup(nil) unless ::BareTest::IRBMode.irb_setup? # must only be called once
    ::BareTest::IRBMode.irb_setup!
  end
end

.irb_setup!Object

:nodoc:



40
41
42
# File 'lib/baretest/irb_mode.rb', line 40

def self.irb_setup! # :nodoc:
  @irb_setup = true
end

.irb_setup?Boolean

:nodoc:

Returns:

  • (Boolean)


44
45
46
# File 'lib/baretest/irb_mode.rb', line 44

def self.irb_setup? # :nodoc:
  @irb_setup
end

Instance Method Details

#insert_line_numbers(code, start_line = 1) ⇒ Object



288
289
290
291
292
# File 'lib/baretest/irb_mode.rb', line 288

def insert_line_numbers(code, start_line=1)
  digits       = Math.log10(start_line+code.count("\n")).floor+1
  current_line = start_line-1
  code.gsub(/^/) { sprintf '  %0*d  ', digits, current_line+=1 }
end

#irb_code_reindented(file, *slice) ⇒ Object

Nicely reformats the assertion’s code



278
279
280
281
282
283
284
285
286
# File 'lib/baretest/irb_mode.rb', line 278

def irb_code_reindented(file, *slice) # :nodoc:
  lines  = File.readlines(file)
  string = lines[*slice].join("").sub(/[\r\n]*\z/, '')
  string.gsub!(/^\t+/) { |m| "  "*m.size }
  indent = string[/^ +/]
  string.gsub!(/^#{indent}/, '  ')

  string
end

#irb_mode_for_assertion(assertion, status, with_setup, and_teardown) ⇒ Object

This method is highlevel hax, try to add necessary API to Test::Assertion Drop into an irb shell in the context of the assertion passed as an argument. Uses Assertion#clean_copy(AssertionContext) to create the context. Adds the code into irb’s history.



298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
# File 'lib/baretest/irb_mode.rb', line 298

def irb_mode_for_assertion(assertion, status, with_setup, and_teardown) # :nodoc:
  handlers        = @suite ? @suite.ancestors.inject({}) { |handlers, suite| handlers.merge(suite.verification_exception_handlers) } : nil
  context         = ::BareTest::Assertion::Context.new(assertion)
  context.extend IRBContext
  context.__status__ = status

  status          = assertion.execute_phase(:setup, context, with_setup.map { |s| [[s.value], s.block] }) if with_setup
  setup_failed    = status

  $stdout = StringIO.new # HAX - silencing 'irb: warn: can't alias help from irb_help.' - find a better way
  irb = IRB::Irb.new(IRB::WorkSpace.new(context))
  $stdout = STDOUT # /HAX
  # HAX - cargo cult, taken from irb.rb, not yet really understood.
  IRB.conf[:IRB_RC].call(irb.context) if IRB.conf[:IRB_RC] # loads the irbrc?
  IRB.conf[:MAIN_CONTEXT] = irb.context # why would the main context be set here?
  # /HAX

  trap("SIGINT") do irb.signal_handle end

  if code = assertion.code then
    #irb_context.code = code
    Readline::HISTORY.push(*code.split("\n")[1..-2])
  end

  catch(:IRB_EXIT) do irb.eval_input end

  teardown_status = assertion.execute_phase(:teardown, context, and_teardown.map { |t| [nil, t] }) unless (setup_failed || !and_teardown)
end

#run_test(assertion, with_setup) ⇒ Object

Formatter callback. Invoked once for every assertion. Gets the assertion to run as single argument.



223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
# File 'lib/baretest/irb_mode.rb', line 223

def run_test(assertion, with_setup)
  rv = super
  # drop into irb if assertion failed
  case rv.status
    when :failure
      start_irb_failure_mode(assertion, rv)
      irb_mode_for_assertion(assertion, rv, with_setup, assertion.suite.ancestry_teardown)
      stop_irb_mode
    when :error
      start_irb_error_mode(assertion, rv)
      irb_mode_for_assertion(assertion, rv, with_setup, assertion.suite.ancestry_teardown)
      stop_irb_mode
    # with other states, irb-mode is not started
  end

  rv
end

#start_irb_error_mode(assertion, status) ⇒ Object

Invoked when we have to drop into irb mode due to an error



259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
# File 'lib/baretest/irb_mode.rb', line 259

def start_irb_error_mode(assertion, status) # :nodoc:
  ancestry = assertion.suite.ancestors.reverse.map { |suite| suite.description }

  puts
  puts "#{status.status.to_s.capitalize} in:    #{ancestry[1..-1].join(' > ')}"
  puts "Description: #{assertion.description}"
  puts "Exception:   #{status.exception} in file #{status.exception.backtrace.first}"
  if assertion.file && match = status.exception.backtrace.first.match(/^([^:]+):(\d+)(?:$|:in .*)/) then
    file, line = match.captures
    file = File.expand_path(file)
    if assertion.file == file then
      code = irb_code_reindented(file, (assertion.line-1)..(line.to_i))
      assertion.code = code
      puts "Code (#{file}):", insert_line_numbers(code, assertion.line-1)
    end
  end
end

#start_irb_failure_mode(assertion, status) ⇒ Object

Invoked when we have to drop into irb mode due to a failure



242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
# File 'lib/baretest/irb_mode.rb', line 242

def start_irb_failure_mode(assertion, status) # :nodoc:
  ancestry = assertion.suite.ancestors.reverse.map { |suite| suite.description }

  puts
  puts "#{status.status.to_s.capitalize} in:  #{ancestry[1..-1].join(' > ')}"
  puts "Description: #{assertion.description}"
  if file = assertion.file then
    code  = irb_code_reindented(file, assertion.line-1,25)
    match = code.match(/\n^  [^ ]/)
    code[-(match.post_match.size-3)..-1] = "" if match
    code << "\n... (only showing first 25 lines)" unless match
    assertion.code = code
    puts "Code (#{file}):", insert_line_numbers(code, assertion.line-1)
  end
end

#stop_irb_modeObject

Invoked when we leave the irb session



328
329
330
# File 'lib/baretest/irb_mode.rb', line 328

def stop_irb_mode # :nodoc:
  puts
end