2

Crafting Rails Applications の本を読んでいて、Rails のソース コードを手に入れました。そこで私は考えさせられる RUBY_EVAL の例をいくつか見つけました。

action_controller/metal/renderers.rb はこれを使用して、_write_render_options の本体を構成し、_handle_render_options メソッドを定義します。

def _write_render_options
  renderers = _renderers.map do |name, value|
    <<-RUBY_EVAL
      if options.key?(:#{name})
        _process_options(options)
        return _render_option_#{name}(options.delete(:#{name}), options)
      end
    RUBY_EVAL
  end

  class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1
    def _handle_render_options(options)
      #{renderers.join}
    end
  RUBY_EVAL
end

_render_option_#{name} メソッドもオンザフライで定義されます

RENDERERS = {}
def self.add(key, &block)
  define_method("_render_option_#{key}", &block)
  RENDERERS[key] = block
  All._write_render_options
end

eval の代替手段があったように私には思えます。キーに関連付けられた &blocks をハッシュの下に保持しないのはなぜですか? _handle_render_options を呼び出すときに、適切なブロックを選択して評価するのでしょうか? 非効率的な if がたくさんあるメソッド本体を構築するのはなぜですか?

わからない。

4

1 に答える 1

2

非効率的な if がたくさんあるメソッド本体を構築するのはなぜですか?

まあ、非効率ではありません。説明したように、実行時にオプションのハッシュがある場合は、オプションのリストで使用可能な各レンダラーをチェックして、実行時にハッシュをループする必要があります。現在の実装では、基本的にこのループを一連の節に展開しています。したがって、実行時にループを実行するよりも実際には高速になります。

実際、コードが現在のように見えるすべての理由はパフォーマンスです。ブロックをメソッドにコンパイルする方が実際には高速であるため、ブロックを保持しないのはそのためです。ただし、Ruby VM/GC はリリースごとに変更され、もはや真実ではないか、アプローチの違いはもはや重要ではないかもしれませんが、最初に作成されたときはそうでした。

于 2013-04-23T00:00:11.213 に答える