Posts tagged "mootools"

Python loops can have else clause?!

I write a lot of Python. I also write a lot of JavaScript. As I switch between the two (often several times in a day) I sometimes find myself trying to do something in one using the syntax of the other. The most common example is joining a list.

# Python

' '.join(['foo', 'bar'])

// JavaScript

['foo', 'bar'].join(' ')

Often — as is the case above — the syntactical differences are minor, but there are times when there's no direct translation.

MooTools, for example, adds the every method to the Array object. This makes it possible to write some rather terse conditional statements.

var numbers = [87, 33, 21, 75];
if (numbers.every(function (n) { return n % 3 == 0; })) {
    window.alert('The numbers are all divisible by 3.');
}

Python lists have no comparable method, so how would one write this in Python?

numbers = [87, 33, 21, 75]
if [n for n in numbers if n % 3 == 0] == numbers:
    print 'The numbers are all divisible by 3.'

This approach involves using a list comprehension to create a list of numbers which are divisible by 3, and comparing this list to numbers. If the lists are equal, everything in numbers is divisible by 3.

Now for something a bit more challenging

Assume that we have a list of documents, and we want to know which of the documents contain all the terms in a list of search terms.

// (MooTools) JavaScript

var terms = ['python', 'list', 'methods'], matches = [];
documents.each(function (document) {
    if (terms.every(function (term) {
        return document.body.indexOf(term) != -1;
    })) matches.append(document);
});

Here, we could use the list comprehension approach as before.

# Python

terms = ['python', 'list', 'methods']
matches = []
for document in documents:
    if [t for t in terms if document.body.find(t) != -1] == terms:
        matches.append(document)

This is reasonably succinct, but not terribly efficient since each document is checked for every search term. Given that we're not interested in documents that lack even a single search term, it should be possible to rewrite this code so that we don't waste time on lost causes.

It turns out that Python has just the thing for the job: in Python, a loop statements may have an else clause!

terms = ['python', 'list', 'methods']
matches = []
for document in documents:
    for term in terms:
        if document.body.find(term) == -1:
            break
    else: # every term was found
        matches.append(document)

From 4. More Control Flow Tools:

Loop statements may have an else clause; it is executed when the loop terminates through exhaustion of the list (with for) or when the condition becomes false (with while), but not when the loop is terminated by a break statement.

I'm looking forward to finding more good spots to make use of else clauses with my Python loops. :D

Positioning elements using MooTools

I've spent the afternoon creating a custom scrollbar for a products viewer which utilizes CSS transitions, reflections, and other goodness.

Simple arithmetic dictates how long to make the scrollbar and where to position it, but I could not get my theoretical calculations to play out in the browser.

It turns out that I'd been calling the wrong MooTools method. I'd been doing…

element.setStyle('left', offset);

rather than…

element.setPosition({ x: offset });

Frustratingly, setStyle('left', offset) appeared to work, but its behaviour was unpredictable. I'm still confused by this, but at least I'm no longer stuck.

Auto-populating input fields with MooTools

Early this year I wrote a post titled Auto-populating input fields with Prototype. Looking at the code now, I realize that it's not very pretty. I'm rewriting this site's JavaScript in MooTools, and the new code is quite a bit more elegant.

// provide input hints
window.addEvent('domready', function () {
    $$('input[placeholder]').addEvents({
        focus: function () {
            if (this.hasClass('placeholder')) {
                this.removeClass('placeholder').set('value', '');
            }
        },
        blur: function () {
            if (this.get('value') === '') {
                this.addClass('placeholder').set('value', this.get('placeholder'));
            }
        }
    }).fireEvent('blur');
});

I really appreciate the fact that MooTools provides addEvents in addition to addEvent. As a result, the code above is clearer than a well-written Prototype equivalent.

MooTools every method

A reasonably common task is to determine whether a particular statement evaluates as true for every item in a collection. Take list, for example, an Array containing several numbers:

var list = [4, -1, 3, 2, 5];

One might wish to determine whether all the numbers in list are positive. The required logic is as follows:

  1. assume that all the numbers in list are positive, then…
  2. loop through list until the assumption is proven to be false, or until all items in list have been tested

In plain JavaScript, this can be achieved using a for loop…

var allPositive = true;
for (var i = 0; i < list.length; i++) {
    if (list[i] <= 0) {
        allPositive = false;
        break;
    }
}

… or a while loop (which is slightly more efficient).

var allPositive = true, i = list.length;
while (i--) {
    if (list[i] <= 0) {
        allPositive = false;
        break;
    }
}

Seriously, though, who is writing vanilla JavaScript in 2010? Everyone and their grandmothers are using JavaScript frameworks these days, and there are plenty of good ones out there. I recently made the switch to MooTools from Prototype, after deciding that while jQuery is fantastic, the MooTools philosophy is more to my liking.

With MooTools, one might consider using the Array object's each method instead of a for or while loop.

var allPositive = true;
list.each(function (item) {
    if (item <= 0) {
        allPositive = false;
    }
});

While this gets the job done, it's suboptimal for two reasons: the positiveness of every item is evaluated, which will often not be necessary; and, well, it ain't pretty. ;)

Enter every

As is so often the case in programming, if something seems fiddly and difficult there's probably a better tool for the job. In this case the Array object's every method is the perfect tool for the job.

var allPositive = list.every(function (item) {
    return item > 0;
});

This is terser than is possible with vanilla JavaScript. It reads better too, in my opinion!