Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Advanced Ruby

Sponsored · Ship Features Fearlessly Turn features on and off without deploys. Used by thousands of Ruby developers.

Advanced Ruby

My afternoon training session at LSRC 2013

Code samples are online at https://gist.github.com/anthonylewis

Avatar for Anthony Lewis

Anthony Lewis

July 18, 2013
Tweet

More Decks by Anthony Lewis

Other Decks in Programming

Transcript

  1. About Me • Senior Engineer at Mass Relevance • @anthonylewis

    [email protected] • http://anthonylewis.com Thursday, July 18, 13
  2. Session Overview • Installation • Ruby Object Model • More

    About Classes • Modules / Mixins • Metaprogramming • Real-World Examples Thursday, July 18, 13
  3. Windows • Planning to use Rails? • Use Rails Installer

    • http://railsinstaller.org • Use Ruby Installer • http://rubyinstaller.org Thursday, July 18, 13
  4. Mac OS X • Planning to use Rails? • Use

    Rails Installer • http://railsinstaller.org • Use Homebrew? • brew install ruby • Try RVM Thursday, July 18, 13
  5. Linux • Check your package system • Does it have

    Ruby 1.9 or later? • Enjoy building from source? • Try RVM Thursday, July 18, 13
  6. Ruby Version Manager • For Mac OS X and Linux

    • Install multiple versions of Ruby • Builds from source • Dev Tools Required • http://rvm.io Thursday, July 18, 13
  7. A Simple Class class Person def initialize(name) @name = name

    end def greet puts "Hi, I'm #{@name}" end end Thursday, July 18, 13
  8. A Simple Class class Person def initialize(name) @name = name

    end def greet puts "Hi, I'm #{@name}" end end Thursday, July 18, 13
  9. • Calling a method is also sending a message send

    p.greet => "Hi, I'm Tony" p.send :greet => "Hi, I'm Tony" Thursday, July 18, 13
  10. • You’ve used class variables and instance variables, but have

    you ever used class instance variables? • Class instance variables look like regular instance variables used in a class method • Class instance variables are not shared between subclasses Class Instance Variables Thursday, July 18, 13
  11. • Here’s a question I love to ask when interviewing

    a Ruby developer: • “How would you implement your own Record class with a before_save callback like the one in ActiveRecord?” Class Instance Variables Thursday, July 18, 13
  12. Class Instance Variables class User < Record before_save :saving def

    saving puts "Saving..." end end Thursday, July 18, 13
  13. • Since before_save is a class method, your first instinct

    is to use a class variable to store a list of methods to call. • Since class variables are shared among subclasses, all subclasses will share the same list of before_save callbacks. Class Instance Variables Thursday, July 18, 13
  14. Class Instance Variables class Record def self.before_save(*methods) @callbacks ||= []

    @callbacks += methods end def self.callbacks @callbacks end Thursday, July 18, 13
  15. Class Instance Variables def save self.class.callbacks.each do |c| send c

    if respond_to? c end puts "Saved" end end Thursday, July 18, 13
  16. • Also known as an Eigenclass • An anonymous class

    for holding singleton methods • A singleton method is a method defined on an instance Singleton Class Thursday, July 18, 13
  17. Singleton Class superman = Person.new("Clark") => superman.greet => "Hi, I'm

    Clark" def superman.fly puts "Up, up and away!" end Thursday, July 18, 13
  18. • The method fly is store in superman’s eigenclass •

    It is not available to any other instance of the class Person Singleton Class superman.fly => "Up, up and away!" Thursday, July 18, 13
  19. • Add module methods as instance methods Include class Person

    include Speaker end p.speak => "Hello" Thursday, July 18, 13
  20. • Add module methods as class methods Extend class Person

    extend Learner end Person.can_learn? => true Thursday, July 18, 13
  21. • Called when a module is included in a class

    Included module Coder def self.included(base) base.extend ClassMethods end # continued... Thursday, July 18, 13
  22. Included def code(lines = 3) "Ruby" * lines end module

    ClassMethods def can_code? true end end end Thursday, July 18, 13
  23. Prepend • Include module methods before methods defined in the

    class class Fibonacci def calc(n) return n if n < 2 return calc(n - 1) + calc(n - 2) end end Thursday, July 18, 13
  24. • Calling super will call the method defined in the

    class Prepend module Memoize def calc(n) @@memo ||= {} @@memo[n] ||= super end end Thursday, July 18, 13
  25. Prepend class Fibonacci prepend Memoize def calc(n) return n if

    n < 2 return calc(n - 1) + calc(n - 2) end end Thursday, July 18, 13
  26. class_eval • Evaluate a code string as if it were

    typed directly into the class definition. • class_eval creates instance methods Thursday, July 18, 13
  27. Note: Ruby provides this functionality out of the box with

    attr_reader, attr_writer, and attr_accessor. Thursday, July 18, 13
  28. • Create a method at runtime define_method class Person define_method

    :punch do |arg| "Ouch!" * arg end end Thursday, July 18, 13
  29. • Called when a method is not found method_missing class

    Person def method_missing method, *args "What's a #{method}?" end end Thursday, July 18, 13
  30. Rails Attributes • Every ActiveRecord object stores the values for

    its attributes in a private variable called @attributes • ActiveRecord also adds methods for accessing each attribute such as title, title=, title?, etc. Thursday, July 18, 13
  31. Rails Attributes p = Post.new p.title = "Hello, World" p.title

    => "Hello, World" Thursday, July 18, 13
  32. Rails Dynamic Finders • Find a record using an attribute’s

    value p = Post.find_by_title("My Cat") Thursday, July 18, 13
  33. Rails Dynamic Finders def method_missing(meth, *args) if meth.to_s =~ /^find_by_(.+)$/

    attr = $1.split('_and_') find_by_attributes(attr, *args) else super end end Thursday, July 18, 13
  34. Rails Dynamic Finders def find_by_attributes(attr, *args) conditions = Hash[attr.map {

    |a| [a, args[attr.index(a)]] }] where(conditions).first end Thursday, July 18, 13
  35. Method Decorators • We’re working on software for a bank

    • They want to track every time the deposit method is called in their Account class • But, of course, we are not allowed to change code inside the deposit method Thursday, July 18, 13
  36. Method Decorators class Account def initialize(balance) @balance = balance end

    def deposit(n) @balance += n puts "Balance is #{@balance}" end end Thursday, July 18, 13
  37. Method Decorators • We decide to track method calls by

    adding a module with a method decorator • Our decorator is a class method that takes an instance method parameter and prints a message every time it is called Thursday, July 18, 13
  38. module TrackMethods def track(meth) self.class_eval do alias_method "old_#{meth}", meth define_method

    meth do |*args| puts "Calling #{meth} " + "with #{args.join(', ')}" self.send "old_#{meth}", *args end end end end Thursday, July 18, 13
  39. Method Decorators class Account extend TrackMethods # deposit is not

    changed track :deposit end Thursday, July 18, 13
  40. Method Decorators a = Account.new(10) => a.deposit 5 => "Calling

    deposit with 5" => "Balance is now 15" Thursday, July 18, 13
  41. User Features • Our boss would like the ability to

    define features that different users can use • He wants to be able to assign features and check them easily • In a real application, we would store these features in a database table • Instead we will store then in a Ruby Set Thursday, July 18, 13
  42. require 'set' class User def initialize @features = Set.new end

    # continued... User Features Thursday, July 18, 13
  43. def method_missing(meth, *args) if meth.to_s =~ /^can_(.*)\?$/ @features.include? $1.to_s elsif

    meth.to_s =~ /^can_(.*)$/ @features << $1.to_s self else super end end end Thursday, July 18, 13
  44. Learn More Ruby • Programming Ruby 1.9 & 2.0 •

    The PickAxe Book • by Dave Thomas, with Chad Fowler and Andy Hunt • Metaprogramming Ruby • by Paolo Perrotta Thursday, July 18, 13
  45. Go Ruby Crazy • why’s (poignant) Guide to Ruby •

    by why the lucky stiff Thursday, July 18, 13
  46. Learn Onscreen • Try Ruby • http://tryruby.org • Ruby Koans

    • http://rubykoans.com • Ruby has damaged your karma. Thursday, July 18, 13