Checking Class or Module Membership


You want to see if an object is of the right type for your purposes.


If you plan to call a specific method on the object, just check to see whether the object reponds to that method:

	def send_as_package(obj)
	 if obj.respond_to? :package
	 packaged = obj.package

	 $stderr.puts "Not sure how to package a #{obj.class}."
	 $stderr.puts 'Trying generic packager.'
	 package =

If you really can only accept objects of one specific class, or objects that include one specific module, use the is_a? predicate:

	def multiply_precisely(a, b)
	 if a.is_a? Float or b.is_a? Float

	 raise ArgumentError, "I can't do precise multiplication with floats."
	 a * b

	multiply_precisely(4, 5) # => 20
	multiply_precisely(4.0, 5)
	# ArgumentError: I can't do precise multiplication with floats.



Whenever possible, you should use duck typing (Object#respond_to?) in preference to class typing (Object#is_a?). Duck typing is one of the great strengths of Ruby, but it only works if everyone uses it. If you write a method that only accepts strings, instead of accepting anything that supports to_str, then you've broken the duck typing illusion for everyone who uses your code.

Sometimes you can't use duck typing, though, or sometimes you need to combine it with class typing. Sometimes two different classes define the same method (especially one of the operators) in completely different ways. Duck typing makes it possible to silently do the right thing, but if you know that duck typing would silently do the wrong thing, a little class typing won't hurt.

Here's a method that uses duck typing to see whether an operation is supported, and class typing to cut short a possible problem before it occurs:

	def append_to_self(x)
	 unless x.respond_to? :<<
	 raise ArgumentError, "This object doesn't support the left-shift operator."
	 if x.is_a? Numeric
	 raise ArgumentError,
	 "The left-shift operator for this object doesn't do an append."
	 x << x

	append_to_self('abc') # => "abcabc"
	append_to_self([1, 2, 3]) # => [1, 2, 3, […]]

	append_to_self({1 => 2})
	# ArgumentError: This object doesn't support the left-shift operator.

	# ArgumentError: The left-shift operator for this object doesn't do an append.
	5 << 5 # => 160
	# That is, 5 * (2 ** 5)

An alternative solution approximates the functionality of Java's interfaces. You can create a dummy module for a given capability, have all appropriate classes include it, and use is_a? to check for inclusion of the module. This requires that each participating class signal its ability to perform a certain task, but it doesn't tie you to any particular class hierarchy, and it saves you from calling the wrong method just because it has the right name.

	module ShiftMeansAppend
	 def <<(x)

	class String
	 include ShiftMeansAppend

	class Array
	 include ShiftMeansAppend

	def append_to_self(x)
	 unless x.is_a? ShiftMeansAppend
	 raise ArgumentError, "I can't trust this object's left-shift operator."
	 x << x
	append_to_self 4
	# ArgumentError: I can't trust this object's left-shift operator.

	append_to_self '4' # => "44"


See Also

  • Recipe 1.12, "Testing Whether an Object Is String-Like"



Date and Time



Files and Directories

Code Blocks and Iteration

Objects and Classes8

Modules and Namespaces

Reflection and Metaprogramming


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 © 2008-2020.
If you may any questions please contact us: