A Rails Developer’s impression of CoffeeScript – Part 2

We had a look at the basics of CoffeeScript in the previous post. In this tutorial, we’ll see how it is supported in Rails and how can we use it. Ruby CoffeeScript is a ruby bridge to the CoffeeScript compiler. The coffee-script library will automatically choose the best JavaScript engine for our platform. The available engines are V8, Node.js, and JavaScriptCore.

To use CoffeeScript with Rails 3.0.x

We can use either of the two gems available:
- Barista – gem that provides CoffeeScript support for Rails and Rack apps
- BistroCar – another gem that serves up CoffeeScript from within our Rails application

The latest versions of Barista depends on the coffee-script gem. It auto-detects the available compilers on our system as there are several ways to install CoffeeScript. We can install via node.js as the official documentation suggests or else we can use the therubyracer gem and we won’t have to install anything else! therubyracer includes V8 (the fast Javascript engine from Google).

Finally the coffee-script gem depends on the coffee-script-source gem. This gem contains the CoffeeScript source code and it is synced with official releases.

RubyInside has a good tutorial for installing necessary gems and get CoffeeScript working in Rails projects. It also describes how to use CoffeeScript with jQuery.

Here is what we need to add to our Gemfile :

gem 'therubyracer', :require => false
gem 'barista'

Next, we need to generate barista_config.rb file which is stored in config/initializers/ that contains a set of options to configure Barista options

# Generate barista configuration file
rails g barista:install

The two basic settings for barista are the root and output_root configurations. The default directory where barista looks for your coffeescript files is the coffeescripts folder in your app directory which you need to manually create. We can change this default location by making changes in barista_config.rb.

 c.root = Rails.root.join("app", "scripts")

Similarly, default location for compiled javascript files generated by Barista gem is the public/javascripts directory. Lets say, we want Barista to compile CoffeeScript files into public/javascripts/compiled, we’ll need to add this line to Barista configuration file :

c.output_root = Rails.root.join("public", "javascripts", "compiled")

CoffeeScript with JQuery

To use CoffeeScript with JQuery, the initial setup is as follows -

# Add this to Gemfile
gem "jquery-rails"

# Run bundle install. To invoke the generator, run:
rails generate jquery:install

Lets start by writing the simplest JS statement in CoffeeScript

alert("Hey")

Generated JS -

(function() {
  alert("Hey");
}).call(this);

Well, parenthesis for arguments are optional in CoffeeScript, so we can write

alert "Hey"

So far, so good.

Executing something on document.ready with Jquery

$('#form_tag').bind('blur', () ->
   alert('coffee-script')
)

Doing it this way, the .bind call would executing too soon, before the document is ready and thus it doesn’t do anything. Wrap it in a call to $(document).ready like this

$(document).ready ->
  $('#dummy_form_tag').bind 'blur', ->
    alert 'coffee-script'

Global functions

If we want to make a global function in coffeescript, we can explicitly assign it as a property of the global window object

window.dummyFunc = (dummy_arg) ->
  alert dummy_arg

Sample code to highlight(in red color) all required but empty fields, on clicking the form. Example –

<%= f.text_field :title, :class => 'required' %>

We give ‘required’ class to all the required input text fields.

$(document).ready ->
  $('#dummy_form').bind 'click', ->
    empty_fields = ($(this)).find("input.required")
    if empty_fields.length
      empty_fields.each ->
        $(this).css "background-color", "red"
      false

Generated JS –

(function() {
  $(document).ready(function() {
    return $('#new_post').bind('click', function() {
      var empty_fields;
      empty_fields = ($(this)).find("input.required");
      if (empty_fields.length) {
        empty_fields.each(function() {
          return $(this).css("background-color", "red");
        });
        return false;
      }
    });
  });
}).call(this);

CoffeeScript Demo (GitHub Repo)

This sample Rails application lets us create posts, each post can have multiple sections. It uses Ryan Bates’s Nifty Generator Plugin to generate form layouts and basic skeleton for controllers and models.

Add_More_coffeescript

Clicking the “Add more” link lets us create more sections. This JavaScript functionality has been created using CoffeeScript.

If we clone the repo and run server.. notice the log -

Started GET "/posts" for 127.0.0.1 at 2011-05-13 00:18:25 +0530
[Barista] Compiling all scripts for barista
[Barista] Compiling all coffeescripts

On every request, Barista compiles the coffee files and generates equivalent JavaScript code. Every coffee file in app/coffeescript has an auto-generated corresponding file in public/javascript directory.

Other support

rack-coffee – Serves up coffeescript from rack middleware
After we’ve required ‘rack/coffee’, we put this in the Rails initializer config block:

config.middleware.use Rack::Coffee, :root => "#{RAILS_ROOT}/public"

coffee-haml-filter Custom haml filter for rendering CoffeeScript inside our Haml templates. Sample Code -

 :coffee
    window.cl: s =>
      if typeof(console) != 'undefined' then console.log(s) else s

CoffeeScript in the wild – Is a comprehensive list of all projects that have adopted CoffeeScript.

Coffeebeans gives us inline CoffeeScript

<%= coffee_script_tag do %>
  	alert 'coffee script is awesome!'
<% end %>

Generated JavaScript -

(function() {
  	alert('coffee script is awesome!');
}).call(this);

Rails 3.1 and CoffeeScript

