182
Ruby is Awesome Vitaly Kushner astrails.com

Ruby is Awesome

Embed Size (px)

DESCRIPTION

Overview of the ruby language and bits of awesome it gives to developers

Citation preview

Page 1: Ruby is Awesome

Ruby is Awesome

Vitaly Kushnerastrails.com

Page 2: Ruby is Awesome

Interesting Times

Page 3: Ruby is Awesome

Fast, Good, or Cheap.Pick two.

Page 4: Ruby is Awesome

Fast, Good, or Cheap.Pick two.

Page 5: Ruby is Awesome

Change Environment

Page 6: Ruby is Awesome

Choose Language

Page 7: Ruby is Awesome

Good Enough

Page 8: Ruby is Awesome

You can do almostanythingwith anylanguage

Page 10: Ruby is Awesome

Paul Grahamhttp://paulgraham.com/

Page 11: Ruby is Awesome

Blub Language Paradox

Page 12: Ruby is Awesome

BASIC was“Good Enough”

Page 13: Ruby is Awesome

No Recursion?!

Page 14: Ruby is Awesome

Beating the averageshttp://paulgraham.com/avg.html

Page 15: Ruby is Awesome

Lisp is good

Page 16: Ruby is Awesome

Ruby is Better!:-)

Page 17: Ruby is Awesome

Ruby is Practical

Page 18: Ruby is Awesome

Ruby is an acceptable LISP

Page 19: Ruby is Awesome

History

Page 20: Ruby is Awesome

History

• Yukihiro Matsumoto (aka "Matz")

Page 21: Ruby is Awesome

History

• Yukihiro Matsumoto (aka "Matz")

• Released in 1993

Page 22: Ruby is Awesome

History

• Yukihiro Matsumoto (aka "Matz")

• Released in 1993

• Got known in US about 2000

Page 23: Ruby is Awesome

History

• Yukihiro Matsumoto (aka "Matz")

• Released in 1993

• Got known in US about 2000

• Gained momentum around 2003-2005

Page 24: Ruby is Awesome

LISP+

Smalltalk+

Python+

Perl

Page 25: Ruby is Awesome

• Simple consistent syntax

• Dynamically typed

• Late binding

• Single Inheritance with Mixin support

Page 26: Ruby is Awesome

• Everything is an object

• Closures

• Garbage Collection

• Multi platform

Page 27: Ruby is Awesome

Ruby is Awesome

Page 28: Ruby is Awesome

Blocks

Page 29: Ruby is Awesome

array.each { |e| puts }

array.each { |e| puts e} array.each do |e| puts eend

Page 30: Ruby is Awesome

map {|x| ...}collect {|x| ...}select {|x| ...}reject {|x| ...}find {|x| ...}any? {|x| ...}all? {|x| ...}sort {|a, b| ...}

Page 31: Ruby is Awesome

File.readlines("foobar.dat").map{|l| l.strip}.sort {|x,y| x[-1] <=> y[-1]}.map {|x| x.upcase}.to_xml

Page 32: Ruby is Awesome

File.readlines("foobar.dat").map{|l| l.strip}.sort {|x,y| x[-1] <=> y[-1]}.map {|x| x.upcase}.to_xml

File.readlines("foobar.dat")

Page 33: Ruby is Awesome

File.readlines("foobar.dat").map{|l| l.strip}.sort {|x,y| x[-1] <=> y[-1]}.map {|x| x.upcase}.to_xml

File.readlines("foobar.dat")

.map {|line| line.strip}

Page 34: Ruby is Awesome

File.readlines("foobar.dat").map{|l| l.strip}.sort {|x,y| x[-1] <=> y[-1]}.map {|x| x.upcase}.to_xml

File.readlines("foobar.dat")

.map {|line| line.strip}

.sort {|x,y| x.to_i <=> y.to_i}

Page 35: Ruby is Awesome

File.readlines("foobar.dat").map{|l| l.strip}.sort {|x,y| x[-1] <=> y[-1]}.map {|x| x.upcase}.to_xml

File.readlines("foobar.dat")

.map {|line| line.strip}

.sort {|x,y| x.to_i <=> y.to_i}

.map {|x| x.upcase}

Page 36: Ruby is Awesome

File.readlines("foobar.dat").map{|l| l.strip}.sort {|x,y| x[-1] <=> y[-1]}.map {|x| x.upcase}.to_xml

