Blog Posts tagged with: javascript

Oct 16 2012

Comments

Introducing Word Magic

You might have noticed that we have a number of authors at Relevance. Some of us studied literature and linguistics. We are a wordy bunch. We're also kind of obsessed with time, so it's shouldn't be a surprise that we would be interested in how language evolves over time. Lucky for us, then, that Google has digitized every book they can get their scanners on and made that data available to the world.

Read More »

Mar 02 2010

Comments

Jasmine for JavaScript Testing: It's Screw.Unit++

I'm pretty excited about Pivotal's JavaScript testing framework, Jasmine. The same folks who brought us Screw.Unit have upped their game. You still get the RSpec-style JavaScript DSL that you know and love, but Jasmine's a bit leaner and meaner, has a more robust architecture under the hood, and is sporting several exciting new features. I'm making plans now to move the Relevance fork of Blue Ridge over to use Jasmine instead of Screw.Unit.

New Infrastructure: No DOM or jQuery

Screw.Unit's biggest weakness is that it uses jQuery to store all its data in the DOM. The tests its going to run, their before/after behaviors, and whether they passed or failed -- it's all stored as attributes on DOM objects. It was a clever hack and works well enough for in-browser tests, but it causes trouble for headless testing.

Here's why: env.js is our DOM simulator. It pretends to be a browser, modeling HTML as JavaScript DOM objects. It strives to be an idealized DOM, separate from any particular browser's implementation. This is a pretty ambitious goal, and env.js does a pretty good job of it.

However, jQuery exercises the hell out of the DOM, and it really pushes env.js' buttons. It has to, since jQuery's biggest job is to adapt itself to whatever browser is running it. It pokes and prods env.js to understand its capabilities, and every new version of jQuery adds new tests. So, just about every time a new version of jQuery is released, it exposes areas of the DOM that env.js hasn't yet implemented, sometimes causing it to crash.

This situation isn't ideal, but it's workable if only your tests that exercised a particular part of the DOM failed due to the jQuery/env.js interaction. However, we often see these problems right away, as jQuery tries to determine capabilities early, sometimes stopping Screw.Unit immediately. Zero tests run. That is unacceptable.

Jasmine (like JSpec) doesn't need the DOM when it's not testing the DOM. It doesn't need jQuery when it's not testing jQuery. Jasmine was designed from the ground-up to be as stand-alone as possible. The folks at Pivotal have listed that as one of their most important design goals.

Easy Install & In-Browser Testing: The Jasmine-ruby Gem

The Jasmine-ruby gem is a Ruby program that generates Jasmine test scaffolding and that can run a small Ruby webserver to serve up your HTML fixtures. My favorite part of this is how environment-independent it is. No matter whether you're writing a Ruby on Rails app, a PHP website, a jQuery plugin, or even a Clojure webapp, it's the same command to generate and run your specs in-browser.

Other New Features

  • Leaner DSL:

    • Only superficial differences.
    • No longer wraps the whole test suite in a "Screw.Unit()" function.
    • Replaced Screw.Unit's matchers with a more JavaScript-y, camelCase syntax.
  • Asynchronous Testing Support

    • Learning from QUnit and JsUnit, Jasmine added testing tools for timers.
    • Very important for testing visual jQuery plugins, animations, etc.
  • Spies

    • Built-in mocking & stubbing.
    • Built-in "did-it-call-my-method?" checks.
  • Officially Maintained

    • Screw.Unit is basically abandonware.
    • Jasmine, however, is seeing active support from Pivotal.

Conclusion

So, a familiar DSL, less worries about the DOM and jQuery compatibility, and nifty new features -- I'm pretty excited to be using Jasmine. So long Screw.Unit, and thanks for all the fish.

Jul 27 2009

Comments

In Boston Aug 15: Triadic Programming

I will be premiering the Triadic Programming keynote at Developer Day Boston on August 15. The talk pulls together ideas I have been working out for over a decade, and proposes a new way to think about the abstractions that programmers use.

