SlideShare a Scribd company logo
Metaprogramming
Alex Koppel
6Wunderkinder

            Alex Koppel – 1/3/2012
What is
       metaprogramming?
!   "Like programming, only meta" – an old colleague

!   Code that writes code

!   "Metaprogramming is the writing of computer
   programs that write or manipulate other programs
   (or themselves) as their data, or that do part of the
   work at run time that would otherwise be done at
   compile time.“ – Wikipedia




                                    Alex Koppel - 6Wunderkinder
Why should you care?
!   Ruby allows metaprogramming

!   Metaprogramming can create stunningly
   effective tools
  !     Rails is metaprogramming

!   You want to be a more effective Ruby
   programmer




                                           6Wunderkinder
Caution!
!   Wield metaprogramming deliberately

!   Your code will be harder to understand
   !   Will other developers lose time figuring out your
       magic?

!   Your code will be more brittle
   !   Altering other classes = dependency
   !   Changes to underlying code can break your app
   !   c.f. Facebooker



                                              6Wunderkinder
Techniques




             6Wunderkinder
Reopening Classes
!   Add additional methods or variables to existing
   classes

!   Very simple, very powerful

!   New code is executed as your files are loaded
   !   In a sense, this is a "static" metaprogramming
   !   Common in monkeypatching

!   Caveat: this creates the class if not yet defined



                                             6Wunderkinder
Code
require 'active_support/core_ext/string/inflections'!

# reopen String class!
class String!
  # add a module!
  include ActiveSupport::CoreExtensions::String::Inflections!
end!




                                              6Wunderkinder
alias_method
!   alias_method(new_name, old_name)

!   Makes an copy of a method
   !   exist v. exists

!   Copy remains if the original is overridden
   !   You may remember alias_method_chain

!   Can be used dynamically in other methods




                                           6Wunderkinder
class Foo!
                   Code
  def bar!
     3!
  end!
  # make a copy of bar!
  alias_method :bar, :old_bar!
  # redefine bar!
  def bar!
     4!
  end!
end!

Foo.new.bar!
# => 4!
Foo.new.old_bar!
# => 3!                          6Wunderkinder
Metaclasses
!   All Ruby objects have a unique class
   !   The "metaclass", a.k.a. "eigenclass"
   !   Classes too
   !   Special cases: Fixnums, true, false, nil

!   You can access this class to change the object
   !   class << object opens up the metaclass
   !   def object.new_method and object.instance_eval
      also work

!   Note: reopening classes and alias_method alter
   the original class, not a metaclass
                                              6Wunderkinder
What are Objects and
                         Classes, really?
        !   An object is actually simple[1]
               !   A collection of instance variables
               !   A reference to a class

        !   When you call a method, Ruby goes up the class
               hierarchy for its definition
               !   Metaclass, then class, then superclass

        !   Changing methods on an individual object is
               really changing its metaclass


[1] http://ruby-doc.org/docs/ProgrammingRuby/html/classes.html   6Wunderkinder
Code 1: Classes
# Using class << self for a class is effectively!
# equivalent to reopening the class (see above)!
class Person!
! # this can be easier than writing tons of def self.s !
  class << self!
     def species!
       "Homo Sapien"!
     end!
  end!
end!

class << Person!
  def species; "Homo Sapien“; end!
end!

Person.species == “Homo Sapien“ # true!   6Wunderkinder
Code 2: Objects
str = "hello world"!
class << str!
  def foo!
     2!
  end!
end!

str.foo!
# => 2!
"hello world".foo!
# => NoMethodError!




                       6Wunderkinder
Case study: non-breaking changes

!   Example from Koala (Facebook SDK)

!   Changing a method to return strings rather than
   hashes

!   Could this be done without breaking apps?

!   Use metaprogramming on the returned strings
   !   Add missing methods
   !   Print deprecation warning




                                         6Wunderkinder
