Rails-like JavaScript using CoffeeScript, Backbone.js and Jasmine


Published on

Published in: Technology

Rails-like JavaScript using CoffeeScript, Backbone.js and Jasmine

  1. 1. Rails-like JavaScriptusing CoffeeScript, Backbone.js and Jasmine Raimonds Simanovskis
  2. 2. AbstractRuby on Rails provides good conventions and structure for your Ruby code so that from thefirst day you can start to build your application. But there are practically no conventions andstructure how to develop your JavaScript code and historically Rails was trying to hide anygenerated JavaScript from you. Nowadays if you want to build rich UI and efficient webapplications you need to learn and use JavaScript and after some time you understand thatyou cant just write a bunch of functions in application.js, you need some conventions andstructure as well.If you are Ruby developer then you should take a look on CoffeeScript which is programminglanguage that compiles into JavaScript but with syntax inspired by Ruby and Python. As it ismore similar to Ruby it will be easier to switch between CoffeeScript and Ruby duringdevelopment as well as your CoffeeScript code will be smaller and more readable thanJavaScript.And if you are building rich UI web application in browser then it is worth to try Backbone.jswhich provides MVC pattern for browser side UI development which will be moreunderstandable and easier to maintain than bunch of JavaScript functions that are bound tobunch of DOM events. And as Backbone.js is made by the same author Jeremy Ashkenas asCoffeeScript 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 feeluncomfortable if you will not test your JavaScript code. If you prefer RSpec testing frameworkin Ruby then in JavaScript (or CoffeeScript) you might like Jasmine testing framework whichsyntax is inspired by RSpec.
  3. 3. Example slides
  4. 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. 5. Backbone.js model in CoffeeScriptclass window.Todo extends Backbone.Model # If you dont 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. 6. Collection of modelsclass window.TodoList extends Backbone.Collection # Reference to this collections 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
  7. 7. class window.TodoView extends Backbone.View tagName: "li" template: Handlebars.compile $(#item-template).html() events: "click .check" : "toggleDone" "dblclick div.todo-content" : "edit" "click span.todo-destroy" : "clear" "keypress .todo-input" : "updateOnEnter" initialize: -> _.bindAll this, render, close, clear @model.bind change, @render @model.bind clear, @clear render: ->Sample $(@el).html @template @model.toJSON() this.setContent() this setContent: -> content = @model.get content view this.$(.todo-content).text content @input = this.$(.todo-input) @input.bind blur, @close @input.val content toggleDone: -> @model.toggle() edit: -> $(@el).addClass "editing" @input.focus() close: -> @model.save content: @input.val() $(@el).removeClass "editing" updateOnEnter: (e) -> this.close() if e.keyCode == 13 clear: -> $(@el).remove() @model.destroy()
  8. 8. Sample Jasmine testsdescribe "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()