Of course, the best part of any technical event is happy hour, so I will be sticking around for the evening to meet folks, along with our excellent co-sponsors from Viget Labs and thoughtbot.

Oh, and there are lots of other interesting talks on the agenda, including one by some guy who apparently knows a bit about JavaScript. Hope to see you there!

Jun 05 2009

Comments

Refactoring JavaScript, 2009 Edition

I am off to Dallas this morning to give an all-new version of the Refactoring JavaScript talk. This year, we will be looking at testing and refactoring jQuery plugins, using Screw.Unit, Smoke, and blue-ridge.

You can grab the slides here, but as usual the slides tell only a little of the story. Instead, grab the project itself, and use git's local history to start at the beginning and watch the refactorings step-by-step.

Jun 04 2009

Comments

Introduction to jQuery

jQuery is a powerful JavaScript library for dealing with HTML, events, animations, and Ajax. Unlike many libraries, jQuery puts the browser object model front-and-center through its ubiquitous wrapped element sets. In this talk, you will learn to progressively enhance your web applications the jQuery way: with unobtrusive, functional JavaScript.

Along the way, you will learn how to:

  • select and modify elements with jQuery's powerful selectors
  • use jQuery's utility functions
  • register event handlers, including dynamic ones that track changes to the page over time
  • play nice with other libraries with `noConflict`
  • create Ajax requests that return HTML, JSON, and other data types
  • breathe life into your interface with effects and animations
  • unit test your JavaScript code with Screw.Unit, Smoke, and blue-ridge

May 12 2009

Comments

Blue Ridge 1.0: JavaScript Unit Testing for Rails. Scandalous!

You wouldn’t consider developing a Rails application without having a solid test suite for your Ruby code, but you’ve somehow convinced yourself to cross your fingers and look the other way when it comes to JavaScript. It doesn’t have to be that way.

Meet Blue Ridge, a Rails plugin that brings the goodness of test-driven and behavior-driven development to your unobtrusive JavaScript code in a Rails-friendly manner.

Blue Ridge

Historically, when selecting a JavaScript testing solution, you were forced to choose whether you wanted a framework that could run your tests in the browser or one that could only run your tests in a headless fashion. By providing a friendly convention-over-configuration wrapper around a collection of open source tools, Blue Ridge gives us the best of both worlds: fast, automation-friendly, and headless testing plus the ability to run your tests in whichever browser is acting up on any given day.

Last summer, Blue Ridge was just a twinkle in our eye. Last week, Blue Ridge made its public debut at RailsConf. Today, we’re pleased to announce version 1.0.

Getting Started

First, install Blue Ridge into your Rails app:

  ./script/plugin install git://github.com/relevance/blue-ridge.git
  ./script/generate blue_ridge

Blue Ridge creates a small example spec to get you started. Run your JavaScript specs to make sure that all is well so far:

  rake test:javascripts

(Hint: You can also use the `spec:javascripts` or `examples:javascripts` aliases. Blue Ridge is compatible with your testing framework of choice, be it test/unit, RSpec, Micronaut, Shoulda, test-spec, etc.).

Next, try running an individual spec. When you installed Blue Ridge, it created a spec file named “application_spec.js”. You can run it like so:

  rake test:javascripts TEST=application

Of course, you really want to generate a spec that’s specific to your app. Let’s say you want to write some tests for a JavaScript file called “public/javascripts/graphics.js”. Run:

  ./script/generate javascript_spec graphics
  rake test:javascripts TEST=graphics

Cool. We can run our JavaScript specs from the command line, and they’re fast! But you just got a bug report regarding JavaScript errors in IE6 (die already!), and you want to write some tests to prove (and then resolve) the bug. To run your spec inside a web browser, simply load the HTML fixture associated with the spec (e.g., “test/javascripts/fixtures/graphics.html” for the tests in “graphics_spec.js”) and see the results of running the tests in that specific browser.

Check out the README for more information on the directory layout and a detailed description of the various Blue Ridge components.

jQuery-Opinionated

