Ruby – moduli e mixin

r7

Un modulo è una raccolta di metodi (funzioni) e costanti per fare qualcosa. Quello che in altri linguaggi namespace o package o module (sì, in Python). Quando si vuole usare un modulo in Ruby basta includerlo nel programma.
Vediamone un esempio pratico di creazione e uso.

#!/usr/bin/ruby
# encoding: UTF-8

# es_mod.rb

module Star
    def line
        puts '*' * 20
    end
end

module Dollar
    def line
        puts '$' * 20
    end
end

include Star
line
include Dollar
line

es_mod

Vediamo che il modulo inizia con la keyword module (righe 6 e 12) e finisce, al solito, con end. Viene richiamato con include <nome del modulo>, righe 18 e 20.

Nell’esempio vediamo che la funzione line che viene eseguita  quella dell’ultimo modulo incluso.

Facciamo una modifica allo script precedente: togliamo le righe con le istruzioni di inclusione dei moduli:

#!/usr/bin/ruby
# encoding: UTF-8

# es_mod_err.rb

module Star
    def line
        puts '*' * 20
    end
end

module Dollar
    def line
        puts '$' * 20
    end
end

line

es_mod_err

Come si vede la funzione line non viene vista.

Possiamo avere anche moduli senza funzioni, solo codice. Poi proviamo a eseguirlo (mod_sf.rb):

#!/usr/bin/ruby
# encoding: UTF-8

# es_mod_sf.rb

module Uno
    puts "uno"
end

module Due
    puts "due"
end

mod_sf

Vediamo che in questo caso il modulo viene eseguito.

Sono da verificare almeno altri due casi, eccoli di seguito.

#!/usr/bin/ruby
# encoding: UTF-8

# mod_c-f.rb

module Uno
    puts "uno"

    def func
        puts "*** func"
    end
end

module Due
    puts "due"
end

Rispetto allo script precedente è stata inserita la funzione func nel modulo Uno. Provate a eseguirlo e vedrete che l’output è esattamente come quello del caso precedente, la funzione non essendo chiamata non viene eseguita. Cosa succede se invece questi moduli venissero inclusi in un main, come nello script seguente (mod_m.rb):

#!/usr/bin/ruby
# encoding: UTF-8

# mod_m.rb

module Uno
    puts "uno"

    def func
        puts "*** func"
    end
end

module Due
    puts "due"
end

include Uno
func

mod_m

Sorpresa! O no? In realtà il codice del modulo non incluso in funzioni serve per definire, inizializzare e simili.

#!/usr/bin/ruby
# encoding: UTF-8

# mod_m2.rb

module Uno
    puts "uno"

    $pi = 3.14159265
    def func
        puts "*** func"
        puts "Uno  - pi = #{$pi}"
    end
end

module Due
    puts "due"
end

include Uno
func
puts "Main - pi = #{$pi}"

mod_m2

Chiamare funzioni senza usare include

È possibile chiamare le funzioni contenute in un modulo senza usare la keyword include, tramite l’operatore ::. Modifichiamo il primo script in questo modo (es_mod2.rb):

#!/usr/bin/ruby
# encoding: UTF-8

# es_mod2.rb

module Star
    def Star.line
        puts '*' * 20
    end
end

module Dollar
    def Dollar.line
        puts '$' * 20
    end
end

Star::line
Dollar::line

es_mod2

Notare che per chiamare le funzioni usiamo :: (righe 18 e 19) e che per definirle usiamo nome-del-modulo.nome-funzione (righe 7 e 13).

I due metodi (usare include e ::) possono coesistere. Poi però sta a voi districarvi. Quando ero piccolo mi facevano sempre fare il debug, era una punizione (il mondo ce l’aveva con me già allora).

Classi nei moduli

Vediamo adesso cosa succede quando abbiamo classi nei moduli (mc.rb):

#!/usr/bin/ruby
# encoding: UTF-8

# mc.rb

module Operaio
    class Lavoro
        def cosa_stai_facendo?
            puts "Io eseguo"
        end
    end
end

module Dirigente
    class Lavoro
        def cosa_stai_facendo?
            puts "Io dirigo"
        end
    end
end

r1 = Dirigente::Lavoro.new
r2 = Operaio::Lavoro.new
r1.cosa_stai_facendo?
r2.cosa_stai_facendo?

mc

Se avete seguito fin qui non dovreste essere sorpresi: viene usata la funzione in nome-modulo::nome-classe.

Piccolo problema logico qui: io seguo abbastanza fedelmente Karthikeyan e ho usato per la funzione un nome che termina con ?. in realtà sarebbe buona norma riservare questi nomi ai predicati, funzioni che restituiscono un valore booleano True o False. Prima o poi dovrete fare il debug, ricordatevelo.

Mixin

In Ruby è che non c’è l’ereditarietà multipla e allora i mixin la simulano: permettono di avere un mix di classi per avere accesso diretto ai loro metodi, è cioè possibile mischiare il codice in diversi moduli, ottenendo i mixin.
Ecco un caso in cui non seguo l’ottimo Karthikeyan. Perché fare un esempio breve dell’uso dei mixin non è facile, anzi…

#!/usr/bin/ruby
# encoding: UTF-8

# es_mod2.rb

module InLettere
    def inlettere
        if @value == 1
            "Uno"
        elsif @value == 2
            "Due"
        elsif @value == 3
            "Tre"
        end
    end
end

module Math
    def somma(val_one, val_two)
        BigInteger.new(val_one + val_two)
    end
end

class Number
    def intValue
        @value
    end
end

class BigInteger < Number

    include InLettere
     extend Math

    def initialize(value)
        @value = value
    end
end

bigint1 = BigInteger.new 10
puts "dieci vale #{bigint1.intValue}"

bigint2 = BigInteger.somma 4, -2
puts "4 - 2 = #{bigint2.intValue}"
puts "vale a dire #{bigint2.inlettere}"

module CurrencyFormatter
    def format
        "€ *#{@value}*"
    end
end

bigint2.extend CurrencyFormatter
puts "la banca dice #{bigint2.format}"

es-mx

Questo l’ho trovato googlando, non è granché ma illustra l’estensione di classi e c’è un mixin alla riga 32.

Ha un altro pregio: con Ruby è molto facile produrre codice aggrovigliato, come in questo caso.
Avvisati, nèh 😉

Posta un commento o usa questo indirizzo per il trackback.

Rispondi

Inserisci i tuoi dati qui sotto o clicca su un'icona per effettuare l'accesso:

Logo di WordPress.com

Stai commentando usando il tuo account WordPress.com. Chiudi sessione /  Modifica )

Google photo

Stai commentando usando il tuo account Google. Chiudi sessione /  Modifica )

Foto Twitter

Stai commentando usando il tuo account Twitter. Chiudi sessione /  Modifica )

Foto di Facebook

Stai commentando usando il tuo account Facebook. Chiudi sessione /  Modifica )

Connessione a %s...

Questo sito utilizza Akismet per ridurre lo spam. Scopri come vengono elaborati i dati derivati dai commenti.

%d blogger hanno fatto clic su Mi Piace per questo: