Extending Specific Objects with Modules

Credit: Phil Tomson

Problem

You want to add instance methods from a module (or modules) to specific objects. You don't want to mix the module into the object's class, because you want certain objects to have special abilities.

Solution

Use the Object#extend method.

For example, let's say we have a mild-mannered Person class:

	class Person
	 attr_reader :name, :age, :occupation

	 def initialize(name, age, occupation)
	 @name, @age, @occupation = name, age, occupation
	 end

	 def mild_mannered?
	 true
	 end
	end

Now let's create a couple of instances of this class.

	jimmy = Person.new('Jimmy Olsen', 21, 'cub reporter')
	clark = Person.new('Clark Kent', 35, 'reporter')
	jimmy.mild_mannered? # => true 
	clark.mild_mannered? # => true 

But it happens that some Person objects are not as mild-mannered as they might appear. Some of them have super powers.

	module SuperPowers
	 def fly
	 'Flying!'
	 end

	 def leap(what)
	 "Leaping #{what} in a single bound!"
	 end

	 def mild_mannered?
	 false
	 end

	 def superhero_name
	 'Superman'
	 end
	end

If we use include to mix the SuperPowers module into the Person class, it will give every person super powers. Some people are bound to misuse such power. Instead, we'll use extend to give super powers only to certain people:

	clark.extend(SuperPowers)
	clark.superhero_name # => "Superman"
	clark.fly # => "Flying!"
	clark.mild_mannered? # => false
	jimmy.mild_mannered? # => true

 

Discussion

The extend method is used to mix a module's methods into an object, while include is used to mix a module's methods into a class.

The astute reader might point out that classes are actually objects in Ruby. Let us see what happens when we use extend in a class definition:

	class Person 
	 extend SuperPowers 
	end

	#which is equivalent to:
	Person.extend(SuperPowers) 

What exactly are we extending here? Within the class definition, extend is being called on the Person class itself: we could have also written self.extend(SuperPowers). We're extending the Person class with the methods defined in SuperPowers. This means that the methods defined in the SuperPowers module have now become class methods of Person:

	Person.superhero_name # => "Superman"
	Person.fly # => "Flying!"

This is not what we intended in this case. However, sometimes you do want to mix methods into a class, and Class#extend is an easy and powerful way to do it.

See Also

  • Recipe 9.3, " Mixing in Class Methods," shows how to mix in class methods with include


Strings

Numbers

Date and Time

Arrays

Hashes

Files and Directories

Code Blocks and Iteration

Objects and Classes8

Modules and Namespaces

Reflection and Metaprogramming

XML and HTML

Graphics and Other File Formats

Databases and Persistence

Internet Services

Web Development Ruby on Rails

Web Services and Distributed Programming

Testing, Debugging, Optimizing, and Documenting

Packaging and Distributing Software

Automating Tasks with Rake

Multitasking and Multithreading

User Interface

Extending Ruby with Other Languages

System Administration



Ruby Cookbook
Ruby Cookbook (Cookbooks (OReilly))
ISBN: 0596523696
EAN: 2147483647
Year: N/A
Pages: 399

Flylib.com © 2008-2020.
If you may any questions please contact us: flylib@qtcs.net