Successfully reported this slideshow.
Your SlideShare is downloading. ×

Ruby is Awesome

Ad
Ad
Ad
Ad
Ad
Ad
Ad
Ad
Ad
Ad
Ad
Upcoming SlideShare
Ruby Language - A quick tour
Ruby Language - A quick tour
Loading in …3
×

Check these out next

1 of 182 Ad

More Related Content

Slideshows for you (20)

Similar to Ruby is Awesome (20)

Advertisement

Recently uploaded (20)

Advertisement

Ruby is Awesome

  1. 1. Ruby is Awesome Vitaly Kushner astrails.com
  2. 2. Interesting Times
  3. 3. Fast, Good, or Cheap. Pick two.
  4. 4. Fast, Good, or Cheap. Pick two.
  5. 5. Change Environment
  6. 6. Choose Language
  7. 7. Good Enough
  8. 8. You can do almost anything with any language
  9. 9. http://www.flickr.com/photos/jantik/254695220/
  10. 10. Paul Graham http://paulgraham.com/
  11. 11. Blub Language Paradox
  12. 12. BASIC was “Good Enough”
  13. 13. No Recursion?!
  14. 14. Beating the averages http://paulgraham.com/avg.html
  15. 15. Lisp is good
  16. 16. Ruby is Better! :-)
  17. 17. Ruby is Practical
  18. 18. Ruby is an acceptable LISP
  19. 19. History
  20. 20. History • Yukihiro Matsumoto (aka "Matz")
  21. 21. History • Yukihiro Matsumoto (aka "Matz") • Released in 1993
  22. 22. History • Yukihiro Matsumoto (aka "Matz") • Released in 1993 • Got known in US about 2000
  23. 23. History • Yukihiro Matsumoto (aka "Matz") • Released in 1993 • Got known in US about 2000 • Gained momentum around 2003-2005
  24. 24. LISP + Smalltalk + Python + Perl
  25. 25. • Simple consistent syntax • Dynamically typed • Late binding • Single Inheritance with Mixin support
  26. 26. • Everything is an object • Closures • Garbage Collection • Multi platform
  27. 27. Ruby is Awesome
  28. 28. Blocks
  29. 29. array.each { |e| puts } array.each { |e| puts e} array.each do |e| puts e end
  30. 30. map {|x| ...} collect {|x| ...} select {|x| ...} reject {|x| ...} find {|x| ...} any? {|x| ...} all? {|x| ...} sort {|a, b| ...}
  31. 31. File.readlines("foobar.dat").map{|l| l.strip}.sort {|x,y| x[-1] <=> y[-1]}.map {|x| x.upcase}.to_xml
  32. 32. 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")
  33. 33. 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}
  34. 34. 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}
  35. 35. 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}
  36. 36. 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
  37. 37. class Hash def to_html_attributes map { |k, v| k + '="' + v + '"' }.join(' ') end end
  38. 38. attrs = { :src => "foo.img", :width => 100, :height => 200, :class => "avatar" } attrs.to_html_attributes => 'class="avatar" height="200" width="100" src="foo.img"'
  39. 39. Closures
  40. 40. class Array def has_any_bigger_then(x) any? {|e| e > x} end end
  41. 41. def incrementor(x) proc {|y| y + x} end inc1 = incrementor(1) inc5 = incrementor(5)
  42. 42. def incrementor(x) proc {|y| y + x} end inc1 = incrementor(1) inc1.call(1) => 2 inc1.call(3) => 4
  43. 43. def incrementor(x) proc {|y| y + x} end inc5 = incrementor(5) inc5.call(1) => 6 inc5.call(3) => 8
  44. 44. # ruby def paidMore(amount) proc {|e| e.salary > amount} end // C# public Predicate<Employee> PaidMore(int amount) { return delegate(Employee e) { return e.Salary > amount; } }
  45. 45. Meta Programming
  46. 46. Extending the language to create new abstractions
  47. 47. Monkey Patching
  48. 48. class Hash def to_html_attributes map { |k, v| k + '="' + v + '"' }.join(' ') end end
  49. 49. attrs = { :src => "foo.img", :width => 100, :height => 200, :class => "avatar" } attrs.to_html_attributes => 'class="avatar" height="200" width="100" src="foo.img"'
  50. 50. 3.megabytes => 3145728
  51. 51. 10.months.from_now => Thu Aug 12 03:25:40 0300 2010
  52. 52. 5.minutes.ago => Mon Oct 12 03:21:02 0200 2009
  53. 53. Duck Typing
  54. 54. .to_s [1, 2, 3].to_s => "123"
  55. 55. .to_s 123.to_s => "123"
  56. 56. .to_s "123".to_s => "123"
  57. 57. "a#{b}c" "a" + b.to_s + c
  58. 58. method_missing
  59. 59. NoMethodError
  60. 60. User.find_by_company("Astrails")
  61. 61. User.find_by_name_and_company( "Vitaly Kushner", "Astrails")
  62. 62. Multiple inheritance is evil :-)
  63. 63. Modules a.k.a. Mixins
  64. 64. module FlyHome def set_home @home = position end def fly_home fly(@home) end end
  65. 65. class Bird < Living include FlyHome def fly(direction) ... def position ... end class Airplane < Machine include FlyHome def fly(direction) ... def position ... end
  66. 66. DSL Domain Specific Language
  67. 67. 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_service end
  68. 68. 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
  69. 69. safe do local { path "/backup/:kind" } s3 :key => YOUR_S3_KEY, :secret => YOUR_S3_SECRET, :bucket => S3_BUCKET, :path => ":kind/" gpg :password => "foobar" ... end
  70. 70. safe do ... mysqldump do options "-ceKq ..." user "astrails" password "foobar" database :blog database :astrails_com do skip_tables :request_logs end end ... end
  71. 71. safe do ... tar do archive "etc-files" do files "/etc" end end end
  72. 72. Rubygems
  73. 73. ➜

