[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

Re: [QUIZ] [Solution] Whiteout (#34

Robin Stocker

6/5/2005 12:26:00 PM

Hi,


Here's my solution for Ruby Quiz #34. It's my first one :)


Well, it's pretty simple..

To find out whether the file was run directly or required:
- if __FILE__ == $0

When whiteout is run directly, it does the following for each ARGV:
- Leaves the shebang intact
- Adds the "require 'whiteout'"
- Converts the rest of the file to whitespace

The conversion to whitespace is done like this:
- Chars in like "\n" and "\r" are ignored
- Each byte is converted to its bit representation
- So we have something like 01100001
- Then, it is converted to whitespace
- 0 results in a " " (space)
- 1 results in a "\t" (tab)

When whiteout was required:
- Opens the file of $0
- Skips to after the require line
- Decodes the whitespace to code
- Runs the code with eval


I don't like the opening of $0 and the eval part.
Also, the encoding to whitespace could be made more efficient in size by
adding more whitespace characters to the "code table".

I'm curious to see the other, probably cleaner solutions.

Bye,
Robin

PS: Here's the code:


#!/usr/bin/ruby


#
# This is my solution for Ruby Quiz #34, Whiteout.
# Author:: Robin Stocker
#


#
# The Whiteout module includes all functionality like:
# - whiten
# - run
# - encode
# - decode
#
module Whiteout

@@bit_to_code = { '0' => " ", '1' => "\t" }
@@code_to_bit = @@bit_to_code.invert
@@chars_to_ignore = [ "\n", "\r" ]

#
# Whitens the content of a file specified by _filename_.
# It leaves the shebang intact, if there is one.
# At the beginning of the file it inserts the require 'whiteout'.
# See #encode for details about how the whitening works.
#
def Whiteout.whiten( filename )
code = ''
File.open( filename, 'r' ) do |file|
file.each_line do |line|
if code.empty?
# Add shebang if there is one.
code << line if line =~ /#!\s*.+/
code << "#{$/}require 'whiteout'#{$/}"
else
code << encode( line )
end
end
end
File.open( filename, 'w' ) do |file|
file.write( code )
end
end

#
# Reads the file _filename_, decodes and runs it through eval.
#
def Whiteout.run( filename )
text = ''
File.open( filename, 'r' ) do |file|
decode = false
file.each_line do |line|
if not decode
# We don't want to decode the "require 'whiteout'",
# so start decoding not before we passed it.
decode = true if line =~ /require 'whiteout'/
else
text << decode( line )
end
end
end
# Run the code!
eval text
end

#
# Encodes text to "whitecode". It works like this:
# - Chars in @@char_to_ignore are ignored
# - Each byte is converted to its bit representation,
# so that we have something like 01100001
# - Then, it is converted to whitespace according to @@bit_to_code
# - 0 results in a " " (space)
# - 1 results in a "\t" (tab)
#
def Whiteout.encode( text )
white = ''
text.scan(/./m) do |char|
if @@chars_to_ignore.include?( char )
white << char
else
char.unpack('B8').first.scan(/./) do |bit|
code = @@bit_to_code[bit]
white << code
end
end
end
return white
end

#
# Does the inverse of #encode, it takes "white"
# and returns the decoded text.
#
def Whiteout.decode( white )
text = ''
char = ''
white.scan(/./m) do |code|
if @@chars_to_ignore.include?( code )
text << code
else
char << @@code_to_bit[code]
if char.length == 8
text << [char].pack("B8")
char = ''
end
end
end
return text
end

end


#
# And here's the logic part of whiteout.
# If it was run directly, whites out the files in ARGV.
# And if it was required, decodes the whitecode and runs it.
#
if __FILE__ == $0
ARGV.each do |filename|
Whiteout.whiten( filename )
end
else
Whiteout.run( $0 )
end


2 Answers

Dave Burt

6/5/2005 1:59:00 PM

0

"Robin Stocker" <robin-lists-ruby-talk@nibor.org> solved:
> Here's my solution for Ruby Quiz #34. It's my first one :)

Welcome to Ruby Quiz, Robin!

Here's my solution, which is basically the same as Robin's. I must cite
NegaPosi by SASADA Koichi for inspiration.

http://www.dave.burt.id.au/ruby/w...

Known bug: "__END__" doesn't work in an eval'd string. No solution
anticipated. NegaPosi has this problem too.

Also, my Whiteout doesn't try and detect whether the given file is a valid
whiteout file or not, so you'll get a syntax error if you "require
'whiteout'" with anything else other that a shebang and whitespace in the
file.

There's an interesting hack at the eval end of my script to make "if $0 ==
__FILE__" blocks work:
eval "$0 = __FILE__; #{ Whiteout.decode(File.read($0)) }"

Cheers,
Dave


Bill Atkins

6/5/2005 3:19:00 PM

0

if __FILE__ == $0
# invoked as an exectuable
ARGV.each do |file|
source = File.read(file)

# save the shebang (if there is one)
shebang = nil
source.sub /^(\#!.*?)\n/ do |m| shebang = m; "" end

# convert the remaining text to whitespace; a given line will
# contain n spaces, where n is the ASCII code of the character
# that line represents tabs (\t) are used to represent 16 spaces

result = source.split(//).collect do |char|
ascii = char[0]

"\t" * (ascii / 16) + " " * (ascii % 16)
end.join "\n"

result = "require 'whiteout'\n" + result
File.open file, "w" do |f| f.write result end
end
else
# required as a library

source = File.read $PROGRAM_NAME

source.sub! /^.*?require 'whiteout'\n/, ""

result = source.split(/\n/).collect do |line|
ascii = 0
line.each_byte do |c|
if c.chr == "\t"
ascii += 16
elsif c.chr == " "
ascii += 1
else
raise "invalid input: #{c.chr}"
end
end

ascii.chr
end.join ""

eval result
end


On 6/5/05, Dave Burt <dave@burt.id.au> wrote:
> "Robin Stocker" <robin-lists-ruby-talk@nibor.org> solved:
> > Here's my solution for Ruby Quiz #34. It's my first one :)
>
> Welcome to Ruby Quiz, Robin!
>
> Here's my solution, which is basically the same as Robin's. I must cite
> NegaPosi by SASADA Koichi for inspiration.
>
> http://www.dave.burt.id.au/ruby/w...
>
> Known bug: "__END__" doesn't work in an eval'd string. No solution
> anticipated. NegaPosi has this problem too.
>
> Also, my Whiteout doesn't try and detect whether the given file is a valid
> whiteout file or not, so you'll get a syntax error if you "require
> 'whiteout'" with anything else other that a shebang and whitespace in the
> file.
>
> There's an interesting hack at the eval end of my script to make "if $0 ==
> __FILE__" blocks work:
> eval "$0 = __FILE__; #{ Whiteout.decode(File.read($0)) }"
>
> Cheers,
> Dave
>
>
>
>


--
Bill Atkins