SlideShare a Scribd company logo
Intro to Advanced Ruby



twitter: bphogan
email: brianhogan at napcs.com
http://spkr8.com/t/7114
What makes Ruby
                       special?


twitter: bphogan
email: brianhogan at napcs.com
http://spkr8.com/t/7114
It's expressive
                                 5.times do
                                   puts "Hello World"
                                 end




twitter: bphogan
email: brianhogan at napcs.com
http://spkr8.com/t/7114
It's dynamic
       class Person

          [:first_name, :last_name, :gender].each do |method|
            attr_accessor method
          end

       end




twitter: bphogan
email: brianhogan at napcs.com
http://spkr8.com/t/7114
It's 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
         end




twitter: bphogan
email: brianhogan at napcs.com
http://spkr8.com/t/7114
It's flexible
        def add(*args)
          args.reduce(0){ |result, item| result + item}
        end

        add 1,1,1,1




twitter: bphogan
email: brianhogan at napcs.com
http://spkr8.com/t/7114
It's dangerous!
                                  class String
                                    def nil?
                                      self == ""
                                    end
                                  end




twitter: bphogan
email: brianhogan at napcs.com
http://spkr8.com/t/7114
Our roadmap for today
         • Requiring files
         • Testing
         • Message passing
         • Classes vs Instances
         • Blocks and Lambdas
         • Monkeypatching
         • Modules
twitter: bphogan
email: brianhogan at napcs.com
http://spkr8.com/t/7114
require



twitter: bphogan
email: brianhogan at napcs.com
http://spkr8.com/t/7114
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: bphogan
email: brianhogan at napcs.com
http://spkr8.com/t/7114
Testing



twitter: bphogan
email: brianhogan at napcs.com
http://spkr8.com/t/7114
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

          end


twitter: bphogan
email: brianhogan at napcs.com
http://spkr8.com/t/7114
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 errors




twitter: bphogan
email: brianhogan at napcs.com
http://spkr8.com/t/7114
Now write the code

                                 class Person
                                   attr_accessor :age
                                   def can_drive?
                                     self.age >= 16
                                   end
                                 end




twitter: bphogan
email: brianhogan at napcs.com
http://spkr8.com/t/7114
And pass the test!

               Loaded suite untitled
               Started
               .
               Finished in 0.00028 seconds.

               1 tests, 1 assertions, 0 failures, 0
               errors




twitter: bphogan
email: brianhogan at napcs.com
http://spkr8.com/t/7114
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: bphogan
email: brianhogan at napcs.com
http://spkr8.com/t/7114
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
      => nil



twitter: bphogan
email: brianhogan at napcs.com
http://spkr8.com/t/7114
Message passing



twitter: bphogan
email: brianhogan at napcs.com
http://spkr8.com/t/7114
.send
     class Person                  p = Person.new
       def name
         @name                     p.send(:name)
       end

       def name=(input)            p.send(:name=, "Homer")
         @name = input
       end
     end




twitter: bphogan
email: brianhogan at napcs.com
http://spkr8.com/t/7114
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
      end




twitter: bphogan
email: brianhogan at napcs.com
http://spkr8.com/t/7114
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
                                 end


twitter: bphogan
email: brianhogan at napcs.com
http://spkr8.com/t/7114
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: bphogan
email: brianhogan at napcs.com
http://spkr8.com/t/7114
Blocks and Lambdas



twitter: bphogan
email: brianhogan at napcs.com
http://spkr8.com/t/7114
Blocks



twitter: bphogan
email: brianhogan at napcs.com
http://spkr8.com/t/7114
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
                   end


twitter: bphogan
email: brianhogan at napcs.com
http://spkr8.com/t/7114
Encapsulation
                             result = wrap(:p) do
                                        "Hello world"
                                      end

                             puts result
                             => "<p>Hello world</p>”




               def wrap(tag, &block)
                 output = "<#{tag}>#{yield}</#{tag}>"
               end




twitter: bphogan
email: brianhogan at napcs.com
http://spkr8.com/t/7114
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
                                 end


twitter: bphogan
email: brianhogan at napcs.com
http://spkr8.com/t/7114
Procs and Lambdas



