Here is my solution. It is quite similar to all the others already posted.

I use Zlib::Deflate to compress the source file, then the bytes are  
converted to base 3 and represented by spaces, tabs and newlines.
This way the result is approx. 3 times bigger than the source.

Dominik

The code:

require "zlib"

def encode_to_ws(str)
     str=Zlib::Deflate.deflate(str, 9)
     res=""
     str.each_byte { |b| res << b.to_s(3).rjust(6,"0") }
     res.tr("012", " \t\n")
end

def decode_from_ws(str)
     raise "wrong length" unless str.length%6 == 0
     str.tr!(" \t\n", "012")
     res=""
     for i in 0...(str.length/6)
         res << str[i*6, 6].to_i(3).chr
     end
     Zlib::Inflate.inflate(res)
end

if $0 == __FILE__
     if File.file?(f=ARGV[0])
         str=IO.read(f)
         File.open(f, "wb") { |out|
             if str =~ /\A#!.*/
                 out.puts $&
             end
             out.puts 'require "whiteout"'
             out.print encode_to_ws(str)
         }
     else
         puts "usage #$0 file.rb"
     end
else
     if File.file?($0)
         str=File.read($0)
         str.sub!(/\A(#!.*)?require "whiteout".*?\n/m, "")
         eval('$0=__FILE__')
         eval(decode_from_ws(str))
     else
         raise "required whiteout from non-file"
     end
end