From: Makoto Kuwata Date: 2008-02-11T02:47:54+09:00 Subject: [ruby-dev:33688] Re: erb.rb の仕様について 桑田です。 回答ありがとうございます。 2008/2/10 Masatoshi SEKI : > > > > 1. ERB#result() で、safe_level が設定されているときに > > Thread を生成してからその中で eval していますが、 > > Thread を生成する理由を教えていただけませんか。 > > たしか、$SAFEはより大きな値しか設定できないからだったと > 思います。 > 呼び出し元の$SAFEが変わってしまうのを避けるためですね。 > 今ならもっとうまい方法があるかもしれません。 こちらに書いてありました。 http://www.ruby-lang.org/ja/man/html/_A5BBA5ADA5E5A5EAA5C6A5A3A5E2A5C7A5EB.html $SAFE って、普通のグローバル変数だと思ってましたが、 そうではないんですね。 それでは、Thread を使うかどうかは仕様ではなく、 「safe_level を設定したときにそれがメインプログラムの $SAFE に影響を及ぼさないこと」が仕様だという理解で よろしいでしょうか。 もしそうなら、次のようにすれば Thread の生成を少なく できていいのかなと思いました。 Index: lib/erb.rb =================================================================== --- lib/erb.rb (revision 15382) +++ lib/erb.rb (working copy) @@ -733,7 +733,7 @@ # code evaluation. # def result(b=TOPLEVEL_BINDING) - if @safe_level + if @safe_level && @safe_level > $SAFE th = Thread.start { $SAFE = @safe_level eval(@src, b, (@filename || '(erb)'), 1) =================================================================== > > 2. 以下のメソッドやモジュールは #:nodoc: がついてますが、 > > これらは非公開であり積極的に使うべきでないと考えて > > いいでしょうか。 > > もっというと、これらをERBの仕様と考えていいかどうかと > > いうことなんですが。 > > - ERB#def_method > > - ERB#def_module > > - ERB#def_class > > - ERB::DefMethod > > > これらは積極的に使ってほしいメソッドです。 > > rdocについてはどなたかが書いてくれたもので、公開(?)と関 > 連はありません。 > > 気分的には、ERB::Compiler関連が非公開(といっても > Rubyなので実質公開)です。 > ERB::Compilerを改造しても怒られないだろうなあ、と期待してます。 > なんと、erb.rb の正式な仕様でしたか。了解しました。 では :nodoc: は取り除いた方がいいですね。 あと Compiler class は ERB の仕様には含めないものとして 考えます。 > > > > 3. ERB#set_eoutvar() って必要でしょうか? > > ERB#initialize() の引数 _eoutvar を使えば変数名 _erbout > > は > > 変更できるから、set_eoutvar() は必要ないように思います。 > > すっかり忘れていましたが、_erboutは変数名しか設定できな > いから > メソッドにしてフックできるようにしたようです。 > > * http://www.druby.org/ilikeruby/erbquote.html > * http://d.hatena.ne.jp/m_seki/20061031#1162304780 これって、非公開としている Compiler オブジェクトが 引数に必要なんですよね。設計としてはあんまりよろしく ないと思いますが、どうでしょうか。 #そもそも set_eoutvar() は非公開メソッド? #なら :nodoc: つけてほしいです。 #丁寧にも RDoc がついているから、ERB の仕様だと #思ってしまいました。 というか、オプション引数のことをまったく考慮していない CGI#initalize() とは違って、ERB#initialize() は引数で eoutvar を取るようにちゃんと設計されているので、 できればこれで済むような設計がいいと思います。 ERB#eoutvar と ERB#eoutvar= はあってもいいと思いますが。 たとえばこんなのはどうでしょうか。要件を満たしているか どうか分かりませんが。 class ERB def initialize(eruby_str, safe_level=nil, trim_mode=nil, eoutvar='_eoutvar') ... @compiler = Compiler.new @compiler.eoutvar = eoutvar ... end def eoutvar=(name) @compiler.eoutvar = name end def eoutvar @compiler.eoutvar end end あるいは ERB class を拡張するのではなくて、composition を使って 使用する Compiler class を指定できるようにするとか。 -- makoto kuwata