Blue Ridge wouldn’t quite fit into the Rails ecosystem if it didn’t come equipped with a few opinions. So by default, it assumes you’re using jQuery. “application_spec.js”, which was generated when you installed the plugin, includes an example of calling jQuery functions inside a test.

  require("spec_helper.js");
  require("../../public/javascripts/application.js");

  Screw.Unit(function() {
    describe("Your application javascript", function() {
      it("provides cliché example", function() {
        expect("hello").to(equal, "hello");
      });

      it("accesses the DOM from fixtures/application.html", function() {
        expect($('.select_me').length).to(equal, 2);
      });
    });
  });

And, no, we don’t actually encourage you to write tests for standard libraries like JQuery and Prototype; it just makes for an easy demo.

Prototype-Friendly

If you prefer Prototype, no problem: “Have it your way.”

  jQuery.noConflict();

  require("spec_helper.js");
  require("../../public/javascripts/prototype.js", {onload: function() {
      require("../../public/javascripts/application.js");
  }});

  Screw.Unit(function() {
      describe("Your application javascript", function() {
          it("accesses the DOM from fixtures/application.html", function() {
              expect($$('.select_me').length).to(equal, 2);
          });
      });
  });

Put jQuery into “no conflict” mode to give the `$` function back to Prototype, require `prototype.js`, and chain any files that are dependent on `prototype.js` in the `onload` callback. Done. Your Prototype-based tests await you.

Act Now, and We’ll Throw in Mocking Support

Blue Ridge includes Smoke, a JavaScript mocking and stubbing toolkit somewhat similar to Mocha. Assume we’re testing a function called `calculateTotalCost`, and you want to ensure that it calls `calculateComponentPrice` for each given component. That test might look something like so:

  it("calculates the total cost of a contract by adding the prices of each component", function() {
    var componentX = {}, componentY = {};
    mock(SalesContract).should_receive("calculateComponentPrice")
      .with_arguments(componentX).exactly(1, "time").and_return(42);
    mock(SalesContract).should_receive("calculateComponentPrice")
      .with_arguments(componentY).exactly(1, "time").and_return(24);
    expect(SalesContract.calculateTotalCost([componentX, componentY])).to(equal, 66);
  });

Fun with TextMate

Running individual specs from the command line is an essential feature, but if you use TextMate like we do, you’d rather not have to leave your editor in order to run a spec. If this describes your development style, take the Blue Ridge TextMate Bundle for a spin.

  cd ~/Library/Application Support/TextMate/Bundles/
  git clone git://github.com/karnowski/blue-ridge-tmbundle.git Blue\ Ridge.tmbundle

Once you reload your bundles (or restart TextMate), just hit Command-R to run the currently-open spec directly from TextMate.

And be sure to check out the snippets as well. Type `it`, `des`, `bef`, or `aft`, and then press the tab key to expand into full `it` blocks, `describe` blocks, etc.

But Wait, There’s More

Want more examples? To see Blue Ridge in action inside a working Rails app, check out the Blue Ridge sample application. Among other things, the sample app includes examples of:

  • using nested `describe` functions
  • setting up per-spec HTML “fixtures”
  • stubbing and mocking functions
  • running the Blue Ridge specs as part of your default Rake task

Money Back Guarantee

Blue Ridge is guaranteed to be bug free and fulfill your every need, or your money back! Of course, in lieu of a full refund, you’re welcome to hop over to the project’s GitHub issue tracker to let us know about any issues or ideas for possible improvements. Even better, fork the repo and start hacking! If you have patches, send us pull requests.

Now, go forth and give your JavaScript code the testing love it deserves!

Apr 30 2009

Comments

JavaScript Testing at RailsConf

Jason and I will be at RailsConf next week speaking about Blue-Ridge, our Rails plugin that makes test-driven JavaScript development easy and natural!

Here's our abstract: > Learn how to enjoy the benefits of test-driven development beyond just your Ruby on Rails code.  JavaScript is code too, and it deserves tests! With the help of some handy plugins, Rails lets you test your unobtrusive JavaScript using tools such as Screw.Unit and Smoke. The tools and approach are library-agnostic; they work well with jQuery, Prototype, and others.

