Книга: Metaprogramming Ruby 2
Назад: Appendix 3: Spell Book
Дальше: You May Be Interested In…

The Spells

Around Alias

Call the previous, aliased version of a method from a redefined method.

​ 
​class​ String
​ 
alias_method :old_reverse, :reverse
​ 
​ 
​def​ reverse
​ 
​"x​#{old_reverse}​x"​
​ 
​end​
​ 
​end​
​ 
​ 
​"abc"​.reverse ​# => "xcbax"​

For more information, see page .

Blank Slate

Remove methods from an object to turn them into Ghost Methods ().

​ 
​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, see page .

Class Extension

Define class methods by mixing a module into a class’s singleton class (a special case of Object Extension ()).

​ 
​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, see page .

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, see page .

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, see page .

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, see page .

Code Processor

Process Strings of Code () from an external source.

​ 
File.readlines(​"a_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, see page .

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, see page .

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, see page .

Dynamic Dispatch

Decide which method to call at runtime.

​ 
method_to_call = :reverse
​ 
obj = ​"abc"​
​ 
​ 
obj.send(method_to_call) ​# => "cba"​

For more information, see page .

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, see page .

Dynamic Proxy

Dynamically forward method calls to another object.

​ 
​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, see page .

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, see page .

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, see page .

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, see page .

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, see page .

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, see page .

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, see page .

Monkeypatch

Change the features of an existing class.

​ 
​"abc"​.reverse ​# => "cba"​
​ 
​ 
​class​ String
​ 
​def​ reverse
​ 
​"override"​
​ 
​end​
​ 
​end​
​ 
​ 
​"abc"​.reverse ​# => "override"​

For more information, see page .

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, see page .

Nil Guard

Override a reference to nil with an “or.”

​ 
x = nil
​ 
y = x || ​"a value"​ ​# => "a value"​

For more information, see page .

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, see page .

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, see page .

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, see page .

Refinement

Patch a class until the end of the file, or 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, see page .

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, see page .

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 at level 2>​
​ 
​end​

For more information, see page .

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, see page .

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, see page .

Shared Scope

Share variables among multiple contexts in the same Flat Scope ().

​ 
lambda {
​ 
shared = 10
​ 
self.class.class_eval ​do​
​ 
define_method :counter ​do​
​ 
shared
​ 
​end​
​ 
define_method :down ​do​
​ 
shared -= 1
​ 
​end​
​ 
​end​
​ 
}.call
​ 
​ 
counter ​# => 10​
​ 
3.times { down }
​ 
counter ​# => 7​

For more information, see page .

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, see page .

String of Code

Evaluate a string of Ruby code.

​ 
my_string_of_code = ​"1 + 1"​
​ 
eval(my_string_of_code) ​# => 2​

For more information, see page .

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, see page .

Назад: Appendix 3: Spell Book
Дальше: You May Be Interested In…