如何dynamic获取方法的源代码,以及该方法所在的文件

我想知道我是否可以在运行中获取源代码方法,以及是否可以获取该方法中的哪个文件。

喜欢

A.new.method(:a).SOURCE_CODE A.new.method(:a).FILE 

使用source_location

 class A def foo end end file, line = A.instance_method(:foo).source_location # or file, line = A.new.method(:foo).source_location puts "Method foo is defined in #{file}, line #{line}" # => "Method foo is defined in temp.rb, line 2" 

不过,它对于Ruby 1.9是新的。 对于Ruby 1.8,你可以使用这个gem ,当我得到第二个时,我将把这个代码复制到backports

到目前为止,没有任何答案显示如何显示方法的源代码在飞行中…

如果你使用John Mair(Pry的制造者)的真棒'method_source'gem其实很简单:该方法必须在Ruby(而不是C)中实现,并且必须从文件(不是irb)加载。

下面是一个使用method_source在Rails控制台中显示方法源代码的例子:

  $ rails console > require 'method_source' > I18n::Backend::Simple.instance_method(:lookup).source.display def lookup(locale, key, scope = [], options = {}) init_translations unless initialized? keys = I18n.normalize_keys(locale, key, scope, options[:separator]) keys.inject(translations) do |result, _key| _key = _key.to_sym return nil unless result.is_a?(Hash) && result.has_key?(_key) result = result[_key] result = resolve(locale, _key, result, options.merge(:scope => nil)) if result.is_a?(Symbol) result end end => nil 

也可以看看:

以下是如何从ruby打印出源代码:

 puts File.read(OBJECT_TO_GET.method(:METHOD_FROM).source_location[0]) 

我为此创造了“ri_for”gem

  >> require 'ri_for' >> A.ri_for :foo 

…输出源(和位置,如果你在1.9)。

GL。 -r

我必须实现一个类似的function(抓住块的来源)作为错误的一部分,你可以看到chunk.rb (依赖于Ryan Davis的RubyParser以及一些非常有趣的源文件glomming代码 )。 你必须修改它来使用Method#source_location ,也许调整一些其他的东西,所以它不包括def

顺便说一下,我认为Rubinius有这个function。出于某种原因,它已经被排除在MRI(标准的Ruby实现),因此这个黑客。

哦,我喜欢method_source中的一些东西! 像使用eval来判断一个expression式是否有效 (并且保持glomming源代码行,直到你停止得到parsing错误,像块一样)…

内部方法不具有源或源位置(例如, Integer#to_s

 require 'method_source' User.method(:last).source User.method(:last).source_location 

使用pry你可以使用show-method来查看一个方法的源代码,甚至可以看到一些ruby c源代码和pry- pry-doc安装。

请注意,我们也可以使用pry-doc插件查看C方法(从Ruby Core); 我们还展示了show-method的替代语法:

 pry(main)> show-method Array#select From: array.c in Ruby Core (C Method): Number of lines: 15 static VALUE rb_ary_select(VALUE ary) { VALUE result; long i; RETURN_ENUMERATOR(ary, 0, 0); result = rb_ary_new2(RARRAY_LEN(ary)); for (i = 0; i < RARRAY_LEN(ary); i++) { if (RTEST(rb_yield(RARRAY_PTR(ary)[i]))) { rb_ary_push(result, rb_ary_elt(ary, i)); } } return result; }