The talk is at 1:50 PM on Tuesday, May 5. Come check it out, and give your JavaScript code the testing love it deserves.

Jan 12 2009

Comments

Why I still prefer Prototype to jQuery

Like most programmers who’ve done Rails development, I’ve become very familiar with the Prototype library for JavaScript. Even apart from being built into Rails, Prototype was a natural choice for me. I knew JavaScript pretty well before I started working with Prototype, and was very pleased by how the library filled in some of the weak spots in the language. Additionally, having already been a Ruby programmer for a few years, Prototype’s philosophy seemed very natural; it clearly draws inspiration from Ruby.

Along the way, though, I’ve been hearing an increasingly strong chorus in favor of jQuery. I had taken a cursory look at jQuery and was impressed, but didn’t see anything compelling enough to make me switch. But increasingly the voices favoring jQuery have included people I really respect, including (over the past few months) several of my colleagues here at Relevance.

I’ve now spent serious time working on two different projects with jQuery. I’ve worked alongside some experienced jQuery users, and really increased my knowledge and level of comfort with jQuery. The work has included a reasonable variety of JavaScript tasks, from simple to complex, so I’ve had a chance to enjoy jQuery’s sweet spot and also to see how it stretches.

And here’s the capsule summary: jQuery is a very nice piece of work, and makes some common tasks easier than their Prototype equivalents. Where it’s good, it’s very good indeed. But its design is uneven, and its scope is limited. For me, at least, Prototype is still the tool of choice. I think it’s a richer, more thorough, and overall better designed library.

I don’t intend this to be an anti-jQuery screed (although I will rant a little about a couple of things that seem particularly poorly designed). Neither is it an exhaustive comparison of Prototype and jQuery. Simply put: praise has been lopsided in favor of jQuery of late, and I feel like singing the praises of my personal favorite.

Note: in this post I’ll be showing code examples using both Prototype and jQuery. To keep things straight, I’ll color-code the listings. Prototype samples will have a green background:

  // This is Prototype!
  $('form').hide();

Samples using jQuery will have a yellow background:

  // This is jQuery!
  $('#form').hide();

The occasional sample that shows the “Plain ol' JavaScript” way to do things will have a grey background:

  // This is ordinary JavaScript!
  document.getElementById('form').style.display = 'none';

Where jQuery Comes Out on Top

jQuery clearly has a core focus and philosophy that unifies its design. The idea seems to be that, since most of what you want to do with JavaScript is to find HTML elements and manipulate them, the design should be optimized in favor of that common use case. And jQuery certainly excels in that case. The jQuery documentation emphasizes the ability of many jQuery methods to be “chained” (because they return the jQuery object). I'm personally more impressed with the implicit iteration: when jQuery is used to find a set of elements, modifications are automatically made to all of those elements.

I would describe the “three pillars” of jQuery this way:

  • searching for elements using CSS selectors
  • operations implicitly applied to all found elements
  • ability to chain operations

Each of those are powerful features, but more importantly, they work beautifully together. They allow jQuery programmers to express complex manipulations of the DOM in very concise ways, without losing clarity.

This section isn't very long, so someone skimming this post might get the idea that I don't think jQuery has a lot going for it. But I really admire this aspect of jQuery. The coding style that arises from these features shapes the way you do everything in jQuery. Furthermore, the fact that three such simple ideas can have such enormous positive effects on code written using the library speaks volumes for the power of good design.

It's just a shame that the rest of jQuery is not as well designed.

In some ways, it's harder to make the case for Prototype, because that case depends on numerous small details, some of which are strengths of Prototype, and some of which are weaknesses of jQuery.

However, I have to say that, while jQuery wins in this area, it doesn't win by as much as some would have you believe. Most of the comparisons I've found on the web are rather ridiculous, because they compare jQuery against very poor examples of Prototype usage. Take this example:

  // Good jQuery
  $('blah blah').addClass('foo');

compared with

  // Prototype (explicit iteration)
  $$('blah blah').each(function(element) {
    element.addClassName('foo');
  });

