On 8 Jul 2002, at 23:57, Yukihiro Matsumoto wrote:

> Instead, parameterized mix-in (e.g. include Enumerable using each_byte
> as each) is a interesting idea, but it should be pretty hard to
> implement.

I also found it interesting. Here's a quick hack that allows the 
following:


s = "Hello\nMatz"
s.parameterized_extend Enumerable, { :each => :each_byte }

print 'Bytes:'
s.map { | i | print " #{i}" }
puts

# called from Enumerable, thus uses each_byte
# => Bytes: 72 101 108 108 111 10 77 97 116 122

print 'Lines:'
s.each { | i | print " #{i.chomp}" }
puts

# called directly, thus uses the original each
# => Lines: Hello Matz


Here's the code (not much tested, works on my 1.6.6 Windows NT).

Regards,
Pit


class Module

  def parameterized_include( mod, map )
    include mod
    _pi_rename_methods map
    _pi_create_delegate mod, map
  end
  
  private

  def _pi_rename_methods( map )
    map.each do
      | method, mapped |
      alias_method _pi_original_method( method ), method
      undef_method method
    end
  end

  def _pi_create_delegate( mod, map )
    module_eval <<-eval_end
      def method_missing( method, *args, &block )
        send( _pi_method_to_send( method, #{mod}, #{map.inspect} 
), *args, &block )
      end
    eval_end
  end

end


class Object

  def parameterized_extend( mod, map )
    instance_eval <<-eval_end
      class << self
        parameterized_include( #{mod}, #{map.inspect} )
      end
    eval_end
  end
  
  private
      
  def _pi_method_to_send( method, mod, map )
    if map.keys.include?( method )
      if mod.method_defined?( _pi_calling_method )
        map[ method ]
      else
        _pi_original_method( method )
      end
    else
      method
    end
  end

  def _pi_original_method( method )
    "__pi_#{method}"
  end
  
  def _pi_calling_method
    if caller[ 2 ] =~ /.*:in `(.*?)'/
      $1
    else
      ''
    end
  end

end