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

Ruby is Magic: Reflections

Ruby is Magic: Reflections

These are the slides from the Cologne.rb meet up (the Cologne/Germany Ruby and Rails user group) for the talk series 'Ruby is Magic'. In this series we take Ruby features most of us use on a regular basis and inspect them very fine grained.

The topic of this talk was 'Reflections'. The talk was held at 23rd of May, 2012 at the simfy headquarters in Cologne/Germany. Due to the fact being a german user group, the slides are in German language.

Enjoy.

Copyright Notice: My Little Pony - Friendship is Magic is Property of Hasbro and The Hub.

Avatar for Dirk Breuer

Dirk Breuer

May 16, 2012
Tweet

More Decks by Dirk Breuer

Other Decks in Technology

Transcript

  1. 23.class # >> Fixnum "Hello World".class # >> String Pony.kind_of?(Meme)

    # >> true pinkie_pie.instance_of?(Pony) # >> true Pony.class # >> Class Array.include?(Enumerable) # >> true Array.included_modules # >> [Enumerable, Kernel] Array.ancestors # >> [Array, Enumerable, Object, Kernel, BasicObject]
  2. class Pony; end class PinkyPie < Pony; end class Brony;

    end PinkyPie < Pony # >> true Pony <=> PinkyPie # >> -1 Pony <=> Pony # >> 0 PinkyPie <=> Pony # >> 1 Brony <=> Pony # >> nil :( Fun Fact
  3. Elemente des Programms zur Laufzeit … … finden (z.B. Objekte

    oder Konstanten) und … benutzen (z.B. Methoden aufrufen) Reflection ist aber auch …
  4. # Get the 'Pony' class by name clazz = Object.const_get("Pony")

    # Create an instance instance = clazz.new("Rainbow Dash") # Call the 'speak' method dynamically instance.send(:speak) # >> 10 seconds flat!
  5. Methoden dynamisch aufrufen? Wie viele Parameter müssen übergeben werden? (arity)

    Wie heißen die Parameter? (parameters) Welchem Objekt ist die Methode zugeordnet? (owner und receiver) Object#method(sym) → method
  6. arity() parameters() () (a) (a=42) (a, *b) (*a, b) (a,

    *b, &c) (a, *b, c) 0 [] 1 [[:req, :a]] -1 [[:opt, :a]] -2 [[:req, :a], [:rest, :b]] -2 [[:rest, :a], [:req, :b]] -2 [[:req, :a], [:rest, :b], [:block, :c]] -3 [[:req, :a], [:rest, :b], [:req, :c]] -n-1* *n: parameters.select {|p| p.first == :req}.count
  7. ObjectSpace.count_objects # { # :TOTAL => 14716, # :FREE =>

    420, # :T_OBJECT => 10, # :T_CLASS => 481, # ... # } ObjectSpace.each_object(Pony) { |obj| puts obj } # >> #<Pony:'Rainbow Dash'>, #<Pony:'Pinkie Pie'> ObjectSpace.each_object(Meme) { |obj| puts obj } # >> Pony
  8. “Ein [vollständig] reflexives System kann seinen eigenen Zustand während der

    Laufzeit abfragen und verändern. Veränderungen wirken sich dabei zur direkt auf das System aus.” Brian C. Smith – Reflection and Semantics in Lisp (1983)
  9. Das Verändern von Elementen des Programms zur Laufzeit z.B. durch

    … … Hinzufügen … Ändern oder Entfernen Reflection beschreibt also auch noch …
  10. # Define new Class 'Foo' Object.const_set("Foo", Class.new) puts Foo.instance_methods(false) #

    >> [] # Add a method to that class Foo.send(:define_method, "bar") do puts "Hello World!" end Foo.new.bar # >> 'Hello World!'
  11. enum "Colors", %w(Red Blue Yellow) Colors.each { |color| puts color.name

    } # Red # Blue # Yellow # … Colors::Red.name # >> Colors::Red Want:
  12. Need: def enum(name, elements) enum_class = Class.new do def self.each(&block)

    @_elements.each(&block) end def name self.class.name end end elements = elements.map do |el| enum_class.const_set(el, Class.new(enum_class)) end enum_class.instance_variable_set("@_elements", elements) Object.const_set(name, enum_class) end
  13. pinkie_pie = Pony.new pinkie_pie.sing # >> "I'm a singing Pony!"

    class Discord def self.silence! Pony.send(:remove_method, :sing) end end Discord.silence! begin pinkie_pie.sing rescue => e puts "Ponies cannot sing anymore!" end # >> 'Ponies cannot sing anymore!'
  14. Typen zur Laufzeit ermitteln Konstanten, Objekte & Methoden dynamisch finden

    dynamisch aufrufen dynamisch manipulieren und löschen! Reflection ermöglicht Meta-Programming
  15. <html> <head> <title>{{@title}}</title> </head> <body> <h1>Welcome to Ruby is Magic</h1>

    <h2>Today we welcome you to episode #{{@episode[:number]}} - {{@episode[:title]}}</h2> <p> {{@episode[:description]}} </p> </body> </html> Template
  16. Controller class Controller < AbstractController def index @title = "Ruby

    is Magic" @episode = { number: 9, title: "Reflections", description: "We gonna show you the magic of reflections in Ruby!" } render :index end end
  17. “Magic” class AbstractController def render(template) view = View.new(view_assigns) rendered_view =

    view.render(template) Rack::Response.new([rendered_view], 200, {"Content-Type" => "text/html"}) end private def view_assigns assigns = {} instance_variables.each do |variable| assigns[variable] = instance_variable_get(variable) end return assigns end end
  18. “Magic” class View def initialize(assigns) assigns.each do |name, value| instance_variable_set(name.to_s,

    value) end end def render(template) TEMPLATES[template].gsub(/{{(.*?)}}/) do |m| instance_eval($1) end end end
  19. $ curl http://localhost:9292 <html> <head> <title>Ruby is Magic</title> </head> <body>

    <h1>Welcome to Ruby is Magic</h1> <h2>Today we welcome you to episode #9 - Reflections</h2> <p> In this brand new episode we gonna show you the magic of reflections in Ruby! </p> </body> </html>
  20. Thanks! Q & A? Dirk Breuer / @railsbros_dirk Sebastian Cohnen

    / @tisba ? “My Little Pony” © Hasbro Studios and DHX Media Vancouver rubyismagic.de