There’s a much better way to do that in Prototype:

  // Prototype (implicit iteration)
  $$('blah blah').invoke('addClassName', 'foo');

The invoke method in Prototype will apply a named method to each element of a collection.

Prototype's DOM methods are also chainable, even when using invoke.

Where It’s a Wash

Critics of Prototype have tended to focus on three issues: code size, performance, and namespace pollution.

These days, Prototype and jQuery have about the same code size. Prototype is a little larger, especially since it doesn’t ship with a minimized version. But if you care about code size, that’s easily remedied. It’s not hard to run a JS minimizer. It’s also worth pointing out that the very small code size gap is not gratuitous; Prototype has more functionality. (In looking at this issue, I’ve compared core Prototype against core jQuery, and also Prototype+Scriptaculous against jQuery+jQuery.ui.)

Although Prototype’s performance has not always been good, it has improved a great deal, in many cases by learning lessons from how jQuery has done things (and in some cases, the patches were even submitted by the jQuery developers). Today, Prototype’s performance is close to that of jQuery, and the very poor performance Prototype used to have for some situations (and in some browsers) has been eliminated.

The other issue is namespace pollution. Prototype adds several top-level names to the JavaScript global namespace, and adds numerous new methods to built-in JavaScript classes. There is a potential for namespace collision, either with other JavaScript libraries or with new JavaScript features. (And it’s more than just potential; real collisions of both kinds have occurred.) jQuery, on the other hand, takes care to limit its use of existing JavaScript namespaces, and can be configured to use only one global name (jQuery).

I fully understand the dangers of Prototype’s approach, but after living with both it and jQuery for some time, I’ve come to appreciate that it also has important benefits. JavaScript is a language that is extremely dynamic and open, and also deeply flawed. Prototype’s developers have chosen to take advantage of that openness to try to fix (or at least smooth over) many of JavaScript’s biggest weaknesses. The fact that Prototype’s facilities feel well integrated into the language is a huge win for me, and it seems to be worth the cost. I don’t expect this argument to convince anyone; this is the kind of thing that boils down to taste and priorities. But for me, Prototype’s and jQuery’s approaches to namespace management have complementary costs and benefits, and I don’t think this is a good reason to choose one library over the other.

Where Prototype Wins

Now I’ll describe where I think Prototype has the advantage, touching on three different areas: a more polished API, some issues with the way jQuery uses this, and a broader, more versatile array of programming facilities.

API Polish

I’ve already mentioned how beautifully designed jQuery’s core is. The problem is that the parts of jQuery outside that core are often poorly designed, in ways that really frustrate me. I’ll describe four.

When using the each method for iteration, the arguments to the iteration function are in the wrong order. (I know, I know … if you program the “jQuery way” you won’t actually use those arguments. I’ll address that later.) Here’s an example:

  // jQuery (non-idiomatic)
  $.each(collection, function(index, item) {
    item.whatever();
  });

When iterating over a collection, you nearly always want to work with the element of the collection, and you rarely need to actually refer to the index. The arguments should be the other way around, so that you could omit the index argument in the vast majority of cases where you don’t need it. Here’s the equivalent in Prototype:

  // Prototype
  collection.each(function(item) {
    item.whatever();
  });

Prototype’s each does pass an index argument to the iteration function, but it’s the second argument, so it can be omitted if not used—which is nearly always.

But jQuery can’t even be consistent about this. Here’s how jQuery’s map works:

  // jQuery
  var result = $.map(collection, function(item) {
    item.whatever();
  });

The argument order for map is item, index—just what you want, but it’s sad that it’s inconsistent with each.

And jQuery’s map is broken in other ways as well … the traditional definition is that the result array has the same number of elements as the original, but with jQuery’s version that’s not true. (What I refer to as “the traditional definition” of map is the one used by Common Lisp, Scheme, Haskell, OCaml, Erlang, Ruby, Python, Perl, Scala, and more.) I won’t dwell on the details of how jQuery’s map is broken, but one consequence is that it’s impossible to use it to produce an array of arrays, because any arrays returned from the mapping function will be flattened into the result array.

