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.

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