twitter: bphogan
email: brianhogan at napcs.com
http://spkr8.com/t/7114
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 2011




twitter: bphogan
email: brianhogan at napcs.com
http://spkr8.com/t/7114
Monkeypatching



twitter: bphogan
email: brianhogan at napcs.com
http://spkr8.com/t/7114
Reopen a class!
         class Object
           def blank?
             self.nil? || self.to_s == ""
           end

            def orelse(other)
              self.blank? ? other : self
            end

         end



twitter: bphogan
email: brianhogan at napcs.com
http://spkr8.com/t/7114
Monkeypatching is an
                 evil process!


twitter: bphogan
email: brianhogan at napcs.com
http://spkr8.com/t/7114
Instead, we use Modules



twitter: bphogan
email: brianhogan at napcs.com
http://spkr8.com/t/7114
Modules
             module OrElseMethods

                 def blank?
                   self.nil? || self.to_s == ""
                 end

                 def orelse(other)
                   self.blank? ? other : self
                 end

             end


twitter: bphogan
email: brianhogan at napcs.com
http://spkr8.com/t/7114
In Ruby, we don’t care
              about the type... we
              care about how the
                 object works.


twitter: bphogan
email: brianhogan at napcs.com
http://spkr8.com/t/7114
Including modules on objects
                      module NinjaBehaviors
                        def attack
                          puts "You've been killed silently!"
                        end
                      end

                      class Person
                        include NinjaBehaviors
                      end

                      p = Person.new
                      p.attack




twitter: bphogan
email: brianhogan at napcs.com
http://spkr8.com/t/7114
Extending classes with modules
       module NinjaCreator

          def new_ninja
            puts "I've created a new Ninja"
          end

       end

       class Person
         extend NinjaCreator
       end

       Person.new_ninja




twitter: bphogan
email: brianhogan at napcs.com
http://spkr8.com/t/7114
Person
              vs
   PersonNinjaRockStarAdmin


twitter: bphogan
email: brianhogan at napcs.com
http://spkr8.com/t/7114
Extending objects with modules
      module NinjaBehaviors
        def attack
          puts "You've been killed silently!"
        end
      end

      module RockStarBehaviors
        def trash_hotel_room
          puts "What a mess!"
        end
      end




twitter: bphogan
email: brianhogan at napcs.com
http://spkr8.com/t/7114
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.attack



twitter: bphogan
email: brianhogan at napcs.com
http://spkr8.com/t/7114
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, OrElseMethods




twitter: bphogan
email: brianhogan at napcs.com
http://spkr8.com/t/7114
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
         end




twitter: bphogan
email: brianhogan at napcs.com
http://spkr8.com/t/7114
Modules can’t contain
          methods that overwrite
            existing methods!


twitter: bphogan
email: brianhogan at napcs.com
http://spkr8.com/t/7114
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, NoSave



twitter: bphogan
email: brianhogan at napcs.com
http://spkr8.com/t/7114
Yes, that’s weird.



twitter: bphogan
email: brianhogan at napcs.com
http://spkr8.com/t/7114
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
                     end




twitter: bphogan
email: brianhogan at napcs.com
http://spkr8.com/t/7114
Demo
        https://github.com/napcs/intro_to_advanced_ruby



twitter: bphogan
email: brianhogan at napcs.com
http://spkr8.com/t/7114
Questions?



twitter: bphogan
email: brianhogan at napcs.com
http://spkr8.com/t/7114

More Related Content

PPTX
OpenAI-Copilot-ChatGPT.pptx
PDF
Basic commands for powershell : Configuring Windows PowerShell and working wi...
PDF
【さくらのクラウド】ローカルルータ導入ガイド
PPTX
MIRACLE LINUX 8をVirtualBoxに入れる時のいくつかのコツ
PDF
kubernetes practice
PDF
EMS 勉強会 第1回 Autopilot 祭り - Autopilot 最新情報
PDF
AWS Lambda@Edge でできること!
PDF
202110 AWS Black Belt Online Seminar AWS Site-to-Site VPN
OpenAI-Copilot-ChatGPT.pptx
Basic commands for powershell : Configuring Windows PowerShell and working wi...
【さくらのクラウド】ローカルルータ導入ガイド
MIRACLE LINUX 8をVirtualBoxに入れる時のいくつかのコツ
kubernetes practice
EMS 勉強会 第1回 Autopilot 祭り - Autopilot 最新情報
AWS Lambda@Edge でできること!
202110 AWS Black Belt Online Seminar AWS Site-to-Site VPN