~

✗
sudo
gem
install
astrails‐safe Successfully
installed
astrails‐safe‐0.2.3 1
gem
installed Installing
ri
documentation
for
astrails‐safe‐0.2.3... Installing
RDoc
documentation
for
astrails‐safe‐0.2.3... ➜

~

✗

  74. 74. Rubyforge.org 8,426 gems
  75. 75. Github.com 7,483 gems
  76. 76. Rails
  77. 77. http://www.flickr.com/photos/ecstaticist/2589723846/
  78. 78. Rails is Fun
  79. 79. optimized for programmers happiness and sustainable productivity
  80. 80. MVC
  81. 81. MVC • Model
  82. 82. MVC •Model • View
  83. 83. MVC •Model • View • Controller
  84. 84. convention over configuration
  85. 85. class User < ActiveRecord::Base end
  86. 86. User.find(123) => SELECT * FROM `users` WHERE (`users`.`id` = 123)
  87. 87. class User < ActiveRecord::Base belongs_to :account has_many :projects end class UsersController < ApplicationController def show @user = User.find(params[:user]) render :template => 'show' end end
  88. 88. class User < ActiveRecord::Base belongs_to :account has_many :projects end class UsersController < ApplicationController def show @user = User.find(params[:user]) render :template => 'show' end end
  89. 89. class User < ActiveRecord::Base belongs_to :account has_many :projects end class UsersController < ApplicationController def show @user = User.find(params[:user]) end end
  90. 90. Models
  91. 91. http://www.flickr.com/photos/slyadnev/3959052112/
  92. 92. ActiveRecord
  93. 93. ORM Object-Relational Mapping
  94. 94. • MySQL • PostgreSQL • MSSql • SQLite • Oracle • ODBC
  95. 95. Associations class User < ActiveRecord::Base has_many :projects end class Project < ActiveRecord::Base belongs_to :user end
  96. 96. u = User.find(1) => SELECT * FROM `users` WHERE (`users`.`id` = 1)
  97. 97. u.projects.count => SELECT count(*) AS count_all FROM `projects` WHERE (`projects`.user_id = 1)
  98. 98. 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)
  99. 99. Project.first.user => SELECT * FROM `projects` LIMIT 1 => SELECT * FROM `users` WHERE (`users`.`id` = 1)
  100. 100. Callbacks • before_validation • before_validation_on_create • after_validation • after_validation_on_create • before_save • before_create • after_create • after_save
  101. 101. Callbacks • before_validation • before_validation_on_create • after_validation • after_validation_on_create • before_save • before_create • after_create • after_save
  102. 102. 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 end end
  103. 103. Validations
  104. 104. validates_presence_of :account_id validates_uniqueness_of :name validates_numericality_of :ccv def validate unless name[0] == ?A errors.add(:name, "Names must start with an A") end end
  105. 105. ActiveSupport
  106. 106. 3.days.ago [1,2,3].to_json 2.weeks.from_now hash.slice(:foo, :bar)
  107. 107. Controllers
  108. 108. http://www.flickr.com/photos/benjamin-nagel/2902721172/
  109. 109. class UsersController < ApplicationController def index @users = User.paginate(:page => params[:page], :per_page => 20) end end
  110. 110. http://yourdomain/users/index
  111. 111. http://localhost:3000/users/index
  112. 112. ActionController::Routing::Routes.draw do |map| map.connect ':controller/:action/:id' map.connect ':controller/:action/:id.:format' end
  113. 113. ActionController::Routing::Routes.draw do |map| map.connect ':controller/:action/:id' map.connect ':controller/:action/:id.:format' end /welcome/home :controller => 'welcome' :action => 'home'
  114. 114. 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'
  115. 115. 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'
  116. 116. /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' } }
  117. 117. REST
  118. 118. REST Representational State Transfer
  119. 119. • HEAD • GET • POST • PUT • DELETE
  120. 120. • index • edit • new • update • create • destroy • show
  121. 121. index GET /users
  122. 122. new GET /users/new
  123. 123. create POST /users
  124. 124. show GET /users/123
  125. 125. edit GET /users/123/edit
  126. 126. update PUT /users/123
  127. 127. destroy DELETE /users/123
  128. 128. map.resources :users do |user| user.resources :projects end 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
  129. 129. users_path => /users
  130. 130. new_user_path => /users/new
  131. 131. user_path(user) => /users/123
  132. 132. edit_user_path(user) => /users/123/edit
  133. 133. Filters
  134. 134. 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
  135. 135. class UsersController < ApplicationController before_filter :login_required, :except => [:new, :create] ... protected def login_required unless session[:user_id] redirect_to "/login" end end end
  136. 136. class UsersController < ApplicationController before_filter :find_user, :only => [:edit, :show, :update, :destroy] ... protected def find_user @user = User.find(params[:id]) end end
  137. 137. def index @users = User.paginate( :page => params[:page], :per_page => 20) end
  138. 138. def new @user = User.new(params[:user]) end
  139. 139. 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" end end
  140. 140. def edit end
  141. 141. def show end
  142. 142. 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" end end
  143. 143. def destroy if @user.destroy flash[:notice] = "User deleted" else flash[:error] = "Failed to delete user" end redirect_to users_path end
  144. 144. Errors
  145. 145. class UsersController < ApplicationController before_filter :find_user, :only => [:edit, :show, :update, :destroy] ... def update if @user.update_attributes(params[:user]) ... end end protected def find_user @user = User.find(params[:id]) end end
  146. 146. ActiveRecord::RecordNotFound
  147. 147. HTTP 404
  148. 148. HTTP 500
  149. 149. Session
  150. 150. Session Store • files • database • cookie
  151. 151. 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) end end
  152. 152. MVC
  153. 153. Views
  154. 154. http://www.flickr.com/photos/brapke/226101874/
  155. 155. def index @users = User.paginate( :page => params[:page], :per_page => 20) end
  156. 156. app/views/users/index.html.erb
  157. 157. ERB <p> Hello <%= h(@user.name) %> </p>
  158. 158. ERB <ul>   <% @user.projects.each do |project| %>     <li><%= h(project.name) %></li>   <% end %> <ul>
  159. 159. 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 } end end
  160. 160. HAML %p = @user.name %ul - @user.projects.each do |project| %li= project.name
  161. 161. Testing
  162. 162. TDD
  163. 163. TDD Test Driven Development
  164. 164. BDD
  165. 165. BDD Behavior Driven Development
  166. 166. Pressure
  167. 167. TATFT
  168. 168. TATFT Test All The Fucking Time
  169. 169. • Test::Unit • RSpec • Shoulda • Cucumber • Webrat
  170. 170. 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_success end
  171. 171. Migrations
  172. 172. 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 end end
  173. 173. Plugins
  174. 174. inherited_resourfce standard implementation for the 7 REST actions
  175. 175. acts_as_tree db schema and methods for storing trees
  176. 176. country_select HTML helper to present a select box of countries
  177. 177. Rails Scales?
  178. 178. http://www.flickr.com/photos/pinksherbet/223270526/
  179. 179. Rails Scales? YES
  180. 180. LinkedIn’s “Bumper Sticker” More then billion page views per month
  181. 181. if you have no scalability problems you are not growing fast enough!
  182. 182. Ruby is Awesome Q &A Vitaly Kushner astrails.com

×