Getting a Reference to a Method

Problem

You want to the name of a method into a reference to the method itself.

Solution

Use the eponymous Object#method method:

	s = 'A string'
	length_method = s.method(:length) # => #
	length_method.arity # => 0
	length_method.call # => 8

 

Discussion

The Object#methods introspection method returns an array of strings, each containing the name of one of the methods available to that object. You can pass any of these names into an object's method method and get a Method object corresponding to that method of that object.

A Method object is bound to the particular object whose method method you called. Invoke the method's Method#call method, and it's just like calling the object's method directly:

	1.succ # => 2
	1.method(:succ).call # => 2

The Method#arity method indicates how many arguments the method takes. Arguments, including block arguments, are passed to call just as they would be to the original method:

	5.method('+').call(10) # => 15

	[1,2,3].method(:each).call { |x| puts x }
	# 1
	# 2
	# 3

A Method object can be stored in a variable and passed as an argument to other methods. This is useful for passing preexisting methods into callbacks and listeners:

	class EventSpawner

	 def initialize
	 @listeners = []
	 @state = 0
	 end

	 def subscribe(&listener)
	 @listeners << listener
	 end

	 def change_state(new_state)
	 @listeners.each { |l| l.call(@state, new_state) }
	 @state = new_state
	 end
	end

	class EventListener
	 def hear(old_state, new_state)
	 puts "Method triggered: state changed from #{old_state} " +
	 "to #{new_state}."
	 end
	end

	spawner = EventSpawner.new
	spawner.subscribe do |old_state, new_state|
	 puts "Block triggered: state changed from #{old_state} to #{new_state}."
	end

	spawner.subscribe &EventListener.new.method(:hear)
	spawner.change_state(4)
	# Block triggered: state changed from 0 to 4.
	# Method triggered: state changed from 0 to 4.

A Method can also be used as a block:

	s = "sample string"
	replacements = { "a" => "i", "tring" => "ubstitution" }

	replacements.collect(&s.method(:gsub))
	# => ["simple string", "sample substitution"]

You can't obtain a reference to a method that's not bound to a specific object, because the behavior of call would be undefined. You can get a reference to a class method by calling method on the class. When you do this, the bound object is the class itself: an instance of the Class class. Here's an example showing how to obtain references to an instance and a class method of the same class:

	class Welcomer
	 def Welcomer.a_class_method
	 return "Greetings from the Welcomer class."
	 end
	 def an_instance_ 
method
	 return "Salutations from a Welcomer object."
	 end
	end

	Welcomer.method("an_instance_method")
	# NameError: undefined method 'an_instance_method' for class 'Class'
	Welcomer.new.method("an_instance_method").call
	# => "Salutations from a Welcomer object."
	Welcomer.method("a_class_method").call
	# => "Greetings from the Welcomer class."

 

See Also

  • Recipe 7.11, "Coupling Systems Loosely with Callbacks," contains a more complex listener example


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