> 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")

----------------------------------------------------------------