Alexey Vasiliev

  • 8+ years experience
    • Linux and Databases administrator
    • Web and Mobile developer (Ruby, Golang, Java, JavaScript, Objective-C, C/C++)
  • Open-Source developer
    • Webp-ffi for Ruby
    • MongodbLogger for Rails
    • SMTRails and SHTRails (shared templates for rails)
    • SkypeKit for Ruby
me

Basic

A Beautiful Programming Language

CoffeeScript

  • Least amount of code to solve problems
  • Readable and Understandable
  • Easy to Maintain

JavaScript?

CoffeeScript

  • JavaScript's less ostentatious kid brother
  • one-to-one with JavaScript
  • better functional syntax
  • compiles to the good parts

coffeescript.org

coffe_site

The CoffeeScript Compiler

CoffeeScript

  • Install Node.js
  • Install npm
  • npm install -g coffee-script
              

The CoffeeScript Compiler

        coffee -h
        Usage: coffee [options] path/to/script.coffee -- [args]

          -b, --bare         compile without a top-level function wrapper
          -c, --compile      compile to JavaScript and save as .js files
          -e, --eval         pass a string from the command line as input
          -h, --help         display this help message
          -i, --interactive  run an interactive CoffeeScript REPL
          -j, --join         concatenate the source CoffeeScript before compiling
          -l, --lint         pipe the compiled JavaScript through JavaScript Lint
          -n, --nodes        print out the parse tree that the parser produces
              --nodejs       pass options directly to the "node" binary
          -o, --output       set the output directory for compiled JavaScript
          -p, --print        print out the compiled JavaScript
          -r, --require      require a library before executing your script
          -s, --stdio        listen for and compile scripts over stdio
          -t, --tokens       print out the tokens that the lexer/rewriter produce
          -v, --version      display the version number
          -w, --watch        watch scripts for changes and rerun commands
      

The CoffeeScript Compiler

        $ coffee -c path/to/script.coffee

        $ coffee --watch experimental.coffee

        $ coffee --print *.coffee > all.js
      

Variables

CoffeeScript

        someText = "Hello folks!"
        alert someText
      
        var someText;
        someText = "Hello folks!";
        alert(someText);
      
  • No variable declarations
  • No semicolons

Variables

CoffeeScript

        if ViktorTsoi?
          alert "I know it!"
      

or

        alert "I know it!" if ViktorTsoi?
      

converted

        if (typeof ViktorTsoi !== "undefined" && ViktorTsoi !== null) {
          alert("I know it!");
        }
      

2 way to create functions

CoffeeScript

  • Named Functions
                function oneCoffee() {
                  return alert("One coffee ready!");
                }
              
  • Function Expressions
                var oneCoffee = function() {
                  return alert("One coffee ready!");
                }
              

Function Expressions in CoffeeScript

CoffeeScript

        oneCoffee = ->
          alert "One coffee ready!"
      

or

        oneCoffee = -> alert "One coffee ready!"
      

converted

        var oneCoffee;
        oneCoffee = function() {
          return alert("One coffee ready!");
        };
      

Returning in function

CoffeeScript

  oneCoffee = ->
   answer = confirm "Ready for some Coffee?"
   "Your answer is " + answer
        
  oneCoffee = ->
   answer = confirm "Ready for some Coffee?"
   "Your answer is #{answer}"
        

converted

  var oneCoffee;
  oneCoffee = function() {
    var answer;
    answer = confirm("Ready for some Coffee?");
    return "Your answer is " + answer;
  };
        

Function parameters

CoffeeScript

  oneCoffee = (msg = "Ready for some Coffee?") ->
   answer = confirm msg
   "Your answer is #{answer}"
        
  var oneCoffee;
  oneCoffee = function(msg) {
    var answer;
    if (msg == null) {
      msg = "Ready for some Coffee?";
    }
    answer = confirm(msg);
    return "Your answer is " + answer;
  };
        

Function examples

CoffeeScript

    square = (x) -> x * x

    area = (x, y) -> x * y
        
    var area, square;

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

    area = function(x, y) {
      return x * y;
    };
        

JQuery to CoffeeScript

CoffeeScript


  $("#tabs #error a").click (e) ->
    e.preventDefault()
        

  $("#tabs #error a").click(function(e) {
    return e.preventDefault();
  });
        

  $("#confirm").queue ->
    $(@).dequeue()
        

  $("#confirm").queue(function() {
    return $(this).dequeue();
  });
        

