From: nobu.nakada@... Date: 2001-12-10T02:35:06+09:00 Subject: [ruby-list:32846] Re: dir_config (mkmf.rb) のオプション指定の優先順位 なかだです。 At Sun, 9 Dec 2001 12:18:22 +0900, TAKAHASHI Masayoshi wrote: > defaultが3通りの意味で使われているのはさすがに「わかりにくい」 > と思うです。 > > というわけで、*1をdefault_args または args、*3をdirにする、 > なんてのがidir/idefault、ldir/ldefaultとの対称性からもわかり > よいんではないかと思いました。どうでしょ。 うーむ。御意。 > それはさておき、引数の数やクラスによって意味が変わるメソッド > を、Rubyでわかりやすく記述するのってむずかしいですよね。 > いつも悩みます。 最近もruby-talkでそんな話がありましたが、そのときに作ったのをつ けておきます。(3)はサブクラスで失敗しますが。 > 「彼の言葉には必ず3通りの意味がある」ってアシモフ『銀河帝国 > の興亡』でしたっけ?<9通りだったかも<どうでもいいって(汗; うむむ、覚えてない。何巻? っつても昔図書館で読んだから手元にな いんだよなぁ。 Index: mkmf.rb =================================================================== RCS file: /cvs/ruby/src/ruby/lib/mkmf.rb,v retrieving revision 1.64 diff -u -2 -p -r1.64 mkmf.rb --- mkmf.rb 2001/12/06 09:54:19 1.64 +++ mkmf.rb 2001/12/09 13:09:27 @@ -336,20 +336,21 @@ def create_header() end -def dir_config(target, idefault=nil, ldefault=nil) - if idefault && ldefault == nil - default = idefault - idefault = default + "/include" - ldefault = default + "/lib" +def dir_config(target, *args) + case args.size + when 0, 1 + default, = args + when 2 + idefault, ldefault = args + else + raise ArgumentError, "too many default directories" end - dir = with_config(target + "-dir", default) + if dir + idefault = dir + "/include" + ldefault = dir + "/lib" + end - idir, ldir = if dir then [ - dir + "/include", - dir + "/lib" - ] else [ - with_config(target + "-include", idefault), - with_config(target + "-lib", ldefault) - ] end + idir = with_config(target + "-include", idefault) + ldir = with_config(target + "-lib", ldefault) if idir module Overload class Signature < Array def invalid TypeError.new("Invalid Signature: #{collect {|a| a.type}.join(', ')}") end def ===(args) if last (l = length) == args.length or return false else (l = length-1) <= args.length or return false end l.times {|i| self[i] === args[i] or return false} true end def dispatch(*types, &block) throw :dispatched, yield(*self) if Signature[*types] === self end end def overload(args) args = Signature[*args] catch(:dispatched) do yield args raise args.invalid end end def self.dispatch(recv, func, args, block) klass = tbl = sig = meth = nil recv.type.ancestors.find do |klass| tbl = klass.instance_eval {@overload} or next tbl = tbl[func] or next sig, meth = tbl.find {|sig, meth| sig === args} meth end or raise Signature[*args].invalid meth.bind(recv).call(*args, &block) end end class Module def overload(func, *types) tbl = meth = nil func = func.intern if func.respond_to? :intern sig = Overload::Signature[*types] instance_eval do tbl = @overload ||= {} meth = instance_method(func) end if meth.arity < 0 or sig.length < meth.arity sig << nil if sig.last elsif sig.length > meth.arity raise ArgumentError, "too many arguments for #{func}(#{sig.length} for #{meth.arity})" end (tbl[func] ||= []) << [sig, meth] module_eval "def #{func}(*args, &block) ::Overload.dispatch(self, :#{func}, args, block) end" end end if $0 == __FILE__ require 'runit/testcase' require 'runit/cui/testrunner' END { RUNIT::CUI::TestRunner.run(RUNIT::TestCase.all_suite) } class TestOverload < RUNIT::TestCase include Overload # (1) dispatch in overload block def do_dispatch(*args) overload(args) do |args| args.dispatch(Fixnum, String, Float) do |i, s, f| [i, s, f] end args.dispatch(String, Fixnum) do |s, i| return [s, i] end args.dispatch(String, Fixnum, ()) do |s, i, *a| return [s, i, *a] end end end # (2) signature case def do_signature(*args) case args = Signature[*args] when Signature[Fixnum, String, Float] i, s, f = args [i, s, f] when Signature[String, Fixnum] s, i = args return s, i when Signature[String, Fixnum, ()] s, i, *a = args return s, i, *a else raise args.invalid end end # (3) separated methods def do_overload(i, s, f) assert_kind_of(TestOverload, self) [i, s, f] end overload(:do_overload, Fixnum, String, Float) def do_overload(s, i) assert_kind_of(TestOverload, self) return [s, i] end overload(:do_overload, String, Fixnum) def do_overload(s, i, *a) assert_kind_of(TestOverload, self) [s, i, *a] end overload(:do_overload, String, Fixnum) # test suit def test_cvar assert_kind_of(Hash, o = type.instance_eval {@overload}) assert_kind_of(Array, o = o[:do_overload]) case self when TestSuper assert_equal(1, o.length) when TestOverload assert_equal(3, o.length) end assert_kind_of(Overload::Signature, o[0][0]) assert_kind_of(UnboundMethod, o[0][1]) end def do_test_result(f) assert_equal([123, "hello", 123.456], __send__(f, 123, "hello", 123.456)) end def do_test_return(f) assert_equal(["hello", 123], __send__(f, "hello", 123)) end def do_test_rest(f) assert_equal(["hello", 123, "abc", "def"], __send__(f, "hello", 123, "abc", "def")) end def do_test_nomatch(f) e = assert_exception(TypeError) {__send__(f, "abc", "def")} assert_match(e.message, /\sString,\s*String\z/) end %w[dispatch overload signature].each do |t| %w[result return rest nomatch].each do |f| eval "def test_#{t}_#{f}; do_test_#{f}(:do_#{t}); end" end end end class TestSuper < TestOverload def do_dispatch(*args) overload(args) do |args| args.dispatch(String, String) do |f, s| [f, s] end return super end end def do_signature(*args) case args = Signature[*args] when Signature[String, String] f, s = args [f, s] else super end end def do_overload(f, s) assert_kind_of(TestSuper, self) [f, s] end overload(:do_overload, String, String) def do_test_super(f) assert_equal(["abc", "def"], __send__(f, "abc", "def")) end %w[dispatch overload signature].each do |t| undef_method "test_#{t}_nomatch" %w[super].each do |f| eval "def test_#{t}_#{f}; do_test_#{f}(:do_#{t}); end" end end end end -- --- 僕の前にBugはない。 --- 僕の後ろにBugはできる。 中田 伸悦