Javascript

Javascript BDD (2)

Just a quick add-on on my previous post, I found there was already a nice BDD framework for javascript : JSSpec.

Go see the demo page, it looks really nice.

Published on Fri, 19 Oct 2007 14:57

Javascript BDD

It was a long time since I delved into Scriptaculous subversion repository. This morning I was browsing it to find out what’s coming for next versions (seems 2.0 is not so far away) and had a good surprise : it seems they add BDD to their test framework.

I must admit my last try to use TDD for my Javascripts do not last long and this is a great reason to try again but this time BDD-Style.

To give you a little overview of what it looks like here’s a snippet extracted from the specs for the BDD framework itself :

Test.context("BDD-style testing",{
  
  setup: function() {
    ...
  },
  
  teardown: function() {
    ...
  },
  
  'should provide extensions to tie in isSomething and respondsTo object methods': function(){
    ...

    testObj.shouldBe('nice');
    testObj.shouldNotBe('broken');
    
    testObj.shouldRespondTo('isNice');
    testObj.shouldRespondTo('isBroken');
  },
  
  'should automatically add extensions to strings': function(){
    'a'.shouldEqual('a');
    'a'.shouldNotEqual('b');
    'a'.shouldNotBeNull();
    'a'.shouldBeA(String);
  }
}

If you’re using RSpec it should (woot!) looks familiar.

Published on Sun, 07 Oct 2007 13:57

Prototype's Enumerable

My previous posts about Prototype were focused on shortcuts and functions to work on forms. This one is all about the Enumerable object.

Well, Enumerable is one of those terrific objects of Prototype. Basically it allows you to add enumeration to your objects or add prototype’s way to do it to standard javascript objects. But as javascript doesn’t allow you to redefine the way your object (or standard object) implements enumeration, it broke the standard javascript enumeration. As you should know, javascript allows you to enumerate through an object properties ( with the “for in” syntax) and takes care to step over unwanted properties, for example :

var myArray = [1,2,3,4]; // Let's build an array object

for ( i in myArray ) {
  console.info(i);
}

// Output to firebug console:
// 1 
// 2 
// 3
// 4

As you’ve seen, even if Array is an object, the enumeration step over methods to only gives you values. If you do the same thing with Prototype library loaded, you’ll get the following :

  var myArray = [1,2,3,4]; // Let's build an array object
  
  for ( i in myArray ) {
    console.info(i);
  }
  
  // Output to firebug console:
  // 0
  // 1
  // 2
  // 3
  // each
  // all
  // any
  // collect
  // detect
  // findAll
  // ...

So I let you imagine how this can break existing code. That’s why so many other javascript framework developers don’t like Prototype’s way of doing and in some way they are right, this is a constraint of Prototype you should be aware of : Prototype don’t play nicely with others.

Then, after this little precautions let’s examine what Prototype’s Enumerable objects can give us.
All you need, to add enumerability to your objects, is to define a function _each which takes a function as parameter and call this function with each iterable elements of your objects.

For example if your objects stores its elements in an Array, you can make your objects enumerable like this :

var MyObject = Class.create();
MyObject.prototype = {
  initialize: function() {
    this.elements = $A(arguments);
  }
  
  // The magic function :)
  _each: function(iterator) {
    for ( var i = 0; i < this.elements.length; i++)
      iterator(this.elements[i]);
  }
};
// Extends MyObject with Enumerable functions
Object.extend(MyObject.prototype, Enumerable);

Now our new object have the following methods :

  • each()
  • all()
  • any()
  • collect()
  • detect()
  • findAll()
  • grep()
  • include()
  • inject()
  • invoke()
  • max()
  • min()
  • partition()
  • pluck()
  • reject()
  • sortBy()
  • toArray()
  • zip()
  • inspect()

Nice for a single method added, isn’t it ?
Let’s see what we can do with this :

// Let's create a new MyObject object :)
var anObject = new MyObject(3,5,4);

// Iterate through values
anObject.each( function(element) {
  doSomething(element);
});

// Verify if all our values are lesser than 6
// return true
anObject.all( function(value) {
  return value < 6;
});

// Verify if any value is greater than 4
// return true
anObject.any( function(value) {
  return value > 4;
});

// Get an array containing all values as string prefixed by 'id_'
// return ['id_3','id_5','id_4']
valuesAsId = anObject.collect( function(value) {
  return 'id_' + value;
});

// Get the first element greater than 3
// return 5
anObject.detect( function(value) {
  return value > 3;
});

// Find all elements greater than 3
// return [5,4]
anObject.findAll( function(value) {
  return value > 3;
});

// Find all elements matching a given pattern
// here we assume our initialization was anObject = new MyObject('jonathan', 'tron');

// return ['jonathan']
anObject.grep(/h/)

// return ['JONATHAN']
anObject.grep(/h/, function(value){
  return value.toUpperCase();
});

// Find if 3 is an element of our object
// return true
anObject.include(3);

// Get the sum of our elements + 10
// return 22
anObject.inject(10, function(sum, value) {
  return sum + value;
});

// Want to call a method on each elements ?
// return ["3","5","4"]
anObject.invoke('toString');

// Want to call a method on each elements but this time with params ?
// return ["11","101","100"]
anObject.invoke('toString', 2);

// Get the greatest element
// return 5
anObject.max();

// Get the smallest element
// return 3
anObject.min();

// Separate the elements in two groups :
// those matching a condition and those no matching it
// return [ [3], [5,4] ]
anObject.partition( function(value) {
  return value <= 3;
});

// Get an array of a particular properties of each element
// here we assume our initialization was :
// anObject = new MyObject( {firstname: 'jonathan', lastname: 'tron'}, 
//                          {firstname: 'sam', lastname: 'stephenson'});
// return ['jonathan','sam']                            
anObject.pluck('firstname');

// Return all element for whose the given function return true
// return [3]
anObject.reject(function(value) {
  return value != 3;
});

// Sort using the given compare function
// here we assume our initialization was :
// anObject = new MyObject( {firstname: 'jonathan', lastname: 'tron'}, 
//                          {firstname: 'sam', lastname: 'stephenson'});
// return [{firstname: 'sam', lastname: 'stephenson'},{firstname: 'jonathan', lastname: 'tron'}]
anObject.sortBy(function(value) {
  return value.lastname.toLowerCase();
});

// Get a new array of elements
// return [3,5,4]
anObject.toArray();

// And the last one, I did not have any need for it by now, but I can imagine it could be helpful when dealing with some sort of columns and rows
// here we assume our initialization was :
// anObject = new MyObject( [1, 2, 3] );
// return [ [1,4,7], [2,5,8], [3,6,9] ]
anObject.zip([4,5,6], [7,8,9]);

But there’s more, what if you want to enumerate but stop the enumeration at some point or skip an iteration ?

Prototype defines two objects for this : $break and $continue.

// Iterate over our values but break if value is 2
[1,2,3].each( function(value) {
  if ( value == 2 ) throw $break;
});

// Iterate over our values but skip to next element if value is 2
[1,2,3].each( function(value) {
  if ( value == 2 ) throw $continue;
});
Published on Thu, 12 Oct 2006 14:45

Working on Forms with Prototype

Prototype besides its nices shortcuts provides some function to work with forms elements. So let’s see what prototype can do for us.

Published on Fri, 21 Jul 2006 22:11

Prototype's Shortcuts

Prototype is a wonderful javascript library written by Sam Stephenson.

The more I use it, the more I love it, it makes writting javascript so less painful.

This post is the first of a series aiming to discover its
features.

So let’s start with the lovely shortcuts provided by Prototype.

Shortcuts are functions whose names are as concise as possible, mostly 1 or 2 letters and wrap some of the most repetitive tasks you end up to write when doing javascript.

Published on Fri, 20 Jan 2006 11:17

RSS