Code
def get_app_access_token!
  info = get_app_access_token_info # hash!
  string = info["access_token"]!

  # make the string compatible with hash accessors!
  command = <<-EOS!
    def [](index)!
       puts "DEPRECATION WARNING"!
       hash = #{hash.inspect} !
       hash[index]!
    end!
  EOS!

  # add those methods just to the string!
  (class << string; self; end).class_eval command!
end!
                                       6Wunderkinder
How does it work?
!   Get the individual string's metaclass:
    !   (class << str; self; end)
    !   Opens the class scope, and returns the (meta)class

!   class_eval
    !   Executes code in the scope of a class (or metaclass)
    !   class_eval requires a class, not an instance
    !   String eval can be used for dynamic content
    !   You can also eval a regular code block

!   Objects altered like this are "singletons"
    !   Has runtime implications



                                                 6Wunderkinder
Problem!
!   Ruby's Marshal.dump is used to serialize objects

!   Marshaling does NOT work with singletons
   !   Singletons can't be cached!

!   Defining instance#_dump doesn't help
   !   Expects String#load to exist

!   Use this carefully in shared code
   !   You never know what your users will do




                                           6Wunderkinder
Solution!
!   Use modules to mix in unique methods
    !   Ruby knows how to handle this, even for objects
module BackwardsCompatible!
  def [](key)!
     puts "Got key! #{key}"!
  end!
end!

my_string = "abc”!
# objects:extend <=> classes:include !
my_string.send(:extend, BackwardsCompatible)!
my_string["foo"]!
Got key! foo!
 => nil !
Marshal.dump(my_string)!
 => "x04bIe:x18BackwardsCompatible"babcx06:x06ET" !
                                           6Wunderkinder
class_eval again
!   Ruby pattern: modules updating the including class
   !   Add before_filters, attrs, etc.
   !   Could use .send in some cases
       !   class_eval is easier to read
   !   Can define dynamic methods
   !   ActiveSupport::Concern works this way

!   class_eval is like reopening a class
   !   But can be used without knowing the class in advance
   !   Won't create the class if it doesn't exist


                                                6Wunderkinder
Code
module ControllerStuff!
  def self.included(base)!
     # execute new code in the scope of!
     # the including class!
     base.class_eval do!
       before_filter :module_method!
       attr_accessor :module_var!
       @module_var = 2!
     end!
  end!
end!


                               6Wunderkinder
Method Missing
!   Intercept calls to non-existent methods

!   Make a class's interface dynamic

!   Example: ActiveRecord
    !   Create dynamic finders on the fly
   !   @user.find_by_name_and_status

!   Example: proxy objects




                                            6Wunderkinder
Pseudo-code for
           ActiveRecord 2.x
def method_missing(method_id, *args, &block)!
  # is it the right find_by_...format?!
! if match(method_id) && match.finder?!
!    # method_missing is a class method !
    self.class_eval %{ # string!
       # define the method!
       def self.#{method_id}(*args)!
         find(:#{finder}, options.merge    !
            (finder_options))!
       end!
    end!
    # now call the new method!
    send(method_id, *arguments)!
  end!
end       !
                                       6Wunderkinder
Important Note
    !   method_missing can be much slower

    !   There are some tricky issues
           !   respond_to? and beyond
           !   Solving each problem can create others [1]

    !   Don't overuse it
           !   Can you use define_method instead?




[1] http://www.slideshare.net/paoloperrotta/the-revenge-of-methodmissing   6Wunderkinder
Reaching into Objects
!   send: call any method on an object (public or not)
   !   Useful for dynamic programming
   !   Can also be used to break encapsulation
   !   public_send (1.9) is safer

!   instance_variable_get, instance_variable_set:
   !   Access variables that lack an accessor
   !   Don't use these




                                            6Wunderkinder
Code
# from Koala (older)!
# Scope: class with Typhoeous module included!

def self.make_request(path, args, verb)!
    # dynamically call the appropriate method!
    # corresponding to the verb requested !
!   self.send(verb, url, :params => args)!
End!

# from Rails!
# Scope: a helper class that needs a !
#        private controller method!

def universal_calculation(arg)!
  # call the method on the controller!
  controller.send(:universal_controller, arg)!
end !                             6Wunderkinder
tl;dr
!   Metaprogramming is awesome

!   Don’t overuse it
   !   But don’t be afraid to use it when appropriate

!   Enjoy :)




                                             6Wunderkinder
