class Tryouts::Tryout

def add_drill(d)

more dreams in +@dream_catcher+, it will be added to drill +d+.
Add a Drill object to the list for this Tryout. If there is one or
def add_drill(d)
  unless @dream_catcher.empty?
    d.add_dreams *@dream_catcher.clone   # We need to clone here b/c
    @dream_catcher.clear                 # Ruby passes by reference.
  end
  drills << d
  d
end

def clean(&block)

A block to executed one time _after_ the drills
def clean(&block)
  return @clean unless block
  @clean = block
end

def dream(*args, &definition)

NOTE: This method is DSL-only. It's not intended to be used in OO syntax.
def dream(*args, &definition) 
  if args.empty?
    dobj = Tryouts::Drill::Dream.from_block definition
  else
    if args.size == 1
      dobj = Tryouts::Drill::Dream.new(args.shift)  # dream 'OUTPUT'
    else
      dobj = Tryouts::Drill::Dream.new(*args)       # dream 'OUTPUT', :format
    end
  end
  @dream_catcher.push dobj
  dobj
end

def drill(dname, *args, &definition)

+args+ is sent directly to the Drill class. The values are specific on the Sergeant.
+name+ is the name of the drill.
Create and add a Drill object to the list for this Tryout
def drill(dname, *args, &definition)
  raise "Empty drill name (#{@name})" if dname.nil? || dname.empty?
  drill = Tryouts::Drill.new(dname, @dtype, *args, &definition)
  self.add_drill drill
end

def from_block(b=nil, &inline)

the external DSL methods: dream, drill, xdrill
Populate this Tryout from a block. The block should contain calls to
def from_block(b=nil, &inline)
  runtime = b.nil? ? inline : b
  instance_eval &runtime
end

def initialize(name, dtype, command=nil, *args)

def initialize(name, dtype, command=nil, *args)
  raise "Must supply command for dtype :cli" if dtype == :cli && command.nil?
  raise "#{dtype} is not a valid drill type" if !@@valid_dtypes.member?(dtype)
  @name, @dtype, @command = name, dtype, command
  @drills, @dream_catcher = [], []
  @passed, @failed = 0, 0
end

def report

Prints error output. If there are no errors, it prints nothing.
def report
  return true if success?
  failed = @drills.select { |d| !d.success? }
  failed.each_with_index do |drill,index|
    dreams, reality = drill.dreams, drill.reality
    title = ' %-59s' % %Q{ERROR #{index+1}/#{failed.size} "#{drill.name}"}
    puts $/, ' ' << title.color(:red).att(:reverse)
    
    if dreams.empty?
      puts '%12s: %s' % ["expected", "[nodream]"]
      puts '%12s: %s' % ["returned", reality.output.inspect]
    else
      dreams.each do |dream|
        puts '%12s: %s' % [ "expected", dream.output.inspect]
      end
      puts '%12s: %s' % ["returned", reality.output.inspect]
      unless reality.error.nil?
        puts '%12s: %s' % ["error", reality.error.inspect]
      end
      unless reality.trace.nil?
        puts '%12s: %s' % ["trace", reality.trace.join($/ + ' '*14)]
        puts
      end
      
    end
  end
  false
end

def run

Execute all Drill objects
def run
  DrillContext.module_eval &setup if setup.is_a?(Proc)
  puts Tryouts::TRYOUT_MSG.bright % @name
  @drills.each do |drill|
    drill.run DrillContext.new
    note = drill.dreams.empty? ? '[nodream]' : ''
    puts drill.success? ? "PASS".color(:green) : "FAIL #{note}".color(:red)
    puts "      #{drill.reality.output.inspect}" if Tryouts.verbose > 0
    if Tryouts.verbose > 1
      drill.reality.stash.each_pair do |n,v|
        puts '%14s: %s' % [n,v.inspect]
      end
    end
    drill.success? ? @passed += 1 : @failed += 1
  end
  DrillContext.module_eval &clean if clean.is_a?(Proc)
end

def setup(&block)

A block to executed one time _before_ starting the drills
def setup(&block)
  return @setup unless block
  @setup = block
end

def success?

Did every Tryout finish successfully?
def success?
  return @success unless @success.nil?
  # Returns true only when every Tryout result returns true
  @success = !(@drills.collect { |r| r.success? }.member?(false))
end

def xdream(*args, &b); end

A quick way to comment out a dream
def xdream(*args, &b); end

def xdrill(*args, &b); @dream_catcher.clear; end # ignore calls to xdrill

ignore calls to xdrill
A quick way to comment out a drill
def xdrill(*args, &b); @dream_catcher.clear; end # ignore calls to xdrill