You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@velocity.apache.org by bob <bo...@accurev.com> on 2000/08/28 02:00:09 UTC

A point (or two)

Howdy guys--

Was browsing your implementation, and I see that y'll
work with a typed object as the context, instead of accepting
just any ol' Object as the context.

Additionally, it seems the context gets bound to the template,
which could be problematic, possibly, when using the same cached
Template by multiple threads at the same time, with different
contexts.

fwiw, I have some WebMacro/IntroSpock code laying around
that assumes the context can be any ol' Object.    Mostly
this is for code-generation, where I throw some weird
read-only tree of objects as my context at a template.

I'd hate to have to go back and wrap it in a hashmap (as the
only entry) and then edit my templates to account for the
extra level of objects.

I've mentioned to Jon, but I'll also post here, Introspock,
my rewrite of WebMacro, is BSD licensed for the parser front-end
though, it uses WebMacro's introspection back-end still.

iSpock handles the Object context, and also keeps the context
from being a stateful member of the Template.  iSpock's templates
are fully parallizeable/re-entrant.

Y'all are welcome to any/all of it that you like.  It's
based on an antlr (www.antlr.org) parser, instead of javacc.

Anyhoo, you can find it at <http://code.werken.com/introspock/>.

	-bob


Re: A point (or two)

Posted by "Daniel L. Rall" <dl...@finemaltcoding.com>.
Jason van Zyl wrote:
> 
> On Sun, 27 Aug 2000, bob wrote:
> 
> >
> > Howdy guys--
> >
> > Was browsing your implementation, and I see that y'll
> > work with a typed object as the context, instead of accepting
> > just any ol' Object as the context.
> 
> But did the objects implement an interface of some sort?
> 
> I think the context needs to adhere to an interface. Daniel
> had the idea of using the Map interface (or something like it).
> I liked this idea from the stand point of scoping nested blocks.
> 
> I haven't implemented it yet, but was planning on using a stack
> of contexts. Using the Map interface a whole set of items could
> be added to a context ... When entering a new block push all
> the items in the current context into the new context. Then you
> effectively get local variables. When you leave the block pop
> the context away. This might be expensive though and might be
> a bit of overkill.
> 
> Anyway I'm not really sure how the context worked in IntroSpock,
> but I'll look at it and we can certainly bat some ideas around :)
> I'm not saying that using an Object for a context is bad, I just
> am not clear how it would work. I'll take a peek at your code.

Using just any old instance of Object would be very flexible.  One of
the reasons that I like Java so much is its support of strict typing and
extensive use of interfaces.  Though I like the idea of using any Object
as a Context conceptually, I'm not certain how well it will work out
with non-technical template developers (often more artist than
programmer).

> > Additionally, it seems the context gets bound to the template,
> > which could be problematic, possibly, when using the same cached
> > Template by multiple threads at the same time, with different
> > contexts.
> 
> Yes, this defintely needs to be fixed. I concentrated on
> the parser and visitors and just popped the context off
> to get it to output, it needs work.

Cool.  +1
-- 

Daniel Rall <dl...@finemaltcoding.com>

suppression of error messages

Posted by bob <bo...@accurev.com>.
btw--

WebMacro has a habit of being verbose in it's error messages,
which can get annoying.

If you attempt $variable.that.results.in.null, it'll spew forth

<!-- Unable to locate $variable.that.results.in.null -->

Which is useful sometimes, but gets in your way sometimes
also, when you do something like this:

	<input type="text" value="$possiblyNull"/>

iSpock allows $!possiblyNull, and the addition of the ! 
suppresses output of warnings.

(Additionally, iSpock allows customization of the comment
characters around/in-front-of warnings/errors that are
printed.)

I think the per-variable suppression of warnings is absolutely
needed.  Comment-customization is just plain nice to have.

	-bob


Re: A point (or two)

Posted by Jason van Zyl <jv...@periapt.com>.
On Mon, 28 Aug 2000, bob wrote:

> > That looks strange to me ... I don't see why
> > you couldn't do that as long as getMethods()
> > returned an object that could proffer up an
> > Iterator or an Enumeration. Maybe I'm missing
> > something.
> 
> Oh, I'm just confused, probably.  When you were using a
> hashmap, I assumed that meant you always did context.get("Foo")
> as opposed to even looking for a context.getFoo().
> 
> I should really go read the code some more.  I think we're
> all agreeing, at this point, and Velocity does indeed 
> Do The Right Thing.
> 
> 	-bob
> 	(sorry to confuse)

