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