class Conference
puts "Hello world (open)"
def venue
end
# …
end
# Hello world (open)
# => nil
Slide 20
Slide 20 text
class Conference < Event
end
> c = Conference.new
> c.class
=> Conference
> c.class.superclass
Slide 21
Slide 21 text
class Conference < Event
end
> c = Conference.new
> c.class
=> Conference
> c.class.superclass
=> ChunkyBacon
Slide 22
Slide 22 text
class ChunkyBacon
end
Event = ChunkyBacon
class Conference < Event
end
> c = Conference.new
> c.class
=> Conference
> c.class.superclass
=> ChunkyBacon
Slide 23
Slide 23 text
def gimme_a_class
[Array, Hash, String][rand(3)]
end
class Conference < gimme_a_class()
end
> c = Conference.new
> c.class
=> Conference
> c.class.superclass
=> ChunkyBacon
Slide 24
Slide 24 text
Open classes
class String
alias_method :old_reverse, :reverse
def reverse
old_reverse.upcase
end
end
> speaker = "Gary"
> speaker.reverse
=> "YRAG"
Slide 25
Slide 25 text
Everything is an object
> String.instance_method(:reverse)
=> #
Slide 26
Slide 26 text
Even classes
Slide 27
Slide 27 text
Wait, what?
Slide 28
Slide 28 text
But, classes have
class methods. They
are special.
Slide 29
Slide 29 text
No.
Slide 30
Slide 30 text
class Conference
def self.in_finland
# return conferences in Finland
end
end
Slide 31
Slide 31 text
Singleton methods
def speaker.talk_length
@talk_length ||= 30
end
Defined for a single object
Slide 32
Slide 32 text
Ruby method lookup
Right, then up
Slide 33
Slide 33 text
Where are singleton
methods sitting?
Slide 34
Slide 34 text
Singleton class
aka ghost class,
eigenclass, metaclass
anonymous class below object's own
class
Slide 35
Slide 35 text
No content
Slide 36
Slide 36 text
Singleton class
Just a regular class, except
» Hidden from the generic class hierarchy
» Cannot be inherited directly
» Only ever has a single instance of itself
Slide 37
Slide 37 text
So, what are class
methods?
Slide 38
Slide 38 text
So, what are class
methods?
Singleton methods for the
class object itself
Slide 39
Slide 39 text
So, what are class
methods?
Singleton methods for the
class object itself
Residing in the singleton class of the
class object
Slide 40
Slide 40 text
No content
Slide 41
Slide 41 text
Singleton classes
are classes and
classes are objects,
so…
Slide 42
Slide 42 text
…a singleton class
must have its own
singleton class
eval
meth = "my_method"
eval <<-END
def #{meth}
"foo"
end
END
Slide 48
Slide 48 text
eval
» Just executes a line of code
» Super powerful…
» …and dangerous in wrong hands
» Code injection hazard
Slide 49
Slide 49 text
instance_eval
» Can also take a string, but also a code block…
» …which it then executes in the scope of the
receiver.
» Methods will become class methods (because self ==
the class)
obj.instance_eval do
self # => obj
@v # => obj's instance var
end
Slide 50
Slide 50 text
instance_eval
class Turtle
def move(&block)
instance_eval(&block)
end
def right(n); end;
# …
end
t = Turtle.new
t.move do
right(3)
up
left(2)
down
end
Slide 51
Slide 51 text
class_eval
» Can only be called for classes and modules
» creates instance methods
» can be used to do stuff inside the class
definition
[String, Array, Hash].each do |cls|
cls.class_eval { include HelloWorld }
end
Slide 52
Slide 52 text
define_method
» Create a method dynamically
» Can be put inside other methods
class Cat < Animal
[:leg, :head, :tail].each do |part|
define_method(part) do
# …
end
end
end
Slide 53
Slide 53 text
method_missing
The catch-all method
» Called whenever a method is not found in the
inheritance chain.
» By default throws a NoMethodError.
» Can be modified to catch any method call, thus
“creating” a ghost method
» The name of which you don't have to even know.
Slide 54
Slide 54 text
method_missing
class Speaker
def method_missing(met, *args)
if met.to_s == "speak"
"I might as well say something: #{args[0]}"
else
super
end
end
end
gary = Speaker.new
gary.talk("Destroy it") # => NoMethodError
gary.speak("Just destroy it!")
# => "I might as well say something: Just destroy it!"
A class method
errrrr...
A singleton method
of the class object
Slide 59
Slide 59 text
class Animal
def self.nattr_accessor(*meths)
meths.each do |meth|
# getter
define_method(meth) do
instance_variable_get("@#{meth}")
end
# setter
define_method("#{meth}=") do |wut|
instance_variable_set("@#{meth}", wut)
end
end
end
end
Slide 60
Slide 60 text
class Cat < Animal
nattr_accessor :legs, :diet
end
c = Cat.new
c.legs = 4
c.diet = "Small birds"
c.legs # => 4
c.diet # => "Small birds"
Slide 61
Slide 61 text
# Making it more reusable
class Object
def self.nattr_accessor(*meths)
meths.each do |meth|
# getter
define_method(meth) do
instance_variable_get("@#{meth}")
end
# setter
define_method("#{meth}=") do |wut|
instance_variable_set("@#{meth}", wut)
end
end
end
end
Slide 62
Slide 62 text
module Nattr
def nattr_accessor(*meths)
meths.each do |meth|
# getter
define_method(meth) do
instance_variable_get("@#{meth}")
end
# setter
define_method("#{meth}=") do |wut|
instance_variable_set("@#{meth}", wut)
end
end
end
end
Slide 63
Slide 63 text
class Animal
include Nattr
end
Won't work (creates instance methods)
Slide 64
Slide 64 text
class Animal
extend Nattr
end
class Cat < Animal
nattr_accessor :legs, :diet
end
c = Cat.new
c.legs = 4
c.diet = "Mice"
c.legs
c.diet
Slide 65
Slide 65 text
Problems with
metaprogramming
Slide 66
Slide 66 text
Abstraction
and
Indirection
Code can become harder to
» Read
» Debug
» Search for
Slide 67
Slide 67 text
Powertool
Apply with care
Use when you need it, not
when you can
Slide 68
Slide 68 text
Where now?
Only scratched the
surface
Slide 69
Slide 69 text
Dave Thomas's
screencasts at Prag
Prog
A bit dated (1.8) but lay a solid
foundation
Paolo Perrotta's
Metaprogramming
Ruby
Slide 70
Slide 70 text
Read the source, Luke
Any non-trivial Ruby
application is bound to
have a bunch of
metaprogramming
sprinkled in.