March 2014 update: I updated this list to match the second edition of the book. I added three spells that are new to Ruby 2.x: Refinement, Refinement Wrapper and Prepended Wrapper. I also dropped a few spells that don't seem to be as relevant today as they used to be, at least in the context of this book: Argument Array, Named Arguments, Pattern Dispatch and Class Extension Mixin.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# =================== | |
# Spell: Around Alias | |
# =================== | |
# Call the previous, aliased version of a method from a redefined method. | |
class String | |
alias :old_reverse :reverse | |
def reverse | |
"x#{old_reverse}x" | |
end | |
end | |
"abc".reverse # => "xcbax" | |
# For more information: http://www.pragprog.com/titles/ppmetr/metaprogramming-ruby |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# =================== | |
# Spell: Blank Slate | |
# =================== | |
# Remove methods from an object to turn them into Ghost Methods (http://gist.github.com/534776). | |
class C | |
def method_missing(name, *args) | |
"a Ghost Method" | |
end | |
end | |
obj = C.new | |
obj.to_s # => "#<C:0x007fbb2a10d2f8>" | |
class D < BasicObject | |
def method_missing(name, *args) | |
"a Ghost Method" | |
end | |
end | |
blank_slate = D.new | |
blank_slate.to_s # => "a Ghost Method" | |
# For more information: http://www.pragprog.com/titles/ppmetr/metaprogramming-ruby |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# ====================== | |
# Spell: Class Extension | |
# ====================== | |
# Define class methods by mixing a module into a class’s singleton class | |
# (a special case of Object Extension - http://gist.github.com/534667). | |
class C; end | |
module M | |
def my_method | |
'a class method' | |
end | |
end | |
class << C | |
include M | |
end | |
C.my_method # => "a class method" | |
# For more information: http://www.pragprog.com/titles/ppmetr/metaprogramming-ruby |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# ============================== | |
# Spell: Class Instance Variable | |
# ============================== | |
# Store class-level state in an instance variable of the Class object. | |
class C | |
@my_class_instance_variable = "some value" | |
def self.class_attribute | |
@my_class_instance_variable | |
end | |
end | |
C.class_attribute # => "some value" | |
# For more information: http://www.pragprog.com/titles/ppmetr/metaprogramming-ruby |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# ================== | |
# Spell: Class Macro | |
# ================== | |
# Use a class method in a class definition. | |
class C; end | |
class << C | |
def my_macro(arg) | |
"my_macro(#{arg}) called" | |
end | |
end | |
class C | |
my_macro :x # => "my_macro(x) called" | |
end | |
# For more information: http://www.pragprog.com/titles/ppmetr/metaprogramming-ruby |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# ================= | |
# Spell: Clean Room | |
# ================= | |
# Use an object as an environment in which to evaluate a block. | |
class CleanRoom | |
def a_useful_method(x); x * 2; end | |
end | |
CleanRoom.new.instance_eval { a_useful_method(3) } # => 6 | |
# For more information: http://www.pragprog.com/titles/ppmetr/metaprogramming-ruby |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# ===================== | |
# Spell: Code Processor | |
# ===================== | |
# Process Strings of Code (http://gist.github.com/535047) from an external source. | |
File.readlines("file_containing_lines_of_ruby.txt").each do |line| | |
puts "#{line.chomp} ==> #{eval(line)}" | |
end | |
# >> 1 + 1 ==> 2 | |
# >> 3 * 2 ==> 6 | |
# >> Math.log10(100) ==> 2.0 | |
# For more information: http://www.pragprog.com/titles/ppmetr/metaprogramming-ruby |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
1 + 1 | |
3 * 2 | |
Math.log10(100) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# ==================== | |
# Spell: Context Probe | |
# ==================== | |
# Execute a block to access information in an object’s context. | |
class C | |
def initialize | |
@x = "a private instance variable" | |
end | |
end | |
obj = C.new | |
obj.instance_eval { @x } # => "a private instance variable" | |
# For more information: http://www.pragprog.com/titles/ppmetr/metaprogramming-ruby |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# ========================== | |
# Spell: Deferred Evaluation | |
# ========================== | |
# Store a piece of code and its context in a proc or lambda for evaluation later. | |
class C | |
def store(&block) | |
@my_code_capsule = block | |
end | |
def execute | |
@my_code_capsule.call | |
end | |
end | |
obj = C.new | |
obj.store { $X = 1 } | |
$X = 0 | |
obj.execute | |
$X # => 1 | |
# For more information: http://www.pragprog.com/titles/ppmetr/metaprogramming-ruby |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# ======================= | |
# Spell: Dynamic Dispatch | |
# ======================= | |
# Decide which method to call at runtime. | |
method_to_call = :reverse | |
obj = "abc" | |
obj.send(method_to_call) # => "cba" | |
# For more information: http://www.pragprog.com/titles/ppmetr/metaprogramming-ruby |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# ===================== | |
# Spell: Dynamic Method | |
# ===================== | |
# Decide how to define a method at runtime. | |
class C | |
end | |
C.class_eval do | |
define_method :my_method do | |
"a dynamic method" | |
end | |
end | |
obj = C.new | |
obj.my_method # => "a dynamic method" | |
# For more information: http://www.pragprog.com/titles/ppmetr/metaprogramming-ruby |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# ==================== | |
# Spell: Dynamic Proxy | |
# ==================== | |
# Forward to another object any messages that don’t match a method. | |
class MyDynamicProxy | |
def initialize(target) | |
@target = target | |
end | |
def method_missing(name, *args, &block) | |
"result: #{@target.send(name, *args, &block)}" | |
end | |
end | |
obj = MyDynamicProxy.new("a string") | |
obj.reverse # => "result: gnirts a" | |
# For more information: http://www.pragprog.com/titles/ppmetr/metaprogramming-ruby |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# ================= | |
# Spell: Flat Scope | |
# ================= | |
# Use a closure to share variables between two scopes. | |
class C | |
def an_attribute | |
@attr | |
end | |
end | |
obj = C.new | |
a_variable = 100 | |
# flat scope: | |
obj.instance_eval do | |
@attr = a_variable | |
end | |
obj.an_attribute # => 100 | |
# For more information: http://www.pragprog.com/titles/ppmetr/metaprogramming-ruby |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# =================== | |
# Spell: Ghost Method | |
# =================== | |
# Respond to a message that doesn’t have an associated method. | |
class C | |
def method_missing(name, *args) | |
name.to_s.reverse | |
end | |
end | |
obj = C.new | |
obj.my_ghost_method # => "dohtem_tsohg_ym" | |
# For more information: http://www.pragprog.com/titles/ppmetr/metaprogramming-ruby |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# ================== | |
# Spell: Hook Method | |
# ================== | |
# Override a method to intercept object model events. | |
$INHERITORS = [] | |
class C | |
def self.inherited(subclass) | |
$INHERITORS << subclass | |
end | |
end | |
class D < C | |
end | |
class E < C | |
end | |
class F < E | |
end | |
$INHERITORS # => [D, E, F] | |
# For more information: http://www.pragprog.com/titles/ppmetr/metaprogramming-ruby |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# ==================== | |
# Spell: Kernel Method | |
# ==================== | |
# Define a method in module Kernel to make the method available to all objects. | |
module Kernel | |
def a_method | |
"a kernel method" | |
end | |
end | |
a_method # => "a kernel method" | |
# For more information: http://www.pragprog.com/titles/ppmetr/metaprogramming-ruby |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# ============================= | |
# Spell: Lazy Instance Variable | |
# ============================= | |
# Wait until the first access to initialize an instance variable. | |
class C | |
def attribute | |
@attribute = @attribute || "some value" | |
end | |
end | |
obj = C.new | |
obj.attribute # => "some value" | |
# For more information: http://www.pragprog.com/titles/ppmetr/metaprogramming-ruby |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# =================== | |
# Spell: Mimic Method | |
# =================== | |
# Disguise a method as another language construct. | |
def BaseClass(name) | |
name == "string" ? String : Object | |
end | |
class C < BaseClass "string" # a method that looks like a class | |
attr_accessor :an_attribute # a method that looks like a keyword | |
end | |
obj = C.new | |
obj.an_attribute = 1 # a method that looks like an attribute | |
# For more information: http://www.pragprog.com/titles/ppmetr/metaprogramming-ruby |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# ================== | |
# Spell: Monkeypatch | |
# ================== | |
# Change the features of an existing class. | |
"abc".reverse # => "cba" | |
class String | |
def reverse | |
"override" | |
end | |
end | |
"abc".reverse # => "override" | |
# For more information: http://www.pragprog.com/titles/ppmetr/metaprogramming-ruby |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# ================ | |
# Spell: Namespace | |
# ================ | |
# Define constants within a module to avoid name clashes. | |
module MyNamespace | |
class Array | |
def to_s | |
"my class" | |
end | |
end | |
end | |
Array.new # => [] | |
MyNamespace::Array.new # => my class | |
# For more information: http://www.pragprog.com/titles/ppmetr/metaprogramming-ruby |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# ================ | |
# Spell: Nil Guard | |
# ================ | |
# Override a reference to nil with an “or.” | |
x = nil | |
y=x || "avalue" # =>"avalue" | |
# For more information: http://www.pragprog.com/titles/ppmetr/metaprogramming-ruby |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# ======================= | |
# Spell: Object Extension | |
# ======================= | |
# Define Singleton Methods by mixing a module into an object’s singleton class. | |
obj = Object.new | |
module M | |
def my_method | |
'a singleton method' | |
end | |
end | |
class << obj | |
include M | |
end | |
obj.my_method # => "a singleton method" | |
# For more information: http://www.pragprog.com/titles/ppmetr/metaprogramming-ruby |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# ================= | |
# Spell: Open Class | |
# ================= | |
# Modify an existing class. | |
class String | |
def my_string_method | |
"my method" | |
end | |
end | |
"abc".my_string_method # => "my method" | |
# For more information: http://www.pragprog.com/titles/ppmetr/metaprogramming-ruby |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# ======================== | |
# Spell: Prepended Wrapper | |
# ======================== | |
# Call a method from its prepended override. | |
module M | |
def reverse | |
"x#{super}x" | |
end | |
end | |
String.class_eval do | |
prepend M | |
end | |
"abc".reverse # => "xcbax" | |
# For more information: http://www.pragprog.com/titles/ppmetr/metaprogramming-ruby |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# ================= | |
# Spell: Refinement | |
# ================= | |
# Patch a class until the end of the file, or (from Ruby 2.1) until the end of the including module. | |
module MyRefinement | |
refine String do | |
def reverse | |
"my reverse" | |
end | |
end | |
end | |
"abc".reverse # => "cba" | |
using MyRefinement | |
"abc".reverse # => "my reverse" | |
# For more information: http://www.pragprog.com/titles/ppmetr/metaprogramming-ruby |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# ========================= | |
# Spell: Refinement Wrapper | |
# ========================= | |
# Call an unrefined method from its refinement. | |
module StringRefinement | |
refine String do | |
def reverse | |
"x#{super}x" | |
end | |
end | |
end | |
using StringRefinement | |
"abc".reverse # => "xcbax" | |
# For more information: http://www.pragprog.com/titles/ppmetr/metaprogramming-ruby |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# ============== | |
# Spell: Sandbox | |
# ============== | |
# Execute untrusted code in a safe environment. | |
def sandbox(&code) | |
proc { | |
$SAFE = 2 | |
yield | |
}.call | |
end | |
begin | |
sandbox { File.delete 'a_file' } | |
rescue Exception => ex | |
ex # => #<SecurityError: Insecure operation `delete' at level 2> | |
end | |
# For more information: http://www.pragprog.com/titles/ppmetr/metaprogramming-ruby |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# ================= | |
# Spell: Scope Gate | |
# ================= | |
# Isolate a scope with the class, module, or def keyword. | |
a = 1 | |
defined? a # => "local-variable" | |
module MyModule | |
b = 1 | |
defined? a # => nil | |
defined? b # => "local-variable" | |
end | |
defined? a # => "local-variable" | |
defined? b # => nil | |
# For more information: http://www.pragprog.com/titles/ppmetr/metaprogramming-ruby |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# ================= | |
# Spell: Self Yield | |
# ================= | |
# Pass self to the current block. | |
class Person | |
attr_accessor :name, :surname | |
def initialize | |
yield self | |
end | |
end | |
joe = Person.new do |p| | |
p.name = 'Joe' | |
p.surname = 'Smith' | |
end | |
# For more information: http://www.pragprog.com/titles/ppmetr/metaprogramming-ruby |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# ======================= | |
# Spell: Singleton Method | |
# ======================= | |
# Define a method on a single object. | |
obj = "abc" | |
class << obj | |
def my_singleton_method | |
"x" | |
end | |
end | |
obj.my_singleton_method # => "x" | |
# For more information: http://www.pragprog.com/titles/ppmetr/metaprogramming-ruby |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# ===================== | |
# Spell: String of Code | |
# ===================== | |
# Evaluate a string of Ruby code. | |
my_string_of_code = "1 + 1" | |
eval(my_string_of_code) # => 2 | |
# For more information: http://www.pragprog.com/titles/ppmetr/metaprogramming-ruby |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# ===================== | |
# Spell: Symbol to Proc | |
# ===================== | |
# Convert a symbol to a block that calls a single method. | |
[1, 2, 3, 4].map(&:even?) # => [false, true, false, true] | |
# For more information: http://www.pragprog.com/titles/ppmetr/metaprogramming-ruby |