Class: QED::Reporter::Abstract

Inherits:
Object
  • Object
show all
Defined in:
lib/qed/reporter/abstract.rb

Overview

Reporter Absract Base Class

Serves as the base class for all other output formats.

Direct Known Subclasses

Dot, Html, Linear, TapY, Verbatim

Constant Summary collapse

INFO_SIGNAL =

Does the system support INFO signal?

Signal.list['INFO']
INTERNALS =

TODO: Use global standard for backtrace exclusions.

/(lib|bin)[\\\/](qed|ae)/
DEFAULT_TRACE_COUNT =

Default trace count. This is the number of backtrace lines that will be provided on errors and failed assertions, unless otherwise overridden with ENV.

3

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(options = {}) ⇒ Abstract

TODO: pass session into initialize


31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
# File 'lib/qed/reporter/abstract.rb', line 31

def initialize(options={})
  @io    = options[:io] || STDOUT
  @trace = options[:trace]

  @record = {
    :demo  => [],
    :step  => [],
    :omit  => [],
    :pass  => [],
    :fail  => [],
    :error => []
  }

  #@demos = 0
  #@steps = 0
  #@omit  = []
  #@pass  = []
  #@fail  = []
  #@error = []

  @source = {}
end

Instance Attribute Details

#ioObject (readonly)

Returns the value of attribute io


25
26
27
# File 'lib/qed/reporter/abstract.rb', line 25

def io
  @io
end

#recordObject (readonly)

Returns the value of attribute record


28
29
30
# File 'lib/qed/reporter/abstract.rb', line 28

def record
  @record
end

#sessionObject (readonly)

Returns the value of attribute session


22
23
24
# File 'lib/qed/reporter/abstract.rb', line 22

def session
  @session
end

Class Method Details

.After(type, &block) ⇒ Object


89
90
91
92
93
# File 'lib/qed/reporter/abstract.rb', line 89

def self.After(type, &block)
#  raise ArgumentError unless %w{session demo demonstration step pass fail error}.include?(type.to_s)
#  type = :demonstration if type.to_s == 'demo'
  define_method("after_#{type}", &block)
end

.Before(type, &block) ⇒ Object


83
84
85
86
87
# File 'lib/qed/reporter/abstract.rb', line 83

def self.Before(type, &block)
#  raise ArgumentError unless %w{session demo demonstration step}.include?(type.to_s)
#  type = :demonstration if type.to_s == 'demo'
  define_method("before_#{type}", &block)
end

.When(type, &block) ⇒ Object


77
78
79
80
81
# File 'lib/qed/reporter/abstract.rb', line 77

def self.When(type, &block)
  #raise ArgumentError unless %w{session demo demonstration step}.include?(type.to_s)
  #type = :demonstration if type.to_s == 'demo'
  define_method(type, &block)
end

Instance Method Details

#after_demo(demo) ⇒ Object

End of a demonstration.


225
226
# File 'lib/qed/reporter/abstract.rb', line 225

def after_demo(demo)  #demo(demo)
end

#after_eval(step) ⇒ Object


213
214
# File 'lib/qed/reporter/abstract.rb', line 213

def after_eval(step)
end

#after_import(file) ⇒ Object


209
210
# File 'lib/qed/reporter/abstract.rb', line 209

def after_import(file)
end

#after_proc(step) ⇒ Object


217
218
# File 'lib/qed/reporter/abstract.rb', line 217

def after_proc(step)
end

#after_session(session) ⇒ Object

After running all demonstrations. This is the place to output a summary of the session, if applicable.


230
231
# File 'lib/qed/reporter/abstract.rb', line 230

def after_session(session)
end

#after_step(step) ⇒ Object


221
222
# File 'lib/qed/reporter/abstract.rb', line 221

def after_step(step)
end

#before_demo(demo) ⇒ Object

Beginning of a demonstration.


139
140
141
# File 'lib/qed/reporter/abstract.rb', line 139

def before_demo(demo) #demo(demo)
  #demos << demo
end

#before_eval(step) ⇒ Object


156
157
# File 'lib/qed/reporter/abstract.rb', line 156

def before_eval(step)
end

#before_import(file) ⇒ Object


144
145
# File 'lib/qed/reporter/abstract.rb', line 144

def before_import(file)
end

#before_proc(step) ⇒ Object


152
153
# File 'lib/qed/reporter/abstract.rb', line 152

def before_proc(step)
end

#before_session(session) ⇒ Object

At the start of a session, before running any demonstrations.


133
134
135
136
# File 'lib/qed/reporter/abstract.rb', line 133

def before_session(session)
  @session    = session
  @start_time = Time.now
end

#before_step(step) ⇒ Object


148
149
# File 'lib/qed/reporter/abstract.rb', line 148

def before_step(step)
end

#call(type, *args) ⇒ Object


72
73
74
75
# File 'lib/qed/reporter/abstract.rb', line 72

