How can I get source code of a method dynamically and also which file is this method locate in

Ruby

Ruby Problem Overview


I would like to know whether I can get source code a method on the fly, and whether I can get which file is this method in.

like

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

Ruby Solutions


Solution 1 - Ruby

Use 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"

Note that for builtin methods, source_location returns nil. If want to check out the C source code (have fun!), you'll have to look for the right C file (they're more or less organized by class) and find the rb_define_method for the method (towards the end of the file).

In Ruby 1.8 this method does not exist, but you can use this gem.

Solution 2 - Ruby

None of the answers so far show how to display the source code of a method on the fly...

It's actually very easy if you use the awesome 'method_source' gem by John Mair (the maker of Pry): The method has to be implemented in Ruby (not C), and has to be loaded from a file (not irb).

Here's an example displaying the method source code in the Rails console with method_source:

  $ 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 

See also:

Solution 3 - Ruby

Here is how to print out the source code from ruby:

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

Solution 4 - Ruby

Without dependencies

method = SomeConstant.method(:some_method_name)
file_path, line = method.source_location
# puts 10 lines start from the method define 
IO.readlines(file_path)[line-1, 10]

If you want use this more conveniently, your can open the Method class:

# ~/.irbrc
class Method
  def source(limit=10)
    file, line = source_location
    if file && line
      IO.readlines(file)[line-1,limit]
    else
      nil
    end
  end
end

And then just call method.source

With Pry you can use the show-method to view a method source, and you can even see some ruby c source code with pry-doc installed, according pry's doc in codde-browing

> Note that we can also view C methods (from Ruby Core) using the > pry-doc plugin; we also show off the alternate syntax for 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; > }

Solution 5 - Ruby

I created the "ri_for" gem for this purpose

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

... outputs the source (and location, if you're on 1.9).

GL. -r

Solution 6 - Ruby

Internal methods don't have source or source location (e.g. Integer#to_s)

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

Solution 7 - Ruby

I had to implement a similar feature (grab the source of a block) as part of Wrong and you can see how (and maybe even reuse the code) in chunk.rb (which relies on Ryan Davis' RubyParser as well as some pretty funny source file glomming code). You'd have to modify it to use Method#source_location and maybe tweak some other things so it does or doesn't include the def.

BTW I think Rubinius has this feature built in. For some reason it's been left out of MRI (the standard Ruby implementation), hence this hack.

Oooh, I like some of the stuff in method_source! Like using eval to tell if an expression is valid (and keep glomming source lines until you stop getting parse errors, like Chunk does)...

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionallenweiView Question on Stackoverflow
Solution 1 - RubyMarc-André LafortuneView Answer on Stackoverflow
Solution 2 - RubyTiloView Answer on Stackoverflow
Solution 3 - RubyAutomaticoView Answer on Stackoverflow
Solution 4 - RubyfangxingView Answer on Stackoverflow
Solution 5 - RubyrogerdpackView Answer on Stackoverflow
Solution 6 - RubyDorianView Answer on Stackoverflow
Solution 7 - RubyAlexChaffeeView Answer on Stackoverflow