If Statement

CoffeeScript


  if age < 18
    alert 'Under age'
        

  alert 'Under age' if age < 18
        

  if age < 18 then alert 'Under age'
        

  if (age < 18) {
    alert('Under age');
  };
        

If Else Statement

CoffeeScript

if age < 18
  alert "Under age"
else
  alert "of age"
      

if age < 18 then alert 'Under age' else alert 'of age'
      
if (age < 18) {
  alert("Under age");
} else {
  alert("of age");
}
      

Operators

CoffeeScript JavaScript
is===
isnt!==
not!
and&&
or||
true, yes, ontrue
false, no, offfalse
@, thisthis
ofin
inno JS equivalent

Operator Examples

CoffeeScript


    if paid() and coffee() is on then pour()
        

    if (paid() && coffee() === true) {
      pour();
    }
        

    coffee() unless paid()
        

    if (!paid()) {
      coffee();
    }
        

Chained Comparisons

CoffeeScript


if 2 < newLevel < 5
  alert "In Range!"
      

if ((2 < newLevel && newLevel < 5)) {
  alert("In Range!");
}
      

Switch Statement

CoffeeScript


    message = switch state
      when 0 then 'good'
      when 1 then 'bad'
      when 2 then 'cat'
      else 'I dont know'
        

    var message;

    message = (function() {
      switch (state) {
        case 0:
          return 'good';
        case 1:
          return 'bad';
        case 2:
          return 'cat';
        default:
          return 'I dont know';
      }
    })();
        

Ranges

CoffeeScript


    range0 = [1..4]
    range1 = [1...4]
        

    var range0, range1;

    range0 = [1, 2, 3, 4];

    range1 = [1, 2, 3];
        

    range = [1..4]
    alert range[1..-1]
    alert range[1...range.length]
    alert range[2..]
    alert range[..]
        

    var range;
    range = [1, 2, 3, 4];
    alert(range.slice(1));
    alert(range.slice(1, range.length));
    alert(range.slice(2));
    alert(range.slice(0));
        

Arrays

CoffeeScript


fruit = ['apple', 'pear', 'orange']
fruit = [
  'apple'
  'pear'
  'orange'
]
      

var fruit;

fruit = ['apple', 'pear', 'orange'];

fruit = ['apple', 'pear', 'orange'];
      

Loops

CoffeeScript


  fruit = ['apple', 'pear', 'orange']
  for fr in fruit
    alert "Fruit: #{fr}"
  alert "Fruit: #{fr}" for fr in fruit
      

  var fr, fruit, _i, _j, _len, _len1;

  fruit = ['apple', 'pear', 'orange'];

  for (_i = 0, _len = fruit.length; _i < _len; _i++) {
    fr = fruit[_i];
    alert("Fruit: " + fr);
  }
  ...
      

Loops

CoffeeScript

  fruit = ['apple', 'pear', 'orange']
  withoutApple = (name for name in fruit when name isnt "apple")
      
  var fruit, name, withoutApple;
  fruit = ['apple', 'pear', 'orange'];
  withoutApple = (function() {
    var _i, _len, _results;
    _results = [];
    for (_i = 0, _len = fruit.length; _i < _len; _i++) {
      name = fruit[_i];
      if (name !== "apple") {
        _results.push(name);
      }
    }
    return _results;
  })();
      

Splats

CoffeeScript

  race = (winner, runners...) ->
    print winner, runners
      
  var race,
    __slice = [].slice;

  race = function() {
    var runners, winner;
    winner = arguments[0], runners = 2 <= arguments.length ? __slice.call(arguments, 1) : [];
    return print(winner, runners);
  };
      

Objects

CoffeeScript

          kids =
            brother:
              name: "Max"
              age: 11
            sister:
              name: "Ida"
              age: 9
        






          var kids;

          kids = {
            brother: {
              name: "Max",
              age: 11
            },
            sister: {
              name: "Ida",
              age: 9
            }
          };
        

Objects