Resources
!   Ruby books

!   URLs:
    !   http://yehudakatz.com/2009/11/15/metaprogramming-
        in-ruby-its-all-about-the-self/
    !   http://ruby-doc.org/docs/ProgrammingRuby/html/
        classes.html
    !   http://www.slideshare.net/paoloperrotta/the-
       revenge-of-methodmissing
   !   http://pragprog.com/book/ppmetr/metaprogramming-
       ruby

!   Google "ruby metaprogramming“


                                              6Wunderkinder
Questions?
  @arsduo
@6Wunderkinder




                 6Wunderkinder

More Related Content

PDF
Glenn Vanderburg — Learning to love JavaScript
PPT
scala-intro
PPTX
Building maintainable javascript applications
PPTX
Object Oriented JavaScript - II
PDF
Metaprogramming with javascript
KEY
Ruby's metaclass
Glenn Vanderburg — Learning to love JavaScript
scala-intro
Building maintainable javascript applications
Object Oriented JavaScript - II
Metaprogramming with javascript
Ruby's metaclass

What's hot (11)

PDF
Paris Web - Javascript as a programming language
PPTX
All of Javascript
PDF
Unbreaking Your Django Application
PPTX
Advanced Object Oriented JavaScript (prototype, closure, scope, design patterns)
PPTX
Javascript Prototype Visualized
PPTX
Introduction to JavaScript Programming
PDF
PPT
OOP in JavaScript
PPTX
Object Oriented Javascript part2
PDF
JavaScript guide 2020 Learn JavaScript
PPTX
Js: master prototypes
Paris Web - Javascript as a programming language
All of Javascript
Unbreaking Your Django Application
Advanced Object Oriented JavaScript (prototype, closure, scope, design patterns)
Javascript Prototype Visualized
Introduction to JavaScript Programming
OOP in JavaScript
Object Oriented Javascript part2
JavaScript guide 2020 Learn JavaScript
Js: master prototypes
Ad

Viewers also liked (20)

