天天看點

rails環境下 ruby環境下class_eval的差別

rails環境下 ruby環境下class_eval的差別

先入為主,先看兩段代碼

1、寫一段純ruby腳本pure_ruby.rb:

module Big
  def middle(tiny)
    class_eval <<-RUBY_EVAL
      def #{tiny}
        "#{tiny}"
      end
    RUBY_EVAL
  end
end

class Size
  include Big

  def little
    middle("tiny")
  end
end

p Size.new.little       #=>class_eval undefine
p Size.instance_methods #=>[:little, :middle, ...]
p Big.instance_methods  #=>[:middle]
           

2、在rails環境下,比如/lib/rails_ruby.rake

desc 'the environment of ruby on rails'
task :rails_ruby, :enviroment => do
  module Big
    def middle(tiny)
      class_eval <<-RUBY_EVAL
        def #{tiny}
          "#{tiny}"
        end
      RUBY_EVAL
    end
  end

  class Size
    include Big

    def little
      middle("tiny")
    end
  end
end
p Size.new.little       #=>:little
p Size.instance_methods #=>[:little, :middle, :tiny, ...]
p Big.instance_methods  #=>[:middle, :tiny]
           

很顯然,從Size.new.little的結果可以看出,include Big後,傳到middle下class_eval的self不是Size而是Size執行個體,而調用class_eval一定是Class或是Module,在rails環境下執行個體可以調用class_eval,這明顯是rails架構的問題,通過pry的跟蹤rails源碼,原來是rails的activesupport下Kernel對calss_eval的重新定義,rails下calss_eval的源碼