viernes, 5 de marzo de 2010

Joose: JavaScript OOP ¡Por fin!

Me estreno en este blog (muy tarde, lo siento) con una entrada acerca de un framework JavaScript que acabo de descubrir, que me parece va a estar presente en mis futuros desarrollos: Joose. Esta librería se centra en uno de los aspectos más pobres de JavaScript, la Orientación a Objetos.

¿Para qué otro framework más?


Existen en la red multitud de frameworks para facilitar la tarea del desarrollador Web (tarea, por otro lado, bastante ingrata sin el uso de alguno o varios de estos frameworks). En general, la mayoría de ellos se centran en facilitar el acceso al DOM, las llamadas AJAX, e incluso ofrecer un entorno para desarrollo de interfaces de usuario.  Sin embargo, Joose se distingue de sus alternativas por enfocarse en el área quizá mas pobre de JavaScript, la orientación a objetos. A pesar de que otros frameworks como Prototype o Dojo ofrecen sus propios métodos para conseguir "más o menos" orientación a objetos en JavaScript, ninguno se acerca a la funcionalidad y organización de Joose. Según los propios desarrolladores, Joose ofrece "orientación a objetos postmoderna" en JavaScript.

Características básicas


No os voy a aburrir con detalles de implementación o documentación exhaustiva (la página os puede proporcionar mucha información), pero os cuento cosas que me han sorprendido gratamente:

  • Mecanismos habituales en la OO, como herencia (múltiple), interfaces, clases abstractas, singletons, etc, pero bien hecho.
  • Getters y Setters automáticos
  • Paquetes (espacios de nombres)
  • Roles (interfaces con esteroides)
  • Filosofía cercana a la orientación a aspectos
  • Persistencia automática de objetos con el storage de HTML5 y (creo) con recursos remotos usando AJAX
  • Reflexión de código y otras cosas chungas que sólo Sebas comprende

Show me the code!


Como este viernes no hay kata, como ejemplo de código publico una solución parcial (lo demás lo implementáis vosotros para probar el framework) a la kata cuatro cuatros de hace un par de semanas.

Role (interfaz) Printable, que requiere implementar el toString:

Role("Printable", {
 requires: "toString"
});

Clase Abstracta Exp, con un método estático (de clase). Implementa Printable:

Class("Exp", {
 does: Printable,
 methods: {
  toString: function(){},
  count4: function(){},
  getValue: function(){}
 },
 classMethods: {
  findExpresion(number) {
   // Resuelvelo tu
  }
 } 
});

Clase Op, que hereda de Exp:

Class("Op", {
 isa: Exp,
 has: {
  _operand: {is: "rw"},
  _left: {is: "rw"},
  _right: {is: "rw"}
 },
 override: {
  toString: function() {
   return "(" + this._left.toString() + this._operand + this._right.toString() + ")"
  },
  count4: function() {
   return this._left.count4() + this._right.count4()
  },
  getValue: function() {
   var result;
   switch(this._operand) {
    case "+":
     result = this._left.getValue() + this._right.getValue();
     break;
    case "-":
     result = this._left.getValue() - this._right.getValue();
     break;
    case "*":
     result = this._left.getValue() * this._right.getValue();
     break;
    case "/":
     if (this._left.getValue() % this._right.getValue() == 0) {
      result = this._left.getValue() / this._right.getValue();
     } else {
      throw "ValueError";
     }    
     break;
   }
   return result;
  }
 }
});

Clase Num, que también hereda de Exp:

Class("Num", {
 isa: Exp,
 has: {
  _value: {is: "rw"}
 }, 
 override: {
  toString: function() {
   return this._value
  },
  count4: function() {
   var stringifiedNumber = this._value + "";
   return countOcurrences(stringifiedNumber, '4');
  },
  getValue: function() {
   return this._value;  
  }
 }
});

Por último,una pequeña prueba de unidad (se usa el console.log que ofrece Firebug). Además, una función auxiliar que siendo puristas habría que haber metido en una clase.

countOcurrences = function(text, character) {
   return (text.length - text.replace(new RegExp(character,"g"), '').length / text.length);
  }

var exp = new Op({ 
  operand: '-', 
  left: new Num({value: 44}), 
  right: new Op({
   operand: '*', 
   left: new Num({value:4}), 
   right: new Num({value:4})})});
console.log(exp.toString());
console.log(exp.count4());
console.log(exp.getValue());

Esto es todo por hoy, espero que os haya gustado, y procuraré postear más a menudo.

2 comentarios:

  1. Javi, supongo que los títulos los prefieres grandes pero, ¿no deberías usar h4 en lugar de h2 para las secciones dentro de un h3?

    ResponderEliminar
  2. @Sebas: Corregido, es lo que pasa cuando no sabes que el título principal es un h3.

    ResponderEliminar