RSS
 

Una nuova casa

20 Sep

Mi sto spostando su blogger, questo è il link del mio nuovo blog.

 
No Comments

Posted in Ruby

 

Leonardo: un generatore di applicazioni Rails 3.1

22 Aug

L’aggiornamento alla versione più recente lo trovi sul mio nuovo blog. Click here for the english version.

Ho creato un nuovo generatore per creare applicazioni rails 3.1 (che attualmente si trova in rc6) ed automatizzare le operazioni che risultano ripetitive.

Il nome della gemma è leonardo ed è suddivisa in due generatori:

  1. leolay: per creare il layout
  2. leosca: per creare la risorsa (sostituisce lo scaffold)

Perchè creare un nuovo generatore se esiste già lo scaffold di rails?

Lo scaffold è un comodo generatore e si può anche personalizzare con facilità ma è adatto per scopi didattici e la personalizzazione è limitata alle sole viste. In produzione mi serviva qualcosa di più completo e personalizzabile.

Preparazione dell’ambiente ed installazione della gemma

Creiamo un nuovo ambiente ruby ed installiamo rails 3.1:
gem install rails –pre
usiamo il –pre perchè in questo momento si trova in release candidate, toglietelo se invece è stata rilasciata

Possiamo installare la gemma semplicemente con:
gem install leonardo

…ma non è necessario e consiglio di usare il procedimento che sto per descrivere:
creiamo una nuova applicazione utilizzando il template che ho preparato, raccomandato per agevolare l’avvio e per meglio sfruttare la gemma:

rails new NewApp -m http://cloud.github.com/downloads/marcomd/Leonardo/template.rb

Se non dovesse funzionare il link potete comunque trovare il template nella root della gemma

Il template chiederà se installare determinate gemme esterne, per una prova consiglio di installarle tutte rispondendo y o premendo invio quando propone un default (es. devise)

Verrà poi eseguito un bundle install per verificare la presenza delle gemme ed in seguito verranno eseguite le varie generazioni, il tutto durerà qualche minuto circa.
La generazione del layout chiederà una conferma per sostituire il file en.yml, rispondete y. Preferisco non forzare la sostituzione per permettere altre ed eventuali esecuzioni del generatore leolay nel caso si volesse aggiornare il layout.

Al termine otterrete un applicazione “pronta per partire” potendo così orientare lo sviluppo sulla parte applicativa.

Spostiamoci nella cartella dell’applicazione ed avviamo il server
cd NewApp
rails s
indirizziamo il browser all’indirizzo http://localhost:3000 per accedere alla home

Se clicchiamo su “Sign in” verrà richiesta l’autenticazione (se l’avete inclusa), per un rapido accesso potete inserire:
email: admin@newapp.com
password: abcd1234

Signed in

Vengono create tre utenze con tre ruoli diversi (nel caso avete incluso le autorizzazioni):

  1. admin@newapp.com
  2. manager@newapp.com
  3. user@newapp.com

Naturalmente si tratta di utenze con finalità legate allo sviluppo per cui ricordate di eliminarle prima di qualsiasi rilascio. Possiamo consultare e modificare i ruoli accedendo al file app/models/ability.rb in quanto la gestione è affidata alla gemma cancan.

Per cambiare la lingua è sufficiente inviare la nuova come valore del parametro lang, esempio:

http://localhost:3000/?lang=it

il generatore attualmente gestisce :en e :it ma aggiungere il supporto ad un’altra lingua è semplice, basta aggiungere il file yml nella cartella dove si trovano i primi due, naturalmente deve avere gli stessi tags.

Generare le risorse

Ora generiamo qualche risorsa utilizzando il generatore leosca, una sorta di scaffold personalizzato:

rails g leosca category name:string active:boolean

rails g leosca product category:references name:string description:text price:decimal

ora creiamo le due nuove tabelle anche sul database:
rake db:migrate

ed eseguiamo anche il popolamento con qualche dato che leosca ha preparato per noi:
rake db:seed

Listing Categories

