Un assaggio di Ruby e Rails

# .oOoOo Un assaggio di Ruby & Rails v0.0.2 .oOoOo

=begin

° Introduzione
Ci sono tanti linguaggi di programmazione, il C per il "basso livello",
il Php per il web, il Visual Basic per le interfacce veloci, Java per le
applicazioni multipiattaforma, Bash per lo scripting di sistema, il Perl
per gli exploit..

Tutti simili e ognuno con le proprie peculiarità. Il C rimarrà ancora per
molto lo standard per il basso livello, ma ad alto livello ci sono state
innovazioni che non tutti i linguaggi di programmazione hanno considerato.

Questo documento non ha la pretesa di essere esaustivo sull'argomento
Ruby / Ruby on Rails, ma vuole essere solo uno "stuzzichino" per stimolare
la curiosità e l'interesse di neofiti e non verso questo linguaggio.

Ruby non discrimina
Da qualsiasi linguaggio arrivi a ruby, sarai (quasi) sempre in grado a scrivere
qualcosa di funzionante; col tempo potrai imparare le tantissime scorciatoie.

---------------------------------------------------------------------------

Ruby



Ruby è un linguaggio ooo, opensource, dinamico, multipiattaforma.

..e soggettivamente bello, conciso, espressivo e naturale.

Non c'è altro da aggiungere, il codice dice tutto

=end



# Ruby/C-style

i=0

while (i<5)

  printf("%s %d\n","ciao", i)

  i+=1

end



# Ruby/geek-style

(0..4).each{|n| p "ciao #{n}"}


# Un po' sintassi e convenzioni

# commento su una riga
=begin
commento su più righe
=end

# punto e virgola solo quando serve
def stampa('3 istruzioni su una riga'); print qualcosa; end

stampa('Finalmente!')

stampa('Basta abusare dei punto e virgola!')



# stampa delle variabili senza uscire dalla stringa

'stringa statica ' + RUBY_PLATFORM

"stringa interpretata #{RUBY_PLATFORM}"



variabile_locale

@variabile_di_istanza

@@variabile_della_classe

$variabile_globale

Costante



ClasseMoltoLunga

Classe.metodo

Modulo::metodo



# hash

dizionario_con_blocco= {:simbolo => 'valore', :simbolo2 => 'valore2'}

dizionario_con_blocco.each_key {|elemento| fai_qualcosa_con elemento}

dizionario_con_blocco[:simbolo] == 'valore'

:test.to_s "test"



# espressioni regolari già nel linguaggio

('Trova la posizione d1 unnumero nella regexp' =~ /[0-9]/) 20


# operatori specifici per i range
((1..10) === 10) == true

((1...10) = 10) false



# dinamico nel modo giusto

"ciao"+4      # errore

"ciao"+4.to_s # => ciao4



# classi

class Uccello

  def vola

    puts 'sto volando'

  end

  def dormi

    "zzz.." # return non è indispensabile

  end

end



# Ereditarietà

# sovrascrivo i metodi della classe di partenza

class Pinguino < Uccello

  def vola

    puts 'non so volare'

  end

  # tutti metodi che non esistono chiameranno questo!

  def method_missing(*args)

    puts 'non so ancora farlo'  

  end

end



Uccello.new.vola     # => sto volando

tux = Pinguino.new

tux.vola             # => non so volare

tux.nuota            # => non so ancora farlo

puts tux.dormi       # => zzz..



titti = Uccello.new


def titti.parla(frase)
  puts frase.gsub(/r/,'l') # espressione regolare

end



titti.parla('Mi è sembrato di vedere un gatto')

# => Mi è semblato di vedele un gatto



class Gatto

  # implementa per voi i metodi nome e nome= per leggere/scrivere

  # la variabile

  attr_writer :nome

  @@quanti=0

  # Overloading e parametri predefiniti

  def initialize(nome='boh')

    @nome = nome

    @@quanti+=1

  end

  def parla(frase)

    puts frase  

  end

  # questo metodo è della classe e non dell'istanza

  def self.quanti?

    puts @@quanti  

  end

end  



# anche le parentesi volendo si possono omettere

silvestro = Gatto.new 'Silvestro'

randagio = Gatto.new # => <Gatto:0xb7ca31d8 @nome="boh">

randagio.nome = 'micio'

randagio.nome # => micio



Gatto.quanti? # => 2


# Duck Typing
# nessuna interfaccia, basta che le classi/istanze implementino il metodo
def cantiamo_insieme(*args)
  args.each{ |cantante| puts "sono  un #{cantante.class} e canto: ";

  cantante.parla('oh oh che bello cantareee..') }

end



# Uccello (parlante) e Gatto possono cantare insieme!

