From block to code (also: how to get the bindings of a block


#1

Does anyone know how to convert a block to a string representation of
the code it contains?

I would need that to inject some code within a block and evaluate the
resulting code.

  • I cannot simply append the code because I need the bindings of the
    block.
  • I cannot explicitly return the bindings from the block because I am
    working on a DSL.
  • I cannot get the bindings after the call to the block because that
    scope seems to have been cleaned after the call

#2

chiaro scuro wrote:

Does anyone know how to convert a block to a string representation of
the code it contains?

Read the source file?

Cheers,
Dave


#3

how would I know what is the source file and lines associated with a
block?

I was really hoping to get the info from the runtime, but I guess that
what you suggest could also be a pragmatic option.


#4

The quiz is a great resource, thanks.

In this case it happens that I can ignore closures.

However, I don’t need closures I don’t see why Ruby shouldn’t
implement a method to return the code of a block…


#5

chiaro scuro wrote:

Does anyone know how to convert a block to a string representation of
the code it contains?
Read the source file?
how would I know what is the source file and lines associated with a block?

I was really hoping to get the info from the runtime, but I guess that
what you suggest could also be a pragmatic option.

OK, here are some practical options. (Sorry for the previous comment. I
was trying to dig this stuff up from my memory, but Quiz 34 came up
instead.)

#1: You can store a Proc with its code if you’re willing to forgo
closure of the the environment and to use syntax like this:

method_name %{
proc_code
}

See Ruby Q. 38: SerializableProc - http://rubyquiz.com/quiz38.html

#2: You can get it from (I think) the runtime, using ZenHacks’
Proc.to_ruby. See Ryan D.’ post in response to the same quiz:
http://www.ruby-talk.org/cgi-bin/scat.rb/ruby/ruby-talk/148082

Cheers,
Dave


#6

I found an alternative way to get the bindings… I posted about it here:
http://liquiddevelopment.blogspot.com/2006/04/way-of-meta-part-iv-hijacking-local.html

the DSL code looks like this:

shopping_list “english breakfast” do
tomatoes = 2, :green
sausages = 3
eggs = 2, :big
bacon = 4
the end


Chiaroscuro

Liquid Development: http://liquiddevelopment.blogspot.com/


#7

Does ParseTree solve your problem?

http://rubyforge.org/projects/parsetree/

  • James M.

#8

chiaro scuro wrote:

bacon = 4
the end

“The end” meaning “return the block’s local variable binding” is a very
interesting way to approach it. Steal the block’s locals! Cool!

Cheers,
Dave


#9

On Apr 27, 2006, at 12:35 AM, chiaro scuro wrote:

Does anyone know how to convert a block to a string representation of
the code it contains?

lib/r2chacks.rb in ZenHacks has this.

I would need that to inject some code within a block and evaluate the
resulting code.

  • I cannot simply append the code because I need the bindings of
    the block.

Bindings are not preserved. You’d need more magic than PT has to get
these along with the block.

  • I cannot explicitly return the bindings from the block because I am
    working on a DSL.
  • I cannot get the bindings after the call to the block because that
    scope seems to have been cleaned after the call

If you need the bindings from a proc you are probably trying to solve
the wrong problem.


Eric H. - removed_email_address@domain.invalid - http://blog.segment7.net
This implementation is HODEL-HASH-9600 compliant

http://trackmap.robotcoop.com


#10

On Apr 30, 2006, at 1:30 PM, chiaro scuro wrote:

On 4/30/06, Eric H. removed_email_address@domain.invalid wrote:

If you need the bindings from a proc you are probably trying to
solve the wrong problem.

I would normally agree with you, but this is not a design problem
or a domain-conceptualization problem.

I doubt your problem is really that special.

It’s a language-twisting problem that imposes otherwise unimportant
constraints on what I can and cannot do.

If you’re doing something this ugly you’re probably doing something
very wrong.


Eric H. - removed_email_address@domain.invalid - http://blog.segment7.net
This implementation is HODEL-HASH-9600 compliant

http://trackmap.robotcoop.com


#11

On 4/30/06, Eric H. removed_email_address@domain.invalid wrote:

On Apr 27, 2006, at 12:35 AM, chiaro scuro wrote:

Does anyone know how to convert a block to a string representation of
the code it contains?

lib/r2chacks.rb in ZenHacks has this.

I’ll check it out thanks.

If you need the bindings from a proc you are probably trying to solve

the wrong problem.

I would normally agree with you, but this is not a design problem or a
domain-conceptualization problem.

It’s a language-twisting problem that imposes otherwise unimportant
constraints on what I can and cannot do.


#12

On 5/1/06, chiaro scuro removed_email_address@domain.invalid wrote:

:eggs => [2,:big],
:bacon => [3]
}