Absolutely no problem! This is how we get things worked
out! It's always hard at first with a new whack of code.

I will also take a look at iSpock, or at least your
parser grammar and code. I can't really look at any
off the WM stuff yet. Hopefully Justin will APL the
code soon so that I can look at it.

jvz.

-- 

Jason van Zyl
jvanzyl@periapt.com


Re: A point (or two)

Posted by bob <bo...@accurev.com>.
> That looks strange to me ... I don't see why
> you couldn't do that as long as getMethods()
> returned an object that could proffer up an
> Iterator or an Enumeration. Maybe I'm missing
> something.

Oh, I'm just confused, probably.  When you were using a
hashmap, I assumed that meant you always did context.get("Foo")
as opposed to even looking for a context.getFoo().

I should really go read the code some more.  I think we're
all agreeing, at this point, and Velocity does indeed 
Do The Right Thing.

	-bob
	(sorry to confuse)



Re: A point (or two)

Posted by Jason van Zyl <jv...@periapt.com>.
On Mon, 28 Aug 2000, bob wrote:

> > Yes, we do the same thing! We just have different names for
> > it. The context is what I call the holder for all the objects,
> > and they can be anything. We do the same thing.
> 
> Okay, then basically, allow
> 	
> 	$foo
> 
> 	#set $foo = "bar"
> 
> to work *just* like
> 
> 	$foo.goober
> 
> 	#set $foo.goober = "bar"
> 
> Do normal introspection to set/get top-level things
> from the context.

Yes.
 
> In a code-generator I did, I had an object that matched
> a java Class that I used as my Context.  I ended up
> with code like:
> 
> 	#foreach $_method in $Methods
> 
> Which used for $Methods
> 
> 	myClass.getMethods()
> 
> and to set the $_method, it called:
> 
> 	myClass.put("_method", each);
> 
> Yes, that indeed *could* fail if myClass didn't provide
> a put/set() type of thing.

That looks strange to me ... I don't see why
you couldn't do that as long as getMethods()
returned an object that could proffer up an
Iterator or an Enumeration. Maybe I'm missing
something.

> Dunno if that's too dangerous.  Maybe a HashMap as a Context
> is indeed a Good Thing.  (And probably, in the context of
> Turbine, it will always be a HashMap.)

Right now a Hashtable holds all the objects in what
Velocity calls a context. I think there are some variations
in what Velocity and iSpock do but we will eventually
understand one another :)

jvz.

-- 

Jason van Zyl
jvanzyl@periapt.com


Re: A point (or two)

Posted by bob <bo...@accurev.com>.
> Yes, we do the same thing! We just have different names for
> it. The context is what I call the holder for all the objects,
> and they can be anything. We do the same thing.

Okay, then basically, allow
	
	$foo

	#set $foo = "bar"

to work *just* like

	$foo.goober

	#set $foo.goober = "bar"

Do normal introspection to set/get top-level things
from the context.

In a code-generator I did, I had an object that matched
a java Class that I used as my Context.  I ended up
with code like:

	#foreach $_method in $Methods

Which used for $Methods

	myClass.getMethods()

and to set the $_method, it called:

	myClass.put("_method", each);

Yes, that indeed *could* fail if myClass didn't provide
a put/set() type of thing.

Dunno if that's too dangerous.  Maybe a HashMap as a Context
is indeed a Good Thing.  (And probably, in the context of
Turbine, it will always be a HashMap.)

	-bob


Re: A point (or two)

Posted by Jason van Zyl <jv...@periapt.com>.
On Mon, 28 Aug 2000, bob wrote:

> > So the actual context object itself could be any object, yes?
> 
> Ayup.
> 
> > So what did you do exactly to get values out of the context
> > in that case? I just want to make sure I fully understand
> > the reason :)
> 
> To be honest, I borrowed Justin's reflection back-end from WebMacro.
> 
> My main goal was to have a better front-end, not delve into the
> wonders of reflection.  
> 
> java.lang.reflect.* is what you need to manipulate the context
> Object.

Yes, we do the same thing! We just have different names for
it. The context is what I call the holder for all the objects,
and they can be anything. We do the same thing.
 