jQuery has a unique method. It returns all the unique elements from an array; that is, it eliminates the duplicates. Very handy. But for some reason, it only works on arrays of DOM elements. It silently fails (by returning a copy of the original array) if you pass it an array of anything else. This is a known problem, but the bug was “fixed” by just updating the documentation to make the behavior clearer. How difficult would it have been to make it work correctly? (Answer: not very, because the bug report came with a patch and tests.) Prototype’s uniq method works in both cases.

Finally: jQuery also has an inArray method. You can call it like this:

  // jQuery
  $.inArray(value, array)

But what does it return? Well, “in array” is a question that has a yes or no answer, so I’m guessing a boolean. Let’s see what the docs say:

Determine the index of the first parameter in the Array …

Ah, it returns the index. But that’s OK … JavaScript supports the notion of “truthiness”, meaning that objects other than true and false can be used where a boolean is expected. Truthiness is useful, because it means boolean results can actually be useful outside of strictly boolean contexts, and returning the actual index in this case is a great example of that. So as long as inArray returns false, null, or undefined if the value is not in the array, we’re in good shape. But I left out part of that documentation above. The rest of it is:

… (-1 if not found).

Gack! How useless is that? The name of the method implies that it’s a boolean query, but the result value is not useful in a boolean context. And if you just try using it that way, making an assumption based on the name, you’ll have fun debugging it, because there won’t be an error; it’ll just always be true.

For fifty years, programming languages have been using two common names for the job that inArray does: index and position. Having a method called inArray that works like this is just sloppy library design.

Leave this Alone!

When complaining about iterator arguments to jQuery’s each, above, I mentioned that the “jQuery way” is not to use the arguments to the iterator function at all. That’s because when jQuery’s each calls your iterator function, it does so in such a way that the variable this is bound to the current item. So the idiomatic way of using each in jQuery is:

  // jQuery
  $.each(collection, function() {
    this.whatever();
  });

That’s the kind of decision that makes really simple cases very easy, but only at the expense of a lot of confusion when things are a bit more complicated. That’s because this is already an important variable in JavaScript, and the callback often needs to refer to the value of this from the scope in which it was defined. Functions in JavaScript are closures, and programmers often need to exploit the ability to refer to variables in the surrounding scope.

Here’s an example. I have an object (called chart), and in a method on that object I need to iterate over an array (stored in the property columns), generating a header for each item using buildHeader, which is another method on chart. Within methods of chart, of course, chart is referred to as this. The basic JavaScript way of doing that is:

  // Ordinary JavaScript, in a method body.
  for (var i=0; i<this.columns.length; i++) {
    this.buildHeader(this.columns[i]);
  }

But that manual iteration sure feels clumsy; it would be nice to be able to do that with each. Let’s do that with jQuery:

  // jQuery (incorrect example)
  $.each(this.columns, function(i, item) {
    this.buildHeader(item);
  });

But that doesn’t work; this within the iterator function has been rebound to the current item. The this variable from the surrounding scope has been shadowed by a different this that refers to the current iteration item. But unlike i and item, this has been shadowed implicitly, by jQuery’s implementation of each.

The preferred jQuery way to write the example is to provide an alias for this that doesn’t get shadowed by each:

  // jQuery (correct example)
  var me = this; // provide alias for this
  $.each(this.columns, function() {
    me.buildHeader(this);
  });

But notice that this in the iteration function is a different this than in the immediately preceding line, even though conventional JavaScript closure semantics would lead you to believe they were the same. When building a complicated class, jQuery’s (ab)use of this can make things very confusing.

Here’s how to do the same thing in Prototype:

  // Prototype
  $A(this.columns).each(function(item) {
    this.buildHeader(item);
  }, this);

Messing with this implicitly is a terrible design decision. It breaks the conventional semantics of JavaScript, rendering the resulting code unclear, and presenting barriers when you need to exploit the usual semantics. I understand the desire to have an implicit iteration variable; good names might be it or item. Unfortunately, JavaScript doesn’t provide a mechanism for jQuery to set those variables from outside the function; it can only manipulate this. But that’s not enough justification for the design choice jQuery makes.

