Ruby 1.9 has some cool new features. One of them is the ability to define default values for the arguments passed to code blocks, like in the following example:
pow = proc { |a, b = 2| a**b } pow.call 3, 3 # 27 pow.call 3 # 9
This is very useful, for instance, when we dynamically create new methods using metaprogramming and want some of the arguments for these methods to be optional.
class MyMath class < < self define_method :pow do |base, exponent = 2| base**exponent end end end MyMath.pow 3 # 9 MyMath.pow 2, 3 # 8
But in Ruby 1.8.x we can’t do that, we can’t define default values the arguments of a code block. So what if your application runs on 1.8.x and you need to dynamically create methods with optional arguments? There is a solution, not so elegant as the Ruby 1.9 approach but still very functional and simple:
class MyMath class < < self define_method :pow do |*args| base, exponent = args[0], args[1] || 2 base**exponent end end end MyMath.pow 3 # 9 MyMath.pow 2, 3 # 8
When we pass a splat (that thing with an asterisk on the left) as the argument to the block, whatever gets there will be treated as an array. This way, we can simulate the existence of default values for those arguments. We can actually pass any number of arguments and define the default values in any way we want.
What is lost, unfortunately, is the ability to validate the number of arguments that the method should receive when called. But we can do that validating the elements inside the array that the block receives.
I usually use this technique to create methods that can optionally receive an options hash, what is very useful when writing plugins or gems, for instance:
module MyModule module ClassMethods def do_the_magic class_eval do define_method :magic_method do |*args| options = args.first || {} # ... end end end end def self.included(base) base.extend ClassMethods end end class MyClass include MyModule do_the_magic end obj = MyClass.new obj.magic_method # works obj.magic_method :abra => "cadabra" # also works!


Recent Comments