Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
Intro to Advanced Rubytwitter: bphoganemail: brianhogan at napcs.comhttp://spkr8.com/t/7114
What makes Ruby                       special?twitter: bphoganemail: brianhogan at napcs.comhttp://spkr8.com/t/7114
Its expressive                                 5.times do                                   puts "Hello World"            ...
Its dynamic       class Person          [:first_name, :last_name, :gender].each do |method|            attr_accessor metho...
Its extendable         module KeywordSearch           def find_all_by_keywords(keywords)             self.where(["name lik...
Its flexible        def add(*args)          args.reduce(0){ |result, item| result + item}        end        add 1,1,1,1twit...
Its dangerous!                                  class String                                    def nil?                  ...
Our roadmap for today         • Requiring files         • Testing         • Message passing         • Classes vs Instances ...
requiretwitter: bphoganemail: brianhogan at napcs.comhttp://spkr8.com/t/7114
require more functionality       Date.today.to_s       NoMethodError: undefined method today for       Date:Class       re...
Testingtwitter: bphoganemail: brianhogan at napcs.comhttp://spkr8.com/t/7114
A simple Unit test          require test/unit          class PersonTest < Test::Unit::TestCase              def test_perso...
Make it fail first...          Loaded suite untitled          Started          E          Finished in 0.000325 seconds.    ...
Now write the code                                 class Person                                   attr_accessor :age      ...
And pass the test!               Loaded suite untitled               Started               .               Finished in 0.0...
Classes and Objects                 • A Ruby Class is an object of type Class                 • An Object is an instance o...
Instance vs class methods      class Person               class Person        def sleep                  def self.sleep   ...
Message passingtwitter: bphoganemail: brianhogan at napcs.comhttp://spkr8.com/t/7114
.send     class Person                  p = Person.new       def name         @name                     p.send(:name)     ...
We reduce complexity with this.      class Sorter                         class Sorter        def move_higher             ...
Then we can add more methods.                                 class Sorter                                   def move_high...
Send and respond_to                class Person                  attr_accessor(:name)                end                p ...
Blocks and Lambdastwitter: bphoganemail: brianhogan at napcs.comhttp://spkr8.com/t/7114
Blockstwitter: bphoganemail: brianhogan at napcs.comhttp://spkr8.com/t/7114
Iteration                   people.each do |person|                     puts person.name                   end            ...
Encapsulation                             result = wrap(:p) do                                        "Hello world"       ...
yield can bind objects!                    navbar = Navbar.create do |menu|                      menu.add "Google", "http:...
Procs and Lambdastwitter: bphoganemail: brianhogan at napcs.comhttp://spkr8.com/t/7114
Delayed Execution      a = lambda{|phrase| puts "#{phrase} at #{Time.now}" }      puts a.call("Hello")      sleep 1      p...
Monkeypatchingtwitter: bphoganemail: brianhogan at napcs.comhttp://spkr8.com/t/7114
Reopen a class!         class Object           def blank?             self.nil? || self.to_s == ""           end          ...
Monkeypatching is an                 evil process!twitter: bphoganemail: brianhogan at napcs.comhttp://spkr8.com/t/7114
Instead, we use Modulestwitter: bphoganemail: brianhogan at napcs.comhttp://spkr8.com/t/7114
Modules             module OrElseMethods                 def blank?                   self.nil? || self.to_s == ""        ...
In Ruby, we don’t care              about the type... we              care about how the                 object works.twit...
Including modules on objects                      module NinjaBehaviors                        def attack                 ...
Extending classes with modules       module NinjaCreator          def new_ninja            puts "Ive created a new Ninja" ...
Person              vs   PersonNinjaRockStarAdmintwitter: bphoganemail: brianhogan at napcs.comhttp://spkr8.com/t/7114
Extending objects with modules      module NinjaBehaviors        def attack          puts "Youve been killed silently!"   ...
Extending objects with modules        ninja = Person.new        ninja.extend NinjaBehaviors        ninja.attack        roc...
Inject code without reopening!      module OrElseMethods         def blank?           self.nil? || self.to_s == ""        ...
self.included class access         module UserValidations           def self.included(base)             base.validates_pre...
Modules can’t contain          methods that overwrite            existing methods!twitter: bphoganemail: brianhogan at nap...
self.included + class_eval      class Person               module NoSave        def save          puts "Original save"    ...
Yes, that’s weird.twitter: bphoganemail: brianhogan at napcs.comhttp://spkr8.com/t/7114
Putting it all together            • Implement “before save” behavior - when we                 call “save” on our object,...
Demo        https://github.com/napcs/intro_to_advanced_rubytwitter: bphoganemail: brianhogan at napcs.comhttp://spkr8.com/...
Questions?twitter: bphoganemail: brianhogan at napcs.comhttp://spkr8.com/t/7114
Upcoming SlideShare
Loading in …5
×

Intro To Advanced Ruby

3,683 views

Published on

Intro talks never let you learn about the things that make a language truly cool. In this talk we'll discover how advanced features of Ruby help us write cleaner more modular code.

Published in: Technology
  • Be the first to comment

Intro To Advanced Ruby

  1. 1. Intro to Advanced Rubytwitter: bphoganemail: brianhogan at napcs.comhttp://spkr8.com/t/7114
  2. 2. What makes Ruby special?twitter: bphoganemail: brianhogan at napcs.comhttp://spkr8.com/t/7114
  3. 3. Its expressive 5.times do puts "Hello World" endtwitter: bphoganemail: brianhogan at napcs.comhttp://spkr8.com/t/7114
  4. 4. Its dynamic class Person [:first_name, :last_name, :gender].each do |method| attr_accessor method end endtwitter: bphoganemail: brianhogan at napcs.comhttp://spkr8.com/t/7114
  5. 5. Its extendable module KeywordSearch def find_all_by_keywords(keywords) self.where(["name like ?", "%" + keywords + "%"]) end end class Project < ActiveRecord::Base extend KeywordSearch end class Task < ActiveRecord::Base extend KeywordSearch endtwitter: bphoganemail: brianhogan at napcs.comhttp://spkr8.com/t/7114
  6. 6. Its flexible def add(*args) args.reduce(0){ |result, item| result + item} end add 1,1,1,1twitter: bphoganemail: brianhogan at napcs.comhttp://spkr8.com/t/7114
  7. 7. Its dangerous! class String def nil? self == "" end endtwitter: bphoganemail: brianhogan at napcs.comhttp://spkr8.com/t/7114
  8. 8. Our roadmap for today • Requiring files • Testing • Message passing • Classes vs Instances • Blocks and Lambdas • Monkeypatching • Modulestwitter: bphoganemail: brianhogan at napcs.comhttp://spkr8.com/t/7114
  9. 9. requiretwitter: bphoganemail: brianhogan at napcs.comhttp://spkr8.com/t/7114
  10. 10. require more functionality Date.today.to_s NoMethodError: undefined method today for Date:Class require date => true Date.today.to_s => "2011-04-09"twitter: bphoganemail: brianhogan at napcs.comhttp://spkr8.com/t/7114
  11. 11. Testingtwitter: bphoganemail: brianhogan at napcs.comhttp://spkr8.com/t/7114
  12. 12. A simple Unit test require test/unit class PersonTest < Test::Unit::TestCase def test_person_under_16_cant_drive p = Person.new p.age = 15 assert !p.can_drive? end endtwitter: bphoganemail: brianhogan at napcs.comhttp://spkr8.com/t/7114
  13. 13. Make it fail first... Loaded suite untitled Started E Finished in 0.000325 seconds.   1) Error: test_person_under_16_cannot_drive(PersonTest): NameError: uninitialized constant PersonTest::Person method test_person_under_16_cannot_drive in untitled document at line 6 1 tests, 0 assertions, 0 failures, 1 errorstwitter: bphoganemail: brianhogan at napcs.comhttp://spkr8.com/t/7114
  14. 14. Now write the code class Person attr_accessor :age def can_drive? self.age >= 16 end endtwitter: bphoganemail: brianhogan at napcs.comhttp://spkr8.com/t/7114
  15. 15. And pass the test! Loaded suite untitled Started . Finished in 0.00028 seconds. 1 tests, 1 assertions, 0 failures, 0 errorstwitter: bphoganemail: brianhogan at napcs.comhttp://spkr8.com/t/7114
  16. 16. Classes and Objects • A Ruby Class is an object of type Class • An Object is an instance of a Class • Classes can have methods just like objects • These are often used as static methods.twitter: bphoganemail: brianhogan at napcs.comhttp://spkr8.com/t/7114
  17. 17. Instance vs class methods class Person class Person def sleep def self.sleep puts "ZZZZZZ" puts "ZZZZZZ" end end end end p = Person.new Person.sleep p.sleep "ZZZZZZ" "ZZZZZZ" => nil => niltwitter: bphoganemail: brianhogan at napcs.comhttp://spkr8.com/t/7114
  18. 18. Message passingtwitter: bphoganemail: brianhogan at napcs.comhttp://spkr8.com/t/7114
  19. 19. .send class Person p = Person.new def name @name p.send(:name) end def name=(input) p.send(:name=, "Homer") @name = input end endtwitter: bphoganemail: brianhogan at napcs.comhttp://spkr8.com/t/7114
  20. 20. We reduce complexity with this. class Sorter class Sorter def move_higher def move_higher puts "moved one higher" puts "moved one higher" end end def move_lower def move_lower puts "moved lower" puts "moved lower" end end def move(type) def move(type) case type self.send "move_" + type when "higher" then move_higher end when "lower" then move_lower end end end endtwitter: bphoganemail: brianhogan at napcs.comhttp://spkr8.com/t/7114
  21. 21. Then we can add more methods. class Sorter def move_higher puts "moved one higher" end def move_lower puts "moved lower" end def move_top puts "moved to the top" end def move_bottom puts "moved to the bottom" end def move(type) self.send "move_" + type end endtwitter: bphoganemail: brianhogan at napcs.comhttp://spkr8.com/t/7114
  22. 22. Send and respond_to class Person attr_accessor(:name) end p = Person.new p.send(:name) if p.respond_to?(:name) p.send(:age) if p.respond_to?(:age)twitter: bphoganemail: brianhogan at napcs.comhttp://spkr8.com/t/7114
  23. 23. Blocks and Lambdastwitter: bphoganemail: brianhogan at napcs.comhttp://spkr8.com/t/7114
  24. 24. Blockstwitter: bphoganemail: brianhogan at napcs.comhttp://spkr8.com/t/7114
  25. 25. Iteration people.each do |person| puts person.name end people.select do |person| person.last_name == "Hogan" end adults = people.reject do |person| person.age <= 18 endtwitter: bphoganemail: brianhogan at napcs.comhttp://spkr8.com/t/7114
  26. 26. Encapsulation result = wrap(:p) do "Hello world" end puts result => "<p>Hello world</p>” def wrap(tag, &block) output = "<#{tag}>#{yield}</#{tag}>" endtwitter: bphoganemail: brianhogan at napcs.comhttp://spkr8.com/t/7114
  27. 27. yield can bind objects! navbar = Navbar.create do |menu| menu.add "Google", "http://www.google.com" menu.add "Amazon", "http://www.amazon.com" end class Menu class Navbar def self.create(&block) def add(name, link) menu = Menu.new @items ||= [] yield menu @items << "<li><a href=#{link}>#{name}</a></li>" menu.to_s(options) end end end def to_s(options) menu = @items.join("n") "<ul>n#{menu}n</ul>" end endtwitter: bphoganemail: brianhogan at napcs.comhttp://spkr8.com/t/7114
  28. 28. Procs and Lambdastwitter: bphoganemail: brianhogan at napcs.comhttp://spkr8.com/t/7114
  29. 29. Delayed Execution a = lambda{|phrase| puts "#{phrase} at #{Time.now}" } puts a.call("Hello") sleep 1 puts a.call("Goodbye") Hello at Sat Apr 09 13:34:07 -0500 2011 Goodbye at Sat Apr 09 13:34:08 -0500 2011twitter: bphoganemail: brianhogan at napcs.comhttp://spkr8.com/t/7114
  30. 30. Monkeypatchingtwitter: bphoganemail: brianhogan at napcs.comhttp://spkr8.com/t/7114
  31. 31. Reopen a class! class Object def blank? self.nil? || self.to_s == "" end def orelse(other) self.blank? ? other : self end endtwitter: bphoganemail: brianhogan at napcs.comhttp://spkr8.com/t/7114
  32. 32. Monkeypatching is an evil process!twitter: bphoganemail: brianhogan at napcs.comhttp://spkr8.com/t/7114
  33. 33. Instead, we use Modulestwitter: bphoganemail: brianhogan at napcs.comhttp://spkr8.com/t/7114
  34. 34. Modules module OrElseMethods def blank? self.nil? || self.to_s == "" end def orelse(other) self.blank? ? other : self end endtwitter: bphoganemail: brianhogan at napcs.comhttp://spkr8.com/t/7114
  35. 35. In Ruby, we don’t care about the type... we care about how the object works.twitter: bphoganemail: brianhogan at napcs.comhttp://spkr8.com/t/7114
  36. 36. Including modules on objects module NinjaBehaviors def attack puts "Youve been killed silently!" end end class Person include NinjaBehaviors end p = Person.new p.attacktwitter: bphoganemail: brianhogan at napcs.comhttp://spkr8.com/t/7114
  37. 37. Extending classes with modules module NinjaCreator def new_ninja puts "Ive created a new Ninja" end end class Person extend NinjaCreator end Person.new_ninjatwitter: bphoganemail: brianhogan at napcs.comhttp://spkr8.com/t/7114
  38. 38. Person vs PersonNinjaRockStarAdmintwitter: bphoganemail: brianhogan at napcs.comhttp://spkr8.com/t/7114
  39. 39. Extending objects with modules module NinjaBehaviors def attack puts "Youve been killed silently!" end end module RockStarBehaviors def trash_hotel_room puts "What a mess!" end endtwitter: bphoganemail: brianhogan at napcs.comhttp://spkr8.com/t/7114
  40. 40. Extending objects with modules ninja = Person.new ninja.extend NinjaBehaviors ninja.attack rockstar = Person.new rockstar.extend RockStarBehaviors rockstar.trash_hotel_room rockstar.extend NinjaBehaviors rockstar.attacktwitter: bphoganemail: brianhogan at napcs.comhttp://spkr8.com/t/7114
  41. 41. Inject code without reopening! module OrElseMethods def blank? self.nil? || self.to_s == "" end def orelse(other) self.blank? ? other : self end end Object.send :include, OrElseMethodstwitter: bphoganemail: brianhogan at napcs.comhttp://spkr8.com/t/7114
  42. 42. self.included class access module UserValidations def self.included(base) base.validates_presence_of :email, :login base.valudates_uniqueness_of :email, :login base.validates_confirmation_of :password end end class User < ActiveRecord::Base include UserValidations endtwitter: bphoganemail: brianhogan at napcs.comhttp://spkr8.com/t/7114
  43. 43. Modules can’t contain methods that overwrite existing methods!twitter: bphoganemail: brianhogan at napcs.comhttp://spkr8.com/t/7114
  44. 44. self.included + class_eval class Person module NoSave def save puts "Original save" def self.included(base) true base.class_eval do end def save end puts "New save" false end end end end Person.send :include, NoSavetwitter: bphoganemail: brianhogan at napcs.comhttp://spkr8.com/t/7114
  45. 45. Yes, that’s weird.twitter: bphoganemail: brianhogan at napcs.comhttp://spkr8.com/t/7114
  46. 46. Putting it all together • Implement “before save” behavior - when we call “save” on our object, we want to declare other methods we want to hook in. class Person before_save, :foo, lambda{|p| p.name = "test"}, SuperFilter endtwitter: bphoganemail: brianhogan at napcs.comhttp://spkr8.com/t/7114
  47. 47. Demo https://github.com/napcs/intro_to_advanced_rubytwitter: bphoganemail: brianhogan at napcs.comhttp://spkr8.com/t/7114
  48. 48. Questions?twitter: bphoganemail: brianhogan at napcs.comhttp://spkr8.com/t/7114

×