If jQuery’s each were properly designed, one could write the basic iteration idiom this way:

  // jQuery (with hypothetical fixed 'each' method)
  $.each(collection, function(it) {
    it.whatever();
  });

Would that be so bad? No; in fact, it would be a huge improvement. This style is just as easy in the simple case, and far less troublesome in more complex cases.

Broader Scope

I mentioned earlier that jQuery has a core of functionality built around querying and manipulating DOM elements. It also has mature support for Ajax operations. Beyond that, though, jQuery doesn’t aim for very extensive facilities. (Of course there are numerous plugins and add-ons that do all kinds of things, as there are for Prototype.)

Prototype, even in the core library, has broader goals. It also has good facilities for DOM searching and manipulation, and for Ajax operations. To a greater degree than jQuery, though, Prototype attempts to raise the level of JavaScript programming across the board. To me, the result is a big win for Prototype.

For example: Prototype includes a nice, simple class-based inheritance facility for JavaScript. That might seem a bit heretical for a prototype-oriented language like JavaScript (and especially for a library called Prototype). But the strength of the prototype-oriented style of OO is that it gives you freedom to move beyond the class-based mechanisms. That doesn’t mean that classes are useless; actually, they’re the most appropriate way of organizing your code a lot of the time.

Prototype also adds useful new basic types (such as ObjectRange, Template, and a true Hash) and adds a wealth of supplementary methods to most of the built-in JavaScript types, greatly increasing the ease of basic programming in the language. For advanced JavaScript programming, Prototype’s new Function methods are worth the price of admission all by themselves. jQuery makes working with the DOM very easy, but is sparing in its assistance related to other JavaScript objects. Prototype, on the other hand, helps across the board.

So while jQuery might be easier to get started with, Prototype grows with you better. Most web developers get started with JavaScript by doing relatively simple DOM manipulation, and jQuery really excels there. But as you get more comfortable and begin trying to do more, you may find that jQuery doesn’t help you as much. Prototype makes JavaScript programming lots of fun even in circumstances where jQuery feels constraining.

Conclusion

I don’t think this makes a slam-dunk case for Prototype over jQuery. And certainly jQuery could improve; its design is not fundamentally limited. (For that matter, many of what I consider the missing pieces in jQuery are available as plugins.) It’s unfortunate that some of jQuery’s API flaws can’t be fixed without breaking compatibility, but in a future version even that may be an option.

At a minimum, though, Prototype can hold its own. For me and many others, it’s still the JavaScript library of choice.

(Thanks to Stuart Halloway, Chad Humphries, Larry Karnowski, Adam Keys, and Jason Rudolph for their comments—in some cases pro, in others con—on a draft of this article.)

Nov 21 2008

Comments

Clojure Wins Again

Steve Yegge's most recent post takes a right angle turn about a third of the way through, and begins a comparison of Emacs Lisp and JavaScript.

And the winner is ... Clojure!

OK, Steve didn't say that. What he did do was call out things he liked about JavaScript and Emacs Lisp.