File.readlines("foobar.dat")

.map {|line| line.strip}

.sort {|x,y| x.to_i <=> y.to_i}

.map {|x| x.upcase}

.to_xml

Page 37: Ruby is Awesome

class Hash def to_html_attributes map { |k, v| k + '="' + v + '"' }.join(' ') endend

Page 38: Ruby is Awesome

attrs = { :src => "foo.img", :width => 100, :height => 200, :class => "avatar"}attrs.to_html_attributes=> 'class="avatar" height="200" width="100" src="foo.img"'

Page 39: Ruby is Awesome

Closures

Page 40: Ruby is Awesome

class Array def has_any_bigger_then(x) any? {|e| e > x} endend

Page 41: Ruby is Awesome

def incrementor(x) proc {|y| y + x}end

inc1 = incrementor(1)

inc5 = incrementor(5)

Page 42: Ruby is Awesome

def incrementor(x) proc {|y| y + x}end

inc1 = incrementor(1)

inc1.call(1)=> 2inc1.call(3)=> 4

Page 43: Ruby is Awesome

def incrementor(x) proc {|y| y + x}end

inc5 = incrementor(5)

inc5.call(1)=> 6inc5.call(3)=> 8

Page 44: Ruby is Awesome

# rubydef paidMore(amount) proc {|e| e.salary > amount}end

// C#public Predicate<Employee> PaidMore(int amount) { return delegate(Employee e) { return e.Salary > amount; } }

Page 45: Ruby is Awesome

Meta Programming

Page 46: Ruby is Awesome

Extending the language to create new abstractions

Page 47: Ruby is Awesome

Monkey Patching

Page 48: Ruby is Awesome

class Hash def to_html_attributes map { |k, v| k + '="' + v + '"' }.join(' ') endend

Page 49: Ruby is Awesome

attrs = { :src => "foo.img", :width => 100, :height => 200, :class => "avatar"}attrs.to_html_attributes=> 'class="avatar" height="200" width="100" src="foo.img"'

Page 50: Ruby is Awesome

3.megabytes=> 3145728

Page 51: Ruby is Awesome

10.months.from_now

=> Thu Aug 12 03:25:40 0300 2010

Page 52: Ruby is Awesome

5.minutes.ago

=> Mon Oct 12 03:21:02 0200 2009

Page 53: Ruby is Awesome

Duck Typing

Page 54: Ruby is Awesome

.to_s

[1, 2, 3].to_s => "123"

Page 55: Ruby is Awesome

.to_s

123.to_s => "123"

Page 56: Ruby is Awesome

.to_s

"123".to_s => "123"

Page 57: Ruby is Awesome

"a#{b}c"

"a" + b.to_s + c

Page 58: Ruby is Awesome

method_missing

Page 59: Ruby is Awesome

NoMethodError

Page 60: Ruby is Awesome

User.find_by_company("Astrails")

Page 61: Ruby is Awesome

User.find_by_name_and_company("Vitaly Kushner", "Astrails")

Page 62: Ruby is Awesome

Multiple inheritance is evil:-)

Page 63: Ruby is Awesome

Modulesa.k.a. Mixins

Page 64: Ruby is Awesome

module FlyHome def set_home @home = position end

def fly_home fly(@home) endend

Page 65: Ruby is Awesome

class Bird < Living include FlyHome def fly(direction) ... def position ...end

class Airplane < Machine include FlyHome def fly(direction) ... def position ...end

Page 66: Ruby is Awesome

DSLDomain Specific Language

Page 67: Ruby is Awesome

class User < ActiveRecord::Base has_many :projects belongs_to :account has_many :reports, :class_name => "User", :foreign_key => :reports_to_id named_scope :activated, :conditions => "activated_at IS NOT NULL" validates_uniqueness_of :name validates_presence_of :crypted_password validates_acceptance_of :terms_of_serviceend

Page 68: Ruby is Awesome

safe do local { path "/backup/:kind" } s3 :key => YOUR_S3_KEY, :secret => YOUR_S3_SECRET, :bucket => S3_BUCKET, :path => ":kind/" gpg :password => "foobar"

mysqldump do options "-ceKq --single-transaction --create-options" user "astrails" password "foobar"

database :blog database :astrails_com do skip_tables :request_logs end end