cantiamo_insieme(titti, silvestro)


# Moduli
module RedBullMetteLeAli
  def vola
    puts 'tutti possono volare basta volerlo!'
    puts "anche #{@nome}" if @nome

  end

end



# Le classi sono dinamiche e posso essere riprese

# includendo più moduli si può creare una ereditarietà multipla

class Gatto

  include RedBullMetteLeAli

end



silvestro.vola

# => tutti possono volare basta volerlo!

# => anche Silvestro



# Ridefinizione delle classi base

class String

  def censura

    self.gsub(/aeiou/,'*')

  end

  # e degli operatori di base!

  def *(stringa)

    # operatore di concatenazione astratto

    self  << " x " << stringa << " ahahh"

  end

end



puts "ciao" * "bau" # => ciao x bau ahahh


# Tutto è un'oggetto anche i numeri
3.times do
  puts "ciao che figo!".gsub(/a|e|i|o|u/,'*')

end



# Separatore numerico _ e conversione automatica dei numeri

i = 500_000_000

while i < 10_000_000_000

  puts "#{i} #{i.class}"; i = i*2

end

# output

# 500000000 Fixnum

# 1000000000 Fixnum

# 2000000000 Bignum

# 4000000000 Bignum

# 8000000000 Bignum



# Ruby come calcolatrice

puts Math::cos(0).to_i # 1

include Math

puts (cos(0) + (PI + 7.5) / 2)


# Ruby come scripting
Dir.open('.').each {|file| fai_qualcosa_con_quel file}

# idem

Dir.open('.').each do |file|

  fai_qualcosa_con_quel file

end





# Ruby e l'interfaccia grafica Gtk

require 'gtk2'

Gtk.init # per inizializzare le librerie


w = Gtk::Window.new

b = Gtk::Button.new 'cliccami'


# assegno un'azione all'evento <cliccato> del pulsante b
b.signal_connect('clicked'){ puts 'ciao'; w.title='ciao'}

# impacchetto il pulsante b nella finestra w
w.add(b)
w.show_all # mostro la finestra w e tutti gli oggetti che contiene

Gtk.main # Loop, entra in esecuzione l'applicazione grafica





=begin

Ruby nel web2.0 con Rails

Ruby on Rails è un framework MVC (Model-View-Controller) che permette

di accedere al db come se si trattasse di oggetti. Permette quindi di

avere classi persistenti, uno sviluppo del db incrementale e tante altre cose.


ATTENZIONE !!
Rails è "magico", ci sono tante convenzioni, quasi tutte sovrascrivibili, per esempio
le tabelle sono chiamate al plurale, mentre i modelli e i controller al singolare.

Iniziamo con un semplice progetto
da cmd o bash:
=end
rails rtest # crea la struttura di base nella cartella rtest

cd rtest    # Sarà sempre la cartella di riferimento



app

 controllers  # manipolano i dati e li richiamano dal database

 models       # descrivono i tipi di dato validi per il modello

 views        # sono i template che mostrano le informazioni

 

config

 database.yml # specifica l'adattatore e il nome del db utilizzato

 routes.rb    # qui vendono mappati i controller nella URL


db
 migrate      # dentro la dir ci sono tutte le migrazioni incrementali
 schema.rb    # la struttura completa del db all'ultima versione

# Configurazione dell'ambiente
# 1. configurare i paramentri del database in config/database.yml

development:

  adapter: sqlite3 # o qualsiasi altro db supportato mysql/firebird/..

  database: db/rtest_dev.sqlite # dove volete creare il db o il suo nome


# Creaiamo il modello 'cartoon', inizialmente è solo un file vuoto, ma ci permetterà di
# interfacciarci con la tabella del db

script/generate model cartoon

# Viene anche creato 'db/migrate/001_create_cartoons.rb', possiamo aprirlo e implementare

# up e down, cioé i metodi che verranno eseguiti quando passeremo ad una versione successiva

# o precedente del db



# -- db/migrate/001_create_cartoons.rb --

class CreateCartoons < ActiveRecord::Migration

  def self.up

    create_table (:cartoons) do |t|

      t.column :name, :string

      t.column :nationality_id, :integer

    end

  end



  def self.down

    drop_table (:cartoons)

  end

end

# -- EOF --



# Si può utilizzare Ruby on Rails anche senza browser in modalità interattiva,

# così da avere molte più informazioni di debug


# dal terminale digitate
script/console

x = Cartoon.new # Crea una istanza della classe Cartoon

x.name = 'pluto'

x.save          # l'istanza viene salvata sul db

Cartoon.new(:name => 'paperino').save # tutto in una sola riga

