14

I have a method that takes a block.

Obviously I don't know what is going to be passed in and for bizarre reasons that I won't go into here I want to print the contents of the block.

Is there a way to do this?

niton
  • 8,771
  • 21
  • 32
  • 52
Derek Ekins
  • 11,215
  • 6
  • 61
  • 71

6 Answers6

9

You can do this with Ruby2Ruby which implements a to_ruby method.

require 'rubygems'
require 'parse_tree'
require 'parse_tree_extensions'
require 'ruby2ruby'

def meth &block
  puts block.to_ruby
end

meth { some code }

will output:

"proc { some(code) }"

I would also check out this awesome talk by Chris Wanstrath of Github http://goruco2008.confreaks.com/03_wanstrath.html He shows some interesting ruby2ruby and parsetree usage examples.

Corban Brook
  • 21,270
  • 4
  • 28
  • 34
  • Does this only work with Ruby 1.8? http://blog.zenspider.com/2009/04/parsetree-eol.html talks about "dropping block/proc support" to deal with ParseTree not being available in ruby 1.9. – Andrew Grimm Nov 04 '09 at 22:21
  • No this will not work in ruby 1.9 as it doesn't provide the needed hooks for ParseTree to work. Apparently there is noway to get the sexp in 1.9. This is not a huge problem because by the time everyone makes the switch to 1.9 other vms like rubinius should be available for prime time. Rubinius natively includes a to_sexp for all objects so it will be trivial to do these sort of operations. – Corban Brook Nov 05 '09 at 04:01
5

In Ruby 1.9+ (tested with 2.1.2), you can use https://github.com/banister/method_source

Print out the source via block#source:

#! /usr/bin/ruby
require 'rubygems'
require 'method_source'

def wait &block
  puts "Running the following code: #{block.source}"
  puts "Result: #{yield}"
  puts "Done"
end

def run!
  x = 6
  wait { x == 5 }
  wait { x == 6 }
end

run!

Note that in order for the source to be read you need to use a file and execute the file (testing it out from irb will result in the following error: MethodSource::SourceNotFoundError: Could not load source for : No such file or directory @ rb_sysopen - (irb)

Nick B
  • 7,639
  • 2
  • 32
  • 28
4

Building on Evangenieur's answer, here's Corban's answer if you had Ruby 1.9:

# Works with Ruby 1.9
require 'sourcify'

def meth &block
  # Note it's to_source, not to_ruby
  puts block.to_source
end

meth { some code }

My company uses this to display the Ruby code used to make carbon calculations... we used ParseTree with Ruby 1.8 and now sourcify with Ruby 1.9.

Seamus Abshere
  • 8,326
  • 4
  • 44
  • 61
2

In Ruby 1.9, you can try this gem which extract the code from source file.

https://github.com/ngty/sourcify

2

In Ruby 2.5 the following works

puts block.source

surgentt
  • 399
  • 1
  • 3
  • 10
1

In ruby 2.7, using the method_source gem (pry depends on it)

Set.instance_method(:merge).source.display
# =>
def merge(enum)
  if enum.instance_of?(self.class)
    @hash.update(enum.instance_variable_get(:@hash))
  else
    do_with_enum(enum) { |o| add(o) }
  end

  self
end

The repo says it works for procs, but I haven't tested it.

pixelearth
  • 13,674
  • 10
  • 62
  • 110