def call(type, *args)
  __send__("count_#{type}", *args) if respond_to?("count_#{type}")
  __send__(type, *args) if respond_to?(type)
end

#clean_backtrace(*btrace) ⇒ Object (private)


274
275
276
277
278
279
280
281
282
283
# File 'lib/qed/reporter/abstract.rb', line 274

def clean_backtrace(*btrace)
  stack = if $DEBUG
            btrace
          else
            btrace.reject{ |bt| bt =~ INTERNALS }
          end
  stack.map do |bt|
    bt.chomp(":in \`__binding__'")
  end
end

#code_snippet(exception, radius = 2) ⇒ String (private)

Produce a pretty code snippet given an exception.


308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
# File 'lib/qed/reporter/abstract.rb', line 308

def code_snippet(exception, radius=2)
  radius = radius.to_i

  file, lineno = file_and_line(exception)

  return nil if file.empty?
  return nil if file == '(eval)'

  source = source(file)
  
  region = [lineno - radius, 1].max ..
           [lineno + radius, source.length].min

  # ensure proper alignment by zero-padding line numbers
  format = " %2s %0#{region.last.to_s.length}d %s"

  pretty = region.map do |n|
    format % [('=>' if n == lineno), n, source[n-1].chomp]
  end #.unshift "[#{region.inspect}] in #{source_file}"

  pretty
end

#count_demo(demo) ⇒ Object

def After(type, target, *args)

type = :demonstration if type.to_s == 'demo'
__send__("after_#{type}", target, *args)

end


107
108
109
# File 'lib/qed/reporter/abstract.rb', line 107

def count_demo(demo)
  @record[:demo] << demo
end

#count_error(step, exception) ⇒ Object


127
128
129
# File 'lib/qed/reporter/abstract.rb', line 127

def count_error(step, exception)
  @record[:error] << [step, exception]
end

#count_fail(step, exception) ⇒ Object


123
124
125
# File 'lib/qed/reporter/abstract.rb', line 123

def count_fail(step, exception)
  @record[:fail] << [step, exception]
end

#count_pass(step) ⇒ Object

def count_eval(step)

@record[:eval] << step

end


119
120
121
# File 'lib/qed/reporter/abstract.rb', line 119

def count_pass(step)
  @record[:pass] << step
end

#count_step(step) ⇒ Object


111
112
113
# File 'lib/qed/reporter/abstract.rb', line 111

def count_step(step)
  @record[:step] << step
end

#demo(demo) ⇒ Object

Reight before demo.


165
166
# File 'lib/qed/reporter/abstract.rb', line 165

def demo(demo)
end

#demosObject


54
# File 'lib/qed/reporter/abstract.rb', line 54

def demos  ; @record[:demo]  ; end

#error(step, exception) ⇒ Object

After running a step that raised an error.


203
204
205
206
# File 'lib/qed/reporter/abstract.rb', line 203

def error(step, exception)
  raise exception if $DEBUG  # TODO: do we really want to do it like this?
  ## @error << [step, exception]
end

#errorsObject


58
# File 'lib/qed/reporter/abstract.rb', line 58

def errors ; @record[:error] ; end

#eval(step) ⇒ Object

Right before evaluation.


185
186
# File 'lib/qed/reporter/abstract.rb', line 185

def eval(step)
end

#fail(step, assertion) ⇒ Object

After running a step that failed.


198
199
200
# File 'lib/qed/reporter/abstract.rb', line 198

def fail(step, assertion)
  ## @fail << [step, assertion]
end

#failsObject


59
# File 'lib/qed/reporter/abstract.rb', line 59

def fails  ; @record[:fail]  ; end

#file_and_line(exception) ⇒ Object (private)

– TODO: Show more of the file name than just the basename. ++


379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
# File 'lib/qed/reporter/abstract.rb', line 379

def file_and_line(exception)
  backtrace = case exception
              when Exception
                exception.backtrace.reject{ |bt| bt =~ INTERNALS }.first
              when Array
                exception.first
              else
                exception
              end

  backtrace =~ /(.+?):(\d+(?=:|\z))/ or return ""

  file, lineno = $1, $2.to_i

  return file, lineno

  #i = backtrace.rindex(':in')
  #line = i ? line[0...i] : line
  #relative_file(line)
end

#file_line(exception) ⇒ Object (private)

Same as file_and_line, exception return file path is relative.


401
402
403
404
# File 'lib/qed/reporter/abstract.rb', line 401

def file_line(exception)
  file, lineno = file_and_line(exception)
  return relative_file(file), lineno
end

#get_tallyObject (private)


251
252
253
254
255
256
257
258
259
# File 'lib/qed/reporter/abstract.rb', line 251

def get_tally
  assert_count = $ASSERTION_COUNTS[:total]
  assert_fails = $ASSERTION_COUNTS[:fail]
  assert_delta = assert_count - assert_fails

  vars = [demos.size, steps.size, fails.size, errors.size, assert_delta, assert_count] #, @pass.size ]

  vars 
