Cosa e’ un Multiplexer?
Un multiplexer e’ un oggetto che funziona moltiplicando un messaggio, e inviandolo a degli oggetti registrati presso di lui.
L’utilita’ di un simile oggetto e’ evidente, ad esempio nel caso si desideri effettuare il log in un file di tutto cio’ che viene stampato a schermo, ma continuando a poter leggere anche i messaggi in tempo reale, si potrebbe usare un Multiplexer che nasconda STDOUT
e un oggetto File. Questa e’ esattamente la funzione del comando tee di UNIX.
class Multiplexer def initialize(*oggetti) @ogg=oggetti end def method_missing(metodo,*args,&blk) @ogg.each { |o| o.send(metodo,*args,&blk) } end endCosa accade qui? Beh, un oggetto
Multiplexer viene inizializzato passsandogli un array di elementi.
Un Multiplexer non risponde a nessun metodo in particolare.
Ogni volta che su di un tale oggetto viene chiamato un metodo a cui lui non sa come rispondere, viene richiamato method_missing. A questo metodo vengono passati:
- un simbolo che rappresenta il metodo chiamato (ad esempio
puts()) - un array contenente tutti i parametri passati al metodo
- un eventuale blocco
>> require 'multiplexer' => true >> require 'stringio' => true >> f1,f2 = StringIO.new, StringIO.new => [#<StringIO:0x27e17a0>, #<StringIO:0x27e1650>] >> m=Multiplexer.new(f1,f2) => #<Multiplexer:0x27d9868 @ogg=[#<StringIO:0x27e17a0>, #<StringIO:0x27e1650>]> >> m.puts 'ciao!' => [#<StringIO:0x27e17a0>, #<StringIO:0x27e1650>] >> f1.string => "ciao!\n" >> f2.string => "ciao!\n" => nil
il file multiplexer.rb ovviamente contiene il nostro codice.
StringIO rappresenta un ottimo modo per fare delle prove con un testo senza scriverlo. Infatti si tratta di una stringa che si comporta com un File (beh, come un IO per essere precisi :)
>> str,ary= 'ciao', [1] => ["ciao", [1]] >> m=Multiplexer.new(str,ary) => #<Multiplexer:0x27c57f8 @ogg=["ciao", [1]]> >> m << 'accodiamo' # tutti e due gli oggetti rispondono a '<<' => ["ciaoaccodiamo", [1, "accodiamo"]] >> str => "ciaoaccodiamo" >> ary => [1, "accodiamo"] >> m.upcase! # un array non sa come diventare maiuscolo! NoMethodError: undefined method `upcase' for [1, "accodiamo"]:Array from ./multiplexer.rb:6:in `send' from ./multiplexer.rb:6:in `method_missing' from ./multiplexer.rb:6:in `each' from ./multiplexer.rb:6:in `method_missing' from (irb):16Possiamo cambiare la definizione del nostro metodo per far si che funzioni nonostante gli errori, usando lo
statement modifier per rescue.
Uno statement modifier serve a cambiare il comportamento di un istruzione in certi casi. Ad esempio:
print x if x == 'ciao'Nel caso di
rescue esso dipende dalla generazione di un eccezione. Basta quindi ridefinire method_missing() cosi’:
def method_missing(met,*arg,&blk) @ogg.each do |o| o.send(met,*arg,&blk) rescue nil end endche significa : ad ogni elemento di
@ogg inviamo il messaggio met con i suoi parametri, se accade un errore recuperiamolo, e non facciamo nulla. Esempio:
>> m=Multiplexer.new('ciao',[]) => #<Multiplexer:0x2751ea8 @ogg=["ciao", []]> >> m.capitalize! => ["Ciao", []]