What's hot (13)

PDF
AWS Black Belt Online Seminar 2016 Amazon WorkSpaces
PPTX
Create a sandbox of company costs with AWS Control Tower and benefit from con...
PPTX
AI-Plugins-Planners-Persona-SemanticKernel.pptx
PPT
Usabilidad y diseño centrado en la experiencia del usuario
PPTX
[DSC DACH 23] ChatGPT and Beyond: How generative AI is Changing the way peopl...
PPT
Software Testing - Tool support for testing (CAST) - Mazenet Solution
PPTX
Microsoft Tunnel 概要
PDF
소프트웨어 아키텍처 문서화
PDF
How browser work
PPT
Selenium ppt
PPT
Apresentação UX e UI - Webdesign - Aula 07
PPTX
Karpenterで君だけの最強のオートスケーリングを実装しよう
PDF
Active Directory_グループポリシー基礎
AWS Black Belt Online Seminar 2016 Amazon WorkSpaces
Create a sandbox of company costs with AWS Control Tower and benefit from con...
AI-Plugins-Planners-Persona-SemanticKernel.pptx
Usabilidad y diseño centrado en la experiencia del usuario
[DSC DACH 23] ChatGPT and Beyond: How generative AI is Changing the way peopl...
Software Testing - Tool support for testing (CAST) - Mazenet Solution
Microsoft Tunnel 概要
소프트웨어 아키텍처 문서화
How browser work
Selenium ppt
Apresentação UX e UI - Webdesign - Aula 07
Karpenterで君だけの最強のオートスケーリングを実装しよう
Active Directory_グループポリシー基礎
Ad

Similar to Intro To Advanced Ruby (20)

KEY
Intro to Ruby
KEY
Intro to Ruby - Twin Cities Code Camp 7
PDF
Ruby 程式語言入門導覽
KEY
Stop Reinventing The Wheel - The Ruby Standard Library
PDF
ruby_bits_slides_ingenieria_programacion.pdf
PDF
Ruby Intro {spection}
PDF
Web Development With Ruby - From Simple To Complex
PDF
Designing Ruby APIs
KEY
Ruby objects
KEY
PDF
Slides chapter3part1 ruby-forjavaprogrammers
PDF
Ruby tricks2
PDF
Learning Ruby
KEY
Rails console
KEY
jRuby: The best of both worlds
PDF
Active Support Core Extensions (1)
PDF
Ruby training day1
PDF
Ruby and Rails by Example (GeekCamp edition)
KEY
Refactor like a boss
PDF
Ruby 2: some new things
Intro to Ruby
Intro to Ruby - Twin Cities Code Camp 7
Ruby 程式語言入門導覽
Stop Reinventing The Wheel - The Ruby Standard Library
ruby_bits_slides_ingenieria_programacion.pdf
Ruby Intro {spection}
Web Development With Ruby - From Simple To Complex
Designing Ruby APIs
Ruby objects
Slides chapter3part1 ruby-forjavaprogrammers
Ruby tricks2
Learning Ruby
Rails console
jRuby: The best of both worlds
Active Support Core Extensions (1)
Ruby training day1
Ruby and Rails by Example (GeekCamp edition)
Refactor like a boss
Ruby 2: some new things
Ad

More from Brian Hogan (18)

