I added an ascii column to your solution... now it's about twice the size ;-)

i = 0
$<.read.scan(/.{0,16}/m) {
     puts(("%08x " % i) + $&.unpack('H4'*8).join(' ') + ' ['+
       $&.split(//).collect { |c| c.inspect[1] == 92 ? '.' :c }.join + ']' )
     i += 16
}

On Sunday 27 July 2008 22:51:04 Mikael H°Úlund wrote:
> Oh hi, I just thought I'd golf a solution. I'm sure other people can
> do a much better job than I making a full hexdumping suite, so I just
> had some fun. Can't seem to get it lower than 78 characters,
> unfortunately.
>
> i=0;$<.read.scan(/.{0,16}/m){puts"%08x "%i+$&.unpack('H4'*8).join('
> ');i+=16}
>
> Expanded and parenthesified, clarified:
>
> i = 0
> ARGF.read.scan(/.{0,16}/m) {
> 	puts(("%08x " % i) + $&.unpack('H4'*8).join(' '))
> 	i += 16
> }
>
> ARGF (aliased as $<) is the file handle of all file names given in the
> arguments concatenated, STDIN if none exactly what we need. The
> regex to scan matches between 0 and 16 characters (including newline)
> greedily. Change it to 1,16 if you don't want the empty line at the end.
>
> Instead of letting the block to scan take an argument, I used a trick
> I picked up from the last Ruby Quiz I participated in (Obfuscated
> Email), and use $& inside the block, which is the last regex match.
> Saves two characters \o/
>
> The unpack returns an array of eight strings, each of four characters,
> with the hexadecimal representation of the ASCII value of two
> consecutive characters. Fun, fun, fun.