How to Get Source Code of a Method Dynamically and Also Which File Is This Method Locate In

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

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.

Can I make ruby print the source code for a dynamic method?

If a class is extended at runtime, is its source safe from being investigated?

No, it is not safe. For example, ParseTree could be used to determine the actual runtime code for the method and reverse-engineer an equivalent implementation.

How could I extract the code of a method dynamically using reflection or something similar?

Reflection allows you to discover the class members like properties or methods, but it only gives information on their signature (parameter names and types and return type etc.) but no information about their implementation.


If you have access to the source code, you can use the C# compiler to do a syntax analysis for you.

See: Get started with syntax analysis (The .NET Compiler Platform SDK).

Especially the Traversing trees chapter explains how you can discover the structure of your code.


But maybe a better way to document your code is to use XML-comments (also called Documentation comments).

In the project options in the Build page, check the XML documentation file check box and then write comments like these:

/// <summary>
/// Base module for sandboxed operations.
/// </summary>
public abstract class SandboxModule
{
/// <summary>
/// Implementing modues must override this method.
/// </summary>
protected abstract void Execute();
}

/// <summary>
/// This is my super cool demo module.
/// </summary>
public class DemoModule : SandboxModule
{
/// <summary>
/// Does something super cool and new.
/// </summary>
/// <remarks>It does so by calling the private method <c>SomethingSuperCoolAndNew</c>.</remarks>
protected override void Execute()
{
int x = 3;
SomethingSuperCoolAndNew(x);
}

/// <summary>
/// Important things happen here.
/// </summary>
/// <param name="someArg">Magic parameter.</param>
private void SomethingSuperCoolAndNew(int someArg)
{
// Do something super cool and new.
}
}

In the output directory (bin\Debug) the compiler will create an XML file looking like this:

<?xml version="1.0"?>
<doc>
<assembly>
<name>StackOverflowTests3</name>
</assembly>
<members>
<member name="T:StackOverflowTests3.SandboxModule">
<summary>
Base module for sandboxed operations.
</summary>
</member>
<member name="M:StackOverflowTests3.SandboxModule.Execute">
<summary>
Implementing modues must override this method.
</summary>
</member>
<member name="T:StackOverflowTests3.DemoModule">
<summary>
This is my super cool demo module.
</summary>
</member>
<member name="M:StackOverflowTests3.DemoModule.Execute">
<summary>
Does something super cool and new.
</summary>
<remarks>It does so by calling the private method <c>SomethingSuperCoolAndNew</c>.</remarks>
</member>
<member name="M:StackOverflowTests3.DemoModule.SomethingSuperCoolAndNew(System.Int32)">
<summary>
Important things happen here.
</summary>
<param name="someArg">Magic parameter.</param>
</member>
</members>
</doc>

This Visual Studio Magazine article explains how you can convert these XML-files into help files: Doing Visual Studio and .NET Code Documentation Right.

The documentations comments are even visible within Visual Studio's IntelliSense tooltips.

how to get source code text in ruby?

You can't get the string representation of a part of the code, edit it and expect Ruby to reevaluate your changes. The only way to do something near to what you want is using ParseTree to get s-expressions of the source, edit and use Ruby2Ruby to generate a string of ruby code. Them add def ... and end to the string and call eval with it.

It's too hard and error-prone to be useful in a real-world situation. But I don't know any other way.

Note: ParseTree only works on Ruby 1.8.

Ruby / Rails -- from where was a method was included?

Whatever context you're in you can get the source location by using:

obj.method(:method).source_location

It won't give you exactly what you want, but the Rails core developers are good about properly namespacing things. The following example can be run from the rails console:

Time.method(:zone).source_location

["/Users/pete/.rvm/gems/ruby-1.9.2-p290@gemset/gems/activesupport-3.2.3/lib/active_support/core_ext/time/zones.rb", 9]

Then you can go to the Rails source and search for that file. Hint: type 't' on Github and start typing. It will bring you to that file and you can see that it is defined directly on the Time class.

Access Pry's show-source method from Ruby file

Ruby has the build-in method Method#source_location which can be used to find the location of the source. The method_source gem builds upon this by extracting the source based upon the source location. However this doesn't work for methods defined in the interactive console. Methods must be defined in a file.

Here is an example:

require 'set'
require 'method_source'

puts Set.method(:[]).source_location
# /home/user/.rvm/rubies/ruby-2.4.1/lib/ruby/2.4.0/set.rb
# 74
#=> nil

puts Set.method(:[]).source
# def self.[](*ary)
# new(ary)
# end
#=> nil

Keep in mind that all core Ruby methods are written in C and return nil as source location. 1.method(:+).source_location #=> nil The standard library is written in Ruby itself. Therefore the example above works for Set methods.

Source code for an eval'ed/dynamically generated function in Python

So I was able to partially figure this out by digging into the IPython source code. It makes use of the builtin module linecache, which contains functions for reading source code from files and caching the results. The inspect and traceback modules both use this module to get the source of a function.

The solution is to create the function the same way as in the question, but using compile with a made-up and unique file name:

source = 'def foo(x, y):' + '\n\t' + 'return x / y'

filename = '<dynamic-123456>' # Angle brackets may be required?
code = compile(source, filename, 'exec')

g = {numpy: numpy, ...} # Modules and such required for function
l = {}
exec(src, g, l)
func = l['foo']

linecache contains a variable cache which is a dictionary mapping file names to (size, mtime, lines, fullname) tuples. You can simply add an entry for the fake file name:

lines = [line + '\n' for line in source.splitlines()]

import linecache
linecache.cache[filename] = (len(source), None, lines, filename)

The function will then work with inspect.getsource(), IPython's ?/?? syntax, and in IPython tracebacks. However, it still doesn't seem to work in built-in tracebacks. This is mostly sufficient for me because I almost always work in IPython.

EDIT: see user2357112's comment below for how to get this working with traceback printing in the builtin interpreter.



Related Topics



Leave a reply



Submit