Unitirb

I'm releasing this little script I wrote called unitirb in the hopes
that other people might find it useful. It's a hacky little
interactive unit test creator. I like it, anyway. Let's call this one
0.1.

Here's how to use it:

% unitirb -r rubylib testname.rb

unitirb starts up a regular irb session, and logs the commands and
their output to a test file named on the command line. The file can be
an existing unitirb test, or a new one is created if none exists. Once
you exit the irb session, you can re-run the session like this:

% ruby testname.rb

The commands are re-run and the output compared to what was originally
obtained. If there's any difference, the test fails.

Unitirb session scripts use Test::Unit, but they aren't too pretty.

There are lots of ways to fool unitirb, I'm sure. I've tried to handle
the most obvious and common stuff, but I can't get all the cases.
Here's one I didn't: rand. Don't do stuff like that, this is just a
stupid little script.

If you accidently hit return at the wrong time and cause a syntax
error, the errored code will be copied into the session anyway...
you'll have to remove it by hand before your test works.

I'm using (a mangled form of) #inspect to dump the results of commands
in a form that can be re-read later in another process. It would be
nice to use yaml for this instead, but I found that yaml doesn't
handle a bunch of classes that I want to work in unitirb.

unitirb:

#!/usr/bin/env ruby

···

#
# unitirb.rb - interactive ruby unit test creation
# $Release Version: 0.7.3 $
# $Revision: 1.1 $
# $Date: 2005/6/6 02:00:18 $
# Copyright 2005 by Caleb Clausen
# based on irb.rb
# by Keiju ISHITSUKA(keiju@ishitsuka.com)
#

ARGV.push "unit" if /^-/===ARGV.last

def_inspect=<<end
  class Object
    #define a more stable version of inspect (for testing purposes)
    alias pristine_inspect inspect
    def inspect
      res=pristine_inspect
      res[/^#</] or return res
      res=["#<",self.class,": ",instance_variables.sort.collect{|v|
        [v,"=",instance_variable_get(v).inspect," "]
      }]
      res.last.pop
      res.push('>')
      res.to_s
    end
  end
  class MatchData
    def inspect
      '#<MatchData: >'
    end
  end
end

name=ARGV.pop
/\.rb$/===name or name="test_#{name}.rb"
print "#{File.exists?(name)?"Append":"Creat"}ing file #{name}\n"
$UnitCode=File.open(name,'a')
$UnitCode.pos==0 and $UnitCode.print "require 'test/unit'\n",def_inspect
$SuiteName="T#{$UnitCode.pos}"
$UnitCode.print <<end
  class #{$SuiteName} < Test::Unit::TestCase
    define_method :test_unnamed do begin
end

END {
  $UnitCode.print %{ rescue Test::Unit::AssertionFailedError:
raise\n rescue e: assert false, "Exception: #{ e.inspect}";\n
end end\n end\n}
  $UnitCode.close
}

eval def_inspect

require "irb"

module IRB
  class WorkSpace
    alias evaluate__nonunit evaluate
    def evaluate(context,code,file=__FILE__,line=__LINE__)
      /^(__? = |[\s\t\v\f\r\n]*exit[\s\t\v\f\r\n]*$)/===code and
return(evaluate__nonunit context,code,file,line)
      if /^[\s\t\v\f\r\n]*require(_gem)?[^a-zA-Z_0-9?!]/===code
        $UnitCode.print(" #{code}")
        return(evaluate__nonunit context,code,file,line)
      end
      $UnitCode.print(" _=#{code}")
      result=evaluate__nonunit context,code,file,line
      $UnitCode.print(' assert_equal
"'+result.inspect.gsub(/([\\"])/){|k|"\\"+k}+'"'+", _.inspect\n\n")
      return result
    end
  end
end

if __FILE__ == $0
  IRB.start(__FILE__)
else
  # check -e option
  if /^-e$/ =~ $0
    IRB.start(__FILE__)
  else
    IRB.setup(__FILE__)
  end
end