Alcune note:

  • L’esportazione dei dati in csv attualmente non funziona se attiva la paginazione ajax, sto cercando un buon metodo per risolvere.
  • Nelle liste vengono inseriti in automatico tutti i campi per poter applicare dei filtri, eliminiamo quelli che non ci interessano. I filtri su campi boolean non funzionano con sqlite3 a causa di un bug nel driver che non genera un sql corretto. Con SQLServer funziona alla perfezione.
  • Gli oggetti relazionati mostrano un link col nome e cliccando si effettua una :show. Nel caso la tabella non abbia il campo :name viene utilizzato l’id che è possibile sostituire con il dato che più lo rappresenta.
  • Solo l’operazione destroy è gestita tramite ajax. Show, edit e create attualmente sono gestite tramite http.
  • Riguardo le utenze create in automatico: con i ruoli di default admin può fare tutto, manager tutte le operazioni crud, user tutte tranne la delete.
  • Le etichette dei campi vengono inserite in automatico ma la traduzione è necessario farsela da se all’interno dei files config/locales/*.yml

Personalizzare il generatore

E’ sufficiente installarlo nel progetto e personalizzarlo secondo le proprie esigenze:
rails g leosca:install
si trova sotto lib ed eventuali modifiche avranno la precedenza sulla gemma

Conclusioni

Per ulteriori approfondimenti o aggiornamenti sugli sviluppi futuri è possibile consultare la homepage del progetto:
https://github.com/marcomd/Leonardo

Altri riferimenti:
http://edgeguides.rubyonrails.org/generators.html
http://railscasts.com/episodes/216-generators-in-rails-3
http://railscasts.com/episodes/218-making-generators-in-rails-3
http://railscasts.com/episodes/242-thor
http://rdoc.info/github/wycats/thor/master/Thor
http://textmate.rubyforge.org/thor/Thor/Actions.html
http://railscasts.com/episodes/265-rails-3-1-overview

 
 

HTC Desire HD

30 May

Uscito a ottobre del 2010, il Desire HD è l’attuale modello di punta di HTC, almeno fino al prossimo mese, data in cui è prevista l’uscita del nuovo modello con cpu dual core. Esce con Android Froyo ma è disponibile l’aggiornamento ad Android 2.3 Gingerbread.

Desire HD

Quello che posso aggiungere alle specifiche fornite dalla casa è che utilizza un display in vetro che non ha nulla da invidiare ad un gorilla glass, molto resistente ai graffi.

Dispone della seconda generazione del processore Qualcomm snapdragon. E’ prodotto con tecnologia a 45nm che significa minor consumi e migliore autonomia, nonostante la batteria di soli 1230mha ed il generoso display da 4,3″ riesce ad arrivare fino a sera. La parte grafica è affidata alla GPU Adreno 205, soluzione progettata e costruita internamente da Qualcomm dopo che ha comprato la divisione “ATI mobile” da AMD. La cpu si occupa anche di altri compiti che solitamente sono gestiti da moduli esterni come la ricezione gps. Questo semplifica la progettazione dei terminali con impatti positivi sui costi, motivo che ha permesso a Qualcomm di diffondere agevolmente la propria soluzione. Questi sono un pò di risultati prestazionali subito dopo averlo scartato dalla confezione:

Rom: Stock 1.72.405.3 (Android 2.2.1)
Kernel: 2.6.32.21 del 01/12/2010
CPU: 245-1024Mhz (no undervolt, no oc)
Quadrant: 1700
Linepack: 40,4 MFLOP
Neocore: 58,3 FPS
Nenamark1: 34,3 FPS
Nenamark2: 11,5 FPS

Sul mercato esistono diverse revisioni: inizialmente la sd da 8gb era di classe 2 della samsung, gli ultimi modelli dispongono di una più veloce classe 4 prodotta da Sandisk e di un display migliore con tecnologia Super LCD. Per capire quale dei due display monta si potrebbero esaminare i sub pixel come spiegato qua o questo più semplice metodo empirico: provarlo sotto la luce del sole, se monta un slcd dovrebbe avere una buona o perlomeno discreta visualizzazione delle immagini.

E’ un telefono molto curato, dalla confezione al software che ti accoglie con benvenuti vari, tutorial, ecc. La qualità generale è molto alta e i materiali sono di ottima fattura, dalla scocca monoblocco in alluminio priva di scricchiolii alla gomma usata negli auricolari. A proposito degli auricolari, sono costruiti bene ma purtroppo non significa che suonano altrettanto bene, peccano infatti sulle frequenze medie e basse. Stesso giudizio per l’altoparlante, ha un suono nitido e cristallino chè reputo ottimo per le suonerie polifoniche ma inadatto per gli mp3. Sinceramente mi sarei aspettato di meglio da un terminale venduto come ottima soluzione per contenuti multimediali.

Confezione:

Cuffie:

Software:
A differenza di altri concorrenti che ho potuto provare come l’LG Optimus dual od il Galaxy S, l’interfaccia mi sembra più ottimizzata che si traduce in un utilizzo generale più piacevole, più fluido, più animazioni: di default lo sfondo è animato, quando si accede si viene accolti da un’appariscente animazione meteo ecc. I widget forniti da htc che si vanno aggiungere a quelli di android, sono tanti, fatti molto bene ed a cui se ne possono aggiungere degli altri scaricandoli dal servizio fornito da htc e vale anche per il set di suoni, sfondi ecc. Registrandosi su htcsense.com è anche possibile monitorare da web gli spostamenti del proprio telefono, utile in caso di smarrimento, un pò meno forse in quelli di furto.

Fotocamera:
Simpatica ed utile la possibilità di applicare effetti di correzione alle foto, è anche possibile vederli applicati mentre si riprende la scena!

Esempio:

Esempio con effetto miglioramento:

E’ sempre meglio non aver troppe aspettative da un cellulare o smartphone che sia. Il rumore nelle foto è spesso presente ed aumenta col diminuire della luce. Di notte la situazione è critica, il doppio flash aiuta molto, sia per le foto che per i video ma a volte non è sufficiente anche per il corto raggio di azione e se si osservano le foto alla loro dimensione originale si capirà subito il motivo.
Il problema non è solo il rumore ma anche ogni piccolo dettaglio risulta come impastato. Tuttavia si possono sfruttare gli 8 megapixel: ridimensionando la fotografia ad una risoluzione inferiore si andranno a mescolare i difetti ottenendo una foto più piccola (ad esempio 5megapixel) ma migliore di quella che normalmente otterremmo con un sensore di quella risoluzione.

Questo è un video girato da me a 480p e 3mbit di bit rate:

Qua si possono trovare degli esempi girati a 720p.


Permessi di root:

Per chi non lo sapesse, è possibile ottenere i permessi di root per avere il pieno controllo del terminale. In questo modo è possibile scegliere una versione alternativa del sistema operativo per migliorare le prestazioni, per sistemare bachi o carenze in determinati ambiti ad esempio migliorando l’autonomia semplicemente sfruttando meglio la batteria. E’ possibile inoltre aggiornare la sezione software che gestisce la ricetrasmissione radio (3g, wifi ecc.) per migliorare anche queste caratteristiche ma devo anche segnalare che questa operazione non è completamente esente da rischi.

Considerando che con questi aggiornamenti non ufficiali si perde la garanzia, io consiglio innanzitutto di usarlo come esce dal negozio per un periodo necessario alla verifica di ogni componente. Dopodichè si deve valutare: se il telefono va bene così com’è e\o non si ha la voglia di perdere molto tempo per star dietro allo sviluppo delle rom alternative io consiglio di limitarsi agli aggiornamenti ufficiali disponibili fino a gingerbread. Lo smanettone invece non dovrebbe pensarci due volte, sarebbe un peccato non sfruttare le enormi potenzialità delle rom modificate.

Pro e contro delle custom rom:

I vantaggi sono:

  • ottimizzazione software sia del kernel che della rom: migliorando il cuore del sistema si possono avere molti vantaggi: prestazioni, autonomia ecc. potrei riassumere che il telefono risulterà più reattivo e privo di fronzoli
  • ottimizzazione della cpu: è possibile abbassare il voltaggio migliorando ulteriormente i consumi in quanto quello di default è oltre il valore necessario. E’ anche possibile aumentare la frequenza di funzionamento massima che si traduce in potenza a disposizione quando serve pur mantenendo i consumi ridotti in standby.
  • backup delle singole applicazioni o dell’intero telefono

 
Gli svantaggi:

  • richiede una discreta dimestichezza informatica generale
  • tempo per seguire gli sviluppi software e scegliere la miglior soluzione per le proprie esigenze
  • presenza di bug che possono inibire l’utilizzo di alcune caratteristiche del desire hd anche se basterebbe scegliere solo release collaudate

Per saperne di più, posso proporre questa raccolta di links fornito gentilmente da un forum di appassionati italiani.

Il consiglio che vale sempre per tutto è fare le cose per gradi: iniziare dalla versione stock => testarla per un periodo necessario ad esplorarla a fondo => provare una custom rom stabile => testarla per un periodo necessario ad esplorarla a fondo => passare eventualmente a qualcos’altro e così via.

Per rimanere aggiornati sulle custom rom è possibile visitare la sezione del forum xda dedicata al Desire HD (in inglese).

Appena riesco farò dei confronti con iPhone4, Optimus Dual (2x), Optimus 7, Nokia N8 ed altri modelli che gentilmente mi metteranno a disposizione (amici e parenti).

 
Comments Off

Posted in Smartphones

 

Files di grandi dimensioni su Windows Server 2008 R2 64Bit

21 Apr

Nel precedente articolo ho esaminato la semplice lettura e scrittura di tre files con dimensioni da 330Mb a 2,6Gb, su un normalissimo PC con Windows XP. Ora vediamo cosa cambia su un server virtuale, sistema produttivo che coinvolge un numero di aziende sempre più ampio.

I linguaggi in esame sono i seguenti:

Ruby 1.8.6 p383 (2009-08-04) [i386-mingw32]
Ruby 1.8.7 p334 (2011-02-18) [i386-mingw32]
Ruby 1.9.2 p180 (2011-02-18) [i386-mingw32]
jruby 1.6.1 (ruby-1.8.7-p330) (2011-04-12) (Java HotSpot(TM) 64-Bit Server VM 1.6.0_23) [Windows Server 2008 R2-amd64-java]
IronRuby 1.1.3.0 (ruby-1.9.2) on .NET 4.0.30319.225
Python 2.7.1 32bit
Python 2.7.1 64bit
Python 3.2.0 32bit
Python 3.2.0 64bit
Php 5.3.6 vc9 unsafe thread
Lua 5.1.4 40
C# 32bit on .NET 2.0.50727.4927
C# 64bit on .NET 2.0.50727.4927
C# 32bit on .NET 4.0.30319.1
C# 64bit on .NET 4.0.30319.1

Solo python fornisce pacchetti di installazione x64 e ne ho approfittato per confrontarli con le versioni a 32 bit. Probabilmente le differenze si noteranno con operazioni matematiche rispetto la sezione IO ma questo apre la strada alla prossima comparazione.

La versione di ruby 1.8.6 è una mingw32 e non mswin32 come nel precedente test. IronRuby invece è l’ultima 1.1.3 che abbraccia il supporto a ruby 1.9.2 e non 1.8.6 come la versione del precedente test con cui, comunque, condivide lo stesso framework .net e la stessa sezione IO.
Questa volta ho anche aggiunto C# nella comparazione, ho compilato quattro versioni differenziando per piattaforma, x86 e x64, ed anche per framework, 3.5 e 4. Il framework .net 3.5 utilizza lo stesso CLR del 2.0.

Una nota di merito a IronRuby, il primo della classe che è persino davanti a C#, linguaggio compilato e con cui condivide molto. E’ vero che questo test non richiede potenza computazionale particolarmente elevata ma è certamente un risultato curioso.

Un riepilogo anche sul consumo della memoria:

Lua 5.1.4 0,7mb
Php 5.3.6 2,2mb
Python 2.7.1 32bit 2,5mb
Python 3.2.0 32bit 3,7mb
Python 2.7.1 64bit 4mb
Python 3.2.0 64bit 5,5mb
Ruby 1.9.2p180 4-6mb
Ruby 1.8.6p383 4-9mb
Ruby 1.8.7p334 4-9mb
C# 32bit on .NET 2.0.50727.4927 7mb
C# 32bit on .NET 4.0.30319.1 7mb
C# 64bit on .NET 2.0.50727.4927 9mb
C# 64bit on .NET 4.0.30319.1 9mb
IronRuby 1.1.3.0 on .NET 4.0.30319.225 11mb
jruby 1.6.1 (JVM 64-Bit Server 1.6.0_23) jruby 1mb + java 200mb

Questo è il codice C# che ho compilato con Visual Studio 2010:

using System;
using System.IO;
 
namespace Split
{
    class Program
    {
 
        /// <summary>
        /// To split a file into n output files
        /// </summary>
        /// <param name="args">Filename and records number to split</param>
        static void Main(string[] args)
        {
            string strInput = args[0];
            string strOutput = "out_{0:000}.txt";
            Int32 nrec_to_split = Convert.ToInt32(args[1]);
 
            DateTime t1 = DateTime.Now;
            Console.WriteLine("C# {1} Started at {0:R}, please wait...", t1, System.Environment.Version);
 
 
            StreamReader sr;
            StreamWriter sw = null;
            sr = new StreamReader(strInput);
            Int16 nsplit = 0;
            Int64 nrec = 0;
            while (sr.Peek() >= 0)
            {
                if (nrec % nrec_to_split == 0)
                {
                    ++nsplit;
                    if (sw != null) sw.Close();
                    sw = new StreamWriter(String.Format(strOutput, nsplit));
                }
                sw.WriteLine(sr.ReadLine());
                ++nrec;
            }
 
            Console.WriteLine("Ended at {0:R}, please wait...", DateTime.Now);
            Console.WriteLine("Elapsed time {0}", DateTime.Now - t1);
        }
 
    }
}
 
Comments Off

Posted in IronRuby .NET, JRuby, Prestazioni, Python, Ruby

 

Ruby, Python, Php e Lua in comparazione con files di grandi dimensioni

19 Apr

Vediamo come si comporta la sezione IO di alcuni tra i più popolari linguaggi script. L’esercizio consiste nel leggere sequenzialmente un grosso file di input e dividerlo in files più piccoli, in termini pratici, splittarlo.

I linguaggi in esame sono:
Ruby 1.8.6 p287 (2008-08-11) [i386-mswin32]
Ruby 1.8.7 p334 (2011-02-18) [i386-mingw32]
Ruby 1.9.2 p180 (2011-02-18) [i386-mingw32]
jruby 1.5.1 (ruby 1.8.7 patch 249) (Java HotSpot(TM) Client VM 1.6.0_14) [x86-java]
jruby 1.5.1 (ruby 1.8.7 patch 249) (Java HotSpot(TM) Client VM 1.6.0_24) [x86-java]
jruby 1.6.1 (ruby-1.8.7-p330) (Java HotSpot(TM) Client VM 1.6.0_24) [Windows XP-x86-java]
IronRuby 1.1.0.0 on .NET 4.0.30319.225
Python 2.6.2
Python 2.7.1
Python 3.2.0
Php 5.3.6 vc9 unsafe thread
Lua 5.1.4 40

Iniziamo col creare i tre files di input necessari per il test:
ruby new.rb input1.txt 185000 1799 => 330Mb
ruby new.rb input2.txt 500000 1799 => 880Mb
ruby new.rb input3.txt 1500000 1799 => 2,6Gb

Il test l’ho eseguito su un PC con cpu Intel E7300 Core2 Duo 2,66Ghz Ram 3,25Gb con Windows XP Professional 32bit, Hard Disk ST3250310AS Barracuda 7200.10 SATA 3.0Gb/s da 250Gb.

Prossimamente lo eseguirò anche su un Server Windows 2008 R2 64bit su VMWare Xeon X7460 Dual Core a 2,66Ghz e 2Gb di ram con dischi SCSI.

Prima e dopo aver creato i tre files di input ho deframmentato il disco. Se i tempi sono incostanti significa che il disco deve essere deframmentato o c’è qualcosa che rallenta il sistema come ad esempio l’antivirus che deve essere disabilitato.

Per ogni file ho eseguito sei elaborazioni e considerando le scarse prestazioni IO del sistema, ho scartato le tre peggiori. Naturalmente, prima di ogni test ho eliminato i files di output.

I grafici parlano da soli.
L’unico commento che posso fare riguarda la versione 1.9.2 di ruby che ha evidenti problemi di IO e questi risultati non sono in linea con le performance generali di questo linguaggio che, come ho potuto rilevare da altri precedenti test, sono invece molto buone.

Questi sono gli script che ho scritto per l’occasione:

# Written by Marco Mastrodonato on 19/04/2011
# Script to split a file into n output files
# Example:
# ruby split.rb par1 par2
# par1 => name [default => input1.txt]
# par2 => record number that determines the number of output files [default => 1650]
 
strinput = ARGV[0] || 'input1.txt'
nrec_to_split = ARGV[1] ? ARGV[1].to_i : 1650
 
unless File.exists? strinput
	puts "File #{strinput} doesn't exists!" 
	exit 1
end
 
stroutput = "out_%03d.txt"
 
t1= Time.now
puts "Ruby #{RUBY_VERSION} #{strinput} started at #{t1}, wait please..."
 
File.open(strinput, "r") do |f|
	nsplit = 0
	nrec = 0
	fileoutput = nil
 
	while line = f.gets
		if nrec % nrec_to_split == 0
			nsplit += 1
			fileoutput.close if fileoutput
			fileoutput = File.open(stroutput % nsplit, 'w')
		end
		fileoutput.write line
		nrec += 1
	end
 
	fileoutput.close if fileoutput
end
 
puts "Ended at #{Time.now}"
puts "Elapsed time #{Time.now - t1}"
exit 0
# Written by Marco Mastrodonato on 19/04/2011
# Script to split a file into n output files
# Example:
# python split.py par1 par2
# par1 => name [default => input1.txt]
# par2 => record number that determines the number of output files [default => 1650]
 
from time import time, gmtime, strftime
import sys
 
try:
	strinput = sys.argv[1]
except:
	strinput = 'input1.txt'
 
stroutput = "out_%03d.txt"
 
try:
	nrec_to_split = int(sys.argv[2])
except:
	nrec_to_split = 1650
 
t1 = time()
print(sys.version)
print(strftime("Started at %a, %d %b %Y %H:%M:%S +0000, wait please...", gmtime()))
 
nrec = 0
nsplit = 0
 
fileinput = open(strinput, "r")
for line in fileinput:
	if nrec % nrec_to_split == 0:
		try:
			fileoutput.close()
		except NameError:
			fileoutput = None
		nsplit += 1
		fileoutput = open(stroutput %nsplit , "w")
	fileoutput.write(line)
	nrec += 1    
fileoutput.close()
fileinput.close()
 
print(strftime("Ended at %a, %d %b %Y %H:%M:%S +0000", gmtime()))
print("Elapsed time %f" %(time() - t1))
<?php
// Written by Marco Mastrodonato on 19/04/2011
// Script to split a file into n output files
// Example:
// php split.php par1 par2
// par1 => name [default => input1.txt]
// par2 => record number that determines the number of output files [default => 1650]
 
$strinput = isset($argv[1]) ? $argv[1] : 'input1.txt';
$nrec_to_split = isset($argv[2]) ? $argv[2] : 1650;
$stroutput = 'out_%03d.txt';
 
$t1 = microtime_float();
echo "Php ".phpversion()." started at ".date('D, d M Y H:i:s T').", wait please...\n";
 
$nsplit = 0;
$nrec = 0;
$fileinput=fopen($strinput,"r");
 
while(!feof($fileinput)) {
	if ($nrec % $nrec_to_split == 0) {
		++$nsplit;
		if (isset($fileoutput)) fclose($fileoutput);
		$fileoutput = fopen(sprintf($stroutput, $nsplit), 'w');
	}
	$buffer = fgets($fileinput);
	fwrite($fileoutput, $buffer);
	++$nrec;
}
 
fclose ($fileinput);
 
echo "Ended at ".date('D, d M Y H:i:s T')."\n"; 
echo "Elapsed time ".(microtime_float() - $t1)."\n";
 
 
function microtime_float() {
	list($usec, $sec) = explode(" ", microtime());
	return ((float)$usec + (float)$sec);
}
 
?>
--[[
Written by Marco Mastrodonato on 19/04/2011
Script to split a file into n output files
Example:
lua split.lua par1 par2
par1 => name [default => input1.txt]
par2 => record number that determines the number of output files [default => 1650]
--]]
strinput = arg and arg[1] or "input1.txt"
stroutput = "out_%03d.txt"
nrec_to_split = arg and arg[2] and tonumber(arg[2]) or 1650
 
local t1 = os.clock()
print(_VERSION .. " started at " .. os.date("%a, %d %b %Y %H:%M:%S +0000"))
 
nsplit = 0
nrec = 0
for line in io.lines(strinput) do
  if nrec % nrec_to_split == 0 then
    if fileOut ~= nil then io.close(fileOut) end
    nsplit = nsplit + 1
    fileOut = io.open(string.format(stroutput, nsplit) , 'w')
  end
  fileOut:write (line .. '\n')
  nrec = nrec + 1
end
 
io.close(fileOut)
 
print("Ended at " .. os.date("%a, %d %b %Y %H:%M:%S +0000"))
print(string.format("Elapsed time: %.2f\n", os.clock() - t1))

Per creare i files ho usato questo semplice script ruby:

# Example:
# ruby new.rb [NOME] [LINES] [RECORD SIZE]
 
stroutput = ARGV[0] || 'input1.txt'
num = ARGV[1] ? ARGV[1].to_i : 185000
size = ARGV[2] ? ARGV[2].to_i : 1799
 
if File.exists? stroutput
	puts "File #{stroutput} already exists!" 
	exit 1
end
 
t1= Time.now
puts "Ruby #{RUBY_VERSION} #{stroutput} started at #{t1}, wait please..."
 
line = "*" * size
 
File.open(stroutput, "w") do |f|
	num.times do
		f.puts line
	end
end
 
puts "Ended at #{Time.now}"
puts "Elapsed time #{Time.now - t1}"
exit 0
 

Pluralizzare in tutte le lingue

08 Sep

In questo articolo mostrerò come utilizzare quel comodo helper di rails, pluralize, con tutte le lingue mediante l’utilizzo di I18n.

Diamo per scontato che l’applicazione sia internazionalizzata, quindi modelli e campi presenti nei file yaml di configurazione.
Ora dobbiamo aggiungere i termini per i quali vogliamo internazionalizzare la pluralità: modelli, attributi ecc.

activerecord: &activerecord
    models: &models
      user: "Utente"
      users: "Utenti"
      activity: "Impiego"
      activities: "Impieghi"
      task: "Incarico"
      tasks: "Incarichi"
      project: "Progetto"
      projects: "Progetti"
 
    attributes: &attributes
      activity:
        task: "Incarico"
        day: "Giorno"
        hours: "Ore"
        hour: "Ora"
        description: "Descrizione"

Ipotizziamo che il nostro modello “Incarico” sia relazionato col modello “Impiego” e che questo abbia un campo di nome “Ore”. Vogliamo creare una frase che descriva quanti impieghi sono presenti per tale incarico ed il totale delle ore.

In base ai dati nel database, vogliamo ottenere frasi del tipo:
Questo incarico ha 1 impiego per un totale di 1 ora.
Questo incarico ha 13 impieghi per un totale di 0 ore.
Questo incarico ha 1 impiego per un totale di 15 ore.

…e in tutte le lingue:

This task has 1 activity with an amount of 15 hours.
Diese Aufgabe haben 1-Aktivität für eine Gesamtmenge von 15 Stunden.
Cette tâche a 1 activité pour un total de 15 heures.
Esta tarea tiene 1 actividad para un total de 15 horas.
このタスクは、 15時間の量1活性を持つ

Vogliamo evitare:
Questo incarico ha 1 impieghi per un totale di 1 ore
This task has 1 activities with an amount of 1 hours

Aggiungiamo la frase in ogni file yaml I18n:

  #it.yml
  task_activities: "Questo incarico ha <strong>{{activities}}</strong> per un totale di <strong>{{hours}}</strong>."
  #en.yml
  task_activities: "This task has <strong>{{activities}}</strong> with an amount of <strong>{{hours}}</strong>."
  #etc.

Per fare ciò ci avvaliamo del comodo helper di rails, pluralize, opportunamente modificato per eliminare il numero dal risultato. Pluralizziamo il termine inglese da usare come chiave per I18n.

Creiamo nell’helper dell’applicazione:

module ApplicationHelper
   #Pluralize without the number
   def I18n_pluralize(count, singular, plural = nil)
     ((count == 1 || count =~ /^1(\.0+)?$/) ? singular : (plural || singular.pluralize))
   end
end

Nella view richiamiamo la frase I18n passando il numero di impieghi ed il totale di ore (per motivi descrittivi ho inserito nella view operazioni che però riterrei più opportuno posizionare nel controller):

  <% tot_hours = @activities.map{|a| a.hours}.inject{|tot,h| tot+h}  || 0 %>
  <% str_hour = t("attributes.activity.#{I18n_pluralize(tot_hours,'hour')}") %>
  <% str_activity = t("models.#{I18n_pluralize(@activities.size,'activity')}") %>
  <%= t :task_activities, :activities => "#{@activities.size} #{str_activity}", :hours => "#{@tot_hours} #{str_hour}" %>

Osserviamo questa riga alla moviola:

t("attributes.activity.#{I18n_pluralize(tot_hours,'hour')}")

In base al numero di ore otteniamo la chiave I18n: hour o hours

chiave = I18n_pluralize(tot_hours,'hour')

equivale

t("attributes.activity.#{chiave}")

se tot_hours = 1 avremo:

t("attributes.activity.hour")

altrimenti:

t("attributes.activity.hours")

Questo è il risultato:
Esempio Pluralize I18n

 
Comments Off

Posted in Ruby on Rails

 

Ruby 1.9.2 prestazioni al top

06 Sep

Con un precedente test, avevo riscontrato che JRuby era la massima espressione per quanto riguardava la velocità nell’eseguire codice ruby, surclassando non solo gli altri interpreti C++ e .Net ma azzardando prepotenti confronti con le ultime due incarnazioni di python. Gli script erano questi e li ho rispolverati anche per questo nuovo confronto.

Ora che Rails 3 è stato rilasciato ed uno degli interpreti consigliati è il nuovo 1.9.2, ero curioso di osservare come si comporta la release ufficiale: direi davvero niente male!
Questa volta ho ristretto il numero dei partecipanti alle sole versioni installate con RVM più un paio di versioni windows: JRuby 1.4.0 ed il più usato 1.8.7 mingw32, giusto per avere un metro di paragone.

Distribuzione Linux: Ubuntu 10.4 64bit
Windows XP 32Bit SP3

Versione Compilatore/Sistema Secondi
Ruby 1.9.2 p0 RVM x86_64-linux 6,6
JRuby 1.4.0 RVM OpenJDK 64-Bit Server VM 1.6.0_18 [amd64-java] 6,8
JRuby 1.5.2 RVM OpenJDK 64-Bit Server VM 1.6.0_18 [amd64-java] 7,0
JRuby 1.4.0 Windows Client VM 1.6.0_15 [x86-java] 7,0
Ruby 1.9.1 p378 RVM x86_64-linux 8,9
Ruby 1.8.7 p249 RVM x86_64-linux 12,2
Ruby 1.8.7 p249 i386-mingw32 23,9

Questo il log completo dell’esecuzione:


marco@d9400:~$ rvm list

rvm rubies

=> jruby-1.4.0 [ amd64-java ]
jruby-1.5.2 [ amd64-java ]
ruby-1.8.7-p249 [ x86_64 ]
ruby-1.9.1-p378 [ x86_64 ]
ruby-1.9.2-p0 [ x86_64 ]

marco@d9400:~$ java -version
java version "1.6.0_18"
OpenJDK Runtime Environment (IcedTea6 1.8.1) (6b18-1.8.1-0ubuntu1)
OpenJDK 64-Bit Server VM (build 16.0-b13, mixed mode)

marco@d9400:~$ ruby -v
jruby 1.4.0 (ruby 1.8.7 patchlevel 174) (2009-11-02 69fbfa3) (OpenJDK 64-Bit Server VM 1.6.0_18) [amd64-java]
marco@d9400:~$ ruby RubyMM186_3.rb --server --fast

Warming up...
Strings test - Elapsed 2.096
Check1: 50000
Check2: 157490
Check3: 50005
Check4: 373847
Arrays test - Elapsed 3.508
Check1: 20900
Check2: 250000
Check3: 250000
Check4: 1500000
Check5: 5749950
Numeric test - Elapsed 2.856
Check1: 6252500
Check2: 1439295494700374021157505910939096377494040420940312
Ruby Partial elapsed time 8.460

1. Starting Ruby tests...
Strings test - Elapsed 1.501
Arrays test - Elapsed 3.054
Numeric test - Elapsed 2.280
Ruby Partial elapsed time 6.835

2. Starting Ruby tests...
Strings test - Elapsed 1.431
Arrays test - Elapsed 3.091
Numeric test - Elapsed 2.249
Ruby Partial elapsed time 6.771

3. Starting Ruby tests...
Strings test - Elapsed 1.505
Arrays test - Elapsed 2.999
Numeric test - Elapsed 2.261
Ruby Partial elapsed time 6.765
-------------------------------------
Average Strings test - Elapsed 1.479
Average Arrays test - Elapsed 3.048
Average Numeric test - Elapsed 2.263

Ruby Average elapsed time 6.790

marco@d9400:~$ rvm use jruby-1.5.2
marco@d9400:~$ ruby -v
jruby 1.5.2 (ruby 1.8.7 patchlevel 249) (2010-08-20 1c5e29d) (OpenJDK 64-Bit Server VM 1.6.0_18) [amd64-java]
marco@d9400:~$ ruby RubyMM186_3.rb --server --fast

Warming up...
Strings test - Elapsed 2.383
Check1: 50000
Check2: 157490
Check3: 50005
Check4: 373847
Arrays test - Elapsed 3.561
Check1: 20900
Check2: 250000
Check3: 250000
Check4: 1500000
Check5: 5749950
Numeric test - Elapsed 3.210
Check1: 6252500
Check2: 1439295494700374021157505910939096377494040420940312
Ruby Partial elapsed time 9.154

1. Starting Ruby tests...
Strings test - Elapsed 1.479
Arrays test - Elapsed 3.092
Numeric test - Elapsed 2.516
Ruby Partial elapsed time 7.087

2. Starting Ruby tests...
Strings test - Elapsed 1.431
Arrays test - Elapsed 3.056
Numeric test - Elapsed 2.508
Ruby Partial elapsed time 6.995

3. Starting Ruby tests...
Strings test - Elapsed 1.423
Arrays test - Elapsed 3.053
Numeric test - Elapsed 2.524
Ruby Partial elapsed time 7.000
-------------------------------------
Average Strings test - Elapsed 1.444
Average Arrays test - Elapsed 3.067
Average Numeric test - Elapsed 2.516

Ruby Average elapsed time 7.027

marco@d9400:~$ rvm use ruby-1.8.7-p249
marco@d9400:~$ ruby -v
ruby 1.8.7 (2010-01-10 patchlevel 249) [x86_64-linux]
marco@d9400:~$ ruby RubyMM186_3.rb

Warming up...
Strings test - Elapsed 3.135
Check1: 50000
Check2: 157490
Check3: 50005
Check4: 373847
Arrays test - Elapsed 4.386
Check1: 20900
Check2: 250000
Check3: 250000
Check4: 1500000
Check5: 5749950
Numeric test - Elapsed 4.629
Check1: 6252500
Check2: 1439295494700374021157505910939096377494040420940312
Ruby Partial elapsed time 12.149

1. Starting Ruby tests...
Strings test - Elapsed 3.181
Arrays test - Elapsed 4.402
Numeric test - Elapsed 4.598
Ruby Partial elapsed time 12.180

2. Starting Ruby tests...
Strings test - Elapsed 3.153
Arrays test - Elapsed 4.387
Numeric test - Elapsed 4.572
Ruby Partial elapsed time 12.113

3. Starting Ruby tests...
Strings test - Elapsed 3.210
Arrays test - Elapsed 4.395
Numeric test - Elapsed 4.583
Ruby Partial elapsed time 12.189
-------------------------------------
Average Strings test - Elapsed 3.181
Average Arrays test - Elapsed 4.395
Average Numeric test - Elapsed 4.584

Ruby Average elapsed time 12.160

marco@d9400:~$ rvm use ruby-1.9.1
marco@d9400:~$ ruby -v
ruby 1.9.1p378 (2010-01-10 revision 26273) [x86_64-linux]
marco@d9400:~$ ruby RubyMM191_3.rb

Warming up...
Strings test - Elapsed 2.452
Check1: 50000
Check2: 157490
Check3: 50005
Check4: 373847
Arrays test - Elapsed 4.488
Check1: 20900
Check2: 250000
Check3: 250000
Check4: 1500000
Check5: 5749950
Numeric test - Elapsed 1.840
Check1: 6252500
Check2: 1439295494700374021157505910939096377494040420940312
Ruby Partial elapsed time 8.780

1. Starting Ruby tests...
Strings test - Elapsed 2.314
Arrays test - Elapsed 4.679
Numeric test - Elapsed 1.843
Ruby Partial elapsed time 8.836

2. Starting Ruby tests...
Strings test - Elapsed 2.319
Arrays test - Elapsed 4.691
Numeric test - Elapsed 1.843
Ruby Partial elapsed time 8.853

3. Starting Ruby tests...
Strings test - Elapsed 2.318
Arrays test - Elapsed 4.705
Numeric test - Elapsed 1.847
Ruby Partial elapsed time 8.870
-------------------------------------
Average Strings test - Elapsed 2.317
Average Arrays test - Elapsed 4.692
Average Numeric test - Elapsed 1.844

Ruby Average elapsed time 8.853

marco@d9400:~$ rvm use ruby-1.9.2
marco@d9400:~$ ruby -v
ruby 1.9.2p0 (2010-08-18 revision 29036) [x86_64-linux]
marco@d9400:~$ ruby RubyMM191_3.rb

Warming up...
Strings test - Elapsed 1.680
Check1: 50000
Check2: 157490
Check3: 50005
Check4: 373847
Arrays test - Elapsed 4.192
Check1: 20900
Check2: 250000
Check3: 250000
Check4: 1500000
Check5: 5749950
Numeric test - Elapsed 1.708
Check1: 6252500
Check2: 1439295494700374021157505910939096377494040420940312
Ruby Partial elapsed time 7.579

1. Starting Ruby tests...
Strings test - Elapsed 1.654
Arrays test - Elapsed 3.178
Numeric test - Elapsed 1.704
Ruby Partial elapsed time 6.536

2. Starting Ruby tests...
Strings test - Elapsed 1.746
Arrays test - Elapsed 3.388
Numeric test - Elapsed 1.699
Ruby Partial elapsed time 6.833

3. Starting Ruby tests...
Strings test - Elapsed 1.644
Arrays test - Elapsed 3.227
Numeric test - Elapsed 1.706
Ruby Partial elapsed time 6.577
-------------------------------------
Average Strings test - Elapsed 1.681
Average Arrays test - Elapsed 3.264
Average Numeric test - Elapsed 1.703

Ruby Average elapsed time 6.649

 
Comments Off

Posted in JRuby, Ruby

 

Creare scheletri di applicazioni con generatori e template

20 Mar

Ultima modifica 01/04/2010

Rails è un meraviglioso strumento che permette di realizzare agevolmente, un’applicazione secondo gli standard moderni. Tuttavia, quando se ne crea una nuova, è necessario eseguire diverse operazioni alquanto noiose: aggiungere plugins o gemme, il recupero di un layout di partenza e tutto ciò che di solito usate nelle vostre applicazioni.
Per risolvere questo problema, dalla versione 2.3 è possibile utilizzare i templates, modelli con cui è possibile diversificare la creazione di scheletri di applicazioni. Si trovano molti esempi su internet, io ne presento uno che mostra i vantaggi in combinazione con un generatore personalizzato per le proprie esigenze. Questa guida spiega come creare un generatore. Se siete impazienti potete partire da qualcosa di già fatto come ho fatto io. Ho personalizzato il nifty-generators di Ryan Bates aggiungendo alcune nuove caratteristiche:

  • Layout: ora supporta stili multipli: classic, cloudy and blackwhite. Niente di che, solo una base da sviluppare
  • Layout: ho inserito il file di configurazione config.rb, contenitore delle costanti applicative come il nome dell’applicazione, lo stile di default ecc.
  • Ho introdotto la localizzazione: il nifty_layout aggiunge i files yaml per la lingua en e it. Nell’application controller viene inserito del codice per la gestione, con il parametro lang si cambia l’impostazione della lingua (esempio ?lang=it) che verrà mantenuta per tutta la sessione. Il nifty_scaffold aggiunge le risorse e i suoi attributi, pronti per essere tradotti.
  • nifty_layout: la div per i messaggi è stata spostata dentro un partial nella cartella shared. Ho preferito fare questo per poterla utilizzare anche tramite ajax
  • nifty_scaffold: le views new e edit, ora utilizzano due partial: render @model che a sua volta richiama il secondo con all’interno i campi. Come la versione originale, supporta haml e sass ed ho aggiunto il supporto a formtastic potendo quindi scegliere la combinazione preferita!

La nuova versione del nifty-generators è scaricata dal template che vi mostrerò, comunque, questi sono i sorgenti, qua invece, potete scaricare l’ultima versione della gemma e del template.

Cos’è che dovrebbe fare il generatore e cosa il template?
Beh, i templates dovrebbero essere un contenitore di operazioni da compiere, eseguiti nella fase di creazione di un nuovo progetto. Con i generatori invece, è possibile fare quasi tutto. In genere, si aggiungono nuove funzionalità o si personalizza qualcosa che già esiste. Può essere eseguito ogni volta che si vuole da riga di comando e naturalmente, richiamato all’interno di un template.

Chi non ha mai usato un template, potrebbe iniziare con un semplice esempio o meglio, con un tutorial:
questo screencast mostra come destreggiarsi e questo invece, è un articolo in html.

I molti esempi che ho visto su internet sono spesso pieni di parametri di configurazione che mi fan venire dei grossi mal di testa. Io invece ho preferito che mi venisse chiesto cosa voglio. Sicuramente, non è ancora perfetto, ma penso che sia una buona base :

#This is a Rails 2.3 template
#Written by Marco Mastrodonato, last update on 01/04/2010 
#
# USAGE: rails yourapp -m template.rb
 
#This is the unique parameter, after first execution use FALSE to avoid installation
install_gems = false
git_http = true
 
WINDOWS = (RUBY_PLATFORM =~ /dos|win32|cygwin/i) || (RUBY_PLATFORM =~ /(:?mswin|mingw)/) 
 
#plugin/install doesn't work on my windows systems
def myplugin(name, url)
  url.sub! 'git://', 'http://' if git_http
  if WINDOWS
    #run "ruby script/plugin install #{url}"
    run "git clone #{url} vendor/plugins/#{name}"
  else
    plugin name, :git => url
  end
end
 
puts '*' * 40
puts "* Processing template#{WINDOWS ? ' on windows system': ''}..."
puts '*' * 40
 
use_git = yes?("Do you think to use git ?")
if use_git
  git :init
  file ".gitignore", <<-EOS.gsub(/^    /, '')
    .DS_Store
    log/*.log
    tmp/**/*
    config/database.yml
    db/*.sqlite3
    nbproject/*
  EOS
end
 
#Everyone must to have it!
plugin 'will_paginate',
        :git => "git://github.com/mislav/will_paginate.git" if yes?("Will Paginate ?")
 
# Attachments with no extra database tables, only one library to install for image processing
plugin 'paperclip',
       :git => "git://github.com/thoughtbot/paperclip.git" if yes?("Paperclip ?")
 
formtastic = yes?("Formtastic ?")
if formtastic
  #gem 'justinfrench-formtastic', :lib => 'formtastic', :source => 'http://gems.github.com'
  #rake "gems:install" if install_gem
 
  #A Rails FormBuilder DSL (with some other goodies) to make it far easier to create beautiful, semantically rich, syntactically awesome, readily stylable and wonderfully accessible HTML forms in your Rails applications.
  plugin 'formtastic',
        :git => "git://github.com/justinfrench/formtastic.git"
  #Adds reflective access to validations
  plugin 'validation_reflection',
        :git => "git://github.com/redinger/validation_reflection.git"
  generate "formtastic"
end
 
if yes?("Add testing framework ?")
  # RSpec's official Ruby on Rails plugin  
  plugin 'rspec', 
    :git => 'git://github.com/dchelimsky/rspec.git'
 
  plugin 'rspec-rails',
         :git => "git://github.com/dchelimsky/rspec-rails.git"
  generate "rspec"
 
  # BDD that talks to domain experts first and code 2nd
  plugin 'cucumber',
         :git => "git://github.com/aslakhellesoy/cucumber.git"
end
 
if yes?("Add authentication ?")
  puts "0. None"
  puts "1. Devise/warden"
  puts "2. Authlogic"
  puts "3. Restful authentication"
  choose = ask("Choose one:")
  case choose
    when "1"
      gem "warden", :version => "0.9.6"
      gem "devise", :version => "1.0.4"
      rake "gems:install" if install_gems
      generate "devise_install"
      generate "devise", "User"
      generate "devise_views"
      #User.create!(:email => 'admin@administrator.com', :password => 'secret')
    when "2"
      gem "authlogic"
      rake "gems:install" if install_gems
      generate "session", "user_session"
      generate "model", "user"
      generate "controller", "user_sessions"
      route "map.resource :user_session"
      create_users_file = Dir['db/migrate/*_create_users.rb'].first
      file create_users_file, <<-EOS.gsub(/^        /, '')
        class CreateUsers < ActiveRecord::Migration
          def self.up
            create_table :users do |t|
              t.string    :login,               :null => false                # optional, you can use email instead, or both
              t.string    :email,               :null => false                # optional, you can use login instead, or both
              t.string    :crypted_password,    :null => false                # optional, see below
              t.string    :password_salt,       :null => false                # optional, but highly recommended
              t.string    :persistence_token,   :null => false                # required
              t.string    :single_access_token, :null => false                # optional, see Authlogic::Session::Params
              t.string    :perishable_token,    :null => false                # optional, see Authlogic::Session::Perishability
 
              # Magic columns, just like ActiveRecord's created_at and updated_at. These are automatically maintained by Authlogic if they are present.
              t.integer   :login_count,         :null => false, :default => 0 # optional, see Authlogic::Session::MagicColumns
              t.integer   :failed_login_count,  :null => false, :default => 0 # optional, see Authlogic::Session::MagicColumns
              t.datetime  :last_request_at                                    # optional, see Authlogic::Session::MagicColumns
              t.datetime  :current_login_at                                   # optional, see Authlogic::Session::MagicColumns
              t.datetime  :last_login_at                                      # optional, see Authlogic::Session::MagicColumns
              t.string    :current_login_ip                                   # optional, see Authlogic::Session::MagicColumns
              t.string    :last_login_ip                                      # optional, see Authlogic::Session::MagicColumns
 
              t.timestamps
            end
 
            add_index :users, :email
            add_index :users, :login, :unique => true
          end
 
          def self.down
            drop_table :users
          end
        end
      EOS
      file 'app/models/user.rb', <<-EOS.gsub(/^        /, '')
        class User < ActiveRecord::Base
          acts_as_authentic
        end
      EOS
      file 'spec/models/user_spec.rb', <<-EOS.gsub(/^        /, '')
        require 'spec_helper'
 
        describe User do
          before(:each) do
            @valid_attributes = {
              :login                 => "login",
              :email                 => "some@thing.com",
              :password              => "password",
              :password_confirmation => "password"
            }
          end
 
          it "should create a new instance given valid attributes" do
            User.create!(@valid_attributes)
          end
        end
      EOS
    when "3"
      plugin 'restful-authentication-i18n',
          :git => "git://github.com/dcrec1/restful-authentication-i18n.git"
      #—include-activation \ —stateful \ —rspec \ —skip-migration \ —skip-routes \ —old-passwords 
      generate "authenticated", "user", "sessions", "—include-activation"
  end
 
  if yes?("Authorization ?")
    gem "cancan"
    rake "gems:install" if install_gems
    #plugin 'cancan', :git => "git://github.com/ryanb/cancan.git" 
    file 'spec/models/ability.rb', <<-EOS.gsub(/^      /, '')
      class Ability  
        include CanCan::Ability  
 
        def initialize(user)  
          user ||= User.new # Guest user  
          if user.role? :admin  
            can :manage, :all  
          else  
            can :read, :all  
          end  
        end  
      end  
    EOS
    generate "migration", "add_roles_mask_to_users roles_mask:integer"
    puts "Add these lines to user model:"
    puts <<-EOS.gsub(/^      /, '')
      named_scope :with_role, lambda { |role| {:conditions => "roles_mask & \#{2**ROLES.index(role.to_s)} > 0 "} }
      def roles=(roles)
        self.roles_mask = (roles & ROLES).map { |r| 2**ROLES.index(r) }.sum
      end
      def roles
        ROLES.reject { |r| ((roles_mask || 0) & 2**ROLES.index(r)).zero? }
      end
      def role_symbols
        roles.map(&:to_sym)
      end
    EOS
 
  end
 
end          
 
haml = yes?("Haml?")
if haml
  # The world's greatest templating system
  #plugin 'haml', :git => "git://github.com/nex3/haml.git"
  gem "haml", :lib => "haml"
  rake "gems:install" if install_gems
  run "haml --rails ."
end
 
if yes?("Layout ?")
  plugin "marcomd-nifty-generators", 
    :lib => "marcomd-nifty-generators",
    :git => "git://github.com/marcomd/nifty-generators.git"
  puts " 1. classic"
  puts " 2. cloudy"
  puts " 3. blackwhite"
  puts "or. write names separed by space"
  style = ask("Choose style:")
  style = case style
    when "1" then "classic"
    when "2" then "cloudy"
    when "3" then "blackwhite"
    else style
  end
  generate "nifty_layout", "application #{style} #{haml ? '--haml' : ''} #{formtastic ? '--formtastic' : ''}"
end
 
# Link to local copy of edge rails
#inside('vendor') { run 'ln -s ~/dev/rails/rails rails' } if yes?("Rails ?")
rake("rails:freeze:gems") if yes?("Freeze rails gems ?")
 
# Mailer dummy config
initializer "mailer.rb", <<-EOS.gsub(/^  /, '')
  mailer_options = YAML.load_file("\#{Rails.root}/config/mailer.yml")
  ActionMailer::Base.smtp_settings = mailer_options
EOS
file "config/mailer.yml", <<-EOS.gsub(/^  /, '')
  :address: mail.authsmtp.com
  :domain: yourdomain.com
  :authentication: :login
  :user_name: USERNAME
  :password: PASSWORD
EOS
 
if yes?("Generate controller home ? (suggested)")
  generate "controller", "home", "index"
  route "map.root :controller => :home"
else
 
end
 
rake "gems:install" if install_gems
# Unpack all gems to vendor/gems
rake "gems:unpack" if yes?("Unpack to vendor/gems ?")
rake "db:create:all"
rake "db:migrate"
File.unlink "public/index.html"
 
git :add => ".", :commit => "-m 'initial commit'" if use_git
 
puts "ENJOY!"

Questo è uno dei possibili risultati:


marco@d9400:~/Rails$ rails Blog -m marcomd.rb
create bla bla bla
applying template: marcomd.rb
Processing template...
plugin will_paginate
Unpacking objects: 100% (57/57), done.
From git://github.com/mislav/will_paginate
* branch HEAD -> FETCH_HEAD
Paperclip ?
y
plugin paperclip
Unpacking objects: 100% (78/78), done.
From git://github.com/thoughtbot/paperclip
* branch HEAD -> FETCH_HEAD
Formtastic ?
y
gem justinfrench-formtastic
generating formtastic_stylesheets
Add testing framework ?
y
plugin rspec
From git://github.com/dchelimsky/rspec
* branch HEAD -> FETCH_HEAD
plugin rspec-rails
From git://github.com/dchelimsky/rspec-rails
* branch HEAD -> FETCH_HEAD
plugin cucumber
From git://github.com/aslakhellesoy/cucumber
* branch HEAD -> FETCH_HEAD
Add authentication ?
y
0. None
1. Devise/warden
2. Authlogic
3. Restful authentication
Choose one:
1
gem warden
gem devise
generating devise_install
Authorization ?
n
Haml?
n
Layout ?
y
plugin marcomd-nifty-generators
From git://github.com/marcomd/nifty-generators
* branch HEAD -> FETCH_HEAD
1. classic
2. cloudy
3. blackwhite
or. write names separed by space
Choose style:
2
generating nifty_layout
Freeze rails gems ?
n
initializer mailer.rb
file config/mailer.yml
Generate controller home ? (suggested)
y
generating controller
route map.root :controller => :home
Unpack to vendor/gems ?
n
rake db:create:all
rake db:migrate
ENJOY!
applied marcomd.rb

Ecco fatto, ora avviamo mongrel


marco@d9400:~/Rails$ cd Blog/
marco@d9400:~/Rails/Blog$ script/server

=> Booting Mongrel
=> Rails 2.3.5 application starting on http://0.0.0.0:3000
=> Call with -d to detach
=> Ctrl-C to shutdown server

http://localhost:3000 e controlliamo il nostro nuovo blog

This is only the beginning

Ora aggiungiamo una risorsa e lanciamo la migrate per allineare il db:


marco@d9400:~/Rails$ cd Blog/
marco@d9400:~/Rails/Blog$ script/generate nifty_scaffold post title:string body:text

exists app/models
create app/models/post.rb
exists db/migrate
create db/migrate/20100319175545_create_posts.rb
exists test/unit
create test/unit/post_test.rb
exists test/fixtures
create test/fixtures/posts.yml
exists app/controllers
create app/controllers/posts_controller.rb
exists app/helpers
create app/helpers/posts_helper.rb
create app/views/posts
create app/views/posts/index.html.erb
create app/views/posts/show.html.erb
create app/views/posts/new.html.erb
create app/views/posts/edit.html.erb
create app/views/posts/_post.html.erb
create app/views/posts/_fields.html.erb
route map.resources :posts
exists test/functional
create test/functional/posts_controller_test.rb

marco@d9400:~/Rails/Blog$ rake db:migrate

(in /home/marco/Rails/Blog)
== CreatePosts: migrating ====================================================
-- create_table(:posts)
-> 0.0016s
== CreatePosts: migrated (0.0017s) ===========================================

Add post resource

I controllers e le viste usano messaggi localizzati, per questo motivo i nomi delle risorse devono essere aggiunti all’interno degli yaml. Dalla versione 0.3.2.3 nifty_scafold lo fa per voi, dovete pensare solo alla traduzione. Tenete presente inoltre, che se per esempio distruggete una risorsa deve essere rimossa dagli yaml manualmente.

#config/locales/en.yml
en:
  activerecord:
    models: &models
      post: "Post"
      posts: "Posts"
    #DO NOT REMOVE MODELS
    attributes: &attributes
      title: "Title"
      body: "Body"
    #DO NOT REMOVE ATTRIBUTES
 
  formtastic:
    titles:
    labels:
    hints:
      post:
        title: "Choose a good title for your article"
        body: "Choose a good body for your article"
    #DO NOT REMOVE HINTS
    actions: &actions
      create: "Create my {{model}}"
      update: "Save changes"
  <<: *models
  <<: *attributes
  <<: *actions
 
#config/locales/it.yml
it:
  activerecord:
    models: &models
      post: "Messaggio"
      posts: "Messaggi"
    #DO NOT REMOVE MODELS
    attributes: &attributes
      title: "Titolo"
      body: "Corpo"
    #DO NOT REMOVE ATTRIBUTES
 
  formtastic:
    titles:
    labels:
    hints:
      post:
        title: "Choose a good title for your article"
        body: "Choose a good body for your article"
    #DO NOT REMOVE HINTS
    actions: &actions
      create: "Crea {{model}}"
      update: "Salva le modifiche"
  #DO NOT REMOVE FORMTASTIC
  <<: *models
  <<: *attributes
  <<: *actions

Ho usato dei commenti del tipo: #DO NOT REMOVE ecc. per posizionare i nomi delle risorse o degli attributi nelle posizioni corrette, per cui è necessario non rimuoverli.

Messaggio creato con successo

Ho da poco iniziato a testare la versione haml e sass per cui potrebbero esserci ancora dei bachi.
Spero che questo articolo possa essere stato utile, buon divertimento!

 
Comments Off

Posted in Ruby on Rails

 

Ruby vs Python vs Windows vs Linux

05 Mar

Nel precedente articolo, ho esaminato le prestazioni di alcuni interpreti ruby e python, su un sistema windows xp. Questa volta, ho eseguito gli stessi script sotto linux: distribuzione ubuntu 9.10 2.6.31-20-generic. Le versioni APT sono state installate tramite gestore di pacchetti, le RVM invece, tramite il Ruby Version Manager e compilate dai sorgenti.

Versione Compilatore/Sistema/VM Secondi
JRuby 1.4.0 APT Java HotSpot(TM) 64-Bit Server VM 1.6.0_16) [amd64-java] 6,1
JRuby 1.4.0 RVM Java HotSpot(TM) 64-Bit Server VM 1.6.0_16) [amd64-java] 6,2
Ruby 1.9.2 preview1 RVM x86_64-linux 6,5
JRuby 1.4.0 Windows Client VM 1.6.0_15 [x86-java] 6,9
Python 2.6.4 Windows 7,5
Ruby 1.9.1 p129 i386-mingw32 8,1
Python 2.6.4 APT x86_64-linux 8,7
Ruby 1.9.1 p378 RVM x86_64-linux 8,7
Ruby 1.9.1 p243 RVM x86_64-linux 8,8
Python 3.1.1 Windows 9,0
Ruby 1.9.1 p243 APT x86_64-linux 9,3
Ruby 1.9.1 p243 i386-mingw32 9,6
Ruby 1.8.7 p249 RVM x86_64-linux 12,2
IronRuby 0.9.3.0 Windows .NET 2.0.0.0 18,9
Ruby 1.9.1 p376 i386-mswin32 20,8
Ruby 1.8.7 p174 APT x86_64-linux 23,0
Ruby 1.8.6 p368 i386-mingw32 23,3
Ruby 1.8.7 p249 i386-mingw32 23,9
IronPython 2.6 Windows .NET 2.0.0.0 256,5
Jython 2.5.1 Windows Client VM 1.6.0_15 [x86-java] Timeout

Win vs Linux

Win vs Linux

 

Ruby vs Ruby vs Python vs Python

24 Jan

Un altro benchmark che mette a confronto alcune recenti versioni di ruby con gli ultimi rilasci di python. Due semplici script per confrontare sintassi e prestazioni di questi moderni linguaggi.
Il sistema su cui ho eseguito la prova è un portatile Dell Inspiron 9400 con Centrino Duo, Intel T7200 4Mb Cache 2Ghz, Ram 2Gb 667Mhz. Sistema operativo Windows XP pro SP3.

Questo è il risultato del primo test, usato come riscaldamento per le vm:

Versione Compilatore Secondi
Python 2.6.4 7,5
Ruby 1.9.1 p129 i386-mingw32 8,2
JRuby 1.4.0 Client VM 1.6.0_15 [x86-java] 9,0
Python 3.1.1 9,1
Ruby 1.9.1 p243 i386-mingw32 9,6
IronRuby 0.9.3.0 .NET 2.0.0.0 20,3
Ruby 1.9.1 p376 i386-mswin32 20,9
Ruby 1.8.6 p368 i386-mingw32 22,9
IronPython 2.6 .NET 2.0.0.0 225,4
Jython 2.5.1 Client VM 1.6.0_15 [x86-java] Timeout

Benchmark senza warm up

Benchmark senza warm up

Il risultato che segue invece, si riferisce alla media delle tre rilevazioni successive al riscaldamento. Le prestazioni di JRuby migliorano del 23%:

Versione Compilatore Secondi
JRuby 1.4.0 Client VM 1.6.0_15 [x86-java] 6,9
Python 2.6.4 7,5
Ruby 1.9.1 p129 i386-mingw32 8,2
Python 3.1.1 9,0
Ruby 1.9.1 p243 i386-mingw32 10,0
IronRuby 0.9.3.0 .NET 2.0.0.0 18,9
Ruby 1.9.1 p376 i386-mswin32 20,6
Ruby 1.8.6 p368 i386-mingw32 23,2
IronPython 2.6 .NET 2.0.0.0 256,5
Jython 2.5.1 Client VM 1.6.0_15 [x86-java] Timeout

Rilevazioni dopo warm up

Rilevazioni dopo warm up

Ed ecco gli script. Ho cercato di ottimizzare le rispettive versioni e per fare ciò, ho dovuto creare due varianti per ogni linguaggio.

Ruby 1.8.6:

def strings_test(ntest)
  r1 = r2 = r3 = 0
  xstr = ""
  ntest.times do 
    #Create a string, add 'abcde1234_' until getting a str size 1000
    xstr = 'abcde1234_' * 10000
 
    #Make letters upcase 
    xstr.upcase!
 
    #Change '1234_' with '67890 ' (space at last position)
    #Now the repeated string should be 'ABCDE67890 '
    xstr.gsub! '1234_', '67890 '
 
    #Cast numbers from 29 upto size/2 to string and add it to xstr variable, ciclying for every number (not add all numbers one time)
    29.upto(xstr.size/2) {|n| xstr << n.to_s}
 
    #Check 1: Count 'A' char 
    #Check 2: Count '9' char 
    0.upto(xstr.size-1) do |n| 
      if xstr[n].chr() == 'A'
        r1+=1 
      elsif xstr[n].chr() == '9'
        r2+=1
      end
    end
 
    #Create an array from xstr using space to split
    r3 += xstr.split.size
 
  end
 
  return r1, r2, r3, xstr
end
 
def arrays_test(ntest, xstr)
  r1 = r2 = r3 = r4 = r5 = 0
  ntest.times do 
    #Clear ar then add 5000 times this element: "I", "am", "great", null, "or", "number", 1
    ar =  []
    5000.times do
      ['I', 'am', 'great', nil, 'or', 'number', 1].each {|a| ar << a}
    end
 
    #...then reverse elements to obtain this order: 1, "number", "or", null, "great", "am", "I"
    ar.reverse!
 
    #...then, count the element with value "great" using two separate cicle
    #the first starting from 31 until 2955 (bounty inclused)
    31.upto(2955) do |n|
      r1 += 1 if ar[n] == 'great'
    end
    #the second looping all the array elements
    ar.each {|n| r2+=1 if n == 'great'}
 
    #Loop inside and build a temporary string with index and value, without put it into a variable and only for elements <> null
    ar.each_index{|i| ar[i] ? "#{i} #{ar[i]}" : r3+=1 }
 
    #delete null value elements and take its size
    ar.compact!
    r4 += ar.size
 
    #then join elements with space and take its size
    r5 += ar.join(' ').size
 
  end
 
  return r1, r2, r3, r4, r5
end
 
def nums_test(ntest)
  r1 = r2 = 0
 
  ntest.times do 
    #Find all prime numbers from 8 to 95 step by 3 and sum all primes got, to check the result
    #51.upto(307) do |n| 
    (8..95).step(3) do |n|
      primes(n).each {|a| r1 += a}
    end
 
    #Calculate factorial numbers start from 2 to 42
    r2 = 0
    for n in 2..42
      r2 += fac(n)
    end
  end
 
  return r1, r2
end
 
#Primes must return an array of prime numbers
def primes(n)
  ar = []
  for x in (2..n)
    prime = true
    for y in (2..x-1)
      if x%y == 0
        prime = false
        break
      end
    end
    ar << x if prime
  end
  return ar
end
 
def fac(n) (1..n).inject{|total, current| total * current} end
 
# ---  START  ---
puts "\nWarming up..."
t1=t2=t3=0
time = Time.now
r1, r2, r3, xstr = strings_test(5)
puts "Strings test - Elapsed %.3f" % (p1=Time.now - time)
puts "Check1: #{r1}"
puts "Check2: #{r2}"
puts "Check3: #{r3}"
puts "Check4: #{xstr.size}"
 
time = Time.now
r1, r2, r3, r4, r5 = arrays_test(50, xstr)
puts "Arrays test  - Elapsed %.3f" % (p2=Time.now - time)
puts "Check1: #{r1}"
puts "Check2: #{r2}"
puts "Check3: #{r3}"
puts "Check4: #{r4}"
puts "Check5: #{r5}"
 
time = Time.now
r1, r2 = nums_test(500)
puts "Numeric test - Elapsed %.3f" % (p3=Time.now - time)
puts "Check1: #{r1}"
puts "Check2: #{r2}"
 
puts "Ruby Partial elapsed time %.3f" % (p1+p2+p3)
 
puts "\n1. Starting Ruby tests..."
 
time = Time.now
r1, r2, r3, xstr = strings_test(5)
puts "Strings test - Elapsed %.3f" % (p1=Time.now - time)
 
time = Time.now
r1, r2, r3, r4, r5 = arrays_test(50, xstr)
puts "Arrays test  - Elapsed %.3f" % (p2=Time.now - time)
 
time = Time.now
r1, r2 = nums_test(500)
puts "Numeric test - Elapsed %.3f" % (p3=Time.now - time)
 
puts "Ruby Partial elapsed time %.3f" % (p1+p2+p3)
t1+=p1;t2+=p2;t3+=p3
 
puts "\n2. Starting Ruby tests..."
 
time = Time.now
r1, r2, r3, xstr = strings_test(5)
puts "Strings test - Elapsed %.3f" % (p1=Time.now - time)
 
time = Time.now
r1, r2, r3, r4, r5 = arrays_test(50, xstr)
puts "Arrays test  - Elapsed %.3f" % (p2=Time.now - time)
 
time = Time.now
r1, r2 = nums_test(500)
puts "Numeric test - Elapsed %.3f" % (p3=Time.now - time)
 
puts "Ruby Partial elapsed time %.3f" % (p1+p2+p3)
t1+=p1;t2+=p2;t3+=p3
 
puts "\n3. Starting Ruby tests..."
 
time = Time.now
r1, r2, r3, xstr = strings_test(5)
puts "Strings test - Elapsed %.3f" % (p1=Time.now - time)
 
time = Time.now
r1, r2, r3, r4, r5 = arrays_test(50, xstr)
puts "Arrays test  - Elapsed %.3f" % (p2=Time.now - time)
 
time = Time.now
r1, r2 = nums_test(500)
puts "Numeric test - Elapsed %.3f" % (p3=Time.now - time)
 
puts "Ruby Partial elapsed time %.3f" % (p1+p2+p3)
t1+=p1;t2+=p2;t3+=p3
 
puts "-------------------------------------"
puts "Average Strings test - Elapsed %.3f" % (t1/3)
puts "Average Arrays test  - Elapsed %.3f" % (t2/3)
puts "Average Numeric test - Elapsed %.3f" % (t3/3)
puts "\nRuby Average elapsed time %.3f" % (t1/3+t2/3+t3/3)

Ruby 1.9.1:

def strings_test(ntest)
  r1 = r2 = r3 = 0
  xstr = ""
  ntest.times do 
    #Create a string, add 'abcde1234_' until getting a str size 1000
    xstr = 'abcde1234_' * 10000
 
    #Make letters upcase 
    xstr.upcase!
 
    #Change '1234_' with '67890 ' (space at last position)
    #Now the repeated string should be 'ABCDE67890 '
    xstr.gsub! '1234_', '67890 '
 
    #Cast numbers to string, from 29 up to size/2. Add it to xstr variable as well, ciclying for every number (not adding all numbers once)
    29.upto(xstr.size/2) {|n| xstr << n.to_s}
 
    #Check 1: Count 'A' char 
    #Check 2: Count '9' char 
    0.upto(xstr.size-1) do |n| 
      if xstr[n] == 'A'
        r1+=1 
      elsif xstr[n] == '9'
        r2+=1
      end
    end
 
    #Create an array from xstr using space to split, its size is the third check
    r3 += xstr.split.size
 
  end
 
  return r1, r2, r3, xstr
end
 
def arrays_test(ntest, xstr)
  r1 = r2 = r3 = r4 = r5 = 0
  ntest.times do 
    #Clear ar then add 5000 times this element: "I", "am", "great", null, "or", "number", 1
    ar =  []
    5000.times do
      ['I', 'am', 'great', nil, 'or', 'number', 1].each {|a| ar << a}
    end
 
    #...then reverse elements to obtain this order: 1, "number", "or", null, "great", "am", "I"
    ar.reverse!
 
    #...then, count the element with value "great" using two separate cicle
    #the first starting from 31 until 2955 (bounty inclused)
    31.upto(2955) do |n|
      r1 += 1 if ar[n] == 'great'
    end
    #the second looping all the array elements
    ar.each {|n| r2+=1 if n == 'great'}
 
    #Loop inside and build a temporary string with index and value, without put it into a variable and only for elements <> null
    ar.each_index{|i| ar[i] ? "#{i} #{ar[i]}" : r3+=1 }
 
    #delete null value elements and take its size
    ar.compact!
    r4 += ar.size
 
    #then join elements with space and take its size
    r5 += ar.join(' ').size
 
  end
 
  return r1, r2, r3, r4, r5
end
 
def nums_test(ntest)
  r1 = r2 = 0
 
  ntest.times do 
    #Find all prime numbers from 8 to 95 step by 3 (bounds included) and sum all primes got, to check the result
    #51.upto(307) do |n| 
    (8..95).step(3) do |n|
      primes(n).each {|a| r1 += a}
    end
 
    #Calculate factorial numbers start from 2 to 42
    r2 = 0
    for n in 2..42
      r2 += fac(n)
    end
  end
 
  return r1, r2
end
 
#Primes must return an array of prime numbers
def primes(n)
  ar = []
  for x in (2..n)
    prime = true
    for y in (2..x-1)
      if x%y == 0
        prime = false
        break
      end
    end
    ar << x if prime
  end
  return ar
end
 
def fac(n) (1..n).inject{|total, current| total * current} end
 
# ---  START  ---
puts "\nWarming up..."
t1=t2=t3=0
time = Time.now
r1, r2, r3, xstr = strings_test(5)
puts "Strings test - Elapsed %.3f" % (p1=Time.now - time)
puts "Check1: #{r1}"
puts "Check2: #{r2}"
puts "Check3: #{r3}"
puts "Check4: #{xstr.size}"
 
time = Time.now
r1, r2, r3, r4, r5 = arrays_test(50, xstr)
puts "Arrays test  - Elapsed %.3f" % (p2=Time.now - time)
puts "Check1: #{r1}"
puts "Check2: #{r2}"
puts "Check3: #{r3}"
puts "Check4: #{r4}"
puts "Check5: #{r5}"
 
time = Time.now
r1, r2 = nums_test(500)
puts "Numeric test - Elapsed %.3f" % (p3=Time.now - time)
puts "Check1: #{r1}"
puts "Check2: #{r2}"
 
puts "Ruby Partial elapsed time %.3f" % (p1+p2+p3)
 
puts "\n1. Starting Ruby tests..."
 
time = Time.now
r1, r2, r3, xstr = strings_test(5)
puts "Strings test - Elapsed %.3f" % (p1=Time.now - time)
 
time = Time.now
r1, r2, r3, r4, r5 = arrays_test(50, xstr)
puts "Arrays test  - Elapsed %.3f" % (p2=Time.now - time)
 
time = Time.now
r1, r2 = nums_test(500)
puts "Numeric test - Elapsed %.3f" % (p3=Time.now - time)
 
puts "Ruby Partial elapsed time %.3f" % (p1+p2+p3)
t1+=p1;t2+=p2;t3+=p3
 
puts "\n2. Starting Ruby tests..."
 
time = Time.now
r1, r2, r3, xstr = strings_test(5)
puts "Strings test - Elapsed %.3f" % (p1=Time.now - time)
 
time = Time.now
r1, r2, r3, r4, r5 = arrays_test(50, xstr)
puts "Arrays test  - Elapsed %.3f" % (p2=Time.now - time)
 
time = Time.now
r1, r2 = nums_test(500)
puts "Numeric test - Elapsed %.3f" % (p3=Time.now - time)
 
puts "Ruby Partial elapsed time %.3f" % (p1+p2+p3)
t1+=p1;t2+=p2;t3+=p3
 
puts "\n3. Starting Ruby tests..."
 
time = Time.now
r1, r2, r3, xstr = strings_test(5)
puts "Strings test - Elapsed %.3f" % (p1=Time.now - time)
 
time = Time.now
r1, r2, r3, r4, r5 = arrays_test(50, xstr)
puts "Arrays test  - Elapsed %.3f" % (p2=Time.now - time)
 
time = Time.now
r1, r2 = nums_test(500)
puts "Numeric test - Elapsed %.3f" % (p3=Time.now - time)
 
puts "Ruby Partial elapsed time %.3f" % (p1+p2+p3)
t1+=p1;t2+=p2;t3+=p3
 
puts "-------------------------------------"
puts "Average Strings test - Elapsed %.3f" % (t1/3)
puts "Average Arrays test  - Elapsed %.3f" % (t2/3)
puts "Average Numeric test - Elapsed %.3f" % (t3/3)
puts "\nRuby Average elapsed time %.3f" % (t1/3+t2/3+t3/3)

Python 2.6:

from time import time
#import psyco
#psyco.full()
#psyco.full(memory=100)
#psyco.profile(0.05, memory=100)
#psyco.profile(0.2)
 
 
def strings_test(ntest):
  r1 = r2 = r3 = 0
  xstr = ""
  for x in xrange(ntest):
    #Create a string, add 'abcde1234_' until getting a xstr size 1000
    xstr = 'abcde1234_' * 10000
 
    #Make letters upcase 
    xstr = xstr.upper()
 
    #Change '1234_' with '67890 ' (space at last position)
    #Now the repeated string should be 'ABCDE67890 '
    xstr = xstr.replace('1234_', '67890 ')
 
    #Cast numbers to string, from 29 up to size/2. Add it to xstr variable as well, ciclying for every number (not adding all numbers once)
    for y in xrange(29,int(len(xstr)/2) + 1):
        xstr += "%s" %y
 
    #Result 1: Count 'A' char 
    #Result 2: Count '9' char 
    for y in xrange(0, len(xstr)):
      if xstr[y] == 'A':
        r1+=1 
      elif xstr[y] == '9':
        r2+=1
 
    #Create an array from xstr using space to split
    r3 += len(xstr.split())
 
 
  return r1, r2, r3, xstr
 
#Slower than other version
def multiremove(ar, what):
  i = 0
  for el in ar:
    if el == what:
      del ar[i]
    i+=1
 
#Ugly but a bit faster
def multiremove2(ar, what):
  todel = [] 
  for y in xrange(0,len(ar)):
    if ar[y] == what:
       todel.append(y)
  todel.reverse()
  for y in todel:
     ar.pop(y)
 
def arrays_test(ntest, xstr):
  r1 = r2 = r3 = r4 = r5 = 0
  for x in xrange(ntest):
    #Clear ar then add 5000 times this element: "I", "am", "great", null, "or", "number", 1
    ar = []
    for y in xrange(0, 5000):
      ar.extend(["I", "am", "great", None, "or", "number", 1])
 
    #...then reverse elements to obtain this order: 1, "number", "or", null, "great", "am", "I"
    ar.reverse()
 
    #...then, count the element with value "great" using two separate cicle
    #the first starting from 31 until 2955 (bounty included)
    for y in xrange(31,2955):
      if ar[y] == "great": r1 +=1
 
    #the second looping all the array elements
    for y in xrange(0, len(ar)):
      if ar[y] == "great": r2+=1
 
    #Loop inside and build a temporary string with index and value, without put it into a variable and only for elements <> null
    for y in xrange(0, len(ar)):
      if ar[y]:
        "%s %s" %(y, ar[y])
      else:
        r3+=1
 
    #delete null value elements and take its size
    multiremove2(ar, None)
    r4 += len(ar)
 
    #then join elements with space and take its size
    r5 += len(" ".join(str(n) for n in ar))
 
  return r1, r2, r3, r4, r5
 
def nums_test(ntest):
  r1 = r2 = 0
  for x in xrange(ntest):
    #Find all prime numbers from 8 to 95 step by 3 (bounds included) and sum all primes got, to check the result
    for n in xrange(8, 96, 3):
      for prime in primes(n):
        r1 += prime
    fac = lambda n:[1,0][n>0] or fac(n-1)*n
    #Calculate factorial numbers start from 2 to 42 (bounds included)
    r2 = 0
    for n in xrange(2, 43):
      r2 += fac(n)
 
  return r1, r2
 
#Primes must return an array of prime numbers
def primes(n):
  ar = []
  for x in xrange(2, n+1):
    prime = True
    for y in xrange(2, x):
      if x%y == 0:
        prime = False
        break
    if prime:
      ar.append(x)
  return ar
 
# ---  START  ---
print "\nWarming up..."
t1=t2=t3=0
stime = time()
r1, r2, r3, xstr = strings_test(5)
p1=time() - stime
print "Strings test - Elapsed %.3f" % (p1)
print "Check1: %s" %r1
print "Check2: %s" %r2
print "Check3: %s" %r3
print "Check4: %d" %(len(xstr))
 
stime = time()
r1, r2, r3, r4, r5 = arrays_test(50, xstr)
p2=time() - stime
print  "Arrays test - Elapsed %.3f" % (p2)
print "Check1: %s" %r1
print "Check2: %s" %r2
print "Check3: %s" %r3
print "Check4: %s" %r4
print "Check5: %s" %r5
 
stime = time()
r1, r2 = nums_test(500)
p3=time() - stime
print "Numeric test  - Elapsed %.3f" % (p3)
print "Check1: %s" %r1
print "Check2: %s" %r2
 
print  "Python Partial elapsed time %.3f" % (p1+p2+p3)
 
print "\n1. Starting Python tests..."
 
stime = time()
r1, r2, r3, xstr = strings_test(5)
p1=time() - stime
print "Strings test - Elapsed %.3f" % (p1)
 
stime = time()
r1, r2, r3, r4, r5 = arrays_test(50, xstr)
p2=time() - stime
print  "Arrays test  - Elapsed %.3f" % (p2)
 
stime = time()
r1, r2 = nums_test(500)
p3=time() - stime
print "Numeric test - Elapsed %.3f" % (p3)
 
print  "Python Partial elapsed time %.3f" % (p1+p2+p3)
t1+=p1;t2+=p2;t3+=p3
 
print "\n2. Starting Python tests..."
 
stime = time()
r1, r2, r3, xstr = strings_test(5)
p1=time() - stime
print "Strings test - Elapsed %.3f" % (p1)
 
stime = time()
r1, r2, r3, r4, r5 = arrays_test(50, xstr)
p2=time() - stime
print  "Arrays test  - Elapsed %.3f" % (p2)
 
stime = time()
r1, r2 = nums_test(500)
p3=time() - stime
print "Numeric test - Elapsed %.3f" % (p3)
 
print  "Python Partial elapsed time %.3f" % (p1+p2+p3)
t1+=p1;t2+=p2;t3+=p3
 
print "\n3. Starting Python tests..."
 
stime = time()
r1, r2, r3, xstr = strings_test(5)
p1=time() - stime
print "Strings test - Elapsed %.3f" % (p1)
 
stime = time()
r1, r2, r3, r4, r5 = arrays_test(50, xstr)
p2=time() - stime
print  "Arrays test  - Elapsed %.3f" % (p2)
 
stime = time()
r1, r2 = nums_test(500)
p3=time() - stime
print "Numeric test - Elapsed %.3f" % (p3)
 
print  "Python Partial elapsed time %.3f" % (p1+p2+p3)
t1+=p1;t2+=p2;t3+=p3
 
print "-------------------------------------"
print "Average Strings test - Elapsed %.3f" % (t1/3)
print "Average Arrays test  - Elapsed %.3f" % (t2/3)
print "Average Numeric test - Elapsed %.3f" % (t3/3)
print "Python Average elapsed time %.3f" % (t1/3+t2/3+t3/3)

Python 3.1:

from time import time
#import psyco
#psyco.full()
#psyco.full(memory=100)
#psyco.profile(0.05, memory=100)
#psyco.profile(0.2)
 
 
def strings_test(ntest):
  r1 = r2 = r3 = 0
  xstr = ""
  for x in range(ntest):
    #Create a string, add 'abcde1234_' until getting a xstr size 1000
    xstr = 'abcde1234_' * 10000
 
    #Make letters upcase 
    xstr = xstr.upper()
 
    #Change '1234_' with '67890 ' (space at last position)
    #Now the repeated string should be 'ABCDE67890 '
    xstr = xstr.replace('1234_', '67890 ')
 
    #Cast numbers from 29 upto 1028 to string and add it to xstr variable, ciclying for every number (not add all numbers one time)
    for y in range(29,int(len(xstr)/2) + 1):
        xstr += "%s" %y
 
    #Result 1: Count 'A' char 
    #Result 2: Count '9' char 
    for y in range(0, len(xstr)):
      if xstr[y] == 'A':
        r1+=1 
      elif xstr[y] == '9':
        r2+=1
 
    #Create an array from xstr using space to split
    r3 += len(xstr.split())
 
 
  return r1, r2, r3, xstr
 
#Slower than other version
def multiremove(ar, what):
  i = 0
  for el in ar:
    if el == what:
      del ar[i]
    i+=1
 
#Ugly but a bit faster
def multiremove2(ar, what):
  todel = [] 
  for y in range(0,len(ar)):
    if ar[y] == what:
       todel.append(y)
  todel.reverse()
  for y in todel:
     ar.pop(y)
 
def arrays_test(ntest, xstr):
  r1 = r2 = r3 = r4 = r5 = 0
  for x in range(ntest):
    #Clear ar then add 5000 times this element: "I", "am", "great", null, "or", "number", 1
    ar = []
    for y in range(0, 5000):
      ar.extend(["I", "am", "great", None, "or", "number", 1])
 
    #...then reverse elements to obtain this order: 1, "number", "or", null, "great", "am", "I"
    ar.reverse()
 
    #...then, count the element with value "great" using two separate cicle
    #the first starting from 31 until 2955 (bounty included)
    for y in range(31,2955):
      if ar[y] == "great": r1 +=1
 
    #the second looping all the array elements
    for y in range(0, len(ar)):
      if ar[y] == "great": r2+=1
 
    #Loop inside and build a temporary string with index and value, without put it into a variable and only for elements <> null
    for y in range(0, len(ar)):
      if ar[y]:
        "%s %s" %(y, ar[y])
      else:
        r3+=1
 
    #delete null value elements and take its size
    multiremove2(ar, None)
    r4 += len(ar)
 
    #then join elements with space and take its size
    r5 += len(" ".join(str(n) for n in ar))
 
  return r1, r2, r3, r4, r5
 
def nums_test(ntest):
  r1 = r2 = 0
  for x in range(ntest):
    #Find all prime numbers from 8 to 95 step by 3 (bounds included) and sum all primes got, to check the result
    for n in range(8, 96, 3):
      for prime in primes(n):
        r1 += prime
    fac = lambda n:[1,0][n>0] or fac(n-1)*n
    #Calculate factorial numbers start from 2 to 42 (bounds included)
    r2 = 0
    for n in range(2, 43):
      r2 += fac(n)
 
  return r1, r2
 
#Primes must return an array of prime numbers
def primes(n):
  ar = []
  for x in range(2, n+1):
    prime = True
    for y in range(2, x):
      if x%y == 0:
        prime = False
        break
    if prime:
      ar.append(x)
  return ar
 
# ---  START  ---
print("\nWarming up...")
t1=t2=t3=0
stime = time()
r1, r2, r3, xstr = strings_test(5)
p1=time() - stime
print("Strings test - Elapsed %.3f" % p1)
print("Check1: %s" % r1)
print("Check2: %s" % r2)
print("Check3: %s" % r3)
print("Check4: %d" % len(xstr))
 
stime = time()
r1, r2, r3, r4, r5 = arrays_test(50, xstr)
p2=time() - stime
print("Arrays test - Elapsed %.3f" % p2)
print("Check1: %s" % r1)
print("Check2: %s" % r2)
print("Check3: %s" % r3)
print("Check4: %s" % r4)
print("Check5: %s" % r5)
 
stime = time()
r1, r2 = nums_test(500)
p3=time() - stime
print("Numeric test - Elapsed %.3f" % p3)
print("Check1: %s" % r1)
print("Check2: %s" % r2)
 
print( "Python Partial elapsed time %.3f" % (p1+p2+p3))
 
print("\n1. Starting Python tests...")
 
stime = time()
r1, r2, r3, xstr = strings_test(5)
p1=time() - stime
print("Strings test - Elapsed %.3f" % p1)
 
stime = time()
r1, r2, r3, r4, r5 = arrays_test(50, xstr)
p2=time() - stime
print( "Arrays test  - Elapsed %.3f" % p2)
 
stime = time()
r1, r2 = nums_test(500)
p3=time() - stime
print("Numeric test - Elapsed %.3f" % p3)
 
print( "Python Partial elapsed time %.3f" % (p1+p2+p3))
t1+=p1;t2+=p2;t3+=p3
 
print("\n2. Starting Python tests...")
 
stime = time()
r1, r2, r3, xstr = strings_test(5)
p1=time() - stime
print("Strings test - Elapsed %.3f" % p1)
 
stime = time()
r1, r2, r3, r4, r5 = arrays_test(50, xstr)
p2=time() - stime
print( "Arrays test  - Elapsed %.3f" % p2)
 
stime = time()
r1, r2 = nums_test(500)
p3=time() - stime
print("Numeric test - Elapsed %.3f" % p3)
 
print( "Python Partial elapsed time %.3f" % (p1+p2+p3))
t1+=p1;t2+=p2;t3+=p3
 
print("\n3. Starting Python tests...")
 
stime = time()
r1, r2, r3, xstr = strings_test(5)
p1=time() - stime
print("Strings test - Elapsed %.3f" % p1)
 
stime = time()
r1, r2, r3, r4, r5 = arrays_test(50, xstr)
p2=time() - stime
print( "Arrays test  - Elapsed %.3f" % p2)
 
stime = time()
r1, r2 = nums_test(500)
p3=time() - stime
print("Numeric test - Elapsed %.3f" % p3)
 
print( "Python Partial elapsed time %.3f" % (p1+p2+p3))
t1+=p1;t2+=p2;t3+=p3
 
print("-------------------------------------")
print("Average Strings test - Elapsed %.3f" % (t1/3))
print("Average Arrays test  - Elapsed %.3f" % (t2/3))
print("Average Numeric test - Elapsed %.3f" % (t3/3))
print("Python Average elapsed time %.3f" % (t1/3+t2/3+t3/3))