:) This is great :) I enjoyed doing the quiz, and tried out a couple of
approaches: the stack based one (which seemed much more complex, and
even then didn't cover all the cases), and this substitution on. Solving
the quiz was fun, but I picked up a lot of little things I didn't know
along the way (either by bumping in to them, or looking at other
people's solutions):

  The pattern match variables $` and $'.
  That you can use any start and end charater to deliminate a %w array
literal (or any of the related literals).
  Having a test case in a script.
  That the ruby command can be given params for the script itself.

Thank you community :)

Cheers,
  Benjohn


module SubValidator
  module_function

  def is_valid(s)
    validate(s) rescue nil
  end

  def validate(s)
    # Replace basic brackets in (valid) packaging, with packages.
    s = s.gsub(/\(B\)|\{B\}|\[B\]/, 'P')

    # Until the string is reduced to a single package...
    while(s!='P')
      # Replace one of more packages in (valid) packing, with a single
package.
      s, old_s = s.gsub(/\(P+\)|\{P+\}|\[P+\]/, 'P'), s

      raise "Couldn't find any packages to package in '#{s}'." if s==old_s
    end
    true
  end
end

require 'test/unit'

class BracketTest < Test::Unit::TestCase
  def test_validators
    [SubValidator].each {|v| check_validator(v)}
  end

  def check_validator( validator )
    # Simple cases that should pass.
    valid_strings = %w<(B) {B} [B] ((B)) {(B)} ([{B}]) ((B)(B))
((((B)(B))(B))(B))>
    valid_strings.each do |s|
      assert_nothing_raised { validator.validate(s) }
    end

    # Simple cases that should fail.
    invalid_strings = %w<() (b) [ B [B [} [B} } {{{{[B]}}} {{{{[B}}}
((B)B)> << ''
    invalid_strings.each do |s|
      assert_raises(RuntimeError) { validator.validate(s) }
    end

    # Try out a complex string - it should validate.
    ok = "[({B}[B](B)[(B){[B][(B)]}]{B}{B})((B))]"
    assert_nothing_raised{ validator.validate ok }

    # Try dropping any of the chars - it should fail to vaildate.
    ok.scan(/./) { assert_raises(RuntimeError) { validator.validate( $`
+ $' ) } }

    # Try adding any of the vaild chars at any point - it should fail to
validate.
    %w<B ( ) { } [ ]>.each do |c|
      ok.scan(//) { assert_raises(RuntimeError) { validator.validate( $`
+ c + $' ) } }
    end
  end

  def test_is_valid
    assert_not_nil( SubValidator::is_valid( '(B)' ) )
    assert_nil( SubValidator::is_valid( '' ) )
  end
end

if __FILE__ == $0
  if( ARGV[0] != '-t' )
    Test::Unit.run = false
    exit( SubValidator::is_valid( ARGV[0] )  ? 0 : 1 )
  else
    ARGV.pop
  end
end