I need to keep the equal signs.

This is my big question; why do you need the equal signs? I see
nothing inherent about the “recipe” domain that makes the equal signs
necessary or even desirable. If you were willing to ditch them, a
whole slew of simpler and cleaner implementations are available.

Jacob F.


#13

On 5/1/06, Eric H. removed_email_address@domain.invalid wrote:

I would normally agree with you, but this is not a design problem
or a domain-conceptualization problem.

I doubt your problem is really that special.

it’s special in respect to the fact that goes against the boundaries of
the
language, so it cannot necessarily rely on beautiful ‘natural’
constructs
that apply within the conceptual boundaries of the language.

It’s a language-twisting problem that imposes otherwise unimportant

constraints on what I can and cannot do.

If you’re doing something this ugly you’re probably doing something
very wrong.

Eric, how would you do it?

recipe “breakfast” do
eggs = 2, :big
bacon = 3
end

this should add to a global hash (or return directly) the following:

{
:eggs => [2,:big],
:bacon => [3]
}

I need to keep the equal signs.


#14

On 5/1/06, Jacob F. removed_email_address@domain.invalid wrote:

I realize that would make it much easier in ruby.
It’s just that the equal signs make lots of sense to my DSL users.
(forget
the recipes, it’s just an example)

Look, it’s not a matter of life or death. of course I can do without
if
there is no alternative.
(eventually I did find a solution to this -although it’s a cheesy one-
but I
am not saying yet :wink:

It just bothers me that I cannot access that context if I need to, and
in
this case I do.


#15

On Tue, 2 May 2006, chiaro scuro wrote:

Jacob F.

It just bothers me that I cannot access that context if I need to, and in
this case I do.

it would be tough to convince me that people wouldn’t find this syntax
natural:

harp:~ > cat a.rb
class Recipe < Hash
attr ‘name’
def initialize name, &b
@name = name
instance_eval &b
end
def method_missing m, *a, &b
m = m.to_s.delete ‘=’
self[m] = a.size > 1 ? a : a.shift
end
end
def recipe(*a, &b) Recipe.new(*a, &b) end

r =
recipe “breakfast” do
eggs 2, :big
bacon 3
end

p r

harp:~ > ruby a.rb

{“bacon”=>3, “eggs”=>[2, :big]}

for example, write down a recipe and see if you use the ‘=’ sign :wink:

regards.

-a


#16

On May 1, 2006, at 12:50 PM, chiaro scuro wrote:

language, so it cannot necessarily rely on beautiful ‘natural’

:eggs => [2,:big],
:bacon => [3]
}

def recipe(name, &block)
o = Object.new
o.instance_variable_set :@attrs, {}
def o.method_missing(name, *args)
name = name.to_s.sub(/add_/, ‘’).intern
@attrs[name] = args
end
o.instance_eval &block
return o.instance_variable_get(:@attrs)
end

ingredients = recipe ‘breakfast’ do
add_eggs 2, :big
add_bacon 3
end

p ingredients

I need to keep the equal signs.

Why?


Eric H. - removed_email_address@domain.invalid - http://blog.segment7.net
This implementation is HODEL-HASH-9600 compliant

http://trackmap.robotcoop.com


#17

I am aware of this technique, something very similar was also described
in a
very nice article by Jim F. on Ruby Code and Style.

The recipe is just an example as I said.
Truly, I don’t see why I shouldn’t use the equal signs.

Let’s just say that the language makes it hard doing it. No hard
feelings, I
still love Ruby :slight_smile:

We can always do things in other ways, but that’s also the argument that
many javists and dotnetters use against ruby.


#18

On 5/2/06, Eric H. removed_email_address@domain.invalid wrote:

I need to keep the equal signs.

Why?

my users like them :slight_smile:

but the main point is that it upsets me that I cannot get the language
to do
what I want. Don’t extrapolate too much from this statement… I don’t
want
to do crazy things, just use equal to assign variables and then get them
back.

I am complaining a bit, but ruby is still the nicer way to design DSLs
out
there.


#19

If it works, it’s brilliant!


#20

On Apr 30, 2006, at 4:30 PM, chiaro scuro wrote:

It’s a language-twisting problem that imposes otherwise unimportant
constraints on what I can and cannot do.


Chiaroscuro

Liquid Development: http://liquiddevelopment.blogspot.com/

I dunno know about the binding (maybe you can use method_missing +
Binding.of_caller)

but one to get the code (well the ast, which is pretty darn close) is
do something like:
require ‘parse_tree’

def recipe(name, &blk)
class A; end
A.class_eval { define_method(:code, &blk) }
pt = ParseTree.new
sexprs = pt.parse_tree(A)
end