You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
WARNING!: Be careful not to override existing functionality by mistake.
Constants
In Ruby any reference that begins with an uppercase letter, including the names of
classes and modules, is a constant. The scope of constants follows its own special rules:
The previous code generates the following tree of constants:
MyModule
MyClass
MyConstant
MyConstant
All the constants in a program are arranged in a tree similar to a file system,
where modules (and classes) are directories and regular constants are files.
Like in a file system, you can have multiple files with the same name, as long
as they live in different directories. You can even refer to a constant by its
path, as you’d do with a file.
Constants’ paths use a double colon as a separator:
W='root constant'moduleRW='outer module constant'moduleMW='inner module constant'
::W# => "root constant"classCX='a class constant'
::W# => "root constant"R::W# => "outer module constant"endC::X# => "a class constant"endM::W# => "inner module constant"endR::W# => "outer module constant"R::M::W# => "inner module constant"R::M::C::X# => "a class constant"
If you’re sitting deep inside the tree of constants, you can provide the absolute
path to an outer constant by using a leading double colon as root:
Y='a root-level constant'moduleMY='a constant in M'Y# => "a constant in M"
::Y# => "a root-level constant"end
The Module class also provides an instance method and a class method that,
confusingly, are both called constants. Module#constants returns all constants in
the current scope, like your file system’s ls command (or dir command, if you’re
running Windows). Module.constants returns all the top-level constants in the
current program, including class names:
moduleMY='a constant in M'classCX='a constant'endC::X# => "a constant"endM.constants# => [:C, :Y]Module.constants.include?:Object# => trueModule.constants.include?:Module# => true
Finally, if you need the current path, check out Module.nesting:
The problems with Ghost Methods boil down to the fact that they are not
really methods: instead, they’re just a way to intercept method calls. Because
of this fact, they behave different than actual methods. For example, they
don’t appear in the list of names returned by Object#methods. In contrast,
Dynamic Methods are just regular methods that happened to be defined with
define_method instead of def, and they behave the same as any other method.
There are times when Ghost Methods are your only viable option. This usually
happens when you have a large number of method calls, or when you don’t
know what method calls you might need at runtime (Like the Builder example).
Ghost Methods can be dangerous. You can
avoid most of their problems by following a few basic recommendations (always
call super, always redefine respond_to_missing?)—but even then, Ghost Methods
can sometimes cause puzzling bugs.
There is is a simple rule of thumb that you can follow when in doubt:
use Dynamic Methods if you can, and Ghost Methods if you have to.
Dynamic Methods
When you call a method, you’re actually sending a message to an object:
obj.send(:my_method,3)# => 6
the first argument to send is the message that you’re sending to the object —that is, a
symbol or a string representing the name of a method. Any remaining arguments (and the block, if one
exists) are simply passed on to the method.
Why would you use send instead of the plain old dot notation? Because with
send, the name of the method that you want to call becomes just a regular
argument. You can wait literally until the very last moment to decide which
method to call, while the code is running. This technique is called Dynamic
Dispatch, and you’ll find it wildly useful.
define_method is executed within MyClass, so my_method is defined as an instance
method of MyClass. This technique of defining a method at runtime is called a Dynamic Method.
There is one important reason to use define_method over the more familiar def
keyword: define_method allows you to decide the name of the defined method at runtime.
The refactoring example of the chapter using Dynamic Methods:
classComputerdefinitialize(computer_id,data_source)@id=computer_id@data_source=data_source# Extracting the names of all components:# First, if you pass a block to Array#grep, the block is evaluated for each element# that matches the regular expression. Second, the string matching the# parenthesized part of the regular expression is stored in the global variable# $1. So, if data_source has methods named get_cpu_info and get_mouse_info, this code# ultimately calls Computer.define_component twice, with the strings "cpu" and "mouse".# Note that define_method works equally well with a string or a symbol. # As a bonus, you don’t even have to write or maintain the list of components. If someone # adds a new component to DS, the Computer class will support it automatically.data_source.methods.grep(/^get_(.*)_info$/){Computer.define_component $1 }enddefself.define_component(name)define_method(name)doinfo=@data_source.send"get_#{name}_info",@idprice=@data_source.send"get_#{name}_price",@idresult="#{name.capitalize}: #{info} ($#{price})"return"* #{result}"ifprice >= 100resultendendend
Method Missing
Method_missing is a private instance method of BasicObject that every object inherits.
nick.send:method_missing,:my_method# => NoMethodError: undefined method `my_method' for #<Lawyer:0x007f801b0f4978>
you can override it to intercept unknown messages. Each message landing on
method_missing’s desk includes the name of the method that was called, plus
any arguments and blocks associated with the call.
classLawyerdefmethod_missing(method, *args)puts"You called: #{method}(#{args.join(', ')})"puts"(You also passed it a block)"ifblock_given?endendbob=Lawyer.newbob.talk_simple('a','b')do# a blockend# => You called: talk_simple(a, b) \n (You also passed it a block)
Overriding method_missing allows you to call methods that don’t really exist.
###Ghost Methods
When you need to define many similar methods, you can spare yourself the
definitions and just respond to calls through method_missing. This is like saying
to the object, “If they ask you something and you don’t understand, do this.”
From the ```’s side, a message that’s processed by method_missing looks like
a regular call—but on the receiver’s side, it has no corresponding method.
This trick is called a Ghost Method.
#####The Hashie Gem Example
require'hashie'# A Mash is a more powerful version of Ruby’s standard OpenStruct class: a hash-like object# whose attributes work like Ruby variables. If you want a new attribute, just# assign a value to the attribute, and it will spring into existence.# Hashie::Mash is a subclass of Ruby’s Hash, and its attributesare actually Ghost Methods.icecream=Hashie::Mash.newicecream.flavor="strawberry"icecream.flavor# => "strawberry"
Looking at Hasie::Mash.method_missing:
moduleHashieclassMash < Hashie::Hashdefmethod_missing(method_name, *args, &blk)# If the name of the called method is the name of a key in the hash (such as# flavor), then Hashie::Mash#method_missing simply calls the [] method to return the# corresponding value. returnself.[](method_name, &blk)ifkey?(method_name)# If the name ends with a "=", then method_missing chops# off the "=" at the end to get the attribute name and then stores its value.match=method_name.to_s.match(/(.*?)([?=!]?)$/)casematch[2]when"="self[match[1]]=args.first# ...else# if the name of the called method doesn’t match any of these cases, then# method_missing just returns a default value.default(method_name, *args, &blk)endend# ...endend
###Dynamic Proxies
Ghost Methods are often used in wrappers for something else (maybe another object, a web service,
or code written in a different language). They collect method calls through method_missing and
forward them to the wrapped object.
#####The Ghee Gem Example
classGheeclassResourceProxy# ...# when you call a method that just reads from an attribute, such as# url or description, that call ends into Ghee::ResourceProxy#method_missing. In turn,# method_missing forwards the call to the object returned by Ghee::ResourceProxy#subject.defmethod_missing(message, *args, &block)subject.send(message, *args, &block)end# this method makes an HTTP call to the GitHub API, receives the GitHub object in JSON format # and converts it to a hash-like object which is actually a Hashie::Mashdefsubject@subject ||= connection.get(path_prefix){|req| req.params.merge!params}.bodyendendend
Here is how Ghee uses this class:
classGheemoduleAPImoduleGists# A proxy does two things. First, it implements methods# that require specific code, such as star. Second, it forwards methods that# just read data, such as url, to the wrapped hash.classProxy < ::Ghee::ResourceProxy# When you call a method that changes the state of an object, such as# Ghee::API::Gists#star, Ghee places an HTTP call to the corresponding GitHub URL.defstarconnection.put("#{path_prefix}/star").status == 204end# ...endendend
An object such as Ghee::ResourceProxy, that catches Ghost Methods and forwards
them to another object, is called a Dynamic Proxy.
#####respond_to_missing?
If you ask an object whether it responds to a Ghost Method the response wil be false:
Ruby provides a clean mechanism to make respond_to? aware of Ghost Methods.
respond_to? calls a method named respond_to_missing?, that is supposed to return
true if a method is a Ghost Method, so you should override respond_to_missing?
every time you override method_missing
#####const_missing
Rake went through an upgrade path: for a few versions, you could
use either the new class names or the old, non-namespaced names. Rake
allowed you to do that by Monkepatching the Module#const_missing method
When you reference a constant that doesn’t exist, Ruby passes the name of
the constant to const_missing as a symbol. Class names are just constants, so
a reference to an unknown Rake class such as Task was routed to Module#const_missing.
In turn, const_missing warned you that you were using an obsolete class name.
require'rake'task_class=Task# => WARNING: Deprecated reference to top-level constant 'Task' found [...]# => Use --classic-namespace on rake command# => or 'require "rake/classic_namespace"' in Rakefile
After the warning, you automatically got the new, namespaced class name
in place of the old one:
task_class# => Rake::Task
#####WARNING!: infinite loops when using method_missing
classRoulettedefmethod_missing(name, *args)person=name.to_s.capitalize3.timesdonumber=rand(10) + 1puts"#{number}..."end"#{person} got a #{number}"endendnumber_of=Roulette.newputsnumber_of.bob# => roulette_failure.rb:7:in `method_missing': stack level too deep (SystemStackError)
In the code above since the variable number is inside the block by the time it is called it doen't exists
so the code will try to call a method called number on the object which doen't exist so the call ends up
in method_missing again thus causing an infinite loop.
This is a common problem with Ghost Methods: since unknown calls become
calls to method_missing, your object might accept a call that’s just plain wrong.
Finding a bug like this one in a large program can be pretty painful.
REMEMBER TO FALL BACK ON BasicObject#method_missing when you get a call you don't know how to handle.
classRoulettedefmethod_missing(name, *args)person=name.to_s.capitalizesuperunless%w[BobFrankBill].include?personnumber=03.timesdonumber=rand(10) + 1puts"#{number}..."end"#{person} got a #{number}"endend
#####WARNING!: existing methods in objects and Blank Slates
When using method missing to redirect messages to other objects problems like the following might come up:
in the previous code you where expecting the call to _my_computer.display to be forwarded to the data_source object and return
the information corresponding the display information of the device in question. However, it returns nil, which means the call
is not getting to the data_source object.
By executing the following
you realize that Object defines a method named display (a seldom-used method
that prints an object on a port and always returns nil). Computer inherits from
Object, so it gets the display method. The call to Computer#display finds a real
method by that name, so it never lands on method_missing. You’re calling a real,
live method instead of a Ghost Method.
This problem tends to crop up with Dynamic Proxies. Whenever the name
of a Ghost Method clashes with the name of a real, inherited method, the
latter wins. If you don’t need the inherited method, you can fix the problem by removing
it.
A skinny class with a minimal number of methods is called a Blank Slate. As it turns out,
Ruby has a ready-made Blank Slate for you to use called BasicObject.
Inheriting from BasicObject is the quicker way to define a Blank Slate in Ruby.
#####Removing specific methods from a class
You can remove a method from a class by using either Module#undef_method or
Module#remove_method. The drastic undef_method removes any method, including
the inherited ones. The kinder remove_method removes the method from the
receiver, but it leaves inherited methods alone.
#####The Builder Example
classBlankSlate# Hide the method named +name+ in the BlankSlate class. Don't# hide +instance_eval+ or any method beginning with "__".defself.hide(name)# ...ifinstance_methods.include?(name._blankslate_as_name) && name !~ /^(__|instance_eval$)/undef_methodnameendend# ...instance_methods.each{ |m| hide(m)}end
Builder doesn’t go as far as removing each and every method from BlankSlate.
It keeps instance_eval (a method that you’ll get to know in the next chapter) and
all the “reserved methods”—methods that are used internally by Ruby, whose
names conventionally begin with a double underscore.
defa_method(a,b)# yield takes care of providing the parameters to the block# if more args are passed to the block than the ones it receives# they will be ignoreda + yield(a,b)end# if less args are passed to the block than the ones specified# the remaining args will be nilla_method(1,2){|x,y| (x + y) * 3}# => 10
Within a method, you can ask Ruby whether the current call includes a block.
You can do that with the Kernel#block_given? method
Blocks are Closures
When you define the block, it simply grabs the bindings that are there at that moment,
and then it carries those bindings along when you pass the block into a method:
as soon as you enter a new scope, the previous
bindings are simply replaced by a new set of bindings.
“Whenever the program changes scope,
some bindings are replaced by a new set of bindings.” Granted, this doesn’t
happen to all the bindings each and every time. For example, if a method
calls another method on the same object, instance variables stay in scope
through the call. In general, though, bindings tend to fall out of scope when
the scope changes.
There are exactly three places where a program leaves the previous scope
behind and opens a new one:
Class definitions
Module definitions
Methods
Scope changes whenever the program enters (or exits) a class or module def-
inition or a method. These three borders are marked by the keywords class,
module, and def, respectively. Each of these keywords acts like a Scope Gate.
There is a subtle difference between class and module on one side and def on
the other. The code in a class or module definition is executed immediately.
Conversely, the code in a method definition is executed later, when you
eventually call the method.
Flattening Scopes
Class.new is a perfect replacement for class. You can also define instance
methods in the class if you pass a block to Class.new
my_var="Success"MyClass=Class.newdo# Now we can print my_var here... puts"#{my_var} in the class definition!"defmy_method# ...but how can we print it here?# no because the def keyword is a scope gate# when the method gets called the variable# won't be availableendend
to access the variable you can use define method method
with a block instead of the def keyword to define the method.
my_var="Success"MyClass=Class.newdo"#{my_var} in the class definition"define_method:my_methoddo"#{my_var} in the method"endendMyClass.new.my_method# => Success in the method
If you replace Scope Gates with method calls, you allow one scope to see
variables from another scope. Technically, this trick should be called nested
lexical scopes, but many Ruby coders refer to it simply as “flattening the scope”.
Sharing Scopes
defdefine_methods# this variable is protected # by the def scope gateshared=0Kernel.send:define_method,:counterdosharedendKernel.send:define_method,:incdo |x|
shared += xendenddefine_methodscounter# => 0inc(4)counter# => 4Spell: SharedScope
BasicObject#instance_eval, which evaluates
a block in the context of an object:
so it can access the receiver’s private methods and instance variables, such as @v.
Even if instance_eval changes self, the block that you pass to instance_eval
can still see the bindings from the place where it’s defined
Are objects used to execute blocks inside of them, just that.
The ideal Clean Room doesn’t have many
methods or instance variables, because the names of those methods and
instance variables could clash with the names in the environment that the
block comes from. For this reason, instances of BasicObject usually make for
good Clean Rooms, because they’re Blank Slates.
Callable Objects
Although most things in Ruby are objects, blocks are not. But why would you
care about that? Imagine that you want to store a block and execute it later.
To do that, you need an object.
A Proc is a block that has been turned into an object. You can create a Proc by passing
the block to Proc.new. Later, you can evaluate the block-turned-object with Proc#call:
inc=Proc.new{|x| x + 1}inc.call(2)# => 3# is the same as:inc=proc{|x| x + 1}inc.call(2)# => 3
This technique is called a Deferred Evaluation.
Ruby provides two Kernel Methods that convert a block to a Proc: lambda and proc.
p=lambda{|x| x + 1}# is the same as:p=->(x){x + 1}
If You want to pass the block to another method (or block) or
you want to convert the block to a Proc you can use the & operator.
However, this argument must be the last in the list of arguments and prefixed by an & sign.
defmath(a,b)yield(a,b)enddefdo_math(a,b, &operation)math(a,b, &operation)enddo_math(2,3){|x,y| x * y}# => 6
The & operator converts a Proc to a block and viceversa.
Procs vs Lambdas
Procs created with lambda actually differ in some respects
from Procs created any other way (You can use the Proc#lambda?
method to check whether the Proc is a lambda).
Procs, Lambdas, and return
The first difference between lambdas and procs is that the return keyword
means different things. In a lambda, return just returns from the lambda:
Procs, Lambdas, and Arity
A particular proc or lambda might have
an arity of two, meaning that it accepts two arguments:
p=Proc.new{|a,b| [a,b]}p.arity# => 2
lambdas tend to be less tolerant than procs (and regular blocks) when it comes to
arguments. Call a lambda with the wrong arity, and it fails with an ArgumentError.
On the other hand, a proc fits the argument list to its own expectations:
If there are too many arguments, a proc drops the excess arguments. If there
are too few arguments, it assigns nil to the missing arguments.
Generally speaking, lambdas are more intuitive than procs because they’re
more similar to methods. They’re pretty strict about arity, and they simply
exit when you call return. For this reason, many Rubyists use lambdas as a
first choice, unless they need the specific features of procs.
A Method object is similar to a block or a lambda. Indeed, you can convert a
Method to a Proc by calling Method#to_proc, and you can convert a block to a
method with define_method. However, there is an important difference between
lambdas and methods: a lambda is evaluated in the scope it’s defined in (it’s
a closure), while a Method is evaluated in the scope of its object.
UnboundMethods are like Methods that have been detached from their original
class or module. You can turn a Method into an UnboundMethod by calling
Method#unbind. You can also get an UnboundMethod directly by calling Module#in-
stance_method. You can’t call an UnboundMethod, but you can use it to generate a normal method
that you can call.
When you use the class keyword, you aren’t just dictating how objects will behave in the future. On the contrary,
you’re actually running code.
Class definitions also return the value of the last statement, just like methods and blocks do:
result=classMyClassselfendresult# => MyClass
Although you can get a reference to the current object through self, there’s no
equivalent keyword to get a reference to the current class. However, in most
situations it’s easy to keep track of the current class just by looking at the
code:
At the top level of your program, the current class is Object, the class of
main. (That’s why, if you define a method at the top level, that method
becomes an instance method of Object).
In a method, the current class is the class of the current object. (Try
defining a method inside another method with def, and you’ll see that the
new method is defined on the class of self. This information is probably
going to win you some Ruby trivia contest).
When you open a class with the class keyword (or a module with the module
keyword), that class becomes the current class.
As you know, wherever you are in a Ruby program, you always have a current
object: self. Likewise, you always have a current class (or module). When you
define a method, that method becomes an instance method of the current
class.
How can you open the class if you don’t know its name? You need some way
other than the class keyword to change the current class. Enter the class_eval
method.
class_eval()
Module#class_eval (also known by its alternate name, module_eval) evaluates a
block in the context of an existing class:
Instance_eval only changes self, while class_eval changes both self and the current class.
(This is not the whole truth: instance_eval does also change the current class,
but you’ll have to wait for Singleton Classes and instance_eval(), on page 127 to learn how exactly.)
Module#class_eval is actually more flexible than class. You can use class_eval on
any variable that references the class, while class requires a constant. Also,
class opens a new scope, losing sight of the current bindings, while class_eval
has a Flat Scope (83).This means you can reference variables from the outer scope in a class_eval block.
Finally, just like instance_eval has a twin method called instance_exec, mod-
ule_eval/class_eval also has an equivalent module_exec/class_exec method that can
pass extra parameters to the block.
Use instance_eval to open an object that is not a class, and class_eval to open a class
definition and define methods with def. But what if you want to open an object
that happens to be a class (or module) to do something else than using def?
Should you use instance_eval or class_eval then?
If all you want is to change self, then both instance_eval and class_eval will do the
job nicely. However, you should pick the method that best communicates
your intentions. If you’re thinking “I want to open this object, and I don’t
particularly care it’s a class,” then instance_eval is fine. If you’re thinking “I want
an Open Class (14) here,” then class_eval is almost certainly a better match.
#####Current Class Wrap-up
The Ruby interpreter always keeps a reference to the current class (or
module). All methods defined with def become instance methods of the
current class.
In a class definition, the current object self and the current class are the
same—the class being defined.
If you have a reference to the class, you can open the class with class_eval
(or module_eval).
#####Class Instance Variables
The Ruby interpreter assumes that all instance variables belong to the current
object self. This is also true in a class definition:
classMyClass@my_var=1end
In a class definition, the role of self belongs to the class itself, so the instance
variable @my_var belongs to the class. Don’t get confused. Instance variables
of the class are different from instance variables of that class’s objects as you
can see in the following example:
The previous code defines two instance variables. Both happen to be named
@my_var, but they’re defined in different scopes, and they belong to different
objects.
A Class Instance Variable can be accessed only by the class itself—
not by an instance or by a subclass. Class variables are different from Class Instance Variables, because they can be
accessed by subclasses and by regular instance methods.
Example:
classLoandefinitialize(book)@book=book@time=Time.nowenddefto_s"#{@book.upcase} loaned on #{@time}"endend
Loan stores the title of a book and the time when it was loaned—that is, the
time when the object was created. You’d like to write a unit test for the to_s
method, but to write that test, you’d have to know the exact time when the
object was created. This is a common problem with code that relies on Time
or Date: such code returns a different result every time it runs, so you don’t
know what result to test for.
In production, Loan always uses the Time class, because @time_class is always
nil. By contrast, the unit tests can rely on a fake time class that always returns the same value.
classFakeTimedefself.now;'Mon Apr 06 12:15:50';endendrequire'test/unit'classTestLoan < Test::Unit::TestCasedeftest_conversion_to_stringLoan.instance_eval{@time_class=FakeTime}loan=Loan.new('War and Peace')assert_equal'WAR AND PEACE loaned on Mon Apr 06 12:15:50',loan.to_sendend
Redefine the following class without using the class keyword:
Now you have a variable that references a class, but the class is still anonymous.
The name of a class is just a constant, so you can assign it yourself:
MyClass=c
When you assign an anonymous
class to a constant, Ruby understands that you’re trying to give a name to
the class, and it does something special: it turns around to the class and
says, “Here’s your new name.” Now the constant references the Class, and the
Class also references the constant. If it weren’t for this trick, a class wouldn’t
be able to know its own name, and you couldn’t write this:
c.name# => "MyClass"
Singleton Methods
Ruby allows you to add a method to a single object.
A method like this one, which is specific to a
single object, is called a Singleton Method. You can define a Singleton Method
with either the syntax above, or the Object#define_singleton_method method.
The Truth About Class Methods
Classes are just objects, and class names are just constants. If you remember this
concept, then you’ll see that calling a method on a class is the same as calling a method on an object:
an_object.a_methodAClass.a_class_method
See? The first line calls a method on an object referenced by a variable, and
the second line calls a method on an object (that also happens to be a class)
referenced by a constant. It’s the same syntax.
Class methods are Singleton Methods of a class.
So, the syntax for defining a Singleton Methods with def is always the same:
defobject.method# Method body hereenddefMyClass.method# Method body hereenddefself.method# Method body hereend
Class Macros
All the attr_* methods are defined on class Module, so you can use them when-
ever self is a module or a class. A method such as attr_accessor is called a Class
Macro. Class Macros look like keywords, but they’re just regular class methods
that are meant to be used in a class definition.
#####Class Macros Applied
The Book class in the Bookworm source code has methods named GetTitle, title2,
and LEND_TO_USER. By Ruby’s conventions, these methods should be named title,
subtitle, and lend_to, respectively. However, there are other projects that use the
Book class, and you have no control over these projects. If you just rename
the methods, you will break the callers.
You can rename the methods if you invent a Class Macro (117) that deprecates the old names:
classBookdeftitle# ...defsubtitle# ...deflend_to(user)puts"Lending to #{user}"# ...defself.deprecate(old_method,new_method)define_method(old_method)do |*args, &block|
warn"Warning: #{old_method}() is deprecated. Use #{new_method}()."send(new_method, *args, &block)endenddeprecate:GetTitle,:titledeprecate:LEND_TO_USER,:lend_todeprecate:title2,:subtitleend
The deprecate method takes the old name and the new name of a method and
defines a Dynamic Method (52) that catches calls to the old name. The
Dynamic Method forwards the calls to the renamed method—but first it prints
a warning on the console to notify the callers that the old name has been
deprecated:
b=Book.newb.LEND_TO_USER("Bill")# => Warning: LEND_TO_USER() is deprecated. Use lend_to().LendingtoBill
Singleton Classes
The Singleton Method can’t live in obj, because obj is not a class. It can’t live
in MyClass, because if it did, all instances of MyClass would share it. And it cannot
be an instance method of MyClass’s superclass, Object. So then, where do Sin-
gleton Methods live?
Class methods are a special kind of Singleton Method—and just as baffling:
defMyClass.my_class_method;end
When you ask an object for its class, Ruby doesn’t always tell you the whole
truth. Instead of the class that you see, an object can have its own special,
hidden class. That’s called the singleton class of the object. (You can also hear
it called the metaclass, or the eigenclass.
Ruby has a special syntax, based on the class keyword, that places you in the scope of the singleton class:
class << an_object# your code hereendsingleton_class.class# => Class
you can also get a reference to the singleton class with the handy Object#singleton_class method:
The previous example also shows that a singleton class is a class—but a very
special one. For starters, it’s invisible until you resort to either Object#single-
ton_class, or the exotic class << syntax. Also, singleton classes have only a single
instance (that’s where their name comes from), and they can’t be inherited.
More important, a singleton class is where an object’s Singleton Methods live:
#####Method Lookup Revisited
f an object has a singleton class, Ruby starts looking for methods in
the singleton class rather than the conventional class, and that’s why you
can call Singleton Methods such as obj#a_singleton_method. If Ruby can’t find the
method in the singleton class, then it goes up the ancestors chain, ending in
the superclass of the singleton class—which is the object’s class. From there,
everything is business as usual.
Like any other object, a singleton class must have its own singleton class:
class << "abc"class << selfself# => #<Class:#<Class:#<String:0x33552c>>>endend
“The superclass of the singleton class is the singleton class of the superclass. It’s easy.”
“There are classes, singleton classes, and modules. There are instance methods, class methods, and Singleton Methods.”
If you put singleton classes together with regular classes and modules,
you end up with the seven rules of the Ruby object model:
There is only one kind of object—be it a regular object or a module.
There is only one kind of module—be it a regular module, a class, or a
singleton class.
There is only one kind of method, and it lives in a module—most often in
a class.
Every object, classes included, has its own “real class,” be it a regular
class or a singleton class.
Every class, with the exception of BasicObject, has exactly one ancestor—
either a superclass, or a module. This means you have a single chain of
ancestors from any class up to BasicObject.
The superclass of the singleton class of an object is the object’s class. The
superclass of the singleton class of a class is the singleton class of the
class’s superclass.
When you call a method, Ruby goes “right” in the receiver’s real class and
then “up” the ancestors chain. That’s all there is to know about the way
Ruby finds methods.
Since class methods are just Singleton Methods that live in the class’s singleton class, now you have three different ways to define a class method. Here they are:
defMyClass.a_class_method;endclassMyClassdefself.another_class_method;endend# this method is the prefered one because# it acknowledges the singleton class explicitlyclassMyClassclass << selfdefyet_another_class_method;endendend
#####Singleton Classes and instance_eval()
class_eval changes both self and the current class.
instance_eval also changes the current class: it changes it to the singleton class of the receiver.
You’ll rarely, if ever, see instance_eval used purposefully to change the current
class, as in the example above. The standard meaning of instance_eval is this: “I want to change self.”
If you want an attribute that’s specific to MyClass, you need a different technique. Define the attribute
in the singleton class:
To understand how this works, remember that an attribute is actually a pair
of methods. If you define those methods in the singleton class, they become
class methods.
The superclass of #BasicObject is none other than good old Class.
BasicObject.singleton_class.superclass# => Class
“when a class includes a module, it gets the module’s
instance methods—not the class methods. Class methods stay out of reach,
in the module’s singleton class.”
Object#extend is simply a shortcut that includes a module in the receiver’s singleton class.
Method Wrappers
If you have a method that you don’t want to modify
directly, because it’s in a library. You want to wrap additional functionality
around this method so that all clients get the additional functionality automatically.
You can give an alternate name to a Ruby method by using Module#alias_method:
In alias_method, the new name for the method comes first, and the original name comes second.
(Ruby also has an alias keyword which is an alternative to Module#alias_method.
It can come useful if you want to alias a method at the top level, where Module#alias_method is not available).
You can alias a method and then redefine it:
classStringalias_method:real_length,:lengthdeflengthreal_length > 5 ? 'long' : 'short'endend"War and Peace".length# => "long""War and Peace".real_length# => 13
The previous code redefines String#length, but the alias still refers to the original
method. This gives you insight into how method redefinition works. When
you redefine a method, you don’t really change the method. Instead, you
define a new method and attach an existing name to that new method. You
can still call the old version of the method as long as you have another name
that’s still attached to it.
You can write an Around Alias in three simple steps:
You alias a method.
You redefine it.
You call the old method from the new method.
In Ruby it’s the method’s name, not the method itself, that is either public or private.
One downside of Around Aliases is that they pollute your classes with one
additional method name. You can fix this small problem somehow by making
the old version of the method private after you alias it. (In Ruby it’s the method’s
name, not the method itself, that is either public or private.)
Another potential problem of Around Aliases has to do with loading. You
should never load an Around Alias twice, unless you want to end up with an
exception when you call the method. Can you see why?
The main issue with Around Aliases, however, is that they are a form of
Monkeypatching. Like all Monkeypatches, they can break existing code that
wasn’t expecting the method to change.
#####More Method Wrappers
Refinements have one additional features that enables you to use them in place of
Around Aliases (135): if you call super from a refined method, you will call the
original, unrefined method. Here comes an example:
Like other Refinements, this Refinement Wrapper only applies
until the end of the file (or, in Ruby 2.1, the module definition). This makes
it generally safer than the equivalent Around Alias, which applies everywhere.
You have a third way of wrapping a method: you can use Module#prepend
This means that a method in a prepended module can override a method in the includer, and call the nonoverridden version with super:
You can call this a Prepended Wrapper. It’s not local like a Refinement
Wrapper, but it’s generally considered cleaner and more explicit than both a
Refinement Wrapper and an Around Alias.
A Binding is a whole scope packaged as an object. The idea is that you can
create a Binding to capture the local scope and carry it around. Later, you can
execute code in that scope by using the Binding object in conjunction with eval.
You can create a Binding with the Kernel#binding method:
Ruby also provides a predefined constant named TOPLEVEL_BINDING, which is
just a Binding of the top-level scope. You can use it to access the top-level scope from anywhere in your program:
classAnotherClassdefmy_methodeval"self",TOPLEVEL_BINDINGendendAnotherClass.new.my_method# => main
The first optional argument to eval is a Binding. The remaining two optional arguments are used to tweak the stack trace in case of exceptions.
eval(statements,@binding,file,line)
Strings of Code vs. Blocks
eval is a special case in the eval* family: it evaluates a String of Code instead of a block, like both class_eval and instance_eval do. However, instance_eval and class_eval can take either a String of Code or a block.
Because a block and a String of Code are so similar, in many cases you have
the option of using either one. Which one should you choose? The short
answer is that you should probably avoid Strings of Code whenever you have
an alternative for security reasons.
The Trouble with eval()
To start with, Strings of Code don’t always play well with your editor’s features, such as syntax coloring and autocompletion.
Strings of Code tend to be difficult to read and modify
Ruby won’t report a syntax error in a String of Code until that string is evaluated, potentially resulting in brittle programs that fail unexpectedly at
runtime.
Code Injection
#####Defending Yourself from Code Injection
When it comes to code injection, some strings are safer than others. Only
strings that derive from an external source can contain malicious code, so
you might simply limit your use of eval to those strings that you wrote yourself.
#####Tainted Objects and Safe Levels
Ruby automatically marks potentially unsafe objects—in particular, objects
that come from external sources—as tainted. Tainted objects include strings
that your program reads from web forms, files, the command line, or even a
system variable. Every time you create a new string by manipulating tainted
strings, the result is itself tainted.
Ruby also provides the notion of safe levels, which complement
tainted objects nicely. When you set a safe level (which you can do by
assigning a value to the $SAFE global variable), you disallow certain potentially
dangerous operations.
You can choose from four safe levels, from the default 0 (“hippie commune,”
where you can hug trees and format hard disks) to 3 (“military dictatorship,”
where every object you create is tainted by default).
By using safe levels carefully, you can write a controlled environment for eval.
Such an environment is called a Sandbox.
new_toplevel is a method that returns a copy of TOPLEVEL_BINDING. The @src instance
variable carries the content of a code tag, and the @safe_level instance variable
contains the safe level required by the user. If no safe level is set, the content of the tag is simply evaluated. Otherwise, ERB builds a quick Sandbox:
it makes sure that the global safe level is exactly what the user asked for and
also uses a Proc as a Clean Room to execute the code in a separate scope.
(Note that the new value of $SAFE applies only inside the Proc. Contrary to what
happens with other global variables, the Ruby interpreter takes care to reset
$SAFE to its former value after the call.)
Checked Attributes with Eval()
defadd_checked_attribute(klass,attribute)eval" class #{klass} def #{attribute}=(value) raise 'Invalid attribute' unless value @#{attribute} = value end def #{attribute}() @#{attribute} end end "end
The object model is an eventful place. Lots of things happen there as your
code runs: classes are inherited, modules are mixed into classes, and methods
are defined, undefined, and removed. You can “catch” these events
like you catch a mouse-click event on a graphical interface.
classStringdefself.inherited(subclass)puts"#{self} was inherited by #{subclass}"endendclassMyString < String;end#=> String was inherited by MyString
The inherited method is an instance method of Class, and Ruby calls it when a
class is inherited. By default, Class#inherited does nothing, but you can override it with your own code as in the earlier example. A method such as Class#inherited is called a Hook Method because you can use it to hook into a particular event. Just as you override Class#inherited to plug into the
lifecycle of classes, you can plug into the lifecycle of modules by overriding
Module#included and (in Ruby 2.0) Module#prepended:
moduleM1defself.included(othermod)puts"M1 was included into #{othermod}"endendmoduleM2defself.prepended(othermod)puts"M2 was prepended to #{othermod}"endendclassCincludeM1prependM2end#=> M1 was included into CM2wasprependedtoC
You can also execute code when a module extends an object by overriding
Module#extended. Finally, you can execute method-related events by overriding
Module#method_added, method_removed, or method_undefined.
moduleMdefself.method_added(method)puts"New method: M##{method}"enddefmy_method;endend#=> New method: M#my_method
These hooks only work for regular instance methods, which live in the object’s
class. They don’t work for Singleton Methods, which live in the object’s
singleton class. To catch Singleton Method events, you can use BasicObject#singleton_method_added, singleton_method_removed, and singleton_method_undefined.
There is an important difference between overriding Module#included and overridingModule#include. Module#included exists solely to be used as a Hook Method, and its defaultimplementation is empty. But Module#include has some real work to do: it must actuallyinclude the module. That’s why our hook’s code also should call the base implementation of Module#include through super. If you forget super, you’ll still catch the event, but you won’t include the module anymore. As an alternative to overriding, you can turn a regular method into a Hook Method by using an Around Alias.