Slide 1

Slide 1 text

Brony User Group Cologne hosted by 16.5.2012

Slide 2

Slide 2 text

Ruby #9 “reflection”

Slide 3

Slide 3 text

“ is the noblest way to learn wisdom.” – ޸෉ࢠ Reflection

Slide 4

Slide 4 text

Reflection bedeutet zur Laufzeit Informationen … über definierte Konstanten, Objekte und ihre Eigenschaften abfragen Reflection

Slide 5

Slide 5 text

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]

Slide 6

Slide 6 text

const_defined? instance_methods instance_variable_defined? … respond_to? method_defined? respond_to? method_defined?

Slide 7

Slide 7 text

pinkie_pie.respond_to?(:speak) # >> true Pony.respond_to?(:speak) # >> false Pony.method_defined?(:speak) # >> true pinkie_pie.method_defined?(:speak) # >> NoMethodError

Slide 8

Slide 8 text

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

Slide 9

Slide 9 text

Elemente des Programms zur Laufzeit … … finden (z.B. Objekte oder Konstanten) und … benutzen (z.B. Methoden aufrufen) Reflection ist aber auch …

Slide 10

Slide 10 text

# 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!

Slide 11

Slide 11 text

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

Slide 12

Slide 12 text

def meth() end # Params: [] # Arity: 0

Slide 13

Slide 13 text

def meth(a) end # Params: [[:req, :a]] # Arity: 1

Slide 14

Slide 14 text

def meth(a=42) end # Params: [[:opt, :a]] # Arity: -1

Slide 15

Slide 15 text

def meth(a, *b) end # Params: [[:req, :a], [:rest, :b]] # Arity: -2

Slide 16

Slide 16 text

def meth(*a, b) end # Params: [[:rest, :a], [:req, :b]] # Arity: -2

Slide 17

Slide 17 text

def meth(a, *b, &c) end # Params: [[:req, :a], [:rest, :b], [:block, :c]] # Arity: -2

Slide 18

Slide 18 text

def meth(a, *b, c) end # Params: [[:req, :a], [:rest, :b], [:req, :c]] # Arity: -3

Slide 19

Slide 19 text

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

Slide 20

Slide 20 text

ObjectSpace

Slide 21

Slide 21 text

ObjectSpace.count_objects # { # :TOTAL => 14716, # :FREE => 420, # :T_OBJECT => 10, # :T_CLASS => 481, # ... # } ObjectSpace.each_object(Pony) { |obj| puts obj } # >> #, # ObjectSpace.each_object(Meme) { |obj| puts obj } # >> Pony

Slide 22

Slide 22 text

“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)

Slide 23

Slide 23 text

Das Verändern von Elementen des Programms zur Laufzeit z.B. durch … … Hinzufügen … Ändern oder Entfernen Reflection beschreibt also auch noch …

Slide 24

Slide 24 text

# 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!'

Slide 25

Slide 25 text

Beispiel

Slide 26

Slide 26 text

Enumerationen Datentyp mit festem Wertebereich Wertebereich wird bei Deklaration festgelegt Wertebereich ist sortiert z.B.: Farben, Städte, Länder

Slide 27

Slide 27 text

enum "Colors", %w(Red Blue Yellow) Colors.each { |color| puts color.name } # Red # Blue # Yellow # … Colors::Red.name # >> Colors::Red Want:

Slide 28

Slide 28 text

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

Slide 29

Slide 29 text

Dinge löschen …

Slide 30

Slide 30 text

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!'

Slide 31

Slide 31 text

Typen zur Laufzeit ermitteln Konstanten, Objekte & Methoden dynamisch finden dynamisch aufrufen dynamisch manipulieren und löschen! Reflection ermöglicht Meta-Programming

Slide 32

Slide 32 text

One More Thing …

Slide 33

Slide 33 text

No content

Slide 34

Slide 34 text

Controller, View-Variablen, ...?

Slide 35

Slide 35 text

{{@title}}

Welcome to Ruby is Magic

Today we welcome you to episode #{{@episode[:number]}} - {{@episode[:title]}}

{{@episode[:description]}}

Template

Slide 36

Slide 36 text

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

Slide 37

Slide 37 text

“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

Slide 38

Slide 38 text

“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

Slide 39

Slide 39 text

$ curl http://localhost:9292 Ruby is Magic

Welcome to Ruby is Magic

Today we welcome you to episode #9 - Reflections

In this brand new episode we gonna show you the magic of reflections in Ruby!

Slide 40

Slide 40 text

Thanks! Q & A? Dirk Breuer / @railsbros_dirk Sebastian Cohnen / @tisba ? “My Little Pony” © Hasbro Studios and DHX Media Vancouver rubyismagic.de