There is a new feature, Template-Local Inline VMs (TLIV), now checked in
and working.  I would like to thank Jose Alberto Fernandez
([EMAIL PROTECTED]) for both valuable public and private motivation
and discussion as well as work leading to this.  He submitted to me a
patch at the same time that I had completed a solution. So I hijacked an
idea or two. :) The best part was that we had arrived at the same basic
technique for namespace management, so either this is comforting because
it argues it's the right way, or comforting that if it isn't, he gets
taken out and flogged with me :)

Summary
-------
TLIV is a feature in which a VM defined inline (inline := within a
template) is accessable only to the defining template.  

When this feature is turned on, you may use inline VM definitions w/o
worry that another template will replace your VM definition.

It also means that it won't replace a globally defined VM.

This feature is OFF by default.

A new, useful behavior that you get using this is shown in the testbed,
vm_test1.vm and vm_test2.vm in association with VM_local_library.vm. 
Very simply, VM_local_library.vm defines two VMs #callrecurse() and
#recurse().  When #callrecurse() is invoked, it invokes #recurse().  But
if you want a local variant of #recurse(), you can define it in the
template that wants the altered behavior. (Yes, like overloading a
method :)  vm_test2.vm does this.  Look at compare/vm_testX.cmp to see
the output.  Because of testbed properties, this is run via a different
JUnit test, invoked by 'build-velocity.sh test-inlinevmscope' in the
build directory.

Useful?  I think so.  You can define a series of actions started by a
controlling global (or local) VM, say rendering some part of a web
page.  The global VMs will be called unless you have a local VM with the
same name, so you can have a base/default with localized presentation.

I think this is the right behavior : when you turn on TLIV, you are
saying that when you invoke #foo() in a template, if defined in that
template, you want that definition of #foo().  Therefore, which #foo()
should not be dependant upon invocation path ( such as if it was invoked
by a global VM.)
 
Details
-------

To activate, set in your velocity.properties file the following :

   velocimacro.permissions.allowInlineLocalScope = true

The rules used by the VMFactory for accepting VM definitions is as
follows :

are they allowed at all ?  (velocimacro.permissions.allowInline)
  no : reject
  yes : is TLIV turned on ?
(velocimacro.permissions.allowInlineLocalScope )
    yes : accept for the defining template *
    no : can inline VMs replace global (
velocimacro.permissions.allowInlineToReplaceGlobal )
      yes : accept for global namespace
      no : does this VM exist in global namespace?
         no : accept (because we aren't replacing ) **
         yes : reject

* because by definition, it not replacing anything : this happens at
template init time and the namespace is cleared at parse time for that
template
** some may argue with this -> maybe we want this to mean, can a VM
affect the global namespace, or just add other for this.  Yes, maybe
that's it. Discussion

I think I tested this rather well, let me know if any problems.

geir

-- 
Geir Magnusson Jr.                               [EMAIL PROTECTED]
Velocity : it's not just a good idea. It should be the law.
http://jakarta.apache.org/velocity

Reply via email to