JavaScript


Here’s a fun bit of JavaScript inspired by Yehuda Katz’s jspec. It lets you call a function with a particular scope, making it ideal for calling functions that depend on a particular scope, but for whatever reason you don’t want to set up that scope statically.

function callWithScope(fn, context, scope) {
  var fn_body = fn.toString().match(/^[^\{]*\{((.*\n*)*)\}/m)[1];
  fn = new Function('__scope__', 'with(__scope__){\n' + fn_body + '\n}');
  return fn.call(context, scope);
}

How might this be used? When writing a JavaScript spec, allowing the describe callback function to call it.

describe("callWithScope", function() {
  it("should not retain the original function scope", function() {
    ...
  })
})

Notice that it doesn’t appear to come from anywhere. When the callback passed to describe is given to callWithScope, the call might look something like this:

callWithScope(callback, this, {it: function(name, body) { ... }})

The describe callback function is turned into a string and turned into a new function of one argument, the scope. It makes it look something like this, though this isn’t entirely accurate:

describe("callWithScope", function(__scope__) {
  with(__scope__) {
    it("should not retain the original function scope", function() {
      ...
    })
  }
})

I’m using this in one project to call functions defined in some external scripts that expect certain objects and functions to be available. Also, since I can pass in my custom scope, I don’t have to do the work of ensuring that every function that needs that scope is declared within it. This allows me to abstract out a lot of shared code.

I’m sure there are a lot of uses for this I haven’t thought of. What’s yours?

Simple and easy javascript dependency management.

Why?

This plugin grew out of my desire to use javascript effectively in my new job. We began using UJS, and that was a good step in the right direction. The problem was that I found myself wanting to break the code I was writing into logical sections, so I created this convention:

The url /account/edit automatically includes /javascripts/account/edit.js if it exists, otherwise it would try /javascripts/account.js, and otherwise nothing. This convention worked pretty well, except that I found that often controllers would share code. I could have just included the controller javascript as well, but on top of that there was another convention: /javascripts/models/base.js, which communicates with the server (getting JSON back), and its subclasses. Controllers didn’t have a 1-1 mapping to models, so I needed some mechanism to specify what should be included where without a bunch of conditional statements in application.rhtml.

How to use it

My solution (from one index.js):

// require prototype menu models/tag models/interest builder moo.fx.pack.js

This is the first line of the file, and it tells my plugin to make sure that it includes these files before it includes this one when using javascript_include_tag. So the output of javascript_include_tag('index') would be this:

<script type="text/javascript" src="/javascripts/prototype.js"></script>
<script type="text/javascript" src="/javascripts/menu.js"></script>
<script type="text/javascript" src="/javascripts/models/tag.js"></script>
<script type="text/javascript" src="/javascripts/models/interest.js"></script>
<script type="text/javascript" src="/javascripts/builder.js"></script>
<script type="text/javascript" src="/javascripts/moo.fx.pack.js"></script>

It also handles recursive includes:

A.js: // require B …

B.js: // require C …

C.js: …

Here calling javascript_include_tag('A') returns:

<script type="text/javascript" src="/javascript/C.js"></script>
<script type="text/javascript" src="/javascript/B.js"></script>
<script type="text/javascript" src="/javascript/A.js"></script>

And, if two different scripts require the same script, it’ll only be included once:

A.js: // require prototype …

B.js: // require prototype

javascript_include_tag('A', 'B'):

<script type="text/javascript" src="/javascript/prototype.js"></script>
<script type="text/javascript" src="/javascript/A.js"></script>
<script type="text/javascript" src="/javascript/B.js"></script>

This even works if you include ‘A’ and ‘B’ in different calls to javascript_include_tag.

Installation

script/plugin install http://eventualbuddha.textdrive.com/svn/javascript_require/

Having a full-time Rails job can really spur you to find out more about what’s going on in Ruby and Rails. I’ve found that I’ve learned quite a bit about what’s going on in the last month and that I’m still learning at a breakneck pace, so here goes, in no particular order:

Piston

“Vendor branch management” gem that lets you store other projects (like Rails plugins) inside your own repository while retaining the ability to update them. This is particularly useful with Rails because you don’t really want to have outbound connections fetching your svn:externals every time you do a Capistrano deploy.

All my svn:externals have been Piston-ized.

EZ-Where

A Rails plugin that allows building the ActiveRecord find options hash based on Ruby code:

Article.findwhere(:all) { |article| article.publishedat < => (from..to) }

Great for complex queries. Using this plugin in WishRadar cut about 45 lines of code that generated SQL manually into about 12 of easy-to-read ruby.

Continuous Builder

An “Official” Rails plugin to make it easy to set up continuous integration testing with email and Campfire notification support. I’ve been using this for about two weeks and it’s pretty reliable, though setting it up with a Subversion post-commit and getting migrations to run is a little tricky. My hacked continuous_builder.rb’s make method:

def make @output = cd #{@options[:application_root]} && #{@options[:bin_path]}rake db:migrate RAILS_ENV=test && #{@options[:bin_path]}rake db:migrate RAILS_ENV=development && #{@options[:bin_path]}rake #{@options[:task_name]} RAILS_ENV=test make_successful? end

To prevent Subversion from blocking when doing a commit, run scripts with STDERR redirected to STDOUT and put the process in the background:

/path/to/continuous-builder 2>&1 &

“My Rails Toolbox” Article

Wonderful list of stuff to use on a Rails site if you’re serious about going to production.

Caboo.se RDOC Documentation Project

They’ve started work on an app to make it easy to produce diffs for documentation purposes. Better Rails docs now!

FixtureScenarios

A large fixture set is very hard to manage, so a plugin to keep them in discrete ’scenarios’ making them independent and “preventing you from changing your assumptions in a dangerous way” is a great idea. Beware, though - it may not play nice with other fixture-related plugins. (in case you’re wondering, it’s better than FixtureSets)

memcached

A network-enabled memory store that basically acts like a giant hash. Good for sessions and whatever other data you need to cache in your app. See the article. Haven’t used it much but I’m looking forward to it (trying to avoid the premature optimization itch).

QueryTrace

A plugin to print a stack trace with each SQL query in your logs. This hasn’t proved invaluable yet, but I’m guessing that once we start optimizing our queries and caching, it’ll be a lifesaver.

hpricot

Fast - like C fast - forgiving HTML parsing. Yeah baby.

Rails 1.2

This will include ActiveResource, DHH’s latest code built to tackle one half of the REST web services problem, as well as some nifty enhancements to routes that will cover the other half.

RSpec

Unit testing done in a more DSLish way. Specify what should happen, and in what contexts, and you’re halfway done with your tests. Really more of a psychological helper than anything else, but that’s what good DSLs are for, right? Check it out at rubyforge. I haven’t tried this yet, but it’s on my list.

One of my biggest annoyances with Firebug was that when you are in the Inspector and wish to get an element into the console, you have to use some JS hackery in order to do it. Well, at some point this limitation was removed — or it never really existed except in my head. All you have to do is reference $1 in the console. Yay!

There are a few tickets on the RoR trac asking for some sort of compression of the source (#5830, #4729, #4191). I’ve traditionally been against this, mainly because I’ve used third-party libraries that were minified, and found them impossible to work with when something goes wrong. With the most recent ticket, I found myself writing another comment and closing it, but I decided to look into it more before I did. I used the Dojo compressor (labeled rhino) and Dean Edward’s packer (labeled packed) to compress prototype.js.

55149 prototype.js (100%) 12479 prototype.js.gz (22.6%) 22541 prototype.packed.js (40.9%) 10450 prototype.packed.js.gz (18.9%) 38696 prototype.rhino.js (70.2%) 11208 prototype.rhino.js.gz (20.3%)

The Dojo compressor works with Prototype without any modification to the source. Dean Edward’s packer required adding semi-colons in a number of places, and took several run-throughs of the packer to debug the result. So you can beat regular ol’ gzipping by 2.3% of the original size (10.2% further reduction) easily with the Dojo compressor, or by 3.7% (16.3% further reduction) with some work on your part with Dean Edward’s packer. These rather modest gains strike me as simply not worth the effort. Anyone have different results?

Ruby on Rails 1.1 is set to come out soon, and a patch I submitted five days ago is going to be included! The patch is adding the ability for Selector (and $$) in Prototype to select based on attribute selectors. This should allow for much easier application of behavior to, say, all text fields. In addition it gives a boost to event:Selectors.