[SOLUTION] Whiteout (#34)

my solution tried to strike a balance between being readable and user friendly
(usage message, etc.) and succicntness. the basic idea is that whiteout.rb is
a self modifying program that stores the whited-out files in it's __END__
section as yaml using the expanded path of the original source file as the
key. this has the nice side effect that all sources remain quite readable
within the whiteout.rb __END__ section. eg:

   jib:~/tmp > ls
   a.rb b.rb whiteout.rb

   jib:~/tmp > cat whiteout.rb
   #!/usr/bin/env ruby
   require 'yaml'

   this, prog, *paths = [__FILE__, $0, ARGV].flatten.map{|x| File::expand_path x}
   usage = "#{ prog } file [files]+"

   f = open this, 'r+'
   s, pos = f.gets, f.pos until s =~ /^__END__$/
   srcs = YAML::load f

   if prog == this
     abort usage if paths.empty?
     abort "#{ prog } must be writable" unless File::stat(this).writable?
     paths.each do |path|
       s, b = IO::read(path).split(%r/(^\s*#\s*!.*\n)/o).reverse.first 2
       srcs[path] = s
       open(path,'w'){|o| o.puts b, "require 'whiteout'\n"}
     end
     f.seek pos and f << srcs.to_yaml and f.truncate f.pos
   else
     eval srcs[prog]
   end

   __END__

···

---
   {}

   jib:~/tmp > cat a.rb
   #!/usr/bin/env ruby
   p 42

   jib:~/tmp > cat b.rb
   #!/usr/bin/env ruby
   p 'forty-two'

   jib:~/tmp > ruby a.rb
   42

   jib:~/tmp > ruby b.rb
   "forty-two"

   jib:~/tmp > whiteout.rb a.rb b.rb

   jib:~/tmp > cat a.rb
   #!/usr/bin/env ruby
   require 'whiteout'

   jib:~/tmp > cat b.rb
   #!/usr/bin/env ruby
   require 'whiteout'

   jib:~/tmp > ruby a.rb
   42

   jib:~/tmp > ruby b.rb
   "forty-two"

   jib:~/tmp > cat whiteout.rb
   #!/usr/bin/env ruby
   require 'yaml'

   this, prog, *paths = [__FILE__, $0, ARGV].flatten.map{|x| File::expand_path x}
   usage = "#{ prog } file [files]+"

   f = open this, 'r+'
   s, pos = f.gets, f.pos until s =~ /^__END__$/
   srcs = YAML::load f

   if prog == this
     abort usage if paths.empty?
     abort "#{ prog } must be writable" unless File::stat(this).writable?
     paths.each do |path|
       s, b = IO::read(path).split(%r/(^\s*#\s*!.*\n)/o).reverse.first 2
       srcs[path] = s
       open(path,'w'){|o| o.puts b, "require 'whiteout'\n"}
     end
     f.seek pos and f << srcs.to_yaml and f.truncate f.pos
   else
     eval srcs[prog]
   end

   __END__
   ---
   "/home/ahoward/tmp/b.rb": "p 'forty-two'\n"
   "/home/ahoward/tmp/a.rb": "p 42\n"

all and all quite fun!

cheers.

-a
--

email :: ara [dot] t [dot] howard [at] noaa [dot] gov
phone :: 303.497.6469
My religion is very simple. My religion is kindness.
--Tenzin Gyatso

===============================================================================