Otto Hirr wrote:
If "foo" is something that should be called by more than one component it should be moved to its own component, defined as a <%method> of component A, or as a function/method in an external Perl module.

But that would then create a new closure, not having access to the
variables in the "parent" closure.


Yes that is true.  If you change this:

<%init>
my $private = 'Hello';
sub foo {
   $m->print($private);
}
foo();

into this:

<%init>
my $private = 'Hello';
$m->comp('foo');

And foo expects to have access to $private you will have problems.

You can do this:

<%once>
my $foo = sub { stuff() };
...
</%once>
<% &$foo() %>

This is something along the lines of what I'm doing.
Instead of stuff() it is the statements.

So am I way off track in doing this? I want to munge the
lexical variables in the component, but don't want to have
to further ship them off to yet another routine. I'm
implementing something like a generic function, templated,
then instantiated into each component.

Shipping the variables off to another component is not necessarily a bad thing. Subroutines that read/write values outside of their scope are often difficult to debug/extend/refactor because their inputs and side effects can be hard to track down. If you stick to using one input channel (passed arguments) and one output channel (return values) you can have a lot more flexibility.

With that said you could try to get around this by using the inheritance model that is built into Mason. For example you could make foo a method of parentcomp and have each of the components where foo is called inherit from parentcomp. Then you can make $private available via a getter method. Here is a very contrived example implementing the foo subroutine above:

Child:
<%flags>
   # inheriting from the parent allows us to see their methods
   # and them to see ours
   inherit => 'parent.comp'
</%flags>
<%shared>
   # setting this in a once or shared block
   # allows our methods to use it
   my $private = 'Hello';
</%shared>
<%init>
   # Here we can call the parent method as if it were our own
   # Look ma! No Parameters!
   $m->comp(SELF:foo);
</%init>
<%method getPrivate>
<%perl>
   # a simple getter method to provide access to this variable
   return $private;
</%perl>
</%method>

Parentcomp:
<%method foo>
% # the parent can call getPrivate as if it were its own method
<% $m->comp('SELF:getPrivate') %>
</%method>

This adds a 3rd* IO channel for your routines (1st = parameters, 2nd = return value, 3rd = member data) but at least its one that can be tracked along an explicit inheritance path. The biggest downside I see with this is that it makes the code a lot more spaghettified.

Parameter passing, however inconvenient it may appear forces you to dot your "i"s and cross your "t"s making the code easier to read 6 months down the road.

-- Ben

* Actually, the 4th IO channel since #3 is Printing the web page, but this is sort of a given in Mason development
-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft
Defy all challenges. Microsoft(R) Visual Studio 2008.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/
_______________________________________________
Mason-users mailing list
Mason-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/mason-users

Reply via email to