tar do archive "etc-files" do files "/etc" end end

end

Page 69: Ruby is Awesome

safe do local { path "/backup/:kind" } s3 :key => YOUR_S3_KEY, :secret => YOUR_S3_SECRET, :bucket => S3_BUCKET, :path => ":kind/" gpg :password => "foobar"

...end

Page 70: Ruby is Awesome

safe do ... mysqldump do options "-ceKq ..." user "astrails" password "foobar"

database :blog database :astrails_com do skip_tables :request_logs end end ...end

Page 71: Ruby is Awesome

safe do ...

tar do archive "etc-files" do files "/etc" end end

end

Page 72: Ruby is Awesome

Rubygems

Page 73: Ruby is Awesome

➜~✗sudogeminstallastrails‐safeSuccessfullyinstalledastrails‐safe‐0.2.31geminstalledInstallingridocumentationforastrails‐safe‐0.2.3...InstallingRDocdocumentationforastrails‐safe‐0.2.3...➜~✗

Page 74: Ruby is Awesome

Rubyforge.org8,426 gems

Page 75: Ruby is Awesome

Github.com7,483 gems

Page 76: Ruby is Awesome

Rails

Page 78: Ruby is Awesome

Rails is Fun

Page 79: Ruby is Awesome

optimized for programmers happiness

and sustainable productivity

Page 80: Ruby is Awesome

MVC

Page 81: Ruby is Awesome

MVC

•Model

Page 82: Ruby is Awesome

MVC

•Model

•View

Page 83: Ruby is Awesome

MVC

•Model

•View

•Controller

Page 84: Ruby is Awesome

convention over configuration

Page 85: Ruby is Awesome

class User < ActiveRecord::Baseend

Page 86: Ruby is Awesome

User.find(123)=> SELECT * FROM `users` WHERE (`users`.`id` = 123)

Page 87: Ruby is Awesome

class User < ActiveRecord::Base belongs_to :account has_many :projectsend

class UsersController < ApplicationController def show @user = User.find(params[:user]) render :template => 'show' endend

Page 88: Ruby is Awesome

class User < ActiveRecord::Base belongs_to :account has_many :projectsend

class UsersController < ApplicationController def show @user = User.find(params[:user]) render :template => 'show' endend

Page 89: Ruby is Awesome

class User < ActiveRecord::Base belongs_to :account has_many :projectsend

class UsersController < ApplicationController def show @user = User.find(params[:user]) endend

Page 90: Ruby is Awesome

Models

Page 92: Ruby is Awesome

ActiveRecord

Page 93: Ruby is Awesome

ORMObject-Relational Mapping

Page 94: Ruby is Awesome

• MySQL

• PostgreSQL

• MSSql

• SQLite

• Oracle

• ODBC

Page 95: Ruby is Awesome

class User < ActiveRecord::Base has_many :projectsend

class Project < ActiveRecord::Base belongs_to :userend

Associations

Page 96: Ruby is Awesome

u = User.find(1)=> SELECT * FROM `users` WHERE (`users`.`id` = 1)

Page 97: Ruby is Awesome

u.projects.count=> SELECT count(*) AS count_all FROM `projects` WHERE (`projects`.user_id = 1)

Page 98: Ruby is Awesome

User.find_by_first_name("Vitaly", :include => :projects)=> SELECT * FROM `users` WHERE (`users`.`first_name` = 'Vitaly') LIMIT 1=> SELECT `projects`.* FROM `projects` WHERE (`projects`.user_id = 1)

Page 99: Ruby is Awesome

Project.first.user=> SELECT * FROM `projects` LIMIT 1=> SELECT * FROM `users` WHERE (`users`.`id` = 1)

Page 100: Ruby is Awesome

Callbacks• before_validation

• before_validation_on_create

• after_validation

• after_validation_on_create

• before_save

• before_create

• after_create

• after_save

Page 101: Ruby is Awesome

Callbacks• before_validation

• before_validation_on_create

• after_validation

• after_validation_on_create

• before_save

• before_create

• after_create

• after_save

Page 102: Ruby is Awesome

class User < ActiveRecord::Base before_save :encrypt_password attr_accessor :password private def enctypt_password unless password.blank? self.salt ||= ActiveSupport::SecureRandom.hex(40) self.crypted_password = encrypt(password, salt) end endend

