Advanced Rails - Building Industrial-Strength Web Apps in Record Time

(Tuis.) #1

18 | Chapter 1: Foundational Techniques


class Object
# The hidden singleton lurks behind everyone
def metaclass; class << self; self; end; end
def meta_eval &blk; metaclass.instance_eval &blk; end

# Adds methods to a metaclass
def meta_def name, &blk
meta_eval { define_method name, &blk }
end

# Defines an instance method within a class
def class_def name, &blk
class_eval { define_method name, &blk }
end
end

This library defines four methods on every object:


metaclass
Refers to the singleton class of the receiver (self).


meta_eval
The equivalent ofclass_evalfor singleton classes. Evaluates the given block in
the context of the receiver’s singleton class.


meta_def
Defines a method within the receiver’s singleton class. If the receiver is a class or
module, this will create a class method (instance method of the receiver’s single-
ton class).


class_def
Defines an instance method in the receiver (which must be a class or module).


Metaid’s convenience lies in its brevity. By using a shorthand for referring to and
augmenting metaclasses, your code will become clearer rather than being littered
with constructs likeclass << self; self; end. The shorter and more readable these
techniques are, the more likely you are to use them appropriately in your programs.


This example shows how we can use Metaid to examine and simplify our singleton
class hacking:


class Person
def name; "Bob"; end
def self.species; "Homo sapiens"; end
end

Class methods are added as instance methods of the singleton class:


Person.instance_methods(false) # => ["name"]
Person.metaclass.instance_methods -
Object.metaclass.instance_methods # => ["species"]

Using the methods from Metaid, we could have written the method definitions as:


Person.class_def(:name) { "Bob" }
Person.meta_def(:species) { "Homo sapiens" }
Free download pdf