Metaprogramming

12,928 views
12,790 views

Published on

Metaprogramming in Ruby with some examples.

Published in: Technology
0 Comments
13 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
12,928
On SlideShare
0
From Embeds
0
Number of Embeds
8,081
Actions
Shares
0
Downloads
154
Comments
0
Likes
13
Embeds 0
No embeds

No notes for slide

Metaprogramming

  1. 1. Object Model and Metaprogramming in Ruby Monday, November 1, 2010
  2. 2. Santiago Pastorino @spastorino Monday, November 1, 2010
  3. 3. Monday, November 1, 2010
  4. 4. Monday, November 1, 2010
  5. 5. Monday, November 1, 2010
  6. 6. Monday, November 1, 2010
  7. 7. Monday, November 1, 2010
  8. 8. Monday, November 1, 2010
  9. 9. Monday, November 1, 2010
  10. 10. Ruby Rails Monday, November 1, 2010
  11. 11. Java get/set version 1 public class User { private String name; public String getName() {    return name;    }    public void setName(String name) {    this.name = name; } } Monday, November 1, 2010
  12. 12. .NET get/set version 1 class User { private string name; public string Name {     get { return name; }     set { name = value; } } } Monday, November 1, 2010
  13. 13. Ruby get/set version 1 class User def name @name end def name=(value) @name = value end end Monday, November 1, 2010
  14. 14. Java get/set version 2 ?public property String name; Monday, November 1, 2010
  15. 15. .NET get/set version 2 class User { public string Name { get; set; } } Monday, November 1, 2010
  16. 16. Ruby get/set version 2 The right way class User attr_accessor :name end Monday, November 1, 2010
  17. 17. Metaprogramming Monday, November 1, 2010
  18. 18. Metaprogramming “Metaprogramming is writing code that writes code.” Monday, November 1, 2010
  19. 19. Metaprogramming “Metaprogramming is writing code that writes code.” Monday, November 1, 2010
  20. 20. Metaprogramming “Metaprogramming is writing code that writes code.” “Metaprogramming is writing code that manipulates language constructs at runtime.” Monday, November 1, 2010
  21. 21. Metaprogramming Monday, November 1, 2010
  22. 22. Metaprogramming • Classes are always open • Everything is an Object even classes and modules • All methods calls have a receiver Monday, November 1, 2010
  23. 23. Classes are Open class Hash def except!(*keys) keys.each { |key| delete(key) } self end end hsh = {:a => 1, :b => 2} hsh.except!(:a) # => {:b => 2} Monday, November 1, 2010
  24. 24. Everything is an Object class User puts self # => User puts self.class # => Class end User.methods.grep /get/ => [:const_get, :class_variable_get, :instance_variable_get] Monday, November 1, 2010
  25. 25. All method calls have a receiver class User attr_accessor :name end Monday, November 1, 2010
  26. 26. Metaprogramming •class_eval • define_method • method_missing Monday, November 1, 2010
  27. 27. attr_reader (class_eval) class User def initialize(name) @name = name end attr_reader :name end u = User.new(‘Santiago’) u.name # => ‘Santiago’ Monday, November 1, 2010
  28. 28. attr_reader (class_eval) class Module def attr_reader(sym) class_eval “def #{sym}; @#{sym}; end” end end class User attr_reader :name # def name; @name; end end Monday, November 1, 2010
  29. 29. attr_reader (class_eval) class Module private def attr_reader(sym) class_eval <<-READER, __FILE__, __LINE__ + 1 def #{sym} @#{sym} end READER end end Monday, November 1, 2010
  30. 30. attr_writer (class_eval) class Module private def attr_writer(sym) class_eval <<-WRITER, __FILE__, __LINE__ + 1 def #{sym}=(value) @#{sym} = value end WRITER end end Monday, November 1, 2010
  31. 31. attr_accessor class Module private def attr_accessor(*syms) attr_reader(syms) attr_writer(syms) end end Monday, November 1, 2010
  32. 32. Metaprogramming • class_eval •define_method • method_missing Monday, November 1, 2010
  33. 33. define_method class User attr_accessor_with_default :age, 22 end user = User.new user.age # => 22 user.age = 26 user.age # => 26 Monday, November 1, 2010
  34. 34. define_method class Module def attr_accessor_with_default(sym, default) class_eval <<-READER, __FILE__, __LINE__ + 1 def #{sym} #{default} end # + something else READER end end Monday, November 1, 2010
  35. 35. define_method class User attr_accessor_with_default :age, 22 end user = User.new user.age # => 22 Monday, November 1, 2010
  36. 36. define_method class USer attr_accessor_with_default :complex_obj, Struct.new(:x, :y) end user = User.new user.complex_obj # => nil Monday, November 1, 2010
  37. 37. define_method 22.to_s # => “22” Struct.new(:x, :y).to_s # => "#<Class:0x00000100966210>" Monday, November 1, 2010
  38. 38. define_method class Module def attr_accessor_with_default(sym, default) class_eval <<-READER, __FILE__, __LINE__ + 1 def #{sym} default end # + something else READER end end Monday, November 1, 2010
  39. 39. define_method class User attr_accessor_with_default :complex_obj, Struct.new(:x, :y) end user = User.new user.complex_obj NameError: undefined local variable or method `default' for #<User:0x00000100978050> Monday, November 1, 2010
  40. 40. define_method class Module def attr_accessor_with_default(sym, default) define_method(sym, Proc.new { default }) end end Monday, November 1, 2010
  41. 41. define_method class Module def attr_accessor_with_default(sym, default) define_method(sym, Proc.new { default }) class_eval(<<-EVAL, __FILE__, __LINE__ + 1) def #{sym}=(value) class << self; attr_accessor :#{sym} end @#{sym} = value end EVAL end end Monday, November 1, 2010
  42. 42. define_method class Person attr_accessor_with_default :complex_obj, Struct.new(:x, :y) end person = Person.new person.complex_obj # => #<Class:0x00000101045c70> person.complex_obj = Struct.new(:a, :b) person.complex_obj # => #<Class:0x000001009be9d8> Monday, November 1, 2010
  43. 43. Metaprogramming • class_eval • define_method •method_missing Monday, November 1, 2010
  44. 44. Method Lookup BasicObject Object XMLx KernelKernel Monday, November 1, 2010
  45. 45. method_missing (An internal DSL) XML.generate(STDOUT) do html do head do title { ‘pagetitle’ } comment ‘This is a test’ end body do h1 style: ‘font-family: sans-serif‘ do ‘pagetitle’ end ul id: ‘info’ do li { Time.now } li { RUBY_VERSION } end end end Monday, November 1, 2010
  46. 46. method_missing (An internal DSL) <html> <head> <title>pagetitle</title> <!-- This is a test --> </head> <body> <h1 style=”font-family: sans-serif”> pagetitle </h1> <ul id=”info”> <li>2010-10-30 17:39:45 -0200</li> <li>1.9.2</li> </ul> </body> </html> Monday, November 1, 2010
  47. 47. method_missing (An internal DSL) class XML def initialize(out) @out = out end def content(text) @out << text.to_s end def comment(text) @out << “<!-- #{text} -->” end end Monday, November 1, 2010
  48. 48. method_missing (An internal DSL) def method_missing(tagname, attributes={}) @out << “<#{tagname}” attributes.each { |attr, value| @out << “#{attr}=’#{value}’” } if block_given? @out << ‘>’ content = yield if content @out << content.to_s end @out << “</#{tagname}>” else @out << ‘/>’ end end Monday, November 1, 2010
  49. 49. method_missing (An internal DSL) class XML def self.generate(out, &block) XML.new(out).instance_eval(&block) end end XML.generate(STDOUT) do # code end Monday, November 1, 2010
  50. 50. method_missing (An internal DSL) XML.generate(STDOUT) do html do head do title { ‘pagetitle’ } comment ‘This is a test’ end body do h1 style: ‘font-family: sans-serif‘ do ‘pagetitle’ end ul id: ‘info’ do li { Time.now } li { RUBY_VERSION } end end end Monday, November 1, 2010
  51. 51. It’s all about the self Monday, November 1, 2010
  52. 52. Singleton Method d = “9/5/1982” def d.to_date # code here end # or class << d def to_date # code here end end Monday, November 1, 2010
  53. 53. Object Model BasicObject Object String (d)d KernelKernel Monday, November 1, 2010
  54. 54. Class Methods? class String def self.to_date # code here end # or class << self def to_date # code here end end end Monday, November 1, 2010
  55. 55. The same d = “9/5/1982” def d.to_date # code here end # or class << d def to_date # code here end end Monday, November 1, 2010
  56. 56. Object Model (BasicObject)BasicObject Object (Object) String (String) Module Class Monday, November 1, 2010
  57. 57. Everything about self class User p self # => User class << self p self # => <Class:User> end end Monday, November 1, 2010
  58. 58. Real life use cases for fibers? require 'fiber' module Eigenclass   def eigenclass     class << self; self end   end   module_function :eigenclass   public :eigenclass end class Object   include Eigenclass end Monday, November 1, 2010
  59. 59. Real life use cases for fibers? class EigenclassesGenerator   def initialize(obj)     @eigenclasses = [obj.eigenclass]     @fiber = Fiber.new do       loop do         Fiber.yield @eigenclasses.last         @eigenclasses[@eigenclasses.length] = @eigenclasses.last.eigenclass       end     end   end   def [](index) if index >= @eigenclasses.length (index - @eigenclasses.length + 2).times { @fiber.resume } end     @eigenclasses[index]   end end Monday, November 1, 2010
  60. 60. Rails Magic? class User < ActiveRecord::Base belongs_to :bill_address has_one :role has_many :orders validates_presence_of :name, :country validates_acceptance_of :terms validates_uniqueness_of :name end Monday, November 1, 2010
  61. 61. Questions? Monday, November 1, 2010
  62. 62. Thank you! Monday, November 1, 2010

×