Page 103: Ruby is Awesome

Validations

Page 104: Ruby is Awesome

validates_presence_of :account_idvalidates_uniqueness_of :namevalidates_numericality_of :ccv

def validate unless name[0] == ?A errors.add(:name, "Names must start with an A") endend

Page 105: Ruby is Awesome

ActiveSupport

Page 106: Ruby is Awesome

3.days.ago

[1,2,3].to_json

2.weeks.from_now

hash.slice(:foo, :bar)

Page 107: Ruby is Awesome

Controllers

Page 109: Ruby is Awesome

class UsersController < ApplicationController def index @users = User.paginate(:page => params[:page], :per_page => 20) endend

Page 110: Ruby is Awesome

http://yourdomain/users/index

Page 111: Ruby is Awesome

http://localhost:3000/users/index

Page 112: Ruby is Awesome

ActionController::Routing::Routes.draw do |map| map.connect ':controller/:action/:id' map.connect ':controller/:action/:id.:format'end

Page 113: Ruby is Awesome

ActionController::Routing::Routes.draw do |map| map.connect ':controller/:action/:id' map.connect ':controller/:action/:id.:format'end

/welcome/home:controller => 'welcome'

:action => 'home'

Page 114: Ruby is Awesome

ActionController::Routing::Routes.draw do |map| map.connect ':controller/:action/:id' map.connect ':controller/:action/:id.:format'end

/users/edit/123:controller => 'users'

:action => 'edit'

:id => '123'

Page 115: Ruby is Awesome

ActionController::Routing::Routes.draw do |map| map.connect ':controller/:action/:id' map.connect ':controller/:action/:id.:format'end

projects/show/456.xml:controller => 'projects'

:action => 'show'

:id => '456'

:format => 'xml'

Page 116: Ruby is Awesome

/talks/create?title=ruby%20is%20awsome&author[name]=Vitaly&author[company]=Astrails

{ :controller => 'talks', :action => 'create', :title => "ruby is awesome", :user => { :name => 'Vitaly', :company => 'Astrails' }}

Page 117: Ruby is Awesome

REST

Page 118: Ruby is Awesome

RESTRepresentational State Transfer

Page 119: Ruby is Awesome

• HEAD

• GET

• POST

• PUT

• DELETE

Page 120: Ruby is Awesome

• index

• new

• create

• show

• edit

• update

• destroy

Page 121: Ruby is Awesome

GET /users

index

Page 122: Ruby is Awesome

new

GET /users/new

Page 123: Ruby is Awesome

create

POST /users

Page 124: Ruby is Awesome

show

GET /users/123

Page 125: Ruby is Awesome

edit

GET /users/123/edit

Page 126: Ruby is Awesome

update

PUT /users/123

Page 127: Ruby is Awesome

destroy

DELETE /users/123

Page 128: Ruby is Awesome

map.resources :users do |user| user.resources :projectsend

GET /users/123/projects:controller => :projects, :action => :index, :user_id => 123

GET /users/123/projects/456:controller => :projects, :action => :show, :user_id => 123, :id => 456

Page 129: Ruby is Awesome

users_path=> /users

Page 130: Ruby is Awesome

new_user_path=> /users/new

Page 131: Ruby is Awesome

user_path(user)=> /users/123

Page 132: Ruby is Awesome

edit_user_path(user)=> /users/123/edit

Page 133: Ruby is Awesome

Filters

Page 134: Ruby is Awesome

class UsersController < ApplicationController before_filter :login_required, :except => [:new, :create] before_filter :find_user, :only => [:edit, :show, :update, :destroy]

def index ... def new ... def create ... def edit ... def show ... def update ... def destroy ...

protected def login_required ...

def find_user ...end

Page 135: Ruby is Awesome

class UsersController < ApplicationController before_filter :login_required, :except => [:new, :create] ...protected def login_required unless session[:user_id] redirect_to "/login" end endend

Page 136: Ruby is Awesome

class UsersController < ApplicationController before_filter :find_user, :only => [:edit, :show, :update, :destroy] ...protected def find_user @user = User.find(params[:id]) endend

Page 137: Ruby is Awesome

def index @users = User.paginate( :page => params[:page], :per_page => 20)end

Page 138: Ruby is Awesome

def new @user = User.new(params[:user])end

