1

inspired by some lisp magic of runtime edit sourcecode,

I want to do it in ruby. looks like I cannot get sourcecode from method/class, is there a way to do it?

I write a sample sourcecode here:

def helloworld n
  "hello #{n}"
end

o = Kernel.method :helloword

Kernel.define_singleton_method o.name do |n|
  eval o.source_code.sub('hello', 'hello world')
end

helloworld 'halida' #=> 'hello world halida'
Guilherme Bernal
  • 8,183
  • 25
  • 43
linjunhalida
  • 4,538
  • 6
  • 44
  • 64
  • See the similar questions on Stackoverflow: http://stackoverflow.com/questions/4740684/ruby-get-source-code or http://stackoverflow.com/questions/3393096/how-can-i-get-source-code-of-a-methods-dynamically-and-also-which-file-is-this-m or http://stackoverflow.com/questions/4719649/ruby-print-source-code or http://stackoverflow.com/questions/1164903/find-the-source-of-eval-code ... – mliebelt Dec 29 '11 at 10:03

3 Answers3

0

You can easily get source code for a method in Ruby.

Imagine the following hypothetical class:

class Klass
  def self.foo
    :foo
  end

  def bar
    :bar
  end
end

As you can see, this class has two methods:

  • a class method .foo
  • an instance method #bar

Use .method and .instance_method to access them programmatically:

m1 = Klass.method :foo
=> #<Method: Klass.foo>

m2 = Klass.instance_method :bar
=> #<UnboundMethod: Klass#bar>

You can use the .source method to view their source code:

puts m1.source
  def self.foo
    :foo
  end
=> nil

puts m2.source
  def self.bar
    :bar
  end
=> nil

Because Ruby has open classes and dynamic loading, you can also add or change methods at run time. Just re-open the class and redefine the method:

Klass.foo
=> :foo

class Klass
  def self.foo
    :foobar
  end
end

Klass.foo
=> :footer

The other methods previously defined in the class will remain unaffected:

Klass.bar
=> :bar

WARNING: Redefining class behavior during runtime (also called "Monkey Patching") is a very powerful tool, it can also be somewhat dangerous. Current versions of Ruby support a much more controlled way of going about this called 'refinements'.

You can learn more about using refinements here

0

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.

Guilherme Bernal
  • 8,183
  • 25
  • 43
  • You absolutely can get a string representation of the source code. Just use `.method.source` for class methods or `.instance_method.source` for instance methods. If you want to edit the string and reapply it you can just open the class redefine the method and use `eval` on the new string. – Jerry Hilts Jun 30 '16 at 16:52
  • See also `class_eval` and `instance_eval` – Jerry Hilts Jun 30 '16 at 16:58
0

Have a look at method_source gem. It's used by pry REPL for show-method command.

Looks like this gem utilizes standard Method#source_location (available in Ruby 1.9) to locate method and get its source code. Obviously, it doesn't work for dynamically defined methods and C methods. See docs for more information.

KL-7
  • 46,000
  • 9
  • 87
  • 74