PDF
Creating and Deploying Static Sites with Hugo
PDF
Automating the Cloud with Terraform, and Ansible
PDF
Create Development and Production Environments with Vagrant
PDF
Docker
PDF
Getting Started Contributing To Open Source
PDF
Rethink Frontend Development With Elm
KEY
Testing Client-side Code with Jasmine and CoffeeScript
KEY
FUD-Free Accessibility for Web Developers - Also, Cake.
KEY
Responsive Web Design
KEY
Web Development with CoffeeScript and Sass
KEY
Building A Gem From Scratch
KEY
Turning Passion Into Words
PDF
HTML5 and CSS3 Today
KEY
Make GUI Apps with Shoes
KEY
The Why Of Ruby
KEY
Story-driven Testing
KEY
Learning To Walk In Shoes
KEY
Rails and Legacy Databases - RailsConf 2009
Creating and Deploying Static Sites with Hugo
Automating the Cloud with Terraform, and Ansible
Create Development and Production Environments with Vagrant
Docker
Getting Started Contributing To Open Source
Rethink Frontend Development With Elm
Testing Client-side Code with Jasmine and CoffeeScript
FUD-Free Accessibility for Web Developers - Also, Cake.
Responsive Web Design
Web Development with CoffeeScript and Sass
Building A Gem From Scratch
Turning Passion Into Words
HTML5 and CSS3 Today
Make GUI Apps with Shoes
The Why Of Ruby
Story-driven Testing
Learning To Walk In Shoes
Rails and Legacy Databases - RailsConf 2009

Recently uploaded (20)

PDF
TokAI - TikTok AI Agent : The First AI Application That Analyzes 10,000+ Vira...
PDF
Spectral efficient network and resource selection model in 5G networks
PDF
Blue Purple Modern Animated Computer Science Presentation.pdf.pdf
PDF
Reach Out and Touch Someone: Haptics and Empathic Computing
PDF
Advanced methodologies resolving dimensionality complications for autism neur...
PDF
KodekX | Application Modernization Development
PDF
Chapter 3 Spatial Domain Image Processing.pdf
PDF
Unlocking AI with Model Context Protocol (MCP)
PDF
Encapsulation theory and applications.pdf
PDF
Electronic commerce courselecture one. Pdf
PPTX
Effective Security Operations Center (SOC) A Modern, Strategic, and Threat-In...
PDF
7 ChatGPT Prompts to Help You Define Your Ideal Customer Profile.pdf
PDF
Empathic Computing: Creating Shared Understanding
DOCX
The AUB Centre for AI in Media Proposal.docx
PPTX
Programs and apps: productivity, graphics, security and other tools
PDF
Per capita expenditure prediction using model stacking based on satellite ima...
PDF
cuic standard and advanced reporting.pdf
PDF
NewMind AI Weekly Chronicles - August'25 Week I
PDF
How UI/UX Design Impacts User Retention in Mobile Apps.pdf
PPTX
sap open course for s4hana steps from ECC to s4
TokAI - TikTok AI Agent : The First AI Application That Analyzes 10,000+ Vira...
Spectral efficient network and resource selection model in 5G networks
Blue Purple Modern Animated Computer Science Presentation.pdf.pdf
Reach Out and Touch Someone: Haptics and Empathic Computing
Advanced methodologies resolving dimensionality complications for autism neur...
KodekX | Application Modernization Development
Chapter 3 Spatial Domain Image Processing.pdf
Unlocking AI with Model Context Protocol (MCP)
Encapsulation theory and applications.pdf
Electronic commerce courselecture one. Pdf
Effective Security Operations Center (SOC) A Modern, Strategic, and Threat-In...
7 ChatGPT Prompts to Help You Define Your Ideal Customer Profile.pdf
Empathic Computing: Creating Shared Understanding
The AUB Centre for AI in Media Proposal.docx
Programs and apps: productivity, graphics, security and other tools
Per capita expenditure prediction using model stacking based on satellite ima...
cuic standard and advanced reporting.pdf
NewMind AI Weekly Chronicles - August'25 Week I
How UI/UX Design Impacts User Retention in Mobile Apps.pdf
sap open course for s4hana steps from ECC to s4