For JavaScript:

  • momentum
  • (namespace) encapsulation
  • delegation (polymorphism?)
  • properties (by Steve's definition)
  • serialize to source

For Emacs Lisp:

  • Macros
  • S-Expressions

I first picked up Clojure looking for many of the same things that Steve wants. I found them. Clojure can do all the things on both lists above. (Serialize to source isn't formal yet, but check the mailing list. And of course, you will have to judge "momentum" for yourself.)

The scary thing is that Clojure wins the language war before you even learn about its signature features. When I started exploring Clojure, I quickly realized it had everything I wanted, which could be summarized as "Lisp that really embraces the Java platform."

Then Clojure changed the definition of what I wanted. Now I also want

If you have half an hour, watch a compelling vision of what software development will look like in 2010.

Jul 31 2008

Comments

Fully Headless JSSpec

Update 2009-05-12 - With the release of Blue Ridge 1.0, fully headless JavaScript testing just got a whole lot easier! Check out the plugin for the current state-of-the-art approach to unit testing JavaScript in your Rails projects.

I have been frustrated at the state of testing for JavaScript. There are a bevy of great (and not-so-great) choices for testing your JavaScript, but nothing that is current, effective, and automated. We used Crosscheck for a while, but the project went stagnant and was awfully heavy-weight besides. On top of which, it didn't offer a BDD-flavored spec syntax.

I've been a fan of JSSpec for a while, but its "runs tests only in the browser" style means that automated server-side, continuous testing was nigh upon impossible.

Then, along came John Resig and his marathon weekend of hacking to mock out the DOM API in a relatively simple JavaScript file and voila! Headless JSSpec testing for Rails apps could become a reality.

If you are interested in trying it out, first download and install Rhino 1.7R1. Make sure you put the js.jar file on a globally accessible path somewhere. Then, get a copy of my javascript_testing repo at Github (http://github.com/relevance/javascript_testing/tree/master). It is a minimal repo, with just enough to get you started. The files in the repo are:

  • env.js -- a clone of John Resig's browser environment file, with a couple of minor tweaks for Script.aculo.us support
  • test_jsspec.rake -- a couple of rake tasks for running the tests, and for integrating them with CruiseControl (will add support for other CI solutions as I can)
  • jsspec/jsspec.js -- an unmodified copy of the jsspec trunk, here for your convenience
  • jsspec/config.js -- a series of, essentially, global includes for your specs. Edit to suit your own environment
  • jsspec/consoleReportForRake.js -- an extension to JSSpec that adds an afterAll hook for reporting errors that blow up your Rake task appropriately (for continuous integration purposes)
  • jsspec/prototypeForJsspec.js -- a minor tweak to Prototype to get it working with the env.js file

To get rolling, copy everything but the rake task into RAILS_ROOT/test/javascripts. Put the rake task in RAILS_ROOT/lib. Edit jsspec/config.js to load any standard JavaScript files your project uses. Then, start writing specs. Here's an example, RAILS_ROOT/test/javascripts/spec_string.js:

load("jsspec/config.js"); 
with(Spec) {  
   describe("Prototype's String.stripTags", function() { with(this) {  

     it("should remove open and close tags", function() {  
        ("<h1>text</h1>".stripTags()).should(equal("text"));
     });

     it("should remove self-closing tags", function() {
        ("text<br/>".stripTags()).should(equal("text"));

     });
   }});
};

Specs.report = "ConsoleReport";  
Specs.run();

To run this, use the targeted version of the rake task:

:trunk:-> rake test:jsspec TEST=spec_string.js
(in /Users/jgehtland/RELEVANCE/project/trunk)
.
.

2 passed. 

Run 2 examples in 0.001seconds.

:trunk:-> 

(Simply running rake test:jsspec will run any file in your test/javascripts folder whose name begins with "spec" and report the results.)

We don't actually encourage you to write specs and tests for standard libraries like Prototype, JQuery, etc. It just makes for an easy demo.

If you want to test something that requires some HTML to bind against, I generally create a folder called test/javascripts/fixtures, and load HTML exemplars in there. For example, to test Prototype's $$ selector, you might create a fixture called fixtures/selector.html that contains the following:

<html>
<body>
  <div class="select_me"/>
  <span class="select_me"/>
  <div class="dont_select_me"/>
</body>
</html>

Your test, spec_selector.js, would now contain:

load("jsspec/config.js"); 
window.location = "fixtures/selector.html";
load("jsspec/jsspec.js");

with(Spec) {  
   describe("Prototype's $$ selector", function() { with(this) {  

     it("should find only elements with the provided class selector", function() {  
        ($$('.select_me').length).should(equal(2));
     });

     it("should find only elements with the provided tag", function() {
       ($$('div').length).should(equal(2));
     });

   }});
};

Specs.report = "ConsoleReport";  
Specs.run();

If you want these tests to be part of your regular CI process, just uncomment the second task in test_jsspec.rake and you can now have CI for your JS, ASAP.

Popular Tags