> i'm having a hard time imagining a case where only the name > of the method would need to be added and not the body - > doesn't really seem like meta-programming - for instance the > method above generates something which will always use > 'method_name' as 'test2'. I've got a couple of cases where I want to wrap a method in a dynamically generated method. Something like this: class Test def do_something(a, b, &block) # Do something with a, b and block. end monitor :do_something end This Module::monitor wraps the original Test#do_something in a block of code which "monitors" (just an example...) the invocation or the execution of the original method. Adding or removing this monitor statement may not affect the behavior of the original method. The arguments to the dynamically generated method are passed to the original method. So is &block... (damn...) This Module::monitor might be implemented like this: class Module def monitor(method_name, *types) org_method = instance_method(method_name) define_method(method_name) do |*args| block = nil # ??? &block # Do a lot of checking on args. # A lot of lines. # You don't want to do that in a string. org_method.bind(self).call(*args, &block) end end end I'm playing with a couple of monitor functions, like statistics, benchmarking, role-validation and type-checking. In each situation, the impact on the code must be reduced to a minimum. The idiom (right term?) of (temporarily) wrapping a method, as described above, doesn't affect the code of the original method at all. That's nice. See the code below for a full example, in which the arguments of a method call are checked on class/behavior. > sure would be easier ruby had some way to declare blocks that > take blocks! ;-) It's introduced in Ruby 1.9... :) Thanks. gegroet, Erik V. - http://www.erikveen.dds.nl/ ---------------------------------------------------------------- # LIBRARY class Module def typed(method_name, *types) org_method = instance_method(method_name) define_method(method_name) do |*args| block = nil # ??? &block if args.length > types.length raise ArgumentError, "Wrong number of arguments (#{args.length} instead of #{types.length})." end args.length.times do |n| arg = args[n] [types[n]].flatten.each do |typ| if typ.kind_of?(Module) unless arg.kind_of?(typ) raise ArgumentError, "Wrong argument type (#{arg.class} instead of #{typ}, argument #{n+1})." end elsif typ.kind_of?(Symbol) unless arg.respond_to?(typ) raise ArgumentError, "#{arg} doesn't respond to :#{typ} (argument #{n+1})." end else raise ArgumentError, "Wrong type in types (#{typ}, argument #{n+1})" end end end org_method.bind(self).call(*args, &block) end end end ---------------------------------------------------------------- # TEST SCRIPT class Thing def go(x, y, z) # x should be Numeric # y should be a String # z should respond to :gsub and :to_s :good end typed :go, Numeric, String, [:gsub, :to_s] end def test(*args) begin puts "#{args.inspect} : OK : #{Thing.new.go(*args).inspect}" rescue Exception => e puts "#{args.inspect} : NOK : #{e.message}" end end test(7) test(7, 8, 9) test(7, 8, "9") test(7, "8", 9) test(7, "8", "9") ----------------------------------------------------------------