PDF
Government Mobile Marketing Guide
ODP
PPTX
Сгореть на работе и восстать из пепла (SQA Days-15)
PPTX
Individuals with disabilities in higher education
PPT
PPT
It og medier.
PPTX
Жизненный цикл тестировщика (Урансофт, семинар TrueTester #3)
PDF
Jumlah ma di ntb
PDF
Krimp: opgave en uitdaging
ODP
PPTX
DOCX
Jasmine soap
PPT
Fall sem 2010 exam set #3
PDF
PDF
Seeds Of Greatness
PDF
ניהול זמנים פסיכומטרי בפרק הכמותי
PPTX
START2GO: LevelUp
PPT
2011 Bucks, Bulls and Once-in-a-Lifetime Permit Number Recommendations, May 4
PPT
Acid rain
PPTX
Understanding the misconception
Government Mobile Marketing Guide
Сгореть на работе и восстать из пепла (SQA Days-15)
Individuals with disabilities in higher education
It og medier.
Жизненный цикл тестировщика (Урансофт, семинар TrueTester #3)
Jumlah ma di ntb
Krimp: opgave en uitdaging
Jasmine soap
Fall sem 2010 exam set #3
Seeds Of Greatness
ניהול זמנים פסיכומטרי בפרק הכמותי
START2GO: LevelUp
2011 Bucks, Bulls and Once-in-a-Lifetime Permit Number Recommendations, May 4
Acid rain
Understanding the misconception
Ad

Similar to Metaprogramming (20)

PDF
Introduction to JavaScript design patterns
PDF
Learning puppet chapter 2
PDF
Metaprogramming Rails
PPTX
Oop's in php
PDF
Metaprogramming in Ruby
PDF
Oop in php_tutorial
PDF
Writing Readable Code
PPT
Oops in PHP
PPTX
JavaScripts internals #1
PDF
Building reusable components with generics and protocols
PDF
Intro to JavaScript
PPT
inheritance
PPTX
The Black Magic of Ruby Metaprogramming
PPT
Intro Java Rev010
PPTX
Deciphering the Ruby Object Model
PPTX
6 Modules Inheritance Gems
PPT
Java inheritance concept, interface, objects, extends
PPT
04 inheritance
PPT
04_inheritance power point presentation.
PPT
Inheritance in java.ppt
Introduction to JavaScript design patterns
Learning puppet chapter 2
Metaprogramming Rails
Oop's in php
Metaprogramming in Ruby
Oop in php_tutorial
Writing Readable Code
Oops in PHP
JavaScripts internals #1
Building reusable components with generics and protocols
Intro to JavaScript
inheritance
The Black Magic of Ruby Metaprogramming
Intro Java Rev010
Deciphering the Ruby Object Model
6 Modules Inheritance Gems
Java inheritance concept, interface, objects, extends
04 inheritance
04_inheritance power point presentation.
Inheritance in java.ppt

Recently uploaded (20)

PDF
Network Security Unit 5.pdf for BCA BBA.
PDF
Agricultural_Statistics_at_a_Glance_2022_0.pdf
PPTX
Effective Security Operations Center (SOC) A Modern, Strategic, and Threat-In...
PDF
Mobile App Security Testing_ A Comprehensive Guide.pdf
PPTX
Detection-First SIEM: Rule Types, Dashboards, and Threat-Informed Strategy
PPTX
Understanding_Digital_Forensics_Presentation.pptx
PPTX
Programs and apps: productivity, graphics, security and other tools
PDF
Building Integrated photovoltaic BIPV_UPV.pdf
PDF
cuic standard and advanced reporting.pdf
PDF
Machine learning based COVID-19 study performance prediction
PPTX
Spectroscopy.pptx food analysis technology
PPTX
ACSFv1EN-58255 AWS Academy Cloud Security Foundations.pptx
PDF
Advanced methodologies resolving dimensionality complications for autism neur...
PDF
Per capita expenditure prediction using model stacking based on satellite ima...
PDF
Review of recent advances in non-invasive hemoglobin estimation
PPTX
KOM of Painting work and Equipment Insulation REV00 update 25-dec.pptx
PDF
Empathic Computing: Creating Shared Understanding
PDF
NewMind AI Weekly Chronicles - August'25 Week I
PPTX
Digital-Transformation-Roadmap-for-Companies.pptx
PDF
How UI/UX Design Impacts User Retention in Mobile Apps.pdf
Network Security Unit 5.pdf for BCA BBA.
Agricultural_Statistics_at_a_Glance_2022_0.pdf
Effective Security Operations Center (SOC) A Modern, Strategic, and Threat-In...
Mobile App Security Testing_ A Comprehensive Guide.pdf
Detection-First SIEM: Rule Types, Dashboards, and Threat-Informed Strategy
Understanding_Digital_Forensics_Presentation.pptx
Programs and apps: productivity, graphics, security and other tools
Building Integrated photovoltaic BIPV_UPV.pdf
cuic standard and advanced reporting.pdf
Machine learning based COVID-19 study performance prediction
Spectroscopy.pptx food analysis technology
ACSFv1EN-58255 AWS Academy Cloud Security Foundations.pptx
Advanced methodologies resolving dimensionality complications for autism neur...
Per capita expenditure prediction using model stacking based on satellite ima...
Review of recent advances in non-invasive hemoglobin estimation
KOM of Painting work and Equipment Insulation REV00 update 25-dec.pptx
Empathic Computing: Creating Shared Understanding
NewMind AI Weekly Chronicles - August'25 Week I
Digital-Transformation-Roadmap-for-Companies.pptx
How UI/UX Design Impacts User Retention in Mobile Apps.pdf

Metaprogramming

  • 1. Metaprogramming Alex Koppel 6Wunderkinder Alex Koppel – 1/3/2012
  • 2. What is metaprogramming? !   "Like programming, only meta" – an old colleague !   Code that writes code !   "Metaprogramming is the writing of computer programs that write or manipulate other programs (or themselves) as their data, or that do part of the work at run time that would otherwise be done at compile time.“ – Wikipedia Alex Koppel - 6Wunderkinder
  • 3. Why should you care? !   Ruby allows metaprogramming !   Metaprogramming can create stunningly effective tools !   Rails is metaprogramming !   You want to be a more effective Ruby programmer 6Wunderkinder
  • 4. Caution! !   Wield metaprogramming deliberately !   Your code will be harder to understand !   Will other developers lose time figuring out your magic? !   Your code will be more brittle !   Altering other classes = dependency !   Changes to underlying code can break your app !   c.f. Facebooker 6Wunderkinder
  • 5. Techniques 6Wunderkinder
  • 6. Reopening Classes !   Add additional methods or variables to existing classes !   Very simple, very powerful !   New code is executed as your files are loaded !   In a sense, this is a "static" metaprogramming !   Common in monkeypatching !   Caveat: this creates the class if not yet defined 6Wunderkinder
  • 7. Code require 'active_support/core_ext/string/inflections'! # reopen String class! class String! # add a module! include ActiveSupport::CoreExtensions::String::Inflections! end! 6Wunderkinder
  • 8. alias_method !   alias_method(new_name, old_name) !   Makes an copy of a method !   exist v. exists !   Copy remains if the original is overridden !   You may remember alias_method_chain !   Can be used dynamically in other methods 6Wunderkinder
  • 9. class Foo! Code def bar! 3! end! # make a copy of bar! alias_method :bar, :old_bar! # redefine bar! def bar! 4! end! end! Foo.new.bar! # => 4! Foo.new.old_bar! # => 3! 6Wunderkinder
  • 10. Metaclasses !   All Ruby objects have a unique class !   The "metaclass", a.k.a. "eigenclass" !   Classes too !   Special cases: Fixnums, true, false, nil !   You can access this class to change the object !   class << object opens up the metaclass !   def object.new_method and object.instance_eval also work !   Note: reopening classes and alias_method alter the original class, not a metaclass 6Wunderkinder
  • 11. What are Objects and Classes, really? !   An object is actually simple[1] !   A collection of instance variables !   A reference to a class !   When you call a method, Ruby goes up the class hierarchy for its definition !   Metaclass, then class, then superclass !   Changing methods on an individual object is really changing its metaclass [1] http://ruby-doc.org/docs/ProgrammingRuby/html/classes.html 6Wunderkinder
  • 12. Code 1: Classes # Using class << self for a class is effectively! # equivalent to reopening the class (see above)! class Person! ! # this can be easier than writing tons of def self.s ! class << self! def species! "Homo Sapien"! end! end! end! class << Person! def species; "Homo Sapien“; end! end! Person.species == “Homo Sapien“ # true! 6Wunderkinder
  • 13. Code 2: Objects str = "hello world"! class << str! def foo! 2! end! end! str.foo! # => 2! "hello world".foo! # => NoMethodError! 6Wunderkinder
  • 14. Case study: non-breaking changes !   Example from Koala (Facebook SDK) !   Changing a method to return strings rather than hashes !   Could this be done without breaking apps? !   Use metaprogramming on the returned strings !   Add missing methods !   Print deprecation warning 6Wunderkinder
  • 15. Code def get_app_access_token! info = get_app_access_token_info # hash! string = info["access_token"]! # make the string compatible with hash accessors! command = <<-EOS! def [](index)! puts "DEPRECATION WARNING"! hash = #{hash.inspect} ! hash[index]! end! EOS! # add those methods just to the string! (class << string; self; end).class_eval command! end! 6Wunderkinder
  • 16. How does it work? !   Get the individual string's metaclass: !   (class << str; self; end) !   Opens the class scope, and returns the (meta)class !   class_eval !   Executes code in the scope of a class (or metaclass) !   class_eval requires a class, not an instance !   String eval can be used for dynamic content !   You can also eval a regular code block !   Objects altered like this are "singletons" !   Has runtime implications 6Wunderkinder
  • 17. Problem! !   Ruby's Marshal.dump is used to serialize objects !   Marshaling does NOT work with singletons !   Singletons can't be cached! !   Defining instance#_dump doesn't help !   Expects String#load to exist !   Use this carefully in shared code !   You never know what your users will do 6Wunderkinder
  • 18. Solution! !   Use modules to mix in unique methods !   Ruby knows how to handle this, even for objects module BackwardsCompatible! def [](key)! puts "Got key! #{key}"! end! end! my_string = "abc”! # objects:extend <=> classes:include ! my_string.send(:extend, BackwardsCompatible)! my_string["foo"]! Got key! foo! => nil ! Marshal.dump(my_string)! => "x04bIe:x18BackwardsCompatible"babcx06:x06ET" ! 6Wunderkinder
  • 19. class_eval again !   Ruby pattern: modules updating the including class !   Add before_filters, attrs, etc. !   Could use .send in some cases !   class_eval is easier to read !   Can define dynamic methods !   ActiveSupport::Concern works this way !   class_eval is like reopening a class !   But can be used without knowing the class in advance !   Won't create the class if it doesn't exist 6Wunderkinder
  • 20. Code module ControllerStuff! def self.included(base)! # execute new code in the scope of! # the including class! base.class_eval do! before_filter :module_method! attr_accessor :module_var! @module_var = 2! end! end! end! 6Wunderkinder
  • 21. Method Missing !   Intercept calls to non-existent methods !   Make a class's interface dynamic !   Example: ActiveRecord !   Create dynamic finders on the fly !   @user.find_by_name_and_status !   Example: proxy objects 6Wunderkinder
  • 22. Pseudo-code for ActiveRecord 2.x def method_missing(method_id, *args, &block)! # is it the right find_by_...format?! ! if match(method_id) && match.finder?! ! # method_missing is a class method ! self.class_eval %{ # string! # define the method! def self.#{method_id}(*args)! find(:#{finder}, options.merge ! (finder_options))! end! end! # now call the new method! send(method_id, *arguments)! end! end ! 6Wunderkinder
  • 23. Important Note !   method_missing can be much slower !   There are some tricky issues !   respond_to? and beyond !   Solving each problem can create others [1] !   Don't overuse it !   Can you use define_method instead? [1] http://www.slideshare.net/paoloperrotta/the-revenge-of-methodmissing 6Wunderkinder
  • 24. Reaching into Objects !   send: call any method on an object (public or not) !   Useful for dynamic programming !   Can also be used to break encapsulation !   public_send (1.9) is safer !   instance_variable_get, instance_variable_set: !   Access variables that lack an accessor !   Don't use these 6Wunderkinder
  • 25. Code # from Koala (older)! # Scope: class with Typhoeous module included! def self.make_request(path, args, verb)! # dynamically call the appropriate method! # corresponding to the verb requested ! ! self.send(verb, url, :params => args)! End! # from Rails! # Scope: a helper class that needs a ! # private controller method! def universal_calculation(arg)! # call the method on the controller! controller.send(:universal_controller, arg)! end ! 6Wunderkinder
  • 26. tl;dr !   Metaprogramming is awesome !   Don’t overuse it !   But don’t be afraid to use it when appropriate !   Enjoy :) 6Wunderkinder
  • 27. Resources !   Ruby books !   URLs: !   http://yehudakatz.com/2009/11/15/metaprogramming- in-ruby-its-all-about-the-self/ !   http://ruby-doc.org/docs/ProgrammingRuby/html/ classes.html !   http://www.slideshare.net/paoloperrotta/the- revenge-of-methodmissing !   http://pragprog.com/book/ppmetr/metaprogramming- ruby !   Google "ruby metaprogramming“ 6Wunderkinder