I decided to learn Ruby and Rails — now I need to get books on both (damn that DHH and his contagious enthusiasm)
Below are some snippets from my first Ruby program: convert.rb. It is a CGI program, that converts PostScript, TeX, CWEB and a couple of other formats to PDF. It also converts .tar.gz, .tar.bz2 and other compressed files to .zip.
[Note: I wrote this program flipping back and forth between the PixAxe1 and a bunch of other online resources — so forgive me if it isn't in the spirit of Ruby.]
Ruby blocks are cool!!!
def ignore_errors &block
begin
block.call
rescue Exception => e
e
end
end
def with_tmpdir &block
result = nil
original = Dir.pwd
tmp = tmpname # creates a temporary name (not safe)
begin
Dir.mkdir tmp
Dir.chdir tmp
result = block.call original
ensure
Dir.chdir original
end
FileUtils.rm_rf tmp
result
end
and it is quiet easy to create DSLs:
# converters operate like so:
# 3 args: first, a symbol naming the converter;
# second, a regexp that if matched the third arg
# is executed: which is a block that takes one
# argument -- a local filename
# the converter should return true or nil:
# true to continue and try other converters;
# nil to return -- as this is the final one.
defconverter(:ps, /\.ps$/) { | x |
sh "ps2pdf #{x}"
nil
}
defconverter(:cweb, /\.w$/) { | x |
sh "cweave #{x} - #{x}.tex"
sh "tex #{x}.tex"
sh "dvips #{x}.dvi"
sh "ps2pdf #{x}.ps"
nil
}
Finally, CGI.rb's HTML output facility make the code elegant (I wish that, optionally, you could output to a stream...)
cgi.out {
cgi.html("PRETTY" => " ") {
cgi.head { cgi.title { 'convert.rb' } } +
cgi.body {
cgi.h3 { 'convert.rb — convert file to PDF or ZIP' } +
cgi.form('get', $0) {
cgi.b { 'url:' } +
cgi.text_field('url', '', 150) + ' ' +
cgi.submit + cgi.br +
cgi.checkbox('zipitup') + ' zip it up? ' +
cgi.small { '[with this turned on, you can convert
unix archive formats (like .tar.gz, .tar.bz2,
...) to .zip format]' }
...
...
...
[snipped]
Here are some initial thoughts:
- I was surprised at how easily and quickly I was able to develop the program
- calling methods (those that don't take args and those that take a single arg) without parenthesis is quiet refreshing:
(Before this, looking at Ruby from the "outside", this convention was disturbing — "How do I pass a function to another function" — but I didn't encounter that problem with this program because it seems to me that you pass in closures (blocks) to other functions...)
compare method.to_a.to_s to method.to_a().to_s()
sh "rpm2cpio #{x} | cpio -dimv --no-absolute-filenames" - love the short, nicely named methods: FileUtils.rm_rf tmp
- ability to specify integer as 100_000_000 is nice