こんにちは.山崎です.

本件ですがひとまず解決しましたので,サマリを報告します.

やりたかったこと:
irbのcompletionとrefeを統合したい.
irb> String.new.to_s.doc?
↑こんなのでString#to_sのドキュメントが出たらうれしい

解決方法:
method_missingを使う方法は?付きのメソッドが拾えなかったので,
irbのプリプロセスでフィルタリングしてirbに渡してやる.
具体的には下記irb_doc_extention.rbを適当なディレクトリにおいて

% irb -r 'irb/completion' -I 適当なディレクトリ -r irb_doc_extention
を実行.

irb> String.new mdoc?
メソッドとしてのドキュメント(String#newのドキュメントが出力)

irb> String.new cdoc?
クラスとしてのドキュメント(Stringクラスのドキュメントが出力)

上記のようにすればmdoc?でメソッドのドキュメントcdoc?でクラスの
ドキュメントが出力されるようになりました.


得た知見:

- メソッド名の途中に?があるのはRuby的にNG(最後はOK)
- refeはクラスツリーをさかのぼってメソッドのドキュメントを探してくれる.
http://www.ruby-lang.org/ja/man/index.cgi?cmd=view;name=ReFe


最後になりましたが,アドバイスいただいたるびきちさん,
どうもありがとうございました.


# irb_doc_extention.rb

require 'irb/ruby-lex'
require 'test/unit/assertions'
require 'stringio'

$nullout = StringIO.new
$debugout = $nullout

class Module
  public :define_method
end

module IRB

  
  module InputFilter
    extend Test::Unit::Assertions

    FilterNotFound = Class.new(RuntimeError)

    FILTERS_DEFAULT = [
                       [ /^(.+)\s+(mdoc|cdoc)\?\s+$/ ,
                         proc{|l,m|
                           cmd = m[1].strip
                           type = m[2]
                           case type
                           when "mdoc" then
                             if (cmd =~ /(.+)\.(.+)$/)
                               "#{$1}.doc_(:#{$2})\n"
                             else
                               "#{cmd}.doc_\n"
                             end
                           when "cdoc" then
                             "#{cmd}.doc_\n"
                           else
                             l
                           end
                         }
                       ],
     ]

    # @pre: l[-1,1] == "\n"
    def self.input_filter(l)
      raise Exception unless "\n" == l[-1,1]
      begin
        match = nil
        x = FILTERS_DEFAULT.find{|re, str| match = l.match(re)}[1]
      rescue
        return l
      end
      s = x.call(l,match)
      $debugout.puts "input_filter:#{s}"
      s
    end
  end
end  


class RubyLex

  alias :set_input_original :set_input
  def set_input(*args,&block)
    set_input_original(*args,&block)
    input_original = @input
    @input = lambda{
      l = input_original.call
      if self.indent == 0 && l.respond_to?(:replace)
        l.replace(IRB::InputFilter.input_filter(l))
      end
      (l.nil?)? l: l.sub(/^\s+/,"")
    }
  end

end



module IRB
  NULLPROC = lambda{}
  IRB.conf[:PRE_PROC]=NULLPROC
  IRB.conf[:POST_PROC]=NULLPROC

  IrbOriginal = Irb
  remove_const :Irb
  class Irb < IrbOriginal
    def prompt(prompt, ltype, indent, line_no)
      if prompt==@context.prompt_i && indent == 0
        super
      else
        ""
      end
    end

  end

  ContextOriginal = Context
  remove_const :Context
  class Context < ContextOriginal
    def evaluate(line, lineno)
      line.replace "IRB.conf[:POST_PROC].call; IRB.conf[:PRE_PROC].call; #{line}"
      super
    end
  end

end

class Object
  def doc_(method_name=nil)

    if method_name.nil? # case for class doc
      class_name = self.class.name
      if (class_name == "Class")
        class_name = self.name
      end
      cmd = "refe #{class_name}"
    else
      class_name = self.class.name
      real_method_name = method_name.to_s # for Symbol
      if class_name == "Class" # if class method
        class_name = self.name
        cmd = "refe #{class_name}.#{real_method_name}"
      else
        cmd ="refe #{class_name},#{real_method_name}"
      end
    end
    print `#{cmd}`
  end
end

-- 
Daisuke Yamazaki <yamajaki / gmail.com>