The Object
and Module
classes define a number of methods for
listing, querying, invoking, and
defining methods. We’ll consider each category in turn.
Object
defines methods for
listing the names of methods defined on the object. These methods
return arrays of methods names. Those name are strings in Ruby 1.8 and
symbols in Ruby 1.9:
o = "a string" o.methods # => [ names of all public methods ] o.public_methods # => the same thing o.public_methods(false) # Exclude inherited methods o.protected_methods # => []: there aren't any o.private_methods # => array of all private methods o.private_methods(false) # Exclude inherited private methods def o.single; 1; end # Define a singleton method o.singleton_methods # => ["single"] (or [:single] in 1.9)
It is also possible to query a class for the methods it defines
rather than querying an instance of the class. The following methods
are defined by Module
. Like the
Object
methods, they return arrays
of strings in Ruby 1.8 and arrays of symbols in 1.9:
String.instance_methods == "s".public_methods # => true String.instance_methods(false) == "s".public_methods(false) # => true String.public_instance_methods == String.instance_methods # => true String.protected_instance_methods # => [] String.private_instance_methods(false) # => ["initialize_copy", # "initialize"]
Recall that the class methods of a class or module are singleton
methods of the Class
or Module
object. So to list class methods,
use Object.singleton_methods
:
Math.singleton_methods # => ["acos", "log10", "atan2", ... ]
In addition to these listing methods, the Module
class defines some predicates for
testing whether a specified class or module defines a named instance
method:
String.public_method_defined? :reverse # => true String.protected_method_defined? :reverse # => false String.private_method_defined? :initialize # => true String.method_defined? :upcase! # => true
Module.method_defined?
checks
whether the named method is defined as a public or protected method.
It serves essentially the same purpose as Object.respond_to?
. In Ruby 1.9, you can
pass false
as the second argument to specify that inherited methods
should not be considered.
To query a specific named method, call method
on any object or instance_method
on any module. The former
returns a callable Method
object
bound to the receiver, and the latter returns an UnboundMethod
. In Ruby 1.9, you can limit
your search to public methods by calling public_method
and public_instance_method
. We covered these
methods and the objects they return in Method Objects:
"s".method(:reverse) # => Method object String.instance_method(:reverse) # => UnboundMethod object
As noted earlier, and in Method Objects, you can use
the method
method of
any object to obtain a Method
object that represents a named method of that object. Method
objects have a call
method just
like Proc
objects do; you can use
it to invoke the method.
Usually, it is simpler to invoke a named method of a specified
object with send
:
"hello".send :upcase # => "HELLO": invoke an instance method Math.send(:sin, Math::PI/2) # => 1.0: invoke a class method
send
invokes on its receiver the method named by its first argument,
passing any remaining arguments
to that method. The name “send” derives from the object-oriented idiom in which invoking a
method is called “sending a message” to an object.
send
can invoke any named
method of an object, including private and protected methods. We saw
send
used earlier to invoke the
private method remove_const
of a
Module
object. Because global
functions are really private methods of Object
, we can use send
to invoke these methods on any object
(though this is not anything that we’d ever actually want to
do):
"hello".send :puts, "world" # prints "world"
Ruby 1.9 defines public_send
as an alternative to send
. This method works like send
, but will only invoke public methods,
not private or protected methods:
"hello".public_send :puts, "world" # raises NoMethodError
send
is a very fundamental
method of Object
, but it has a
common name that might be overridden in subclasses. Therefore, Ruby
defines __send__
as a synonym, and
issues a warning if you attempt to delete or redefine __send__
.
If you want to define a new instance method of a class or module,
use define_method
. This instance method of Module
takes the name of the new method (as
a Symbol
) as its first argument.
The body of the method is provided either by a Method
object passed as the second argument
or by a block. It is important to understand that define_method
is private. You must be inside
the class or module you want to use it on in order to call it:
# Add an instance method named m to class c with body b def add_method(c, m, &b) c.class_eval { define_method(m, &b) } end add_method(String, :greet) { "Hello, " + self } "world".greet # => "Hello, world"
To define a class method (or any singleton method) with define_method
, invoke it on the
eigenclass:
def add_class_method(c, m, &b) eigenclass = class << c; self; end eigenclass.class_eval { define_method(m, &b) } end add_class_method(String, :greet) {|name| "Hello, " + name } String.greet("world") # => "Hello, world"
In Ruby 1.9, you can more easily use define_singleton_method
, which is a method
of Object
:
String.define_singleton_method(:greet) {|name| "Hello, " + name }
One shortcoming of define_method
is that it does not allow you
to specify a method body that expects a block. If you need to
dynamically create a method that accepts a block, you will need to use
the def
statement with class_eval
. And if the method you are
creating is sufficiently dynamic, you may not be able to pass a block
to class_eval
and will instead have
to specify the method definition as a string to be evaluated. We’ll
see examples of this later in the chapter.
To create a synonym or an alias for an existing method, you can
normally use the alias
statement:
alias plus + # Make "plus" a synonym for the + operator
When programming dynamically, however, you sometimes need to
use alias_method
instead. Like define_method
,
alias_method
is a private method of
Module
. As a method, it can accept
two arbitrary expressions as its arguments, rather than requiring two
identifiers to be hardcoded in your source code. (As a method, it also
requires a comma between its arguments.) alias_method
is often used for
alias chaining existing methods. Here is a simple example; we’ll
see more later in the chapter:
# Create an alias for the method m in the class (or module) c def backup(c, m, prefix="original") n = :"#{prefix}_#{m}" # Compute the alias c.class_eval { # Because alias_method is private alias_method n, m # Make n an alias for m } end backup(String, :reverse) "test".original_reverse # => "tset"
As we learned in Undefining Methods, you can use the
undef
statement to undefine a
method. This works only if you can express the name of a method as a
hardcoded identifier in your program. If you need to dynamically
delete a method whose name has been computed by your program, you have
two choices: remove_method
or
undef_method
. Both are private
methods of Module
. remove_method
removes the definition of the method from the current
class. If there is a version defined by a superclass, that version
will now be inherited. undef_method
is more severe; it prevents any invocation of the specified method
through an instance of the class, even if there is an inherited
version of that method.
If you define a class and want to prevent any dynamic
alterations to it, simply invoke the freeze
method of the class. Once frozen, a
class cannot be altered.
When the method name resolution algorithm (see Method Lookup) fails to find a method, it looks up a
method named method_missing
instead. When this method is invoked, the first argument is a symbol
that names the method that could not be found. This symbol is followed
by all the arguments that were to be passed to the original method. If
there is a block associated with the method invocation, that block is
passed to method_missing
as well.
The default implementation of method_missing
, in the Kernel
module, simply raises a NoMethodError
. This exception, if uncaught,
causes the program to exit with an error message, which is what you
would normally expect to happen when you try to invoke a method that
does not exist.
Defining your own method_missing
method for a class allows you
an opportunity to handle any kind of invocation on instances of the
class. The method_missing
hook is
one of the most powerful of Ruby’s dynamic capabilities, and one of
the most commonly used metaprogramming techniques. We’ll see examples
of its use later in this chapter. For now, the following example code
adds a method_missing
method to the
Hash
class. It allows us to query
or set the value of any named key as if the key were the name of a
method:
class Hash # Allow hash values to be queried and set as if they were attributes. # We simulate attribute getters and setters for any key. def method_missing(key, *args) text = key.to_s if text[-1,1] == "=" # If key ends with = set a value self[text.chop.to_sym] = args[0] # Strip = from key else # Otherwise... self[key] # ...just return the key value end end end h = {} # Create an empty hash object h.one = 1 # Same as h[:one] = 1 puts h.one # Prints 1. Same as puts h[:one]
Method Visibility: Public, Protected, Private introducedpublic
, protected
, and private
. These look like language keywords
but are actually private instance methods defined by Module
. These methods are usually used as a
static part of a class definition. But, with class_eval
, they can also be used
dynamically:
String.class_eval { private :reverse } "hello".reverse # NoMethodError: private method 'reverse'
private_class_method
and
public_class_method
are similar,
except that they operate on class methods and are themselves
public:
# Make all Math methods private # Now we have to include Math in order to invoke its methods Math.private_class_method *Math.singleton_methods
18.118.7.102