CoffeeScript

  obj =
    name: 'French'
    strength: 1
    brew: -> alert("brewing #{@name}")
    pour: (amount = 1) ->
      if amount is 1
         "Poured a single cup"
      else
         "Poured #{amount} cups"
        
  var obj;

  obj = {
    name: 'French',
    strength: 1,
    brew: function() {
      return alert("brewing " + this.name);
    },
    pour: function(amount) {
      if (amount == null) {
        amount = 1;
      }
      if (amount === 1) {
        return "Poured a single cup";
      } else {
        return "Poured " + amount + " cups";
      }
    }
  };
        

Object Iteration with of

CoffeeScript

"#{coffee} has #{attrs.in_stock}" for coffee, attrs of coffees
      
var attrs, coffee;

for (coffee in coffees) {
  attrs = coffees[coffee];
  "" + coffee + " has " + attrs.in_stock;
}
      

Object Iteration with hasOwnProperty

CoffeeScript


objects = { test: 1, apple: true }
hasApple = (value for own key, value of objects when value isnt true)
      

var hasApple, key, objects, value,
  __hasProp = {}.hasOwnProperty;

objects = {
  test: 1,
  apple: true
};

hasApple = (function() {
  var _results;
  _results = [];
  for (key in objects) {
    if (!__hasProp.call(objects, key)) continue;
    value = objects[key];
    if (value !== true) {
      _results.push(value);
    }
  }
  return _results;
})();
        

Object Orientation

Constructor and Properties

Object Orientation

  class Base
    constructor: (@name) ->
    eat: (count) ->
      alert "I eat #{count} #{@name}"

  base = new Base("apple")
  base.eat(5)
      

-> or =>?

Object Orientation

  class Base
    constructor: (@name) ->
    eat: (count) =>
      alert "I eat #{count} #{@name}"
    notEat: =>
      $.ajax
        url: "some url"
        success: (data) =>
          @eat(data)
      

Inheritance

Object Orientation

  class Base
    constructor: (@name) ->
    eat: (count) =>
      alert "I eat #{count} #{@name}"

  class Apple extends Base
    constructor: (@name) ->
    eat: (count) =>
      alert "Apple method"
      super(count)
      

:: is prototype

Object Orientation

  String::dasherize = ->
    this.replace /_/g, "-"

  alert "one_two".dasherize()
      
  String.prototype.dasherize = function() {
    return this.replace(/_/g, "-");
  };

  alert("one_two".dasherize());
      

Possible problems

Call methods

Possible problems

  doSomething "123"

  doSomething # <- invalid
      
  doSomething("123");

  doSomething;
      

Optional parenthesis

Possible problems


    doSomething () ->  'hello'
        

    doSomething(function() {
      return 'hello';
    });
        

    doSomething() ->  'hello'
        

    doSomething()(function() {
      return 'hello';
    });
        

Implicit parenthesis

Possible problems


action = (token, i) ->
      @tokens.splice i, 0, @generate 'CALL_END', ')', token[2]
      

var action;

action = function(token, i) {
  return this.tokens.splice(i, 0, this.generate('CALL_END', ')', token[2]));
};
      

Optional commas

Possible problems


  doSomething 1,
    2
    3
    4
        

  doSomething(1, 2, 3, 4);

        

  doSomething 1,
  2
  3
  4
        

  doSomething(1, 2);
  3;
  4;
        

Optional commas

Possible problems


  doSomething (->
  'hello'), 1
        

  doSomething((function() {}, 'hello'), 1);

        

  doSomething (->
    'hello'), 1
        

  doSomething((function() {
    return 'hello';
  }), 1);
        

Optional curly brackets

Possible problems


  action({key: value}, {option: value}, otherValue);
      

  action(key: value, option: value, otherValue)
      

  action({
    key: value,
    option: value
  }, otherValue);
      

Tricky if

Possible problems

  # in one line
  @detectEnd i + 1, condition, action
    if token[0] is 'CALL_START'
        

  if (token[0] === 'CALL_START') {
    this.detectEnd(i + 1, condition, action);
  }
        
  # in one line
  @detectEnd i + 1, condition, action
    if token[0] is 'CALL_START' else false
        
  // in one line
  this.detectEnd(i + 1, condition,
    action(token[0] === 'CALL_START' ? void 0 : false));

        

Nested made flat

Possible problems


  js = (parser.parse lexer.tokenize code).compile options
      

  var js;

  js = (parser.parse(lexer.tokenize(code))).compile(options);
      

<Thank You!>

Contact information