CoffeeScript for the Rubyist
Upcoming SlideShare
Loading in...5
×
 

CoffeeScript for the Rubyist

on

  • 4,492 views

Presented at RailsConf 2012 on April 23rd, 2012. This talk is an intro to the CoffeeScript language from a Rubyists perspective.

Presented at RailsConf 2012 on April 23rd, 2012. This talk is an intro to the CoffeeScript language from a Rubyists perspective.

Statistics

Views

Total Views
4,492
Views on SlideShare
3,907
Embed Views
585

Actions

Likes
7
Downloads
64
Comments
1

9 Embeds 585

http://www.scoop.it 187
http://lanyrd.com 149
http://www.numbernook.com 109
http://www.travisbenning.com 106
http://127.0.0.1 22
http://revolution.dev 7
https://twitter.com 3
http://duckduckgo.com 1
http://173.245.56.11 1
More...

Accessibility

Categories

Upload Details

Uploaded via as Apple Keynote

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n

CoffeeScript for the Rubyist CoffeeScript for the Rubyist Presentation Transcript

  • COFFEESCRIPT A Rubyist’s Love Affair
  • Mark Bates
  • DistributedProgramming with Ruby Addison-Wesley 2009http://books.markbates.com
  • Programming in CoffeeScript Addison-Wesley 2012 http://books.markbates.com
  • A (BRIEF) HISTORY LESSON
  • “I need to come up with a scripting languagefor web browsers. I know! Ill make it cool and Lispy! ” Dramatic Re-enactment (1995)
  • “ Yeah, So... Java is getting really popular. So were going to need you to rewrite your language into something a bit more Java- esque and name it something like JavaScript.  Yeah, and were going to need it in a week. Thanks, thatd be great. ” Dramatic Re-enactment (1995)
  • var MyApp.Models.Product = Backbone.Model.extend({ isLiked: function() { var _ref; return ! ((_ref = this.like()) != null ? _ref.isNew() : void 0); }; like: function() { return new MyApp.Models.Like(this.get("like")); }; image: function(size) { var img; if (size == null) { size = "full"; } if (this.get("image") != null) { img = this.get("image")[size]; } if (img == null) { img = "/images/fallback/product_" + size + "_default.png"; } return img; };});
  • FAST FORWARD About 15 Years
  • var MyApp.Models.Product = Backbone.Model.extend({ isLiked: function() { var _ref; return ! ((_ref = this.like()) != null ? _ref.isNew() : void 0); }; like: function() { return new MyApp.Models.Like(this.get("like")); }; image: function(size) { var img; if (size == null) { size = "full"; } if (this.get("image") != null) { img = this.get("image")[size]; } if (img == null) { img = "/images/fallback/product_" + size + "_default.png"; } return img; };});
  • class MyApp.Models.Product extends Backbone.Model isLiked: -> !@like()?.isNew() like: -> new MyApp.Models.Like(@get("like")) image: (size = "full") -> if @get("image")? img = @get("image")[size] unless img? img = "/images/fallback/product_#{size}_default.png" return img
  • WHAT IS COFFEESCRIPT?
  • What is CoffeeScript?
  • What is CoffeeScript?“A little language that compiles into JavaScript.”
  • What is CoffeeScript?“A little language that compiles into JavaScript.”Easily integrates with your current JavaScript
  • What is CoffeeScript?“A little language that compiles into JavaScript.”Easily integrates with your current JavaScriptEasier to read, write, maintain, refactor, etc...
  • What is CoffeeScript?“A little language that compiles into JavaScript.”Easily integrates with your current JavaScriptEasier to read, write, maintain, refactor, etc...A Hybrid of Ruby and Python.
  • What is CoffeeScript?“A little language that compiles into JavaScript.”Easily integrates with your current JavaScriptEasier to read, write, maintain, refactor, etc...A Hybrid of Ruby and Python.Helpful.
  • What CoffeeScript Is Not?Not Magic!Limited by what JavaScript can already do
  • “I’m happy writing JavaScript.I don’t need to learn another language. ”
  • FINE WITH ME
  • BUT...
  • .MODEL SMALL DISP: MOV BL,VAL1.STACK 64 ADD BL,VAL2.DATA MOV AH,00H VAL1 DB 01H MOV AL,BL VAL2 DB 01H MOV LP,CL LP DB 00H MOV CL,10 V1 DB 00H DIV CL V2 DB 00H MOV CL,LP NL DB 0DH,0AH,$ MOV V1,AL.CODE MOV V2,AHMAIN PROC MOV DL,V1 MOV AX,@DATA ADD DL,30H MOV DS,AX MOV AH,02H INT 21H MOV AH,01H INT 21H MOV DL,V2 MOV CL,AL ADD DL,30H SUB CL,30H MOV AH,02H SUB CL,2 INT 21H MOV AH,02H MOV DL,VAL2 MOV DL,VAL1 MOV VAL1,DL ADD DL,30H MOV VAL2,BL INT 21H MOV AH,09H MOV AH,09H LEA DX,NL LEA DX,NL INT 21H INT 21H LOOP DISP MOV AH,02H MOV DL,VAL2 MOV AH,4CH ADD DL,30H INT 21H INT 21H MAIN ENDP MOV AH,09H END MAIN LEA DX,NL INT 21H
  • .MODEL SMALL DISP: Assembly MOV BL,VAL1.STACK 64 ADD BL,VAL2.DATA MOV AH,00H VAL1 DB 01H MOV AL,BL VAL2 DB 01H MOV LP,CL LP DB 00H MOV CL,10 V1 DB 00H DIV CL V2 DB 00H MOV CL,LP NL DB 0DH,0AH,$ MOV V1,AL.CODE MOV V2,AHMAIN PROC MOV DL,V1 MOV AX,@DATA ADD DL,30H MOV DS,AX MOV AH,02H INT 21H MOV AH,01H INT 21H MOV DL,V2 MOV CL,AL ADD DL,30H SUB CL,30H MOV AH,02H SUB CL,2 INT 21H MOV AH,02H MOV DL,VAL2 MOV DL,VAL1 MOV VAL1,DL ADD DL,30H MOV VAL2,BL INT 21H MOV AH,09H MOV AH,09H LEA DX,NL LEA DX,NL INT 21H INT 21H LOOP DISP MOV AH,02H MOV DL,VAL2 MOV AH,4CH ADD DL,30H INT 21H INT 21H MAIN ENDP MOV AH,09H END MAIN LEA DX,NL INT 21H
  • #include <stdio.h> Cint fibonacci(){ int n = 100; int a = 0; int b = 1; int sum; int i; for (i = 0; i < n; i++) { printf("%dn", a); sum = a + b; a = b; b = sum; } return 0;}
  • public static void fibonacci() { Java int n = 100; int a = 0; int b = 1; for (int i = 0; i < n; i++) { System.out.println(a); a = a + b; b = a - b; }}
  • def fibonacci Ruby a = 0 b = 1 100.times do printf("%dn", a) a, b = b, a + b endend
  • “I can write an app just as well in Javaas I can in Ruby, but damn it if Rubyisn’t nicer to read and write! ”
  • SAME GOES FORCOFFEESCRIPT
  • SYNTAX
  • $(function() { $ -> success = (data) -> success = function(data) { if data.errors? if (data.errors != null) { alert "There was an error!" alert("There was an error!"); else } else { $("#content").text(data.message) $("#content").text(data.message); } $.get(/users, success, json) }; $.get(/users, success, json);}); JavaScript CoffeeScript
  • Syntax RulesNo semi-colons (ever!)No curly braces*No ‘function’ keywordRelaxed parenthesesWhitespace significant formatting
  • Parentheses Rules# Not required without arguments:noArg1 = -> # do something# Not required without arguments:noArg2 = () -> # do something # Required without arguments:# Required with Arguments: noArg1()withArg = (arg) -> noArg2() # do something # Not required with arguments: withArg("bar") withArg "bar"
  • Parentheses Rulesvar noArg1, noArg2, withArg;noArg1 = function() {};noArg2 = function() {};withArg = function(arg) {};noArg1();noArg2();withArg("bar");withArg("bar");
  • Parentheses Rules# Bad:$ "#some_id" .text()# $("#some_id".text());# Good:$("#some_id").text()# $("#some_id").text();
  • Whitespace
  • Whitespace$(function() {success = function(data) {if (data.errors != null) {alert("There was an error!");} else {$("#content").text(data.message);}};$.get(/users, success, json);});
  • Whitespace$(function() { def fibonaccisuccess = function(data) { a = 0if (data.errors != null) { b = 1alert("There was an error!"); 100.times do} else { printf("%dn", a)$("#content").text(data.message); a, b = b, a + b} end}; end$.get(/users, success, json);});
  • Whitespace$(function() { def fibonacci a = 0 success = function(data) { b = 1 if (data.errors != null) { alert("There was an error!"); 100.times do } else { printf("%dn", a) $("#content").text(data.message); a, b = b, a + b } end }; end $.get(/users, success, json);});
  • Whitespace$ -> success = (data) -> if data.errors? alert "There was an error!" else $("#content").text(data.message) $.get(/users, success, json)
  • Whitespace$(function() { var success; success = function(data) { if (data.errors != null) { return alert("There was an error!"); } else { return $("#content").text(data.message); } }; return $.get(/users, success, json);});
  • RUBYSCRIPT?
  • Conditionals
  • Conditionalsif true doSomething()unless true doSomething()
  • Conditionalsif true doSomething() if true doSomething() doSomething() unless trueunless true doSomething()
  • Conditionalsif true doSomething() if true doSomething() doSomething() unless trueunless true doSomething() if true doSomething() else doSomethingElse()
  • Objects/HashessomeObject = {conf: "RailsConf", talk: "CoffeeScript"}someObject = conf: "RailsConf" talk: "CoffeeScript"someFunction(conf: "RailsConf", talk: "CoffeeScript")
  • Objects/Hashesvar someObject;someObject = { conf: "RailsConf", talk: "CoffeeScript"};someObject = { conf: "RailsConf", talk: "CoffeeScript"};someFunction({ conf: "RailsConf", talk: "CoffeeScript"});
  • Rangesa = [1..5]b = [1...5]c = [1..100]d = [100..1]
  • Rangesa = [1..5] var a, b, c, d, _i, _j, _results, _results1; a = [1, 2, 3, 4, 5];b = [1...5] b = [1, 2, 3, 4];c = [1..100] c = (function() { _results = [];d = [100..1] for (_i = 1; _i <= 100; _i++){ _results.push(_i); } return _results; }).apply(this); d = (function() { _results1 = []; for (_j = 100; _j >= 1; _j--){ _results1.push(_j); } return _results1; }).apply(this);
  • String Interpolationname = "RailsConf 2012"console.log "Hello #{name}"# Hello RailsConf 2012console.log Hello #{name}# Hello #{name}
  • String Interpolationname = "RailsConf 2012" var name;console.log "Hello #{name}" name = "RailsConf 2012";# Hello RailsConf 2012 console.log("Hello " + name);console.log Hello #{name}# Hello #{name} console.log(Hello #{name});
  • Heredocshtml = """ <div class="comment" id="tweet-#{tweet.id_str}"> <hr> <div class=tweet> <span class="imgr"><imgsrc="#{tweet.profile_image_url}"></span> <span class="txtr"> <h5><a href="http://twitter.com/#{tweet.from_user}"target="_blank">@#{tweet.from_user}</a></h5> <p>#{tweet.text}</p> <p class="comment-posted-on">#{tweet.created_at}</p> </span> </div> </div>"""
  • Heredocsvar html;html = "<div class="comment" id="tweet-" + tweet.id_str+ "">n <hr>n <div class=tweet>n <span class="imgr"><img src="" + tweet.profile_image_url + ""></span>n <span class="txtr">n <h5><a href="http://twitter.com/" + tweet.from_user + "" target="_blank">@" + tweet.from_user + "</a></h5>n <p>" +tweet.text + "</p>n <p class="comment-posted-on">"+ tweet.created_at + "</p>n </span>n </div>n</div>";
  • Functionsp = (name) -> console.log "Hello #{name}"p(RailsConf 2012)
  • Functionsvar p;p = function(name) { return console.log("Hello " + name);};p(RailsConf 2012);
  • Functionsp = (name)-> console.log "Hello #{name}"p(RailsConf 2012)
  • Functionsp = (name)-> console.log "Hello #{name}" CoffeeScriptp(RailsConf 2012)
  • Functionsp = (name)-> console.log "Hello #{name}" CoffeeScriptp(RailsConf 2012)p = ->(name) { puts "Hello #{name}"} Ruby 1.9p.call(RailsConf 2012)
  • Default ArgumentscreateElement = (name, attributes = {}) -> obj = document.createElement name for key, val of attributes obj.setAttribute key, val obj
  • Default Argumentsvar createElement;createElement = function(name, attributes) { var key, obj, val; if (attributes == null) { attributes = {}; } obj = document.createElement(name); for (key in attributes) { val = attributes[key]; obj.setAttribute(key, val); } return obj;};
  • Splats*splatter = (first, second, others...) -> console.log "First: #{first}" console.log "Second: #{second}" console.log "Others: #{others.join(, )}"splatter [1..5]...
  • Splats*var splatter, __slice = [].slice;splatter = function() { var first, others, second; first = arguments[0], second = arguments[1], others = 3<= arguments.length ? __slice.call(arguments, 2) : []; console.log("First: " + first); console.log("Second: " + second); return console.log("Others: " + (others.join(, )));};splatter.apply(null, [1, 2, 3, 4, 5]);
  • Loops & Comprehensionsfor someName in someArray console.log someNamefor key, value of someObject console.log "#{key}: #{value}"
  • Loops & Comprehensionsvar key, someName, value, _i, _len;for (_i = 0, _len = someArray.length; _i < _len; _i++) { someName = someArray[_i]; console.log(someName);}for (key in someObject) { value = someObject[key]; console.log("" + key + ": " + value);}
  • Loops & Comprehensionsnumbers = [1..5]console.log number for number in numbers
  • Loops & Comprehensionsvar number, numbers, _i, _len;numbers = [1, 2, 3, 4, 5];for (_i = 0, _len = numbers.length; _i < _len; _i++) { number = numbers[_i]; console.log(number);}
  • Loops & Comprehensionsnumbers = [1..5]console.log number for number in numbers when number <= 3
  • Loops & Comprehensionsvar number, numbers, _i, _len;numbers = [1, 2, 3, 4, 5];for (_i = 0, _len = numbers.length; _i < _len; _i++) { number = numbers[_i]; if (number <= 3) { console.log(number); }}
  • Loops & Comprehensionsnumbers = [1, 2, 3, 4, 5]low_numbers = (number * 2 for number in numbers when number <= 3)console.log low_numbers # [ 2, 4, 6 ]
  • Loops & Comprehensionsvar low_numbers, number, numbers;numbers = [1, 2, 3, 4, 5];low_numbers = (function() { var _i, _len, _results; _results = []; for (_i = 0, _len = numbers.length; _i < _len; _i++) { number = numbers[_i]; if (number <= 3) { _results.push(number * 2); } } return _results;})();console.log(low_numbers);
  • Classesclass Employeeemp = new Employee()emp.firstName = "Mark"
  • Classesvar Employee, emp;Employee = (function() { Employee.name = Employee; function Employee() {} return Employee;})();emp = new Employee();emp.firstName = "Mark";
  • Classesclass Employee constructor: (@options = {}) -> salary: -> @options.salary ?= "$250,000"emp = new Employee()console.log emp.salary() # "$250,000"emp = new Employee(salary: "$100,000")console.log emp.salary() # "$100,000"
  • Classesvar Employee, emp;Employee = (function() { Employee.name = Employee; function Employee(options) { this.options = options != null ? options : {}; } Employee.prototype.salary = function() { var _base, _ref; return (_ref = (_base = this.options).salary) != null ? _ref : _base.salary = "$250,000"; }; return Employee;})();emp = new Employee();console.log(emp.salary());emp = new Employee({ salary: "$100,000"});console.log(emp.salary());
  • Extending Classesclass Manager extends Employee constructor: -> super @options.salary ?= "$500,000"manager = new Manager()console.log manager.salary() # "$500,000"
  • Extending Classesvar Manager, manager, __hasProp = {}.hasOwnProperty, __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key]= parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype;child.prototype = new ctor; child.__super__ = parent.prototype; return child; };Manager = (function(_super) { __extends(Manager, _super); Manager.name = Manager; function Manager() { var _base; Manager.__super__.constructor.apply(this, arguments); if ((_base = this.options).salary == null) { _base.salary = "$500,000"; } } return Manager;})(Employee);manager = new Manager();console.log(manager.salary());
  • Extending Classesclass Manager extends Employee constructor: -> super @options.salary ?= "$500,000" salary: -> "#{super} + $10k"manager = new Manager()console.log manager.salary() # "$500,000 + $10k"
  • Extending Classesvar Manager, manager, __hasProp = {}.hasOwnProperty, __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; }function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor; child.__super__ =parent.prototype; return child; };Manager = (function(_super) { __extends(Manager, _super); Manager.name = Manager; function Manager() { var _base; Manager.__super__.constructor.apply(this, arguments); if ((_base = this.options).salary == null) { _base.salary = "$500,000"; } } Manager.prototype.salary = function() { return "" + Manager.__super__.salary.apply(this, arguments) + " + $10k"; }; return Manager;})(Employee);manager = new Manager();console.log(manager.salary());
  • Bound Functionsclass User constructor: (@name) -> sayHi: -> console.log "Hello #{@name}"bob = new User(bob)mary = new User(mary)log = (callback)-> console.log "about to execute callback..." callback() console.log "...executed callback"log(bob.sayHi)log(mary.sayHi)
  • Bound Functionsabout to execute callback...Hello undefined...executed callbackabout to execute callback...Hello undefined...executed callback
  • Bound Functionsclass User constructor: (@name) -> sayHi: -> console.log "Hello #{@name}"bob = new User(bob)mary = new User(mary)log = (callback)-> console.log "about to execute callback..." callback() console.log "...executed callback"log(bob.sayHi)log(mary.sayHi)
  • Bound Functionsclass User constructor: (@name) -> sayHi: -> console.log "Hello #{@name}"bob = new User(bob)mary = new User(mary)log = (callback)-> console.log "about to execute callback..." callback() console.log "...executed callback"log(bob.sayHi)log(mary.sayHi)
  • Bound Functionsclass User constructor: (@name) -> sayHi: => console.log "Hello #{@name}"bob = new User(bob)mary = new User(mary)log = (callback)-> console.log "about to execute callback..." callback() console.log "...executed callback"log(bob.sayHi)log(mary.sayHi)
  • Bound Functionsabout to execute callback...Hello bob...executed callbackabout to execute callback...Hello mary...executed callback
  • Bound Functionsclass User constructor: (@name) -> sayHi: => console.log "Hello #{@name}"
  • Bound Functionsvar User, __bind = function(fn, me){ return function(){ return fn.apply(me,arguments); }; };User = (function() { User.name = User; function User(name) { this.name = name; this.sayHi = __bind(this.sayHi, this); } User.prototype.sayHi = function() { return console.log("Hello " + this.name); }; return User;})();
  • FINALLYOne of my favorite features
  • Existential Operatorif foo? console.log "foo"console.log "foo" if foo?
  • Existential Operatorif (typeof foo !== "undefined" && foo !== null) { console.log("foo");}if (typeof foo !== "undefined" && foo !== null) { console.log("foo");}
  • WAIT! IT GETS BETTER!
  • Existential Operatorconsole?.log "foo"
  • Existential Operatorconsole?.log "foo"if (typeof console !== "undefined" && console !== null) { console.log("foo");}
  • Existential Operatorif currentUser?.firstName? console.log currentUser.firstName
  • Existential Operatorif currentUser?.firstName? console.log currentUser.firstNameif ((typeof currentUser !== "undefined" && currentUser !==null ? currentUser.firstName : void 0) != null) { console.log(currentUser.firstName);}
  • What Didn’t I Cover?ScopingSecurityStrict ModeFixes common ‘mistakes’OperatorsThe `do` keywordPlenty more!
  • Thank You
  • Thank YoumyName = "Mark Bates"you.should buyBook("Programming in CoffeeScript") .at("http://books.markbates.com")you.should followMe(@markbates)