Page 139: Ruby is Awesome

def create @user = User.new(params[:user]) if @user.save flash[:notice] = "User created" redirect_to user_path(@user) else flash.now[:error] = "Failed to create a user" render :action => "new" endend

Page 140: Ruby is Awesome

def editend

Page 141: Ruby is Awesome

def showend

Page 142: Ruby is Awesome

def update if @user.update_attributes(params[:user]) flash[:notice] = "User updated" redirect_to user_path(@user) else flash.now[:error] = "Failed to update user" render :action => "edit" endend

Page 143: Ruby is Awesome

def destroy if @user.destroy flash[:notice] = "User deleted" else flash[:error] = "Failed to delete user" end redirect_to users_pathend

Page 144: Ruby is Awesome

Errors

Page 145: Ruby is Awesome

class UsersController < ApplicationController before_filter :find_user, :only => [:edit, :show, :update, :destroy] ... def update if @user.update_attributes(params[:user]) ... end endprotected def find_user @user = User.find(params[:id]) endend

Page 146: Ruby is Awesome

ActiveRecord::RecordNotFound

Page 147: Ruby is Awesome

HTTP 404

Page 148: Ruby is Awesome

HTTP 500

Page 149: Ruby is Awesome

Session

Page 150: Ruby is Awesome

Session Store

• files

• database

• cookie

Page 151: Ruby is Awesome

class UserSessionController < ApplicationController def create unless user = User.authenticate( params[:login], params[:password]) flash.now[:error] = "Login failed" render :action => :new return end

session[:user_id] = user.id redirect_to user_path(user) endend

Page 152: Ruby is Awesome

MVC

Page 153: Ruby is Awesome

Views

Page 155: Ruby is Awesome

def index @users = User.paginate( :page => params[:page], :per_page => 20)end

Page 156: Ruby is Awesome

app/views/users/index.html.erb

Page 157: Ruby is Awesome

<p> Hello <%= h(@user.name) %></p>

ERB

Page 158: Ruby is Awesome

<ul>  <% @user.projects.each do |project| %>    <li><%= h(project.name) %></li>  <% end %><ul>

ERB

Page 159: Ruby is Awesome

def index @users = User.paginate(...) respond_to do |format| # default action is to render index.html.erb format.html format.xml { @users.to_xml } format.json { @users.to_json } endend

Page 160: Ruby is Awesome

%p = @user.name

%ul - @user.projects.each do |project| %li= project.name

HAML

Page 161: Ruby is Awesome

Testing

Page 162: Ruby is Awesome

TDD

Page 163: Ruby is Awesome

TDDTest Driven Development

Page 164: Ruby is Awesome

BDD

Page 165: Ruby is Awesome

BDDBehavior Driven Development

Page 166: Ruby is Awesome

Pressure

Page 167: Ruby is Awesome

TATFT

Page 168: Ruby is Awesome

TATFTTest All The Fucking Time

Page 169: Ruby is Awesome

• Test::Unit

• RSpec

• Shoulda

• Cucumber

• Webrat

Page 170: Ruby is Awesome

it "should be able to show media" do @media = stub_media Media.stub!(:find).and_return(@media) get :show, :id => @media.id response.should be_successend

Page 171: Ruby is Awesome

Migrations

Page 172: Ruby is Awesome

class CreateProjects < ActiveRecord::Migration def self.up create_table :projects do |t| t.integer :user_id, :null => false t.string :title, :null => false t.text :description, :null => false t.integer :budget, :null => false

t.timestamps end end

def self.down drop_table :projects endend

Page 173: Ruby is Awesome

Plugins

Page 174: Ruby is Awesome

inherited_resourfcestandard implementation for the 7 REST actions

Page 175: Ruby is Awesome

acts_as_treedb schema and methods for storing trees

Page 176: Ruby is Awesome

country_selectHTML helper to present a select box of countries

Page 177: Ruby is Awesome

Rails Scales?

Page 179: Ruby is Awesome

Rails Scales?

YES

Page 180: Ruby is Awesome

LinkedIn’s “Bumper Sticker” More then billion page views per month

Page 181: Ruby is Awesome

if you have no scalability problems

you are not growing fast enough!

Page 182: Ruby is Awesome

Ruby is AwesomeQ & A

Vitaly Kushnerastrails.com