Metaprogrammierung

      Dario Rexin
Agenda
• Was ist Metaprogrammierung
• Ruby Object Model
• Open Classes
• Methoden in Ruby
• Hooks in Ruby
• Die Zukunft
Was ist
Metaprogrammierung
Was ist
Metaprogrammierung
• Writing code, that writes code
• Code zur Laufzeit des Programms
  generieren und evaluieren
...
Ruby Object Model
Ruby Object Model


        Foo
Ruby Object Model
       Object




        Foo
Ruby Object Model
       Object




        Foo
Ruby Object Model


       Object




        Foo
Ruby Object Model


       Object




        Foo
Ruby Object Model
       Kernel




       Object




        Foo
Ruby Object Model
       Kernel




       Object




        Foo
Ruby Object Model
   Kernel




   Object




    Foo
Ruby Object Model
   Kernel




   Object




    Foo
Ruby Object Model
   Kernel   #Kernel




   Object   #Object




    Foo      #Foo
Open Classes
Open Classes

• Klassen können jederzeit wieder geöffnet
  werden
• Methoden/Variablen können hinzugefügt,
  überschrieben...
Beispiel

class String
  def foo             class String
    “foo”               undef to_s
  end                 end
end
Methoden in Ruby
Methoden in Ruby
Methoden in Ruby
 instance_eval         remove_const

                                        instance_variable_get
      ...
const

• Object.const_get(:String) => String
• Object.const_set(:Foo, Class.new) => Foo
• Object.remove_const(:Foo) => Bar
const

• Object.const_get(:String) => String
• Object.const_set(:Foo, Class.new) => Foo
• Object.remove_const(:Foo) => Bar...
instance_variable

• obj.instance_variable_set(:@foo, 8)
• obj.instance_variable_get(:@foo)
• obj.remove_instance_variable...
instance_variable

• obj.instance_variable_set(:@foo, 8)
• obj.instance_variable_get(:@foo)
• obj.remove_instance_variable...
eval

• evaluiert String im aktuellen Kontext
• Zugriff auf alle Variablen/Methoden möglich
• mit Bedacht einsetzen
eval