Intro To Advanced Ruby

  • 1. Intro to Advanced Ruby twitter: bphogan email: brianhogan at napcs.com http://spkr8.com/t/7114
  • 2. What makes Ruby special? twitter: bphogan email: brianhogan at napcs.com http://spkr8.com/t/7114
  • 3. It's expressive 5.times do puts "Hello World" end twitter: bphogan email: brianhogan at napcs.com http://spkr8.com/t/7114
  • 4. It's dynamic class Person [:first_name, :last_name, :gender].each do |method| attr_accessor method end end twitter: bphogan email: brianhogan at napcs.com http://spkr8.com/t/7114
  • 5. It's 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 end twitter: bphogan email: brianhogan at napcs.com http://spkr8.com/t/7114
  • 6. It's flexible def add(*args) args.reduce(0){ |result, item| result + item} end add 1,1,1,1 twitter: bphogan email: brianhogan at napcs.com http://spkr8.com/t/7114
  • 7. It's dangerous! class String def nil? self == "" end end twitter: bphogan email: brianhogan at napcs.com http://spkr8.com/t/7114
  • 8. Our roadmap for today • Requiring files • Testing • Message passing • Classes vs Instances • Blocks and Lambdas • Monkeypatching • Modules twitter: bphogan email: brianhogan at napcs.com http://spkr8.com/t/7114
  • 9. require twitter: bphogan email: brianhogan at napcs.com http://spkr8.com/t/7114
  • 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: bphogan email: brianhogan at napcs.com http://spkr8.com/t/7114
  • 11. Testing twitter: bphogan email: brianhogan at napcs.com http://spkr8.com/t/7114
  • 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 end twitter: bphogan email: brianhogan at napcs.com http://spkr8.com/t/7114
  • 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 errors twitter: bphogan email: brianhogan at napcs.com http://spkr8.com/t/7114
  • 14. Now write the code class Person attr_accessor :age def can_drive? self.age >= 16 end end twitter: bphogan email: brianhogan at napcs.com http://spkr8.com/t/7114
  • 15. And pass the test! Loaded suite untitled Started . Finished in 0.00028 seconds. 1 tests, 1 assertions, 0 failures, 0 errors twitter: bphogan email: brianhogan at napcs.com http://spkr8.com/t/7114
  • 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: bphogan email: brianhogan at napcs.com http://spkr8.com/t/7114
  • 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 => nil twitter: bphogan email: brianhogan at napcs.com http://spkr8.com/t/7114
  • 18. Message passing twitter: bphogan email: brianhogan at napcs.com http://spkr8.com/t/7114
  • 19. .send class Person p = Person.new def name @name p.send(:name) end def name=(input) p.send(:name=, "Homer") @name = input end end twitter: bphogan email: brianhogan at napcs.com http://spkr8.com/t/7114
  • 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 end twitter: bphogan email: brianhogan at napcs.com http://spkr8.com/t/7114
  • 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 end twitter: bphogan email: brianhogan at napcs.com http://spkr8.com/t/7114
  • 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: bphogan email: brianhogan at napcs.com http://spkr8.com/t/7114
  • 23. Blocks and Lambdas twitter: bphogan email: brianhogan at napcs.com http://spkr8.com/t/7114
  • 24. Blocks twitter: bphogan email: brianhogan at napcs.com http://spkr8.com/t/7114
  • 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 end twitter: bphogan email: brianhogan at napcs.com http://spkr8.com/t/7114
  • 26. Encapsulation result = wrap(:p) do "Hello world" end puts result => "<p>Hello world</p>” def wrap(tag, &block) output = "<#{tag}>#{yield}</#{tag}>" end twitter: bphogan email: brianhogan at napcs.com http://spkr8.com/t/7114
  • 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 end twitter: bphogan email: brianhogan at napcs.com http://spkr8.com/t/7114
  • 28. Procs and Lambdas twitter: bphogan email: brianhogan at napcs.com http://spkr8.com/t/7114
  • 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 2011 twitter: bphogan email: brianhogan at napcs.com http://spkr8.com/t/7114
  • 30. Monkeypatching twitter: bphogan email: brianhogan at napcs.com http://spkr8.com/t/7114
  • 31. Reopen a class! class Object def blank? self.nil? || self.to_s == "" end def orelse(other) self.blank? ? other : self end end twitter: bphogan email: brianhogan at napcs.com http://spkr8.com/t/7114
  • 32. Monkeypatching is an evil process! twitter: bphogan email: brianhogan at napcs.com http://spkr8.com/t/7114
  • 33. Instead, we use Modules twitter: bphogan email: brianhogan at napcs.com http://spkr8.com/t/7114
  • 34. Modules module OrElseMethods def blank? self.nil? || self.to_s == "" end def orelse(other) self.blank? ? other : self end end twitter: bphogan email: brianhogan at napcs.com http://spkr8.com/t/7114
  • 35. In Ruby, we don’t care about the type... we care about how the object works. twitter: bphogan email: brianhogan at napcs.com http://spkr8.com/t/7114
  • 36. Including modules on objects module NinjaBehaviors def attack puts "You've been killed silently!" end end class Person include NinjaBehaviors end p = Person.new p.attack twitter: bphogan email: brianhogan at napcs.com http://spkr8.com/t/7114
  • 37. Extending classes with modules module NinjaCreator def new_ninja puts "I've created a new Ninja" end end class Person extend NinjaCreator end Person.new_ninja twitter: bphogan email: brianhogan at napcs.com http://spkr8.com/t/7114
  • 38. Person vs PersonNinjaRockStarAdmin twitter: bphogan email: brianhogan at napcs.com http://spkr8.com/t/7114
  • 39. Extending objects with modules module NinjaBehaviors def attack puts "You've been killed silently!" end end module RockStarBehaviors def trash_hotel_room puts "What a mess!" end end twitter: bphogan email: brianhogan at napcs.com http://spkr8.com/t/7114
  • 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.attack twitter: bphogan email: brianhogan at napcs.com http://spkr8.com/t/7114
  • 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, OrElseMethods twitter: bphogan email: brianhogan at napcs.com http://spkr8.com/t/7114
  • 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 end twitter: bphogan email: brianhogan at napcs.com http://spkr8.com/t/7114
  • 43. Modules can’t contain methods that overwrite existing methods! twitter: bphogan email: brianhogan at napcs.com http://spkr8.com/t/7114
  • 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, NoSave twitter: bphogan email: brianhogan at napcs.com http://spkr8.com/t/7114
  • 45. Yes, that’s weird. twitter: bphogan email: brianhogan at napcs.com http://spkr8.com/t/7114
  • 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 end twitter: bphogan email: brianhogan at napcs.com http://spkr8.com/t/7114
  • 47. Demo https://github.com/napcs/intro_to_advanced_ruby twitter: bphogan email: brianhogan at napcs.com http://spkr8.com/t/7114
  • 48. Questions? twitter: bphogan email: brianhogan at napcs.com http://spkr8.com/t/7114

