Block as string

Hi All,
Is there an easy way to get a block / proc / lambda as a string…
without
any fancy serialization, no binding… just the code block as string?

Thanks!

L-P

You’ll want to check out ruby2ruby:
http://seattlerb.rubyforge.org/ruby2ruby/

There’s nothing built into Ruby that will get you this.

Jason

mmm, I’m looking for a jRuby compatible solution… Ruby2Ruby look like
its
C dependant.
any other idea?

2009/6/2 Jason R. [email protected]

Louis-Philippe wrote:

any other idea?

Well, you can remember the string form at the time you define the
lambda.

def fn(str)
res = eval “lambda { #{str} }”
class <<res; self; end.class_eval { define_method(:source) { str } }
res
end

a = fn “|x| puts x+x”
a[“Hello”]
puts a.source

Thanks Brian,
It’s a neat trick! I’ll remember it!

I’m not sure I’ll use it though, as it require you define the function
inside a string…
a bit cumbersome.

what I need is some sort of macro system (the LISP macro, not the C
one),
to parse the block before calling it. I was thinking to make it a
string,
then parsing with regex, would have done it… but seems not. I’ll work
out
an other logic around the problem then ;).

L-P

2009/6/3 Brian C. [email protected]

Slightly enhanced version

module Kernel
alias :orig_lambda :lambda
def lambda(src=nil,*rest,&blk)
if src.nil?
orig_lambda(&blk)
else
res = eval “lambda { #{src} }”, *rest
class << res; self; end.class_eval { define_method(:source) { src
} }
res
end
end
end

a = lambda { |x| puts x+x }
b = lambda %{ |x| puts x+x+x }
a[“a”]
b[“b”]
puts b.source

%{…} performs substitutions as per double-quoted string

prefix = “hello”
c = lambda %{ |x| puts "#{prefix} " + x }
puts c.source
c[“world”]

%q{…} is like single-quoted string

d = lambda %q{ |x| puts "#{prefix} " + x }, binding
puts d.source
d[“world”]
prefix = “goodbye”
d[“world”]

Louis-Philippe wrote:

I’m not sure I’ll use it though, as it require you define the function
inside a string…
a bit cumbersome.

How about using %{ … } for the string? Then it looks more like a
normal lambda.

a = fn %{ |x| puts x+x }
a[“Hello”]
puts a.source

Or you can read the source from its own file, or for longer snippets you
can use a here-doc.

a = fn <<‘EOF’
{ |x| puts x }
EOF

what I need is some sort of macro system (the LISP macro, not the C one),
to parse the block before calling it. I was thinking to make it a string,
then parsing with regex, would have done it…

Ruby doesn’t have macros. If you write a block in the usual way, the
Ruby interpreter will turn it into a Block object, and you cannot get
its source form back (in MRI anyway)

If you are only interested in simple regexp source transformations, then
you should start from a string form as above, transform, then eval.

For more complex transformations, still starting with a string, you
might be able to use one of the ruby-in-ruby implementations (e.g.
rubinius) or ParseTree to parse and transform it, I’m not sure.

On 6/3/09, Louis-Philippe [email protected] wrote:

what I need is some sort of macro system (the LISP macro, not the C one),
to parse the block before calling it. I was thinking to make it a string,
then parsing with regex, would have done it… but seems not. I’ll work out
an other logic around the problem then ;).

RubyMacros is an implementation of lisp-like macros for ruby…
however, unlike ParseTree, it doesn’t allow you to get at the contents
of a block. It does however, provide lisp-like forms as well. Maybe
you can put whatever code you need into a form? Take a look here:

http://github.com/coatl/rubymacros

On Jun 2, 2009, at 14:47 , Louis-Philippe wrote:

mmm, I’m looking for a jRuby compatible solution… Ruby2Ruby look
like its
C dependant.
any other idea?

jruby has their own parsetree equivalent, but I don’t know of / doubt
they have their own r2r equivalent. I know they haven’t bothered to
conform to the unified_ruby “spec” that I set up for all PT related
projects to ensure compatibility… so my guess is you’re out of luck.

Thanks guys,
while I think RubyMacro is a great idea (!!!),
I will wait until it get a bit more maturity and speed before using it.

I’ll probably stick one of your trick onto a block Brian, something
like:


$var = “global var”

def parsed_execution(list)
cmd_array = list.split("\n").map { |i| i.chomp.lstrip.rstrip }

process cmd_array here

cmd_array.each_with_index do |o,i|
puts “cmd #{i}:”
$var = “Finished!!” if i == cmd_array.size-1
eval o
end
end

parsed_execution <<-BLOCK
puts “Line 1”
puts $var
puts “replacing global var…”
$var = “new global var” # will never get printed!!!
puts $var
BLOCK

I choosed the <<-EOF string because it is less likely to introduce
conflict
with the inner syntax… though %Q with a rightly choosed symbol might
also
be interesting.
what would be even neater would be to alias the <<- or %Q as something
smaller or more intuitive for my DSL, but I believe this is
impossible…

Thanks!

L-P

2009/6/3 Caleb C. [email protected]

Louis-Philippe wrote:

I’ll probably stick one of your trick onto a block Brian, something
like:

OK - not sure why you’re eval’ing it a line at a time though, instead of
all at once, as that would prevent you doing lots of interesting things,
like loops written across multiple lines.

I see you’re using a global var. You may want to check out instance_eval
(to set the default method receiver to an arbitrary object), and the
‘binding’ parameter to eval (to be able to access local variables from a
different scope)

Regards,

Brian.

Thanks Brian,
The single line evaluation will be usefull in my purpose built DSL,
I’m essentially trying to build an iterative execution structure on top
of a
recusive context-free one.
Too complex to explain in a couple lines, and still not all clear to
me…
so the code I pasted is only an example, my project is all built using
classes and more cleanly scoped variables.

L-P

2009/6/4 Brian C. [email protected]