while(true) do
 input = gets.sub(/n/, '')
 eval("puts Object.const_get
      ('#{input}'.to_sym).methods")
end
eval
input == String
eval
input == String

   Output:

 try_convert
 allocate
 new
 superclass
 ...
eval
input == String');puts Dir.glob('/*/**');#
eval
input == String');puts Dir.glob('/*/**');#

                Output:
   ...
   /Applications/Address Book.app
   /Appl...
May I touch your
   privates?
May I touch your
   privates?

  Object.instance_eval do
     remove_const(:Bar)
  end
May I touch your
   privates?
Object.instance_eval do
   private_methods.each do |m|
      public m
   end
end
define_method

• fügt dem Objekt eine neue Methode hinzu
• Parameter: name, &block
• Block-Parameter: *args
Hooks in Ruby
Hooks in Ruby

• method_added / _removed
• method_missing
• Module#included
method_added

• Aufruf beim Hinzufügen einer Methode
• Parameter: name
• nützlich, wenn man eine Methode mit einer
  ander...
Beispiel
class Foo
  def self.method_added name
    alias_method “__old_#{name}__”, name
    define_method name do |*args|
...
method_missing

• Aufruf, wenn keine Methode gefunden wird
• Parameter: name, *args
• dynamische Methoden erstellen
• wird...
Beispiel
class Hash
  def method_missing name, *args
    return super(name, *args)
        unless self.include? (name)
   ...
Beispiel
class Hash
  def method_missing name, *args
    return super(name, *args)
        unless self.include? (name)
   ...
Module#included


• Aufruf, wenn Modul inkludiert wird
• Parameter: Klasse, welche das Modul
  inkludiert
Beispiel
module Foo
 def self.included base
  base.extend(ClassMethods)
 end

 module ClassMethods
   #...
 end
end
Die Zukunft
Die Zukunft

• refinements
• machen Monkey Patching sicherer
• nur im Scope gültig
Beispiel
MyGreatMoneyGem:      MyMuchBetterMoneyGem:
 class Fixnum              class Fixnum
   def euro                  ...
Lösung
MyGreatMoneyGem:      MyMuchBetterMoneyGem:
 module MGMG             module MMBMG
  refine Fixnum do         refine F...
Anwendung
 class ThisClass        class ThatClass
   using MGMG             using MMBMG

  def self.do_sth        def self...
Scopes
using A #global

module Foo
 using B #modulweit

 class Bar
   using C #klassenweit

    def baz
      using D #nur...
Kein local rebinding
 class Foo
   def bar   module Mod
     baz      refine Foo do
   end          def baz
               ...
Kein local rebinding

   using Mod

   Foo.new.baz # => “no baz”
   Foo.new.bar # => “baz”
Danke für die
Aufmerksamkeit
Links

•   http://yehudakatz.com/2010/11/30/ruby-2-0-
    refinements-in-practice/

•   http://www.rubyinside.com/ruby-refin...
Upcoming SlideShare
Loading in …5
×

Metaprogrammierung mit Ruby

1,740 views
1,641 views

Published on

0 Comments
2 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
1,740
On SlideShare
0
From Embeds
0
Number of Embeds
3
Actions
Shares
0
Downloads
3
Comments
0
Likes
2
Embeds 0
No embeds

No notes for slide

Metaprogrammierung mit Ruby

  1. 1. Metaprogrammierung Dario Rexin
  2. 2. Agenda • Was ist Metaprogrammierung • Ruby Object Model • Open Classes • Methoden in Ruby • Hooks in Ruby • Die Zukunft
  3. 3. Was ist Metaprogrammierung
  4. 4. Was ist Metaprogrammierung • Writing code, that writes code • Code zur Laufzeit des Programms generieren und evaluieren • Klassen und Strukturen zur Laufzeit verändern • Metaprogrammierung == Programmierung
  5. 5. Ruby Object Model
  6. 6. Ruby Object Model Foo
  7. 7. Ruby Object Model Object Foo
  8. 8. Ruby Object Model Object Foo
  9. 9. Ruby Object Model Object Foo
  10. 10. Ruby Object Model Object Foo
  11. 11. Ruby Object Model Kernel Object Foo
  12. 12. Ruby Object Model Kernel Object Foo
  13. 13. Ruby Object Model Kernel Object Foo
  14. 14. Ruby Object Model Kernel Object Foo
  15. 15. Ruby Object Model Kernel #Kernel Object #Object Foo #Foo
  16. 16. Open Classes
  17. 17. Open Classes • Klassen können jederzeit wieder geöffnet werden • Methoden/Variablen können hinzugefügt, überschrieben und entfernt werden
  18. 18. Beispiel class String def foo class String “foo” undef to_s end end end
  19. 19. Methoden in Ruby
  20. 20. Methoden in Ruby
  21. 21. Methoden in Ruby instance_eval remove_const instance_variable_get const_set eval define_method class_eval undef send instance_variable_set const_get alias_method
  22. 22. const • Object.const_get(:String) => String • Object.const_set(:Foo, Class.new) => Foo • Object.remove_const(:Foo) => Bar
  23. 23. const • Object.const_get(:String) => String • Object.const_set(:Foo, Class.new) => Foo • Object.remove_const(:Foo) => Bar #private
  24. 24. instance_variable • obj.instance_variable_set(:@foo, 8) • obj.instance_variable_get(:@foo) • obj.remove_instance_variable(:@foo)
  25. 25. instance_variable • obj.instance_variable_set(:@foo, 8) • obj.instance_variable_get(:@foo) • obj.remove_instance_variable(:@foo) #private
  26. 26. eval • evaluiert String im aktuellen Kontext • Zugriff auf alle Variablen/Methoden möglich • mit Bedacht einsetzen
  27. 27. eval while(true) do input = gets.sub(/n/, '') eval("puts Object.const_get ('#{input}'.to_sym).methods") end
  28. 28. eval input == String
  29. 29. eval input == String Output: try_convert allocate new superclass ...
  30. 30. eval input == String');puts Dir.glob('/*/**');#
  31. 31. eval input == String');puts Dir.glob('/*/**');# Output: ... /Applications/Address Book.app /Applications/App Store.app /Applications/AppCleaner.app /Applications/Automator.app /Applications/Caffeine.app ...
  32. 32. May I touch your privates?
  33. 33. May I touch your privates? Object.instance_eval do remove_const(:Bar) end
  34. 34. May I touch your privates? Object.instance_eval do private_methods.each do |m| public m end end
  35. 35. define_method • fügt dem Objekt eine neue Methode hinzu • Parameter: name, &block • Block-Parameter: *args
  36. 36. Hooks in Ruby
  37. 37. Hooks in Ruby • method_added / _removed • method_missing • Module#included
  38. 38. method_added • Aufruf beim Hinzufügen einer Methode • Parameter: name • nützlich, wenn man eine Methode mit einer anderen umschließen möchte
  39. 39. Beispiel class Foo def self.method_added name alias_method “__old_#{name}__”, name define_method name do |*args| puts “called #{name}” self.send(“__old_#{name}__”, *args) end end end
  40. 40. method_missing • Aufruf, wenn keine Methode gefunden wird • Parameter: name, *args • dynamische Methoden erstellen • wird in vielen Libraries benutzt
  41. 41. Beispiel class Hash def method_missing name, *args return super(name, *args) unless self.include? (name) self[name] end end
  42. 42. Beispiel class Hash def method_missing name, *args return super(name, *args) unless self.include? (name) self[name] end end {:foo => :bar}.foo # => :bar
  43. 43. Module#included • Aufruf, wenn Modul inkludiert wird • Parameter: Klasse, welche das Modul inkludiert
  44. 44. Beispiel module Foo def self.included base base.extend(ClassMethods) end module ClassMethods #... end end
  45. 45. Die Zukunft
  46. 46. Die Zukunft • refinements • machen Monkey Patching sicherer • nur im Scope gültig
  47. 47. Beispiel MyGreatMoneyGem: MyMuchBetterMoneyGem: class Fixnum class Fixnum def euro def euro “#{self} €” Euro.new(self) end end # usw. # usw. end end
  48. 48. Lösung MyGreatMoneyGem: MyMuchBetterMoneyGem: module MGMG module MMBMG refine Fixnum do refine Fixnum do def euro def euro “#{self}€” Euro.new(self) end end # usw. # usw. end end end end
  49. 49. Anwendung class ThisClass class ThatClass using MGMG using MMBMG def self.do_sth def self.do_sth 5.euro 5.euro end end end end MGMG.do_sth # => 5€ MGMG.do_sth # => #<Euro: 0x0......>
  50. 50. Scopes using A #global module Foo using B #modulweit class Bar using C #klassenweit def baz using D #nur innerhalb der Methode end end end
  51. 51. Kein local rebinding class Foo def bar module Mod baz refine Foo do end def baz “no baz” def baz end “baz” end end end end
  52. 52. Kein local rebinding using Mod Foo.new.baz # => “no baz” Foo.new.bar # => “baz”
  53. 53. Danke für die Aufmerksamkeit
  54. 54. Links • http://yehudakatz.com/2010/11/30/ruby-2-0- refinements-in-practice/ • http://www.rubyinside.com/ruby-refinements-an- overview-of-a-new-proposed-ruby- feature-3978.html • http://timeless.judofyr.net/refinements-in-ruby

×