Piszę Ruby czytam Javascript…

Czy możliwość pisania w Rubym kodu, który jest automagicznie zamieniany na Javascript uruchamiany w przeglądarce nie brzmi intrygująco ?

Na liście ruby-talk kilka dni temu pojawił się post Paula Battley'a informujący o takim eksperymentalnym konwerterze. Dodam jeszcze, że cały kod który dokonuje tej konwersji ma około 250 linii... Musiałem sprawdzić, czy to rzeczywiście działa.

Postanowiłem napisać kawałek kodu w Rubym który wylicza n-tą liczbę z ciągu Fibonacciego. Gotowy efekt mojej pracy jest tutaj. Tak wygląda kod w Ruby:

RUBY:
  1. class Fibonacci
  2.     def initialize
  3.         @cache = {'0'=>0, '1'=>1}
  4.     end
  5.    
  6.     def calculate(n)
  7.         if @cache[n.to_s ]
  8.             return @cache[n.to_s ]
  9.         else
  10.             @cache[n.to_s ] = self.fib(n)
  11.             return @cache[n.to_s ]
  12.         end
  13.     end
  14.  
  15.     def fib(n)
  16.         @curr = 0
  17.         @succ = 1
  18.         n.times do |i|
  19.             # jasne, ze nie jest to ruby way
  20.             @tmp = @curr
  21.             @curr = @succ
  22.             @succ = @tmp + @succ
  23.         end
  24.         return @curr
  25.     end
  26. end
  27.  
  28. require 'rb2js'
  29. puts RB2JS.class_to_js(Fibonacci, :debug => true)

po konwersji na JS wygląda tak:

JavaScript:
  1. function Fibonacci() {
  2.    var self = this;
  3.    self.instanceVariables = {};
  4.    self.instanceVariables['@cache'] = {
  5.         "0" : Number(0), "1" : Number(1)
  6.    }
  7. }
  8. Fibonacci.prototype = {
  9.    calculate : function(n) {
  10.       var self = this;
  11.       if(rb_true(self.instanceVariables['@cache'][n.toString()])) {
  12.          return self.instanceVariables['@cache'][n.toString()]
  13.       } else {
  14.          {
  15.             self.instanceVariables['@cache'][n.toString()] = self.fib(n);
  16.             return self.instanceVariables['@cache'][n.toString()]
  17.          }
  18.       }
  19.    },
  20.    fib : function(n) {
  21.       var self = this;
  22.       self.instanceVariables['@curr'] = Number(0);
  23.       self.instanceVariables['@succ'] = Number(1);
  24.       n.times(function(i) {
  25.          {
  26.             self.instanceVariables['@tmp'] = self.instanceVariables['@curr'];
  27.             self.instanceVariables['@curr'] = self.instanceVariables['@succ'];
  28.             self.instanceVariables['@succ'] = self.instanceVariables['@tmp'] +
  29.                  self.instanceVariables['@succ']
  30.           }
  31.       });
  32.       return self.instanceVariables['@curr']
  33.    }
  34. }

Cały konwerter to oczywiście bardziej proof-of-concept niż prawdziwe narzędzie, ale szlak został już przetarty...

[ ]
Spodobało się? Podziel się z innymi: These icons link to social bookmarking sites where readers can share and discover new web pages.
  • del.icio.us
  • Wykop
  • Gwar
  • Digg
  • Technorati

Liczba komentarzy: 10 »

  1. Manthios said,

    lipiec 8, 2006 @ 08:39

    Ciekawa koncepcja :)

    Rozumiem, ze uzycie “calculate(n)” mialo wprowadzic pewien poziom skomplikowania dla konwertera - tak?

    — P.J.S.

  2. daniel said,

    lipiec 8, 2006 @ 09:30

    Dziękuję :)
    calculate dodatkowo cache’uje wyniki obliczen ciagu (trzymane sa @cache) stad taki dodatkowy stopien komplikacji.

  3. Manthios said,

    lipiec 8, 2006 @ 18:42

    No to moze sam fib(n) moglby korzystac z tego cache-a? Albo niech go chociaz pre-wypelnia w trakcie liczenia “dalszych” wynikow :) Wiem, wiem… nie o to chodzilo… przymykam sie ;)

  4. daniel said,

    lipiec 8, 2006 @ 20:56

    Tak jest czytelniej IMHO, ale skoro się pytasz to implementacja najszybszego zdaje się algortymu dla wyliczania liczb fibonacciego jest tutaj.
    Cala dyskusja na ruby-talk jest tutaj.

  5. Manthios said,

    lipiec 8, 2006 @ 21:55

    Zwracam honor! Nie wiedzialem, ze ludzie z tego doktoraty pisza :)

  6. daniel said,

    lipiec 8, 2006 @ 22:07

    hmm, chyba nie brałes nic ode mnie… ;)

  7. Suler said,

    lipiec 10, 2006 @ 13:14

    Valar enters the blogosphere. The world ends ;-)

  8. daniel said,

    lipiec 10, 2006 @ 14:00

    Suler na powietrzu, żebym zryżał…

  9. Adam Hoscilo said,

    lipiec 13, 2006 @ 14:03

    Mala optymalizaja (czytaj czepianie sie :)):
    @curr, @succ, i @tmp mozna zmienic ze zmiennych instancyjnych na lokalne i
    moze to zaoszczedzic jeden cykl procesora na milion.
    Chyba, ze RB2JS wymaga tu zmiennych instancyjnych (nie wyglada na to).
    Do tego pytanie czy przy konwersji tworzone sa jakiekolwiek obiekty czy analizowana jest tylko klasa.

    PS Zapomnialem sie przywitac. Witam:)

  10. daniel said,

    lipiec 13, 2006 @ 14:46

    No wreszcie ktoś to zauważyl !! Niestety tak musiałem zrobić żeby JS działał poprawnie :) w przeciwnym razie tworzone są w JS lokalne zmienne wewnątrz pętli i całość nie działa. Gratuluje spostrzegawczości!

    WItam serdecznie również.

RSS feed for comments on this post

Dodaj komentarz