Cartoon.find(:first) # restituisce pluto

Cartoon.find :all    # restituisce array con pluto e paperino

exit



# Se il record esiste, 'save', eseguirà CREATE altrimenti UPDATE



script/generate model nationality



# analocamente aggiungete

[..]

t.column :nation, :string

[..]



rake db:migrate # rake --tasks per vedere tutto quello che fare


# Porta il db all'ultima versione del database, cioè esegue incrementalmente tutte le 'up'
# Se si è già all'ultima non c'é nessun output
# rake db:migrate VERSION=0 fà rollback ed esegue i metodi 'down' fino alla versione 0

# -- file app/models/nationality.rb
class Cartoon < ActiveRecord::Base

  belongs_to :nationality

end

# -- file app/models/nationality.rb

class Nationality < ActiveRecord::Base

  has_many :cartoons

end



lupin = Cartoon.new(:name => 'Lupin')

lupin.nationality = Nationality.new(:nation => 'Giappone')

lupin.save

lupin3 = Cartoon.find :first

lupin3.nationality.nation # Giappone

lupin3.nationality_id     # 4 gestito in automatico



# Finora tutto quello che è stato realizzato era indipendente dal web

# adesso bisogna interfacciare i modelli creati con i controllori (controller)

# e viste (view) opportune.



# Un metodo molto comodo per essere subito operativi sono gli scaffold; possono essere

# utilizzati a runtime oppure si possono utilizzare come codice di partenza per fare

# input/output con il db.



# ATTENZIONE gli scaffold sono veloci da utilizzare, ma non sono la risposta a tutto,

# ci sono degli scaffold di terze parti in stile web 2.0 che supportano l'ordinamento delle

# colonne e le chiavi esterne, ma se vogliamo fare qualcosa di più di un semplice

# "modulo d'inserimento" bisogna programmare e sporcarci le mani :-)



# -- file app/controllers/nationality_controller.rb

class NationalityController < ApplicationController

  scaffold :nationality # generato a runtime metodi edit/add/list che funzionano subito

end



# Genera il codice dello scaffold una volta, quindi se si aggiungerà una colonna bisognerà

# modificarlo; lo si può utilizzare come base di partenza per aggiungere il supporto alla

# chiave esterna (nel nostro caso).

script/generate scaffold cartoon


# Gestiamo la chiave esterna
# -- file app/controllers/cartoons_controller.rb
  #[...]
  def show
    @cartoon = Cartoon.find(params[:id])

    # Serve per poter visualizzare la nazionalità associata nella vista

    @nationality = Nationality.find(@cartoon.nationality_id) # aggiunto

  end

  #[...]

# --



# Adesso bisogna che la vista sappia dove visualizzare questo nuovo oggetto.

# La vista, in questo caso, è 'show.rhtml' perché è associata al metodo show del controllore.

# I file .rhtml, sono simili ai file .php/.asp, ma dovrebbero solo contenere

# html e variabili da stampare racchiuse in <%= @var %>, se tuttavia dobbiamo aggiungere della

# logica, possiamo sempre includere il codice in <% for elem in @elementi %>


# ATTENZIONE al posto di </>%= dovete mettere <%=

# -- file app/views/cartoons/show.rhtml
  #[...]
  <p>Nazione:                   # aggiunto

    </>%= @nationality.nation %>  # aggiunto

  </p>                          # aggiunto

  #[...]

# --



# Riguardo la parte d'inserimento (add) e di modifica (edit), dobbiamo aggiungere il combobox o lista

# a scomparsa per la selezione dei paesi presenti. Visto che il form per le suddette operazioni risulterebbe

# molto simile, Rails permette di condividere i campi a livello di vista,

# tramite <%= render :partial => 'form' %>



# -- file app/views/cartoons/_form.rhtml

#[...]

  <p><label for="cartoon_nationality">Nazione</label></br>

  </>%= select("cartoon", "nationality_id", Nationality.find_all.collect {|p| [ p.nation, p.id ] }) %></p>

#[...]



# Link utili:

# - http://www.ruby-lang.org              Ruby

# - http://www.rubyonrails.org            Video/manuali/api

# - http://ruby-gnome2.sourceforge.jp/it/ Ruby + Gnome

#

# - http://www.rubyquiz.com               Spunti e tecniche per usare Ruby come si deve

# - http://www.railsweenie.com            Forum

# - http://www.railscasts.org             Tanti video introduttivi su rails da scaricare

#

# In italiano:

# - http://ruby-it.org/                   Comunità italiana di Ruby

# - http://www.extendi.it/ruby-on-rails   Blog su Rails

# - http://www.therubymine.com            Diversi articoli su Ruby e Rails

#