################################################################### # veloce con RuBy | x programmatori pt I # www.erroredigitale.tk # ################################################################### Premessa: La mia non vuole essere una guida al ruby, un ottima guida e' linkata nella bibliografia a fine articolo, Lo scopo dell'articolo e' di illustrare le potenzialita' di questo linguaggio,per quelli piu' schizofrenici [come me] che vogliono vedere subito qualcosa di concreto e soprattuto per chi ha gia' esperienza con un linguaggio di programmazione orientato agli oggetti e vuole imparare le basi di ruby in meno di un ora ;). Prima di intraprendere questo articolo, o dopo averlo letto, e' consigliata la lettura dei tutorial presenti a questo link: http://ruby-it.org/pages/Guide+in+Italiano Scritto da phoby [www.erroredigitale.tk|erroredigitale@gmail.com] ############################################################################################################################ ############################################################################################################################ INDICE: 1-INTRODUZIONE 2-PURO Object Oriented 3-INSTALLAZIONE 4-FONDAMENTALI 5-VARIE ED EVENTUALI 6-@WORK 7-LINKS UTILI 8-DO YOU SPEAK ENGLISH? 9-...COSA MANCA?? ############################################################################################################################ ______________ <[1|INTRODUZIONE]> Ruby come molti già sanno, è un linguaggio di programmazione nato in Oriente che sta prendendo (o a preso?!) piede in Europa e America; questo qualche anno dopo il Giappone a causa dell'assenza di documentazione scritta in inglese, ma una volta colmata questa mancanza il linguaggio ha iniziato a diffondersi: la situazione in Italia non la conosco dato che la mia esperienza con Ruby è di sole due settimane...settimane intense :( ma mi ritengo molto soddisfatto da questo linguaggio: E' semplice! Ma non come si potrebbe dire del semplice di Visual basic, visual basic è semplice ma incoerente, visual basic è limitativo, ruby è semplice perchè benpensato. E' leggibile! Il codice scritto in ruby è chiaro,elegante! Per quanto riguarda la rete, che è il campo in cui sto usando ruby, posso dire che ha una libreria adatta ad ogni necessità, partendo dai protocollo comuni come ftp,http, passando per ssh e per finire, potete addirittura realizzare un webserver modellato alle vostre esigenze in poche righe di codice...non ci credete? ecco il codice del webserver che sto usando per testare i miei script cgi: _________________________________________________________________ require 'webrick' include WEBrick class RubyWebServer def initialize(config={}) config.update(:Port => 8080) @config=config end def start_webrick() @server = HTTPServer.new(@config) yield @server if block_given? ['INT', 'TERM'].each { |signal| trap(signal) { @server.shutdown } } @server.start end def stop_webrick() @server.shutdown end end server=RubyWebServer.new(:DocumentRoot => '/var/www') server.start_webrick() ________________________________________________________________ L'uso della libreria webrick non verrà spiegato, almeno non in questo articolo,in questo articolo lo scopo sarà realizzare un programma che mostri la descrizione degli articoli che sono in downloand sul mio sito, ovvero www.erroredigitale.tk, e il link al quale reperirli.E' un programma semplice che volevo realizzare da tempo ;) Essendo abituato a programmare in java, chiamerò le variabili di istanza "attributi", e le azioni che esso può compiere "metodi". I metodi in ruby si chiamano "messaggi". _____________________ <[2|Puro ObjectOriented]> In ruby non esistono i tipi di dato primitivi disponibili ad esempio in java, ogni cosa è un oggetto. Un numero intero è un istanza di una classe di tipo FixNum, e, dato che ruby è ruby, non abbiamo alcun limite sulla dimensione dei numeri che possiamo memorizzare: se il numero è troppo grosso per i vostri 32 bit il valore verrà assegnato alla classe BigNum. Si possono usare le graffe, io ho sempre odiato l'utilizzo di costrutti tipo begin..end...etc, ma in ruby li accetto, stanno bene, non uso più le graffe nonostante le possa usare. Un altro aspetto che sottolinea la coerenza del linguaggio:se ogni cosa è un oggetto che senso avrebbe fare 1+2.. Beh quella scrittura, in realtà è tradotta così: 1.+(2) ovvero viene invocato il metodo + dell'oggetto di tipo FixNum di valore 1, passandogli come parametro un oggetto con valore 2, sempre di tipo FixNum; a[2] questo invece equivale a scrivere a.[](2) vi è consentito anche ridefinire il metodo + e qualsiasi altro. Come in altri linguaggi, quali il java, Object è la "superclasse suprema", padre di tutti e una classe puà avere un solo padre. Installiamo l'occorrente e iniziamo a programmare... _______________ <[3|INSTALLAZIONE]> Ora ci limitiamo a installare l'interpete, sia che usiate windows che usiate linux, l'installazione è molto semplice. Per windows esiste un installer che trovate al link di seguito, l'installer vi fornirà un ambiente completo con tanto di editor: http://rubyforge.org/frs/download.php/18566/ruby186-25.exe Se usate linux basterà usare il gestore di pacchetti della propria distro, ad esempio per debian e derivate: apt-get install ruby I programmi vanno scritti in file con estensione rb, il file esempio.rb andrà lanciato così: ruby esempio.rb Oppure è possibile scrivere il codice interattivamente lanciando ruby senza parametri. Finito ;) ______________ <[4|FONDAMENTALI]> Innanzitutto una istruzione per riga, senza alcun ; di fine istruzione In ruby l'indentazione è obbligatoria, un while così non verra compilato: int a = 0; while(a==0) { print(a); a++;} //l'esempio è in pseudo-sintassi C In ruby faremo: a=0 #la dichiarazione della variabili non è obbligatoria è il codice si commenta con cancelletto while (a==0) do puts (a) a=a+1 end do-end delimitano un blocco di codice : do -> { end -> } Le parentesi nei metodi possono essere omesse, quindi puts(a) si poteva scrivere puts a Puts serve a stampare nell'output standard [per ora la consolle] Se vogliamo mostrare il contenuto di una variabile con puts a="ciao" puts(a) #oppure puts a #oppure puts("Il valore di a: #{a}") In quest'ultima notazione si può inserire il contenuto della variabile in mezzo a una stringa usando #{} Inserendo il nome dell variabile tra le graffe. Ora definiamo una classe esempio con un suo metodo chiamato metodo1: class Esempio def metodo1(a,b) puts a puts b end end Le variabili di istanza si usano anteponendo il simbolo @ al nome della variabile, per le variabili di classe @@. Come creiamo un oggeto? Invocando il metodo new della classe: prova = Esempio.new prova.metodo1 ("2","4") #stamperà 2 4 Il costruttore,che è il metodo invocato alla costruzione dell'oggetto, può essere ridefinito [quello di default non fa nulla] e si chiama initialize... class Esempio def initialize(attributo) @attributo=attributo end def getAttributo return @attributo end end prova=Esempio.new(2) attributoDiProva=prova.getAttributo puts attributoDiProva #stampera' 2 Supponiamo di avere la class Persona così definita: class Persona def initialize(nome,cognome) @nome=nome @cognome=cognome end def getNome() return @nome end def getCognome() return @cognome end end Vogliamo definire la classe studente, sottoclasse di Persona: class Studente < Persona def initialize(nome,cognome,matricola) super(nome,cognome) #richiama il costruttore della superclasse @matricola=matricola end def getMatricola() return @matricola end end Cosa c'è di nuovo? Il < viene usato per indicare che stiamo scrivendo una sottoclasse di una classe che indichiamo di seguito, super è un metodo che richiama il costruttore della superclasse. Naturalmente la sottoclasse eredita attributi e metodi della superclasse. In ruby non si può accedere alle variabili di istanza, ma si può fare molto di meglio, si accede tramite messaggio [quello che chiamavamo metodo in ruby si chiama messaggio] ad esempio così: class Prova def initialize(a) @attributo = a end def attributo() return @attributo end end E siccome in ruby si possono omettere le parentesi potremo fare cosi: prova=Prova.new("2") attributo=prova.attributo #sembra di accedere all'attributo ma in realtà stiamo invocando un metodo Un altro concetto, dopodiche i fondamentali per questo primo articolo su ruby giungeranno al termine. Con ruby possiamo passare come parametro [più o meno vedetela così] un blocco di codice, e richiamarlo all'interno del metodo chiamato tramite la parola special yield, ad esempio def metodo1() puts "ciao" yield end metodo1() { a=0 while(a<10) { puts a a++ } } stampera a monitor: ciao 0 1 2 3 4 5 6 7 8 9 La chiamata al metodo1 può anche essere scritta senza graffe ma così: metodo1 do a=0 while(a<10) { puts a a++ } end e anche così metodo1 do a=0 while(a<10) do puts a a++ end end Questo concetto è fondamentale e viene usato spessissimo in ruby ma non è ancora del tutto completo: quando richiamiamo il blocco di codice con il costrutto yield, possiamo passare dei parametri al blocco chiamato, il blocco chiamato ricevera i parametri nelle variabili indicare tra i caratteri || vediamo un esempio per capire meglio: def metodo count=0 while (count < 10) do yield(count) count++ end end metodo() do |val| #chiamo il metodo puts val end L'out sarà: 0 1 2 3 4 5 6 7 8 9 ____________________ <[5|VARIE ED EVENTUALI]> Questo articolo ha ridotto davvero all'osso gli essenziali di ruby, ma se sono riuscito a spiegarmi vi avrà sicuramente incuriosito se siete dei programmatori java, come lo ero io. Vediamo ad esempio come questo modo di ragionare ci semplifica la vita, usiamo un pò gli array... #ARRAY# a=[] #creo un array vuoto a.push("ciao") #inserisco un oggetto di tipo stringa con valore ciao a.push(2) #inserisco un oggetto di tipo FixNum con valore 2 stringa = a.to_s #to_s è un metodo che genera una stringa che rappresenta l'oggetto puts stringa #stamperà ciao2 primo_elemento=a.at(0) #prende il primo elemento dell'array secondo_elemento=a.at(1) #prende il secondo elemento dell'array a.del("stringa") #cancella l'oggetto "stringa" Supponiamo di voler scorre l'array in una maniera più elegante, alla ruby, usiamo il metodo each della classe Array che potrebbe essere così definito: def each a=0 while(a"valore","colore"=>"rosso"} arr.each do |key,value| do puts "#{key}:#{value}" end stamperà a monitor: chiave:valore colore:rosso valore:0 I dettagli gli trovate sulla documentazione ufficiale,linkata a fine pagina. # == # Anche questo è un metodo che ritorna true o false, e di questo vedremo l'estrema importanza. In java se scrivavamo String a = "ciao" String b= "ciao" if(a==b) System.out.println("sono uguali") else System.out.println("sono diversi") Il risultato sarebbe stato: sono diversi Questo perchè confrontava i puntatori, che puntavano a due locazioni diverse, perchè due oggetti distinti. In ruby invece, possiamo decidere in base a cosa definire l'uguaglianza di due oggetti della stessa classe, ridefinendo il metodo ==. Il come modificare questi operatori va al di fuori di quello che voglio spiegare in questo articolo, magari nei prossimi ma comunque c'è materiale validissimo [molto più di questo] in rete. Voglio solo incuriosirvi dicendo che i metodi < > e == si basano sul ritorno di un unico metodo chiamato <=> che ritorna -1 ,0 o 1 a seconda di come è definito. Guardatevelo meglio sui link che vi darò a fine articolo che sinceramente al momento neanche io lo ricordo bene. # socket # Ora proviamo ad usare le socket per creare un server che saluti,chiuda la connessione e termini, includiamo la libreria socket con il comando require... require 'socket' server=TCPServer.new("127.0.0.1",11000) #creo un server in ascolto sulla 11000 socket=server.accept socket.puts("ciao ciao") #manda una stringa al client di questa socket server.accept è un metodo che si blocca in attesa di una connessione, quando la ottiene restituisce un oggetto di tipo socket su cui poter mandare e ricevere dati in maniera molto semplice, nel nostro esempio abbiamo mandato una stringa, quindi usiamo il metodo puts che riceve come parametro una stringa. # conversione di tipo # Tutti gli oggetti contengono i seguenti metodi: to_i() che ritorna il valore intero dell'oggetto su cui è invocato il metodo to_s() che ritorna una stringa to_a() che ritorna un array Se ad esmepio scrivo "2"+2 avrò ovviamente un errore se scrivo: a="2" b=2 c=a+b anche questo darà un errore, ma questo no: a="2" b=2 c=a.to_i + b # procedura che torna più valori # Siamo abiutuati a tornare un solo valore per ogni procedura[metodo], ma possiamo tornare anche un array in cui immettere più valori, ma grazie alla sintassi di ruby non ci accorgeremo neanche di usare gli array...es: def test() a=[] a.push(1,2) return a end a,b=test() puts a puts b l'out sarà: 1 2 Il metodo test torna un array,l'array che contiene due variabili verrà espanso, e il primo valore assegnato ad a e il secondo a b. Con la stessa logica si può realizzare il passaggio di parametri multipli ma questa la tralascio.... #metodi di classe e metodi privati# Un metodo di classe è un metodo che può essere usato senza instanziare l'oggetto della classe che contiene il metodo, e viene invocato specificando la classe in cui reperire il metodo, e si definisci così: class Prova def Prova.metodo() #metodo statico puts "sono un metodo statico" end end Prova.metodo() #invoco il metodo Un metodo privato, è un metodo eseguibile solo da oggetti della stessa classe e per indicare i metodi privati basta inserire la parola private prima di definire i metodi privati: class ciao def metodoPubblico1() #### end def metodoPubblico2() #### end private # da qui in poi i metodi sono privati def metodoPrivato1() #### end def metodoPrivato2() #### end end # leggere dati da un xml # Supponiamo di avere il seguente xml: 1 3 Supponendo di avere il contenuto dell'xml caricato in una stringa, usando l'opportuna libreria di ruby, il tutto sarà piuttosto semplice : require 'rexml/document' #carico la libreria doc = REXML::Document.new "12" #passo al costruttore la stringa doc.elements.each("//item") do |item| #itero sugli elementi dell'xml puts item.elements["id"].text #accesso testo contenuti negli elementi di item con campo uguale a id puts item.attribute("attribute") #accesso attributo di nome "attribute" di item end Con la stringa passata "//item" si indica il livello a cui trovare gli elementi item E questo mi sembra fantastico ;) __________ <[6| @ work ]> L'home-page del mio sito [www.erroredigitale.tk] è raggiungibile tramite questo indirizzo che è quello su cui lavoreremo: www.officina.netsons.org/ed/index.php Il sito ha una sezione chiamata "biblio", che contiene tutti gli articoli messi sul sito,reperiti dal web o scritti da erroredigitale. Il database di questa sezione, è un file xml che si trova al seguente link: www.officina.netsons.org/ed/adminPanel/download_sez/file_sez.xml Ogni entry dell'xml ha la seguente struttura ladata: viene salvata la data in cui viene pubblicato sul nostro sito l'articolo descrizione: descrizione dell'articolo pubblicato nomefile: il nome del file che contiene l'articolo link : l'indirizzo completo a cui reperire l'articolo sezione: la sezione della biblio in cui compare [es: informazione,programmazione,cracking,etc,etc] id : viene usato dal pannello di amministrazione del portale, a noi questo campo non interessa e verrà ignorato. Per questo semplice programma che vogliamo realizzare, ci limiteremo a scandire tutte le entry dell'xml,e per ogni entry aggiungere un array di due elementi ad un array principale, il primo valore dell'array da aggiungere è la descrizione, il secondo il link. Dopo risfoglieremo l'array, e mostreremo in out il risultato. Ovviamente si poteva fare in maniera più semplice, ma volevo farvi usare gli array, il programma è a solo scopo didattico. Iniziamo con buttare il primo codice della classe: class ErroreDigitaleDataBase # partenza programma def start xml_string=getXmlFromWeb() array = getArray(xml_string) array.each do |item| puts "descrizione:#{item.at(0)} link:#{item.at(1)}" end end private #scarica l'xml dal web e ritorna il contenuto come stringa def getXmlFromWeb() #################da implementare end #sfoglia l'xml passato come stringa #ritorna un array, dove ogni elemento dell'array a sua volta è un array di due elementi, #in prima posizione abbiamo la descrizione e in seconda il link def getArray(xml) #################da implementare end end Mancano da implementare i metodi getArray,getXmlFromWeb, partiamo da quello più semplice: def getXmlFromWeb() require 'net/http' #usiamo la libreria standard di ruby per gestire l'http conn = Net::HTTP.new('www.officina.netsons.org', 80) #crea connessione http all'ip e porta specificata resp, data = conn.get('/.../file_sez.xml') #richiesta di tipo GET, chiediamo il file file_sez.xml nella root #del server; il metodo get() torna due oggetti, il primo è di tipo HTTPResponse #e lo ignoriamo e non ve lo spiego perchè non rientra nei fini dell'articolo #il secondo sono i dati, ovvero quello che abbiamo chiesto data = data.to_s #convertiamo i dati ricevuti in stringa return data end def getArray(xml_string) ret=[] require 'rexml/document' doc = REXML::Document.new xml_string doc.elements.each("//item") do |item| #itero sugli elementi dell'xml descrizione = item.elements["descrizione"].text link = item.elements["link"].text tmp=[].push(descrizione,link) ret.push(tmp) end return ret end Riporto tutto il codice senza commenti e revisionato: ____________________________________________________ require 'net/http' require 'rexml/document' class ErroreDigitaleDataBase def start xml_string=getXmlFromWeb() array = getArray(xml_string) array.each do |item| puts "descrizione:#{item.at(0)} \n link:#{item.at(1)}\n\n" end end private def getXmlFromWeb() conn = Net::HTTP.new('www.officina.netsons.org', 80) resp, data = conn.get('/ed/adminPanel/download_sez/file_sez.xml') data = data.to_s return data end def getArray(xml_string) ret=[] doc = REXML::Document.new xml_string doc.elements.each("//item") do |item| descrizione = item.elements["descrizione"].text link = item.elements["link"].text tmp=[].push(descrizione,link) ret.push(tmp) end return ret end end ed = ErroreDigitaleDataBase.new ed.start ____________________________________________________ _______________ <[7| LINKS UTILI ]> http://www.ruby-lang.org http://ruby-it.org http://www.rubyforge.org http://simplehttp.rubyforge.org/ -> libreria http semplificata,ottima! http://www.rubycentral.com/book -> libro di riferimento per chi vuole imparare ruby http://www.officina.netsons.org/ed/download_sez.php?search=ruby -> erroredigitale _________________________ <[8| DO YOU SPEAK ENGLISH ?]> Ho realizzato da poco il gioco del tresette in ruby ed è stato ospitato su www.rubyforge.org, che è l'equivalente di sourceforge, solo che interamente dedicato a ruby. Il codice funziona..bisognerebbe: 1-scrivere le regole del tresette in inglese [prioritario] 2-ottimizzare il codice e documentarlo in inglese 3-creare un client grafico Se sei interessato e potresti contribuire contattaci alla seguente mail,indicando come soggetto della mail "ruby tresette" : erroredigitale@gmail.com Ovviamente per contribuire non intendiamo denaro, ma codice e traduzioni,soprattutto la traduzione delle regole ;) Vogliamo esportare questo gioco all'estero ;) ________________ <[9| COSA MANCA?? ]> Di ruby non abbiamo parlato di gems, che è il gestore delle librerie di ruby:immaginatelo come l'equivalente dei gestori dei pacchetti delle distro linux, solo che gestiscono le librerie di ruby. Una volta installato, se abbiamo ad esempio bisogno della libreria simplehttp, basterà scrivere gem install simplehttp Inoltre iscrivendosi a rubyforge e registrando il proprio progetto si rende disponibile il proprio lavoro a tutta la comunità e gems compreso. Non abbiamo citato le espressioni regolari che sono un ottimo punto forte di ruby, ma potete trovare sul cook book.... Il resto devo ancora impararlo ;) P.S. la pt II di questo articolo ci sarà solo se ci sarà gente interessata -> mail to:erroredigitale@gmail.com ############################################################################################################################## ############################################################################################################################## Lo so ho saltato molti particolari, ma non volevo scrivere un papiro. Ho scritto quanto serviva per rendere il contenuto coerente. Un saluto speciale a tutto lo staff di www.hackingz0ne.altervista.org. pace regaz!