$ cat /dev/random
ripley's miscellanous debris

Habemus Ruby ADesklets Binding

(2006/05/19)

Ruby e’ come la mortadella... fino fino fino che te se sciogglie in bbocca :-)

E’ stato piu’ semplice del previsto e gia’ ieri sera sono riuscito ad avere un prototipo che ben approssima un binding stabile delle adesklets.

Devo confessare che di grande aiuto mi e’ stato il neonato binding in perl a cui mi sono ispirato per la prima fase di prototipazione.

Il risultato e’ stato una libreria ruby molto “cammellosa”.

L’approccio del binding perl e’ fortemente procedurale… ma con ruby si puo’ fare di meglio che scrivere codice perl piu’ leggibile.

E cosi’ ho cercato di dargli un tocco piu’ ruby:

Analisi iniziale

Tutto e’ cominciato dalla necessita’ di studiare il funzionamento delle adesklets, e bisogna dire che il manuale e’ sufficientemente completo da darti un’idea abbastanza precisa del suo principio di funzionamento.

In particolare la sezione Extending adesklets spiega molto bene come un binding puo’ colloquiare con la sua istanza adesklets.

Tra i due binding attualmente presenti:

Prima prototipazione

Per prima cosa ho convertito la parte fondamentale del binding in perl (e cioe’ la componente che inizializza la comunicazione verso l’istanza adesklets) per testare di aver compreso bene il principio di funzionamento.

ADesklets e’ di fatto una console di comandi Imlib2 (Imlib2 sono delle librerie grafiche), come suggerisce il tutorial possiamo verificarlo di persona:

ripley@ubik:/home/ripley$ adesklets :
adesklets 0.6.1 (Thu May 18 09:45:13 CEST 2006), on Linux 2.6.12-10-386
[gcc 4.0.2 20050808 (prerelease) (Ubuntu 4.0.1-4ubuntu9)]
Press TAB for hints.
0 >>> window_resize 100 100
command 0 ok: window_resize 100 100
1 >>> window_show
command 1 ok: window_show
2 >>>

Soluzione simpatica non c’e’ che dire :-)

In pratica le nostre desklets dovranno fare altrettanto, e cioe’:

  1. avviare un’instanza adesklets
  2. inviare i comandi attraverso lo stdin (dell’istanza adesklets)
  3. ricevere le risposte attraverso lo stdout (come sopra :-)
  4. ricevere gli eventi attraverso lo stderr (idem :-P)

Il primo test (funzionante) che ho potuto fare e’ stato:

require 'adesklets'

ADesklets::open_streams

ADesklets::window_resize 100 100
ADesklets::window_show

sleep(10)

Bleahh!!! non sembra ruby… e’ veramente brutto come approccio :-)

Rubyficare prima dell’uso

Una desklets scritta come sopra non e’ molto ruby, come approccio e’ troppo poco orientato agli oggetti.

Allora ho dato un’occhiata al binding python ed effettivamente le desklets scritte in python (tutte al momento visto che il binding in perl e’ stato introdotto da poco e quello ruby esiste solo da ieri :-D):

import adesklets

class My_Events(adesklets.Events_handler):
    def __init__(self):
        adesklets.Events_handler.__init__(self)

    def __del__(self):
        adesklets.Events_handler.__del__(self)

    def ready(self):
        adesklets.window_resize(100,100)
        adesklets.window_reset(adesklets.WINDOW_MANAGED)
        adesklets.window_set_transparency(True)
        adesklets.window_show()

    def quit(self):
        print 'Quitting...'

    def alarm(self):
        print 'Alarm. Next in 10 seconds.'
        return 10

    def motion_notify(self, delayed, x, y):
        print 'Motion notify:', x, y, delayed

beh… al momento il mio binding in ruby permette di scrivere le desklets cosi’:

class Test1 < ADesklets::Base
  def ready(args)
        window_resize(100,100)
        window_show
  end

  def button_pressed(args)
        puts args
  end

  def motion_notify(args)
        puts args
  end   
end

Completare il binding

Il team che sviluppa adesklets ha pensato bene di scrivere un paio di script che esportano le costanti e i comandi adesklets dal codice sorgente (in C) in 2 file di testo nella directory scripting dei sorgenti (enums e prototypes).

Da questi 2 file i due binding esistenti generano le costanti e i metodi necessari ad interfacciarsi con adesklets.

Questa e’ stata una buona idea e ruby e’ molto amichevole nel parsing e generazione di file di testo e quindi ho scritto un piccolissimo script che genera’ una libreria ruby con le definizioni necessarie:

require 'erb'

TEMPLATE = ERB.new <<-EOT
### Autogenerated
module ADesklets
module AutoGenerated

  ## constants
<% @constants.each do |constant| %%>
  <%= constant.name %%> = <%= constant.value %%>
<% end %%>

## functions
<% @functions.each do |function| %%>
  ## <%= function.comment %%>
  def <%= function.name %%>(*args)
    $session.command("<%= function.name %%> \#{args.join(' ')}")
  end
<% end %%>

end
end
EOT

RConstant = Struct.new(:name, :value)
RFunction = Struct.new(:name, :comment)

@constants = Array.new
@functions = Array.new

open('../enums') do |f|
  f.each_line do |line|
    name, value = line.split
    @constants << RConstant.new(name, value)
  end
end

open('../prototypes') do |f|
  f.each_line do |line|
    comment = line
    name = line.split[0]
    @functions << RFunction.new(name, comment)
  end
end

puts TEMPLATE.result(binding)

Quasi quasi e’ stato troppo semplice :-)

E perche’ tutto sto pippotto? non potevi targzippare i sorgenti e basta?

Beh si li potevo e li targizzippero’ (anzi ho gia’ postato nella ml adesklets-dev e credo che non dovrebbero avere problemi ad integrarle nel pacchetto appena possibile) ma la cosa che piu’ conta e che questo dimostra che

un pincopallino qualunque da qualunque buco del c..o del mondo
puo' realizzare qualcosa che a qualcun'altro puo' servire o migliorare

Questo E’ il software libero!

tutti hanno una possibilita’:

quelli che sanno come fare e quelli
che non sanno ma hanno la voglia di imparare.

Se volete potete provare il binding da subito senza aspettare che lo finisca di stabilizzare (qualche modifichina ancora gliela voglio fare :-P) e che venga eventualmente integrato nella distribuzione ufficiale delle adesklets.

Download adesklets-ruby


Full of CC licensed ripley's debris
HTML and CSS Design by Nicolas Fafchamps
Generated with Rote and Rog