Traversing the contents of a proc (for a DSL)

S

Siemen Baader

Hi List,

Is it possible to traverse and modify the statements inside a Proc
after it has been created?

I'm playing with a small DSL for HTML, which should look like this.

html {
head { title {"Hello World"} }
body {
h1 { "hello"}
p {
"text body"
"more text"
}
}
}

If it is possible to recursively traverse through the statements in
each block, I could join the lines together with the + operator, and
the implementation would be fairly easy - just recursive calls that
return text. But it does not look like this is possible...

An alternative would be to create a new object for each node in the
HTML (eg body or h1), and let each method call inside this node assign
its content to an array there. Less functional style and more
overhead, but doable. But this requires either that I catch the
creation of new strings (no idea if that is possible) for them to be
added to the node as well, or that I introduce a new method to create
strings.

Any comments highly appreciated!

cheers,
Siemen
 
K

Kyle

[Note: parts of this message were removed to make it a legal post.]

Generally - no. A proc is compiled code, it doesn't remember its own source
code. There are libraries that provide some deeper introspection tools -- like
the ParseTree / Ruby2Ruby libraries. Also, there are several DSLs very simllar
to what you're talking about already -- check out Markaby:

http://markaby.rubyforge.org/
 
S

Siemen Baader

[Note: parts of this message were removed to make it a legal post.]

Generally - no. A proc is compiled code, it doesn't remember its own source
code. There are libraries that provide some deeper introspection tools --
like
the ParseTree / Ruby2Ruby libraries. Also, there are several DSLs very
simllar
to what you're talking about already -- check out Markaby:

http://markaby.rubyforge.org/
Thanks! The two introspection libs look really interesting.

I know that there are plenty of templating tools available. But I'm just
playing around with DSLs and chose HTML because it is such a well-known
domain with familiar problems.

For this little exercise, I'll go with the solution with the extra method
for text and objects for each node that I sketched because it has no
external dependencies..

cheers,

Siemen
 
R

Ryan Davis

Generally - no. A proc is compiled code, it doesn't remember its own = source=20
code. There are libraries that provide some deeper introspection tools = -- like=20
the ParseTree / Ruby2Ruby libraries. Also, there are several DSLs very = simllar=20
to what you're talking about already -- check out Markaby:=20
=20
http://markaby.rubyforge.org/

agreed... except don't look at markaby. It is overly complicated and =
overly clevar (and slow as a result). Look at Ara's tagz. Excellent =
implementation.
 
F

Florian Gilcher

agreed... except don't look at markaby. It is overly complicated and
overly clevar (and slow as a result). Look at Ara's tagz. Excellent
implementation.

Markaby is also Ruby 1.8 only, though I can't figure out why. Some of
the clevarness kind of fails to be portable.

Regards,
Florian
 
R

Ryan Davis

Thanks! The two introspection libs look really interesting.
=20
I know that there are plenty of templating tools available. But I'm = just
playing around with DSLs and chose HTML because it is such a = well-known
domain with familiar problems.

The point wasn't (necessarily) to use them, but to study them. You =
simply don't need to traverse the proc to do what you want to do.

Example (one of several variants):
class PseudoLisp
def self.convert &b
self.new.instance_eval(&b)
end
=20
def method_missing(msg, *args, &b)
if args.empty? then
puts "(#{msg})"
else
puts "(#{msg} #{args.join(' ')})"
end
end
end
=20
PseudoLisp.convert do
happy
sad 42
end

#=3D> (happy)
#=3D> (sad 42)
 
S

Siemen Baader

[Note: parts of this message were removed to make it a legal post.]

The point wasn't (necessarily) to use them, but to study them. You simply
don't need to traverse the proc to do what you want to do.

Yes, I will definitely have a look at them!


class PseudoLisp
def self.convert &b
self.new.instance_eval(&b)
end

def method_missing(msg, *args, &b)
if args.empty? then
puts "(#{msg})"
else
puts "(#{msg} #{args.join(' ')})"
end
end
end

PseudoLisp.convert do
happy
"string created"
sad 42
end

#=> (happy)
#=> (sad 42)

Thanks a lot for the example!

There is one caveat with it - I also need to catch the creation of strings.
Of course I can work around this by using a method call to construct text
(eg text "text body"). Hm.. maybe I can also hook into something with
ObjectSpace or String.new; I have to check that out when I come back to my
dev machine...

-- Siemen
PS. It looks like I'm always double posting for some reason, my apologies,
List.. I'll hope it is fixed now..
 
P

Paul Smith

PS. It looks like I'm always double posting for some reason, my apologies,
List.. I'll hope it is fixed now..

Are you posting form Google mail? For some reason that I don't
understand, my posts always look double posted to me, but are only
actually posted the once.
 
B

Brian Candler

Siemen said:
I'm playing with a small DSL for HTML, which should look like this.

html {
head { title {"Hello World"} }
body {
h1 { "hello"}
p {
"text body"
"more text"
}
}
}

If it is possible to recursively traverse through the statements in
each block, I could join the lines together with the + operator, and
the implementation would be fairly easy - just recursive calls that
return text. But it does not look like this is possible...

Two string literals on the same line are concatenated - so in the above
example you could get away with a simple pre-processor that joins the
lines together in the right places.

However this won't work for

str1
str2

If this is what you want - i.e. each expression appearing on a line of
its own has its value sent to the output string - then probably native
Ruby is not the right tool. HAML, ERB and Cucumber are examples of DSLs
where a non-Ruby syntax fits better.
 
S

Siemen Baader

[Note: parts of this message were removed to make it a legal post.]

Are you posting form Google mail? For some reason that I don't
understand, my posts always look double posted to me, but are only
actually posted the once.

Yes I am, and it still looks like they are double-posted. Yours do not to
me. Sounds reasonable, there is probably something weird going on with its
conversation view algorithm..
 
S

Siemen Baader

[Note: parts of this message were removed to make it a legal post.]

Two string literals on the same line are concatenated - so in the above
example you could get away with a simple pre-processor that joins the
lines together in the right places.


However this won't work for

str1
str2

If this is what you want - i.e. each expression appearing on a line of
its own has its value sent to the output string - then probably native
Ruby is not the right tool. HAML, ERB and Cucumber are examples of DSLs
where a non-Ruby syntax fits better.

Yes. Again, this is more an exercise to see what can be done with an inline
DSL, so I'll just stick with what I got.

It would have been quite easy with Lisp though, as I would have access to
each line and join them .. But apart from that, I'm not fluent with Lisp :)

 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,770
Messages
2,569,583
Members
45,074
Latest member
StanleyFra

Latest Threads

Top