Editor's Notes

  • #2: Brian P. Hogan\n
  • #3: Ruby is a language that we can bend to our will\n
  • #4: It can be easy to read\n
  • #5: We can call methods as strings, etc\n
  • #6: \n
  • #7: \n
  • #8: \n
  • #9: \n
  • #10: Require loads in another Ruby file. It&amp;#x2019;s like import or include in other languages. \n
  • #11: We want to call the &amp;#x2018;today&amp;#x2019; method on the Date class to get the current date by using the system time. This method isn&amp;#x2019;t actually loaded for us by default. We require the &amp;#x2018;date&amp;#x2019; library which adds those features to the language.\n
  • #12: Unit testing in Ruby is built in. All we have to do is include the testing library.\n
  • #13: To use tests in Ruby, we only need to require the testing library and define our methdos with a special naming convention. Let&amp;#x2019;s use a test to drive the development of a function that will tell us if a person is allowed to drive. We don&amp;#x2019;t write the code. We have no idea how the code will work, but we do know that if a person is under 16 then they cannot drive. So in our test, we create a new Person, set the person&amp;#x2019;s age to 15, and then we call a method called &amp;#x201C;can_drive?&amp;#x201D; which we assert should not be true. If the assert statement returns true, the test passes.\n
  • #14: Our person class isn&amp;#x2019;t defined, so when we run this test, it fails. That&amp;#x2019;s ok. This is how we do test-driven development in Ruby. We writea simple test, then we write the class to make the test pass.\n
  • #15: So here&amp;#x2019;s the class. We use attr_accessor to create a getter and setter for age, then we write the can_drive? method to ensure that the age is greater than or equal to 16. Remember that in Ruby, the return value of a fuction is implicit - the last evaluated statement is the return value.\n
  • #16: Now our test passes and we can repeat this process each time we add a new feature.\n
  • #17: Now let&amp;#x2019;s talk about classes and objects. In many languages, a class is a blueprint for an object. In Ruby, that&amp;#x2019;s kind of true, but you should really think of classes AS objects. That means classes can also have methods.\n
  • #18: Instance methods are defined on the instance scope. To call them, we need to create an instance of the class to cal the method. This is the most common method. Class methods are methods we define on the class object itself. We can use the self. prefix to attach the method to the class object instead of the object instance. This is how we define the equivalent of a static method.\n
  • #19: But the idea of methods is something of a Java thing. Under the hood, Ruby is really a message passing language. Method calls are transated into messages, and are basically a conveience layer.\n
  • #20: We can use that to our advantage when writing more complex programs. send lets us call methods as a string. We can use respond_to? to ask if the method exists!\n
  • #21: \n
  • #22: \n
  • #23: We can use respond_to? to ask if the method exists!\n
  • #24: Lambdas let us execute code later. Sometimes we can&apos;t evaluate code right at runtime. Instead we need to context of other code instead.\n
  • #25: \n
  • #26: We use blocks all the time when we iterate\n
  • #27: We can also use blocks to wrap other code. Let&apos;s build a navigation bar\n
  • #28: We can also use blocks to wrap other code. Let&apos;s build a navigation bar\n
  • #29: \n
  • #30: The lambdas get evaluated when we fire the .call method. So here we declare a lambda and we take in one variable called &amp;#x201C;phrase&amp;#x201D;. We timestamp it. We pass the variables we want to the .call method and the time is displayed with a different value each time. We&amp;#x2019;re not actually running the code in the lambda until later.\n
  • #31: We can reopen classes\n
  • #32: In Ruby, we can reopen any class we want, even ones in the standard library. We can then make changes to the methods there. \n
  • #33: This is the surest way to shoot yourself, and your team, in the face. \n
  • #34: We still need to modify core classes at times. The Rails framework couldn&amp;#x2019;t exist without some patches like this, and modifying classes and objects is the way we write modular code.\n
  • #35: Modules let us extend objects without inheritance.\n
  • #36: A ninja is a person. Just because a person is now a ninja does not mean they are not a person anymore.\n
  • #37: We use include to add the module&apos;s methods to the instance. In this case, every Person is now a Ninja. \n
  • #38: We use the extend keyword to add the module&apos;s methods as class methods. Remember, classes are objects too. When we extend, we add the methods to the object.\n
  • #39: \n
  • #40: An instance is also an object. So instead of adding the Ninja module to the Person class, we can add it to just specific instances using extend, which is just a method that adds methods to the object.\n
  • #41: Now each instance is independant and we can add our modules to each one without affecting the others.\n
  • #42: This callback lets us hook into the class that includes the module. So getting back to our &amp;#x201C;blank&amp;#x201D; callback, let&amp;#x2019;s say we wanted all of our objects in our application to be able to have our &amp;#x201C;blank&amp;#x201D; method on it. Now we have a completely self-contained plugin that does not open any classes. This is how we cleanly modify Ruby code.\n
  • #43: One really nice feature of self.included is that we can call any class methods of the class that includes the module. So we can make behaviors. This lets us separate our concerns.\n
  • #44: Modules are inserted into the object&apos;s inheritence chain. When\nwe call a method, Ruby looks first in the object. If the method\nisn&apos;t found there, it looks at the parent object, and then it looks\nat the included modules. \n\n
  • #45: class_eval lets us declare methods on the class. We can use it inside of self.included to safely override existing methods.\n
  • #46: But these weird concepts let us organize our code in ways that don&amp;#x2019;t paint us into a corner later. We can make plugins that, just by adding a file to our app, we seamlessly prevent records from being deleted and instead just mark them as updated. \n
  • #47: We&amp;#x2019;ll use all of these concepts to drive the development of an extension that lets us declare callbacks that should be run before we save an object. Assume the save method saves the data to some data store somewhere.\n
  • #48: \n
  • #49: \n