Vanwege de hype rond Ruby on Rails wilde ik wel eens Ruby proberen. Met Ruby on Rails heb je in ongeveer 15 minuten een min of meer werkende applicatie maar dan weet je eigenlijk nog niets van Ruby en ik denk dat het beter is om een taal te leren kennen en daarna je te wagen aan leuke frameworks. Dus eerst maar even iets simpels:
Ik gebruik Amarok als music player. Amarok houdt een soort van score bij op basis van het aantal keer dat de track speelt en hoe lang je de track beluistert. Ik wou de meest gedraaide tracks naar mijn mp3 player hebben, willekeurig totdat het filesystem vol is. Grappig om mee te beginnen, want je moet dan een paar dingen doen: een klein beetje rekenen en een database aanspreken (Amarok gebruikt een database)
Het script is nog niet af. Het liefst wil ik ik dit aanroepen met als verplicht argument een doel directory en dat het script dan zelf bepaalt hoeveel ruimte er nog beschikbaar is. Ook het eigenlijke kopieren moet nog in Ruby maar voor nu vindt ik xargs voldoende.
Met nul kennis van Ruby heeft me dit 45 minuten gekost. De meeste tijd ging zitten in de error handling. In Perl en PHP is het meer gedoe. Ik heb ook nog een PHP versie gemaakt (copy-paste vanuit Ruby). Het is een beetje flauw om PHP als voorbeeld te nemen: het is niet bedacht om vanaf de command line te draaien dus die bizarre manier om iets naar STDERR te schrijven zullen we PHP maar vergeven…
Hierbij het ruby script:
require "mysql"
# TODO: returns free space on device
def get_free_space
return 500 * 1024 * 1024
end
begin
space = get_free_space;
dbh = Mysql.real_connect("localhost", "", "", "amarok")
sql = "SELECT * FROM statistics WHERE percentage > 90 ORDER BY RAND()"
res = dbh.query(sql)
while space > 0 && row = res.fetch_hash do
begin
filesize = File.size(row['url'])
if space - filesize > 0
puts row['url']
end
space -= filesize
rescue SystemCallError
# Can't read file, for whatever reason. Report on STDERR and ignore
$stderr.puts "Can't read " + row['url']
end
end
rescue MysqlError => e
puts e.error
ensure
res.free
dbh.close
end
En het equivalent in PHP:
<?php
function mysql_error_catch()
{
print mysql_error();
mysql_close();
die;
}
// TODO: returns free space on device
function get_free_space()
{
return 500 * 1024 * 1024;
}
$space = get_free_space();
$dbh = @mysql_connect("localhost", "amarok", "!amarok");
mysql_select_db('amarok');
if (!$dbh)
mysql_error_catch();
$sql = "SELECT * FROM statistics WHERE percentage > 90 ORDER BY RAND()";
$res = mysql_query($sql);
if (!$res)
mysql_error_catch();
while ($space > 0 && $row = mysql_fetch_assoc($res))
{
if ($filesize = @filesize($row['url']))
{
if ($space - $filesize > 0)
{
echo "{$row['url']}\n";
$space -= $filesize;
}
}
else
{
// Can't read file, for whatever reason. Report on STDERR and ignore
$fp = fopen("php://stderr", "w");
fwrite($fp,"Can't read ".$row['url']);
fclose($fp);
}
}
mysql_close();
?>
Ok, ruby ziet er redelijk leesbaar uit. Het enige wat ik wat minder vindt zijn de ‘begin’ en ‘end’ definities in plaats van accolades {}. Dan moet je zoveel typen.
@ alles over:
Als je dat minder vind zul je super blij zijn dat je geen $ voor alle vars hoeft te doen. *joepie*
‘k Ben nu een paar weken met Rails bezig maar ik blijf het erg lastig vinden…