end

#import(file) ⇒ Object

Right before import.


169
170
# File 'lib/qed/reporter/abstract.rb', line 169

def import(file)
end

#localize_file(file) ⇒ Object (private)


441
442
443
444
445
446
447
448
449
# File 'lib/qed/reporter/abstract.rb', line 441

def localize_file(file)
  j = 0
  [file.to_s.size, Dir.pwd.size].max.times do |i|
    if Dir.pwd[i,1] != file[i,1]
      break j = i
    end
  end
  file[j..-1]
end

#omitsObject


56
# File 'lib/qed/reporter/abstract.rb', line 56

def omits  ; @record[:omit]  ; end

#pass(step) ⇒ Object

After running a step that passed.


193
194
195
# File 'lib/qed/reporter/abstract.rb', line 193

def pass(step)
  #@pass << step
end

#passesObject


57
# File 'lib/qed/reporter/abstract.rb', line 57

def passes ; @record[:pass]  ; end

239
240
241
242
243
244
245
246
247
248
# File 'lib/qed/reporter/abstract.rb', line 239

def print_tally  #assert_count = AE::Assertor.counts[:total]
  #assert_fails = AE::Assertor.counts[:fail]
  #assert_delta = assert_count - assert_fails


  mask = "%s demos, %s steps: %s failures, %s errors (%s/%s assertions)"  #vars = [demos.size, steps.size, fails.size, errors.size, assert_delta, assert_count] #, @pass.size ]


  io.puts mask % get_tally
end

235
236
237
# File 'lib/qed/reporter/abstract.rb', line 235

def print_time
  io.puts "\nFinished in %.5f seconds.\n\n" % [Time.now - @start_time]
end

#proc(step) ⇒ Object

Right before evaluation.


181
182
# File 'lib/qed/reporter/abstract.rb', line 181

def proc(step)
end

#relative_file(file) ⇒ Object (private)


431
432
433
434
435
436
437
438
# File 'lib/qed/reporter/abstract.rb', line 431

def relative_file(file)
  pwd = Dir.pwd
  idx = (0...pwd.size).find do |i|
    file[i,1] != pwd[i,1]
  end
  idx ||= 1
  file[(idx-1)..-1]
end

#rule(step) ⇒ Object

Right before rule section.


173
174
# File 'lib/qed/reporter/abstract.rb', line 173

def rule(step)
end

#sane_backtrace(exception) ⇒ Object (private)


265
266
267
268
269
270
271
# File 'lib/qed/reporter/abstract.rb', line 265

def sane_backtrace(exception)
  if trace_count
    clean_backtrace(*exception.backtrace[0, trace_count])
  else
    clean_backtrace(*exception.backtrace)
  end
end

#source(file) ⇒ String (private)

Cache the source code of a file.


363
364
365
366
367
368
369
370
371
# File 'lib/qed/reporter/abstract.rb', line 363

def source(file)
  @source[file] ||= (
    if File.exist?(file)
      File.readlines(file)
    else
      ''
    end
  )
end

#step(step) ⇒ Object

Right before text section.


177
178
# File 'lib/qed/reporter/abstract.rb', line 177

def step(step)  #show text ?
end

#stepsObject


55
# File 'lib/qed/reporter/abstract.rb', line 55

def steps  ; @record[:step]  ; end

#structured_code_snippet(exception, radius = 2) ⇒ Hash (private)

Return a structure code snippet in an array of lineno=>line hash elements.


341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
# File 'lib/qed/reporter/abstract.rb', line 341

def structured_code_snippet(exception, radius=2)
  radius = radius.to_i

  file, lineno = file_and_line(exception)

  return {} if file.empty?

  source = source(file)    

  region = [lineno - radius, 1].max ..
           [lineno + radius, source.length].min

  region.map do |n|
    {n => source[n-1].chomp}
  end
end

#success?Boolean


67
68
69
# File 'lib/qed/reporter/abstract.rb', line 67

def success?
  record[:error].size + record[:fail].size == 0
end

#trace?Boolean


62
63
64
# File 'lib/qed/reporter/abstract.rb', line 62

def trace?
  @trace
end

#trace_countInteger? (private)

Looks at ENV to determine how much trace output to provide. If it is not set, or set to`false` or `off`, then the default trace count is used. If set to `0`, `true`, 'on' or 'all' then aa complete trace dump is provided. Otherwise the value is converted to an integer and that many line of trace is given.


418
419
420
421
422
423
424
425
426
427
428
# File 'lib/qed/reporter/abstract.rb', line 418

def trace_count
  cnt = ENV['trace']
  case cnt
  when nil, 'false', 'off'
    DEFAULT_TRACE_COUNT
  when 0, 'all', 'true', 'on'
    nil
  else
    Integer(cnt)
  end
end