From: Daisuke Yamazaki <yamajaki / gmail.com>
Subject: [ruby-list:42768] Re: ?がメソッド名の途中にあるのはNG?
Date: Wed, 30 Aug 2006 14:13:29 +0900

るびきちです。

> ↓こんな感じにかければうれしかった.
> irb(main):001:0> Array.new.inject.help

irbに渡す前に preprocessor を通すことを思い出しました。

たとえば
Array.new.inject ?
のように / \?$/ な行を
Array.new.help(:inject)
と置き換えて解釈させるのです。

これは拙作irbshのirb拡張部分です。
たとえば
foo () 1
を
def foo() 1 end
と同じ働きにさせたりなど拡張文法を定義しています。
この拡張はirbshと独立しているので試してみては?
FILTERS_DEFAULTは勝手に定義してしまってください。

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 = [
      [ /^cd +(.+?)\s*$/, proc{|l,m|
          "irbsh_cd %q[#{m[1]}]\n"}],
      [ /^ +(cd|pushd)\s*$/, proc{|l,m|
          "irbsh_#{m[1]}\n"}],
      [ /^ +(cd|pushd) +(.+)\s*$/, proc{|l,m|
          "irbsh_#{m[1]} %q[#{m[2]}]\n"}],
      [ /;$/, proc{|l,m|
          "Irbsh.disable_output;#{m.pre_match}\n"
        }],
      [ /\$$/, proc{|l,m|
          "Irbsh.enable_dryrun;#{m.pre_match}\n"
        }],
      [ /^ /, proc{|l,m|
          "irbsh_system %Q(#{l.chomp})\n"
        }],
      [/^defun +(\S+)\s*\(([^\)]*)\)/, proc{|l,m|
          %Q!self.class.__send__(:define_method,:#{m[1]}) do |#{m[2]}|#{m.post_match}!
        }],
      [ /^([a-z][a-zA-z0-9]*)\s+\(([^\)]*)\)/, proc{|l,m|
          %Q!self.class.__send__(:define_method,:#{m[1]}) do |#{m[2]}|#{m.post_match.chomp} end\n!
        }],
    ]

    # @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
    }
  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


> これなのですが,Rubyのドキュメントを読む限りメソッド名で?を特別扱いすると
> いう記述はないようなのですが,どのあたりに書いてある話でしょう?

んー。どのみちエラーですね。

irbsh[30@06:23](main):003:0> def ?a(x) 1 end
SyntaxError: compile error
(irbsh):3: syntax error, unexpected tINTEGER
IRB.conf[:POST_PROC].call; IRB.conf[:PRE_PROC].call; def ?a(x) 1 end
                                                           ^
	from (irbsh):3
	from :0
irbsh[30@14:28](main):004:0> def a?a(x) 1 end
SyntaxError: compile error
(irbsh):4: syntax error, unexpected '(', expecting '\n' or ';'
IRB.conf[:POST_PROC].call; IRB.conf[:PRE_PROC].call; def a?a(x) 1 end
                                                             ^
	from (irbsh):4
	from :0
irbsh[30@14:29](main):005:0> def a?(x) 1 end
nil


> そうですね.でもメソッドチェインで補完しながら調べられる今の方法も
> 捨てがたいんです.

というわけで preprocessor 案をお試しください。

--
rubikitch
http://www.rubyist.net/~rubikitch/