2. Abstract
Ruby on Rails provides good conventions and structure for your Ruby code so that from the
first day you can start to build your application. But there are practically no conventions and
structure how to develop your JavaScript code and historically Rails was trying to hide any
generated JavaScript from you. Nowadays if you want to build rich UI and efficient web
applications you need to learn and use JavaScript and after some time you understand that
you can't just write a bunch of functions in application.js, you need some conventions and
structure as well.
If you are Ruby developer then you should take a look on CoffeeScript which is programming
language that compiles into JavaScript but with syntax inspired by Ruby and Python. As it is
more similar to Ruby it will be easier to switch between CoffeeScript and Ruby during
development as well as your CoffeeScript code will be smaller and more readable than
JavaScript.
And if you are building rich UI web application in browser then it is worth to try Backbone.js
which provides MVC pattern for browser side UI development which will be more
understandable and easier to maintain than bunch of JavaScript functions that are bound to
bunch of DOM events. And as Backbone.js is made by the same author Jeremy Ashkenas as
CoffeeScript then you can develop your browser side UI in CoffeeScript and Backbone.js.
If you are Ruby developer then testing culture is in your blood and you should feel
uncomfortable if you will not test your JavaScript code. If you prefer RSpec testing framework
in Ruby then in JavaScript (or CoffeeScript) you might like Jasmine testing framework which
syntax is inspired by RSpec.
4. Sample CoffeeScript
# Assignment: # Splats:
number = 42 race = (winner, runners...) ->
opposite = true print winner, runners
# Conditions: # Existence:
number = -42 if opposite alert "I knew it!" if elvis?
# Functions: # Array comprehensions:
square = (x) -> x * x cubes = (math.cube num for num in list)
# Arrays:
list = [1, 2, 3, 4, 5]
# Objects:
math =
root: Math.sqrt
square: square
cube: (x) -> x * square x
5. Backbone.js model
in CoffeeScript
class window.Todo extends Backbone.Model
# If you don't provide a todo, one will be provided for you.
EMPTY: "empty todo..."
# Ensure that each todo created has `content`.
initialize: ->
unless this.get "content"
this.set content: this.EMPTY
# Toggle the `done` state of this todo item.
toggle: ->
this.save done: !this.get "done"
6. Collection of models
class window.TodoList extends Backbone.Collection
# Reference to this collection's model.
model: Todo
url: '/todos'
# Filter down the list of all todo items that are finished.
done: ->
this.filter (todo) -> todo.get 'done'
# Filter down the list to only todo items that are still not finished.
remaining: ->
this.without this.done()...
nextOrder: ->
return 1 unless @length
this.last().get('order') + 1
# Todos are sorted by their original insertion order.
comparator: (todo) ->
todo.get 'order'
8. Sample Jasmine
tests
describe "Todo", ->
todo = null
ajaxCall = (param) -> jQuery.ajax.mostRecentCall.args[0][param]
beforeEach ->
todo = new Todo
todos = new TodoList [todo]
it "should initialize with empty content", ->
expect(todo.get "content").toEqual "empty todo..."
it "should initialize as not done", ->
expect(todo.get "done").toBeFalsy()
it "should save after toggle", ->
spyOn jQuery, "ajax"
todo.toggle()
expect(ajaxCall "url").toEqual "/todos"
expect(todo.get "done").toBeTruthy()