Ruby - Add class methods at runtime.






4.20/5 (2 votes)
Sep 1, 2006
1 min read

59402
Short article showing how to add methods to a class instance at runtime.
Introduction
This is a very brief article about one great feature of the Ruby language - dynamically adding methods to classes at runtime.
Basically I have been learning the Ruby language and thought I would share few snippets with people in small articles, so if you are not familiar with Ruby take a quick look and see what you think - you never know it might spark your interest!
Adding methods to class instances
One great feature of Ruby is that it allows you to add methods to individual class instances on the fly. The code is pretty self explanatory so I won't go into any details.
Update - 15 Sep 2006
- In response to some comments regarding how you use reflection etc in ruby I have added a new block of code showing how to reflect against a class, call methods dynamically and a simple benchmark showing the timings for each method.## ---- Add methods to a class instance at runtime. ---- ## # Create a very simple class. <CODE __designer:dtid="281474976710672">class TestAddMethod def method1 puts "Method1 Called." end end # Create a new instance of this class.t = TestAddMethod.new
# Add a method to this instance.def t.method2 puts "Method2 Called." end
# Call both methods.t.method1 t.method2
# Output: # Method1 Called. # Method2 Called. # Override existing method with new functionality.def t.method1 puts "I replaced the normal method with this." end
# Call the modified method.t.method1
# Output: # I replaced the normal method with this. # Add to existing methods.def t.method1 puts "Again I replaced the normal method with this, now I am going to call the method on the original class: " # Calls the original method defined at the top (on this instances SuperClass). super end
# Call the modified method.t.method1
# Output: # Again I replaced the normal method with this, now I am going to call the method on the original class: # Method1 Called. ------- Section below added in response to some questions/comments from Baj22:require "benchmark" include Benchmark
# Define a simple class.class TestClass def method1 puts "Called!" end def method2 puts "Called!" end def method3 puts "Called!" end def method4 end end
# Define a simple class.class TestClass2 < TestClass def method4 puts "Called!" end end
# List the methods supported.puts "TestClass supports #{TestClass.methods.length} method(s)" # Result: TestClass supports 76 method(s) TestClass.methods.each do |method| puts "\t #{method}" end
# Result: # to_a # respond_to? # display # etc, etc # List the methods supported.t = TestClass.new() puts "T Instance supports #{t.methods.length} method(s)" #' Result: T Instance supports 46 method(s) t.methods.each do |method| puts "\t #{method}" end
# Result: # to_a # respond_to? # display # etc, etc # Check if a class supports a method by name.puts "r responds to 'Method1' = #{t.respond_to?("method1")}" # Result: true. puts "r responds to 'UNKNOWN' = #{t.respond_to?("UNKNOWN")}" # Result: false.
# Walk the inheritance tree.cls = TestClass2 begin print cls cls = cls.superclass print " < " if cls end while cls
# Result: TestClass2 < TestClass < Object # Call a method dynimically.t.send(:method1)
# Result: Called!method1 = t.method(:method1) method1.call # Result: Called! method4 = t.method(:method4)
# Test dynamic calls.n = 100000 bm(12) {|x| x.report("Method.Call") { n.times { method4.call } } x.report("Instance.send") { n.times { t.send(:method4) } } x.report("Instance.Method") { n.times { t.method4} }
} #Result # user system total real #Method.Call 0.040000 0.000000 0.040000 ( 0.060000) #Instance.send 0.080000 0.000000 0.080000 ( 0.090000) #Instance.Method 0.050000 0.000000 0.050000 ( 0.051000)
More Info
There are other ways to add methods to classes - one is to use a mix-in - where you essentially include all of the methods from a module in a class definition. This allows you to mimic some of the multiple inheritance functionality seen in C++.
Anyway - thanks for your time. Any comments/questions are welcome. As I play with Ruby more I will try to post more articles on things that I find interesting.
History
Version 1.1