Rails 3.1 will have native CoffeeScript supports(via Sprockets 2). RubyInside has another good tutorial on how to start using CoffeeScript in Rails 3.1. This default can be turned off by commenting out the depedndencies in the generated Gemfile. If we want to write code in JS, we still can – just leave off the .coffee suffix from the filename. The application.js file is no longer shipping with .coffee added for the simple reason that it’ll have no code. But if coffee is available, we’ll be generating JS stubs for new controllers (like helpers) with the coffee extension on). Write .js files, like we were doing before. Be sure not to write coffeescript in .coffee files if we don’t want to use coffeescript. By doing so, we will be using coffeescript. Instead we should only write javascript in .js files.

 

A Rails developer’s impression of CoffeeScript – Part 1

DHH has announced that Rails 3.1 will ship with CoffeeScript as default option for writing JavaScript.

All web apps use JavaScript (if you don’t, I don’t want to know you! ), and most Rails developers who are used to writing clean and pretty ruby code find it cumbersome to write JavaScript with all its curly braces and colons, (well, at least I did). Compared to that, CoffeeScript is wonderfully easy to understand and maintain. Lets hear it direct from the horse’s mouth -

  • CoffeeScript is neat language that provides an alternative syntax for writing JavaScript; the code compiles one-to-one into the equivalent JS, and there is no interpretation at runtime.
  • Its integration with existing JavaScript libraries is seamless (like jQuery, Facebook JS SDK, Google API etc)
  • Works wonderfully in browsers that support JavaScript and JavaScript platforms like node.js
  • The code generated by CoffeeScript is syntactically correct and passes through JSLint without warnings.

A lot of writing about coffee. Let’s brew some -

var square;
square = function(x) {
   return x * x;
};

Equivalent CoffeeScript -

square = (x) -> x * x

It doesn’t need to explicitly declare the variable ‘square’. The function body starts after ‘->’. We don’t need to use semicolons ; to terminate expressions. And we don’t need an explicit return statement, the last expression evaluated is returned.

How easy that makes a developer’s life! Understandably, Coffeescript has found acceptance in a lot of big rails projects. It is used by Github, 37 signals and more..

Getting Started

  * Lets get it working first – Check out the installation
  * The command-line version of coffee is available as a Node.js utility. The core compiler however, does not depend on Node, and can be run in any JavaScript environment, or in the browser.
  * Check out – the TextMate bundle for CoffeeScript


Why Ruby/Rails devs would love it or The similarity with familiar Ruby/Rails syntax


Variable declaration and expressions
You don’t need to use semicolons ; to terminate expressions, ending the line will do just as well, (although semicolons can still be used to fit multiple expressions onto a single line.) Also, no explicit variable declaration needed. Example -

company = "vinsol"

Functions
Functions are defined by an optional list of parameters in parentheses, an arrow, and the function body. The empty function looks like this: -> .CoffeeScript uses significant whitespace to delimit blocks of code – very haml-like. Last evaluated expression is returned (no need explicitly ‘return’ values). Almost everything can be wrapped in an anonymous function and used as an expression. Example -

square = (x) ->
   x * x

Default Arguments for functions
Functions may also have default values for arguments. We can override the default value by passing a non-null argument. You also have ruby-style string interpolation. Double-quoted strings can have interpolated values, using #{ … }

about_me = (profession = "developer") ->
    alert "I'm a #{profession}"

Function Calling
You don’t need to use parentheses to call a function if you’re passing arguments. The function call would wrap till the end of line for arguments.

console.log square 2 #=> console.log(square(2)) 

Significant Indendation
Instead of using curly braces { } to surround blocks of code in functions, if- statements, switch, and try/catch, use indentation.

if  x == 2
   alert "Value is 2!"
else
   alert "Value is not 2!"

Iterators
We can loop over arrays, ranges, hashes and objects using for operator in the postfix.

alert "I'm a #{profession}" for profession in ['developer', 'designer', 'tester']

Other goodies

Single line conditionals
It provides you with Post fix if-else conditionals. It compiles to ternary operator when possible and closure wrapping otherwise.

status = if couple then 'married' else 'single'
options or= defaults

Class inheritance using extends keyword
CoffeeScript gives a basic class structure,very much like ruby. It lets you add super class, assign prototype-properties and write the constructor.
Constructor functions begin with the name ‘constructor’. You are provided with concise constructors. Rather than doing this.length = length for class constructors, you can simply use the @ shorthand for this, (@length, @breadth) -> with an empty method body would form our constructor.

class Rectangle
  constructor: (@length, @breadth) ->

  area: ->
    alert "Area = " + (@length * @breadth)

class Square extends Rectangle

figure1 = new Rectangle 1,2
figure2 = new Square 1,1

figure1.area()
figure2.area()

Splats
Variable number of arguments get passed as an array in the last argument with ‘…’. Splats are used both for function definition as well as invocation.

gold = silver = rest = "unknown"

awardMedals = (first, second, others...) ->
  gold   = first
  silver = second
  rest   = others

contenders = [
  "Michael Phelps"
  "Liu Xiang"
  "Yao Ming"
  "Allyson Felix"
]
awardMedals contenders...
alert "Gold: " + gold
alert "Silver: " + silver
alert "The Field: " + rest

Heredocs
You can use single-quotes (otherwise – triple-quotes) for multi-line strings, leading indentation common to all lines will be stripped. Example -

 sample  = 'Lorem ipsum - 
 lorem ipsum.. '

Literals in coffeescript for objects and arrays.
When each property is listed on its own line, the commas are optional. Objects may be created using indentation instead of explicit braces, similar to YAML.

 matrix = [
    1,0,1
    0,0,1
    1,1,0
]
en =
  form:
    company: "Vinsol"
    location: "Delhi"

Next Post will cover CoffeeScript in Rails 3 and Rails 3.1