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

The Spooky Science of Ruby

The Spooky Science of Ruby

Grab a scalpel as we put Ruby on the table to look at this lovely language's internals. We'll start with class inheritance and method lookup, and then explore the mysterious singleton class and how it fits in. We'll use our newfound knowledge to turn children into zombies and find a cure to turn them back again. Okay, so maybe it won't be too spooky, but you'll come away having a better understanding of Ruby objects and their internals (and braaaains!).

Zoe Kay

June 25, 2015
Tweet

Other Decks in Programming

Transcript

  1. The Spooky Science of Ruby a.k.a. Zombies like to Metaprogram

    Zoe Kay June 25, 2015 Open Source Bridge
  2. Hi!

  3. Disclaimer • You won’t use this daily • Metaprogramming is

    a dangerous tool • This talk is not about judging Ruby good or bad, it’s about understanding it
  4. Disclaimer of the disclaimer • Use this for debugging •

    Write better code • Figure out other people’s code • Fun!
  5. class Child attr_accessor :intelligence, :creativity def initialize @intelligence = 1

    @creativity = 1 end def play self.intelligence += 1 self.creativity += 1 end end
  6. >> Child.ancestors => [Child, Object, Kernel, BasicObject]
 >> Child.superclass =>

    Object
 >> Child.superclass.superclass => BasicObject
  7. “Object is the default root of all Ruby objects.” >>

    Child.ancestors => [Child, Object, Kernel, BasicObject] - Ruby Docs http://ruby-doc.org/core-2.2.2/Object.html
  8. >> NilClass.ancestors => [NilClass, Object, Kernel, BasicObject] >> Class.ancestors =>

    [Class, Module, Object, Kernel, BasicObject] >> Module.ancestors => [Module, Object, Kernel, BasicObject]
  9. “Methods on Object are available to all classes unless explicitly

    overridden.” >> Child.ancestors => [Child, Object, Kernel, BasicObject] - Ruby Docs http://ruby-doc.org/core-2.2.2/Object.html
  10. “Object mixes in the Kernel module, making the built-in kernel

    functions globally accessible.” >> Child.ancestors => [Child, Object, Kernel, BasicObject] - Ruby Docs http://ruby-doc.org/core-2.2.2/Object.html
  11. >> Kernel.methods =>[:sprintf, :format, :Integer, :Float, :String, :Array, :Hash, :warn,

    :rai se, :fail, :global_variables, :__method__, :__callee__, :__dir__, :eval, :l ocal_variables, :iterator?, :block_given?, :catch, :throw, :loop, :trace_va r, :untrace_var, :at_exit, :syscall, :open, :printf, :print, :putc, :puts, :gets, :readline, :select, :readlines, :`, :p, :test, :srand, :rand, :trap, :exec, :fork, :exit!, :system, :spawn, :sleep, :exit, :abort, :load, :requi re, :require_relative, :autoload, :autoload?, :proc, :lambda, :binding, :ca ller, :caller_locations, :Rational, :Complex, :set_trace_func, :pp, :freeze , :===, :==, :<=>, :<, :<=, :>, :>=, :to_s, :inspect, :included_modules, :i nclude?, :name, :ancestors, :instance_methods, :public_instance_methods, :p rotected_instance_methods, :private_instance_methods, :constants, :const_ge t, :const_set, :const_defined?, :const_missing, :class_variables, :remove_c lass_variable, :class_variable_get, :class_variable_set, :class_variable_de fined?, :public_constant, :private_constant, :singleton_class?, :include, : prepend, :module_exec, :class_exec, :module_eval, :class_eval, :method_defi ned?, :public_method_defined?, :private_method_defined?, :protected_method_ defined?, :public_class_method, :private_class_method, :instance_method, :p ublic_instance_method, :pretty_print_cycle, :pretty_print, :pretty_print_in stance_variables, :pretty_print_inspect, :nil?, :=~, :! ~, :eql?, :hash, :class, :singleton_class, :clone, :dup, :taint, :tainted?, :untaint, :untrust, :untrusted?, :trust, :frozen?, :methods, :singleton_met hods, :protected_methods, :private_methods, :public_methods, :instance_vari ables, :instance_variable_get, :instance_variable_set, :instance_variable_d efined?, :remove_instance_variable, :instance_of?, :kind_of?, :is_a?, :tap, :send, :public_send, :respond_to?, :extend, :display, :method, :public_meth od, :singleton_method, :define_singleton_method, :object_id, :to_enum, :enu m_for, :pretty_inspect, :equal?, :!, :! =, :instance_eval, :instance_exec, :__send__, :__id__]
  12. “BasicObject is the parent class of all classes in Ruby.

    It's an explicit blank class.” >> Child.ancestors => [Child, Object, Kernel, BasicObject] - Ruby Docs http://ruby-doc.org/core-2.2.2/BasicObject.html
  13. class Dog
 end
 
 >> Dog.ancestors
 => [Dog, Object, Kernel,

    BasicObject] 
 class Dog < BasicObject
 end
 
 >> Dog.ancestors
 => [Dog, BasicObject]
  14. #read_book #read_book Child Kernel Object Human Adult #read_book class Human;

    end
 class Adult < Human
 end
 class Child < Human
 end B Ob
  15. Child Object Human B A class Child < Human include

    module A include module B ... end zoe
  16. Child Object Human B A class Child < Human include

    module A include module B ... end zoe
  17. Child Object Human B A class Child < Human include

    module A include module B ... end zoe
  18. Child Object Human B A class Child < Human prepend

    module A include module B ... end zoe
  19. Child Object Human B A class Child < Human prepend

    module A include module B ... end zoe
  20. Child Object Human B A class Child < Human prepend

    module A include module B ... end zoe
  21. class Child < Human include SugarCrash include MysteryModule prepend MoreSugar

    include EvenMoreSugar end >> Child.instance_method(:eat_sugar)
  22. class Child < Human include SugarCrash include MysteryModule prepend MoreSugar

    include EvenMoreSugar end >> Child.instance_method(:eat_sugar) => #<UnboundMethod: Child(EvenMoreSugar)#eat_sugar>
  23. class Child < Human include SugarCrash include MysteryModule prepend MoreSugar

    include EvenMoreSugar end >> Child.instance_method(:eat_sugar) => #<UnboundMethod: Child(EvenMoreSugar)#eat_sugar>
  24. class Child < Human include SugarCrash include MysteryModule prepend MoreSugar

    include EvenMoreSugar end >> Child.instance_method(:eat_sugar) => #<UnboundMethod: Child(EvenMoreSugar)#eat_sugar>
  25. class Child < Human include SugarCrash include MysteryModule prepend MoreSugar

    include EvenMoreSugar end >> Child.instance_method(:eat_sugar) => #<UnboundMethod: Child(EvenMoreSugar)#eat_sugar>
  26. >> Zombie.const_set(‘FAVORITE_FOOD’, ‘brains’) => “brains” >> Zombie::FAVORITE_FOOD => "brains" >>

    Zombie::FAVORITE_FOOD = 'limbs' => warning: already initialized constant Zombie::FAVORITE_FOOD
 => “limbs"

  27. >> Zombie.const_set(‘FAVORITE_FOOD’, ‘brains’) => “brains” >> Zombie::FAVORITE_FOOD => "brains" >>

    Zombie::FAVORITE_FOOD = 'limbs' => warning: already initialized constant Zombie::FAVORITE_FOOD
 => “limbs"
 >> Zombie::FAVORITE_FOOD
 => "limbs"
  28. class Zombie def eat puts “Mm, brains” end end class

    Zombie define_method(:eat) { puts “Mm, brains” } end
  29. class Zombie def eat puts “Mm, brains” end end class

    Zombie define_method(:eat) { puts “Mm, brains” } end
  30. class Zombie def eat puts “Mm, brains” end end zombie_proc

    = Proc.new do
 puts “Mm, brains”
 end
 class Zombie define_method(:eat) { puts “Mm, brains” } end
  31. class Zombie def eat puts “Mm, brains” end end zombie_proc

    = Proc.new do
 puts “Mm, brains”
 end
 Zombie.send(:define_method, :eat, zombie_proc ) class Zombie define_method(:eat) { puts “Mm, brains” } end
  32. >> zoe.play >> zoe.intelligence => 12 >> zoe.play >> zoe.intelligence

    => 22
 >> martin.play >> martin.intelligence
  33. >> zoe.play >> zoe.intelligence => 12 >> zoe.play >> zoe.intelligence

    => 22
 >> martin.play >> martin.intelligence => 1
  34. >> zoe.play >> zoe.intelligence => 12 >> zoe.play >> zoe.intelligence

    => 22
 >> martin.play >> martin.intelligence => 1 >> martin.play
  35. >> zoe.play >> zoe.intelligence => 12 >> zoe.play >> zoe.intelligence

    => 22
 >> martin.play >> martin.intelligence => 1 >> martin.play >> martin.intelligence
  36. >> zoe.play >> zoe.intelligence => 12 >> zoe.play >> zoe.intelligence

    => 22
 >> martin.play >> martin.intelligence => 1 >> martin.play >> martin.intelligence => 2
  37. >> class Child
 >> def self.run
 >> puts "Aaah zombies!!"


    >> end
 >> end
 >> def Child.run
 >> puts “Aaah zombies!!”
 >> end

  38. >> class Child
 >> def self.run
 >> puts "Aaah zombies!!"


    >> end
 >> end
 >> def Child.run
 >> puts “Aaah zombies!!”
 >> end
 >> Child.singleton_methods
  39. >> class Child
 >> def self.run
 >> puts "Aaah zombies!!"


    >> end
 >> end
 >> def Child.run
 >> puts “Aaah zombies!!”
 >> end
 >> Child.singleton_methods => [:run]

  40. >> class Child
 >> def self.run
 >> puts "Aaah zombies!!"


    >> end
 >> end
 >> def Child.run
 >> puts “Aaah zombies!!”
 >> end
 >> Child.singleton_methods => [:run]
 >> Child.singleton_class.instance_methods(false)
  41. >> class Child
 >> def self.run
 >> puts "Aaah zombies!!"


    >> end
 >> end
 >> def Child.run
 >> puts “Aaah zombies!!”
 >> end
 >> Child.singleton_methods => [:run]
 >> Child.singleton_class.instance_methods(false) => [:run]
  42. Child Kernel Object Human Basi Objec Object Singleton Human Singleton

    Child Singleton Basic Object Singleton >> Child.run
  43. Child Kernel Object Human Basi Objec Object Singleton Human Singleton

    Child Singleton Basic Object Singleton >> Child.run .run
  44. Child Kernel Object Human Basi Objec Object Singleton Human Singleton

    Child Singleton Basic Object Singleton >> Child.run >> Child.new .run
  45. Child Kernel Object Human Basi Objec Object Singleton Human Singleton

    Child Singleton Basic Object Singleton >> Child.run >> Child.new .run .new
  46. Child Kernel Object Human Basi Objec Object Singleton Human Singleton

    Child Singleton Basic Object Singleton >> Child.run
  47. >> zoe.singleton_class => #<Class:#<Child:0x007f8048b69cf0>>
 >> zoe.singleton_class.superclass => Child
 >> zoe.singleton_class.superclass


    .superclass => Human
 >> zoe.singleton_class.superclass
 .superclass.superclass => Object

  48. >> zoe.singleton_class => #<Class:#<Child:0x007f8048b69cf0>>
 >> zoe.singleton_class.superclass => Child
 >> zoe.singleton_class.superclass


    .superclass => Human
 >> zoe.singleton_class.superclass
 .superclass.superclass => Object
 >> zoe.singleton_class.superclass
 .superclass.superclass.superclass
  49. >> zoe.singleton_class => #<Class:#<Child:0x007f8048b69cf0>>
 >> zoe.singleton_class.superclass => Child
 >> zoe.singleton_class.superclass


    .superclass => Human
 >> zoe.singleton_class.superclass
 .superclass.superclass => Object
 >> zoe.singleton_class.superclass
 .superclass.superclass.superclass => BasicObject
  50. >> Child.singleton_class => #<Class:Child>
 >> Child.singleton_class.superclass => #<Class:Human>
 >> Child.singleton_class.superclass


    .superclass => #<Class:Object>
 >> Child.singleton_class.superclass
 .superclass.superclass
  51. >> Child.singleton_class => #<Class:Child>
 >> Child.singleton_class.superclass => #<Class:Human>
 >> Child.singleton_class.superclass


    .superclass => #<Class:Object>
 >> Child.singleton_class.superclass
 .superclass.superclass => #<Class:BasicObject>
  52. >> katie.class => Child
 >> katie.intelligence => 23
 >> katie.get_bitten_by_zombie

    => “Why, it’s just a flesh wound!”
 >> katie.intelligence
  53. >> katie.class => Child
 >> katie.intelligence => 23
 >> katie.get_bitten_by_zombie

    => “Why, it’s just a flesh wound!”
 >> katie.intelligence => 23

  54. >> katie.class => Child
 >> katie.intelligence => 23
 >> katie.get_bitten_by_zombie

    => “Why, it’s just a flesh wound!”
 >> katie.intelligence => 23
 >> katie.singleton_methods
  55. >> katie.class => Child
 >> katie.intelligence => 23
 >> katie.get_bitten_by_zombie

    => “Why, it’s just a flesh wound!”
 >> katie.intelligence => 23
 >> katie.singleton_methods => [:get_bitten_by_zombie]
  56. class Child < Human prepend ZombieVaccine ... def get_bitten_by_zombie horrible_zombie_change

    end end module ZombieVaccine def get_bitten_by_zombie magical_science_magic end end
  57. >> roshni.get_bitten_by_zombie => “Why, it’s just a flesh wound!” >>

    roshni.method(:get_bitten_by_zombie) => #<Method: Child(ZombieVaccine)#get_bitten> >> roshni = Child.new => #<Child:0x007fb813064690 @intelligence=1, @creativity=1>
  58. >> jonan = Child.new >> jonan.get_bitten_by_zombie => “Aaaagh!!” >> Child.instance_method(:get_bitten_

    by_zombie) => #<UnboundMethod: Child(Human)#get_bitten_by_zombie> >> Human.instance_methods => [:get_bitten_by_zombie]
  59. “Contrast this with remove_method, which deletes a method from the

    particular class; Ruby will still search superclasses and mixed-in modules for a possible receiver.” “undef_method prevents the current class from responding to any calls to the named method.” - APIdock http://apidock.com/ruby/Module/undef_method
  60. >> roshni.get_bitten_by_zombie => NoMethodError: undefined method `get_bitten_by_zombie’ for #<Child: 0x007f8048b69cf0>


    >> zoe.get_bitten_by_zombie => NoMethodError: undefined method `get_bitten_by_zombie’ for #<Child: 0x007f8048b69cf0>

  61. >> roshni.get_bitten_by_zombie => NoMethodError: undefined method `get_bitten_by_zombie’ for #<Child: 0x007f8048b69cf0>


    >> zoe.get_bitten_by_zombie => NoMethodError: undefined method `get_bitten_by_zombie’ for #<Child: 0x007f8048b69cf0>
 >> katie.get_bitten_by_zombie
  62. >> roshni.get_bitten_by_zombie => NoMethodError: undefined method `get_bitten_by_zombie’ for #<Child: 0x007f8048b69cf0>


    >> zoe.get_bitten_by_zombie => NoMethodError: undefined method `get_bitten_by_zombie’ for #<Child: 0x007f8048b69cf0>
 >> katie.get_bitten_by_zombie => NoMethodError: undefined method `get_bitten_by_zombie’ for #<Child: 0x007f8048b69cf0>
  63. • ancestors • Object, Kernel, BasicObject • include vs prepend

    • const_set • const_get • define_method • singleton class + singleton methods • remove_method • undef_method What was covered?