> ** Jon: Would it be safe for me to describe how the reflection
> stuff works, since I'm familiar with the WM code, or would that
> be walking a fine copyright line?
> 
> > I check to make sure that something called $element
> > doesn't already live in the context. If it does, then
> > I store it. Then the new value of $element is scoped
> > to the #foreach block. When the block is done I remove
> > $element from the context, and put the old one back
> > in if there was one. This seemed more correctly to
> > me in terms of scoping.
> 
> Ahh.  We're on slight different wavelengths, then
> about the reflective aspects of this all.  In iSpock,
> the context is the 'currently active object'.  In the
> template, it starts out as the object passed into the
> process() method.  But, an accessors like
> 
> 	$user.FirstName
> 
> and 
> 
> 	#set $User.FirstName = "Bob"
> 
> might cause statements to be directed to a  radically 
> different object, possibly of non-HashMap variety.  
> That call might result in reflectin something equiv to
> 
> 	context.get("User").getFirstName();
> 
> and 
> 
> 	context.get("User").setFirstName("Bob");
> 
> Yes, I personally argue that you shouldn't be directly
> mutating 'business objects' from the template.  It's
> just wrong and evil.  But, bet your last dollar that
> there are people out there with code that does.

We do the same things :)

> > I am trying to explain the internals of what's
> > been done in a design document so I can just
> > throw it on the table. That way we can fix any
> > of the design flaws that I've initially made.
> > This document will explain how the parser currently
> > works, how the visitors work, and can be done
> > easily what is hard, what the limitations are
> > and anything else I can think of...
> 
> Okay, good.  Your explanation of #include rests my
> fears there.  I look forward to the design doc.  Is
> it online yet?

No, I've just started it!

jvz.

-- 

Jason van Zyl
jvanzyl@periapt.com


Re: A point (or two)

Posted by bob <bo...@accurev.com>.
> So the actual context object itself could be any object, yes?

Ayup.

> So what did you do exactly to get values out of the context
> in that case? I just want to make sure I fully understand
> the reason :)

To be honest, I borrowed Justin's reflection back-end from WebMacro.

My main goal was to have a better front-end, not delve into the
wonders of reflection.  

java.lang.reflect.* is what you need to manipulate the context
Object.

** Jon: Would it be safe for me to describe how the reflection
stuff works, since I'm familiar with the WM code, or would that
be walking a fine copyright line?

> I check to make sure that something called $element
> doesn't already live in the context. If it does, then
> I store it. Then the new value of $element is scoped
> to the #foreach block. When the block is done I remove
> $element from the context, and put the old one back
> in if there was one. This seemed more correctly to
> me in terms of scoping.

Ahh.  We're on slight different wavelengths, then
about the reflective aspects of this all.  In iSpock,
the context is the 'currently active object'.  In the
template, it starts out as the object passed into the
process() method.  But, an accessors like

	$user.FirstName

and 

	#set $User.FirstName = "Bob"

might cause statements to be directed to a  radically 
different object, possibly of non-HashMap variety.  
That call might result in reflectin something equiv to

	context.get("User").getFirstName();

and 

	context.get("User").setFirstName("Bob");

Yes, I personally argue that you shouldn't be directly
mutating 'business objects' from the template.  It's
just wrong and evil.  But, bet your last dollar that
there are people out there with code that does.

> I am trying to explain the internals of what's
> been done in a design document so I can just
> throw it on the table. That way we can fix any
> of the design flaws that I've initially made.
> This document will explain how the parser currently
> works, how the visitors work, and can be done
> easily what is hard, what the limitations are
> and anything else I can think of...

Okay, good.  Your explanation of #include rests my
fears there.  I look forward to the design doc.  Is
it online yet?

	-bob


Re: A point (or two)

Posted by Jason van Zyl <jv...@periapt.com>.
On Mon, 28 Aug 2000, bob wrote:

> > But did the objects implement an interface of some sort?
> 
> Nope.  Just java.lang.Object.  Introspcection/Reflection 
> took care of the rest.  The context should be pretty
> opaque to the most of Velocity, with the exception of
> the reflect code. 

So the actual context object itself could be any object, yes?

So what did you do exactly to get values out of the context
in that case? I just want to make sure I fully understand
the reason :)
 
> > I haven't implemented it yet, but was planning on using a stack
> > of contexts. Using the Map interface a whole set of items could
> > be added to a context ... When entering a new block push all
> > the items in the current context into the new context. Then you
> > effectively get local variables. When you leave the block pop
> > the context away. This might be expensive though and might be
> > a bit of overkill.
> 
> Ahh, at least WebMacro and iSpock both dealt with a single
> instance of the context object for the entire walk of the 
> tree.  No 'local' variables, per se.  I know of some code
> that takes advantage of the fact the named iterator 
> variable is still valid after a #foreach block is done.

Right now in velocity in for something like this:

#foreach $element in $list
{
     $element
}

I check to make sure that something called $element
doesn't already live in the context. If it does, then
I store it. Then the new value of $element is scoped
to the #foreach block. When the block is done I remove
$element from the context, and put the old one back
in if there was one. This seemed more correctly to
me in terms of scoping.

> And some code will #include a template to mere set
> variables contained within.  If those got popped after
> the #include statement, all would be lost. ;)

Actually something like

#set $this = "that"

#include "whatever.inc"

where whatever.inc is:

#set $that = "this"

$that and $this are in the same context. In
the parser when there is an #include or #parse
I save the current steam, open the file to be
#included or #parsed reset the lexer and start
pulling in the new file.

The upshot of that a template with abitrarily
nest #includes and #parses end as a single
AST. It's like one document, and scope only
changes when you enter a block. #includes
and #parses don't push or pop wouldn't cause
any pushing or popping of contexts, but blocks
inside them would.

I am trying to explain the internals of what's
been done in a design document so I can just
throw it on the table. That way we can fix any
of the design flaws that I've initially made.
This document will explain how the parser currently
works, how the visitors work, and can be done
easily what is hard, what the limitations are
and anything else I can think of...

jvz.


-- 

Jason van Zyl
jvanzyl@periapt.com


Re: A point (or two)

Posted by bob <bo...@accurev.com>.
> But did the objects implement an interface of some sort?

Nope.  Just java.lang.Object.  Introspcection/Reflection 
took care of the rest.  The context should be pretty
opaque to the most of Velocity, with the exception of
the reflect code. 

> I haven't implemented it yet, but was planning on using a stack
> of contexts. Using the Map interface a whole set of items could
> be added to a context ... When entering a new block push all
> the items in the current context into the new context. Then you
> effectively get local variables. When you leave the block pop
> the context away. This might be expensive though and might be
> a bit of overkill.

Ahh, at least WebMacro and iSpock both dealt with a single
instance of the context object for the entire walk of the 
tree.  No 'local' variables, per se.  I know of some code
that takes advantage of the fact the named iterator 
variable is still valid after a #foreach block is done.

And some code will #include a template to mere set
variables contained within.  If those got popped after
the #include statement, all would be lost. ;)

	-bob


Re: A point (or two)

Posted by Jason van Zyl <jv...@periapt.com>.
On Sun, 27 Aug 2000, bob wrote:

> 
> Howdy guys--
> 
> Was browsing your implementation, and I see that y'll
> work with a typed object as the context, instead of accepting
> just any ol' Object as the context.

But did the objects implement an interface of some sort?

I think the context needs to adhere to an interface. Daniel
had the idea of using the Map interface (or something like it).
I liked this idea from the stand point of scoping nested blocks.

I haven't implemented it yet, but was planning on using a stack
of contexts. Using the Map interface a whole set of items could
be added to a context ... When entering a new block push all
the items in the current context into the new context. Then you
effectively get local variables. When you leave the block pop
the context away. This might be expensive though and might be
a bit of overkill.

Anyway I'm not really sure how the context worked in IntroSpock,
but I'll look at it and we can certainly bat some ideas around :)
I'm not saying that using an Object for a context is bad, I just
am not clear how it would work. I'll take a peek at your code.

jvz.

> Additionally, it seems the context gets bound to the template,
> which could be problematic, possibly, when using the same cached
> Template by multiple threads at the same time, with different
> contexts.

Yes, this defintely needs to be fixed. I concentrated on
the parser and visitors and just popped the context off
to get it to output, it needs work.
 
> fwiw, I have some WebMacro/IntroSpock code laying around
> that assumes the context can be any ol' Object.    Mostly
> this is for code-generation, where I throw some weird
> read-only tree of objects as my context at a template.
> 
> I'd hate to have to go back and wrap it in a hashmap (as the
> only entry) and then edit my templates to account for the
> extra level of objects.

We'll see what we can do :)
 
> I've mentioned to Jon, but I'll also post here, Introspock,
> my rewrite of WebMacro, is BSD licensed for the parser front-end
> though, it uses WebMacro's introspection back-end still.
> 
> iSpock handles the Object context, and also keeps the context
> from being a stateful member of the Template.  iSpock's templates
> are fully parallizeable/re-entrant.
> 
> Y'all are welcome to any/all of it that you like.  It's
> based on an antlr (www.antlr.org) parser, instead of javacc.

Much appreciated! Thank a lot Bob!

jvz.

-- 

Jason van Zyl
jvanzyl@periapt.com