From 4454ad59ecbc047ddf1fddc112426affb59ca2fa Mon Sep 17 00:00:00 2001 From: Marius Gavrilescu <marius@ieval.ro> Date: Fri, 26 Dec 2014 20:40:06 +0200 Subject: [PATCH] Tidy POD --- lib/HTML/Element/Library.pod | 1188 ++++++++++++++++------------------ 1 file changed, 565 insertions(+), 623 deletions(-) diff --git a/lib/HTML/Element/Library.pod b/lib/HTML/Element/Library.pod index d3675e2..39935b9 100644 --- a/lib/HTML/Element/Library.pod +++ b/lib/HTML/Element/Library.pod @@ -1,3 +1,5 @@ +=encoding utf-8 + =head1 NAME HTML::Element::Library - HTML::Element convenience functions @@ -9,13 +11,13 @@ HTML::Element::Library - HTML::Element convenience functions =head1 DESCRIPTION -This method provides API calls for common actions on trees when using +This method provides API calls for common actions on trees when using L<HTML::Tree>. =head1 METHODS -The test suite contains examples of each of these methods in a -file C<t/$method.t> +The test suite contains examples of each of these methods in a file +C<t/$method.t> =head2 Positional Querying Methods @@ -25,11 +27,11 @@ Return a list of all nodes under the same parent. =head3 $elem->sibdex -Return the index of C<$elem> into the array of siblings of which it is -a part. L<HTML::ElementSuper> calls this method C<addr> but I don't think -that is a descriptive name. And such naming is deceptively close to the -C<address> function of C<HTML::Element>. HOWEVER, in the interest of -backwards compatibility, both methods are available. +Return the index of C<$elem> into the array of siblings of which it is +a part. L<HTML::ElementSuper> calls this method C<addr> but I don't +think that is a descriptive name. And such naming is deceptively close +to the C<address> function of C<HTML::Element>. HOWEVER, in the +interest of backwards compatibility, both methods are available. =head3 $elem->addr @@ -37,11 +39,11 @@ Same as sibdex =head3 $elem->position() -Returns the coordinates of this element in the tree it inhabits. -This is accomplished by succesively calling addr() on ancestor -elements until either a) an element that does not support these -methods is found, or b) there are no more parents. The resulting -list is the n-dimensional coordinates of the element in the tree. +Returns the coordinates of this element in the tree it inhabits. This +is accomplished by succesively calling addr() on ancestor elements +until either a) an element that does not support these methods is +found, or b) there are no more parents. The resulting list is the +n-dimensional coordinates of the element in the tree. =head2 Element Decoration Methods @@ -51,8 +53,8 @@ In L<HTML::Element>, Sean Burke discusses super-literals. They are text which does not get escaped. Great for includng Javascript in HTML. Also great for including foreign language into a document. -So, you basically toss C<super_literal> your text and back comes -your text wrapped in a C<~literal> element. +So, you basically toss C<super_literal> your text and back comes your +text wrapped in a C<~literal> element. One of these days, I'll around to writing a nice C<EXPORT> section. @@ -69,54 +71,55 @@ Oftentimes, the HTML to be worked with will have multiple sample rows: <LI>bacon </OL> -But, before you begin to rewrite the HTML with your model data, you typically only want 1 or 2 sample rows. +But, before you begin to rewrite the HTML with your model data, you +typically only want 1 or 2 sample rows. -Thus, you want to "crunch" the multiple sample rows to a specified amount. Hence the C<crunch> method: +Thus, you want to "crunch" the multiple sample rows to a specified +amount. Hence the C<crunch> method: $tree->crunch(look_down => [ '_tag' => 'li' ], leave => 2) ; -The C<leave> argument defaults to 1 if not given. The call above would "crunch" the above 4 sample rows to: +The C<leave> argument defaults to 1 if not given. The call above would +"crunch" the above 4 sample rows to: <OL> <LI>bread <LI>butter </OL> - =head3 Simplifying calls to HTML::FillInForm -Since HTML::FillInForm gets and returns strings, using HTML::Element instances -becomes tedious: +Since HTML::FillInForm gets and returns strings, using HTML::Element +instances becomes tedious: 1. Seamstress has an HTML tree that it wants the form filled in on 2. Seamstress converts this tree to a string 3. FillInForm parses the string into an HTML tree and then fills in the form 4. FillInForm converts the HTML tree to a string - 5. Seamstress re-parses the HTML for additional processing + 5. Seamstress re-parses the HTML for additional processing I've filed a bug about this: L<https://rt.cpan.org/Ticket/Display.html?id=44105> -This function, fillinform, -allows you to pass a tree to fillinform (along with your data structure) and -get back a tree: - - my $new_tree = $html_tree->fillinform($data_structure); - - +This function, fillinform, allows you to pass a tree to fillinform +(along with your data structure) and get back a tree: + my $new_tree = $html_tree->fillinform($data_structure); =head3 Mapping a hashref to HTML elements -It is very common to get a hashref of data from some external source - flat file, database, XML, etc. -Therefore, it is important to have a convenient way of mapping this data to HTML. +It is very common to get a hashref of data from some external source - +flat file, database, XML, etc. Therefore, it is important to have a +convenient way of mapping this data to HTML. -As it turns out, there are 3 ways to do this in HTML::Element::Library. -The most strict and structured way to do this is with -C<content_handler>. Two other methods, C<hashmap> and C<datamap> require less manual mapping and may prove -even more easy to use in certain cases. +As it turns out, there are 3 ways to do this in +HTML::Element::Library. The most strict and structured way to do this +is with C<content_handler>. Two other methods, C<hashmap> and +C<datamap> require less manual mapping and may prove even more easy to +use in certain cases. -As is usual with Perl, a practical example is always best. So let's take some sample HTML: +As is usual with Perl, a practical example is always best. So let's +take some sample HTML: <h1>user data</h1> <span id="name">?</span> @@ -131,55 +134,58 @@ And let's start with the most strict way to get what you want: $tree->content_handler(email => $ref->{email} , gender => $ref->{gender}) ; +In this case, you manually state the mapping between id tags and +hashref keys and then C<content_handler> retrieves the hashref data +and pops it in the specified place. -In this case, you manually state the mapping between id tags and hashref keys and -then C<content_handler> retrieves the hashref data and pops it in the specified place. - -Now let's look at the two (actually 2 and a half) other hash-mapping methods. +Now let's look at the two (actually 2 and a half) other hash-mapping +methods. $tree->hashmap(id => $ref); -Now, what this function does is super-destructive. It finds every element in the tree -with an attribute named id (since 'id' is a parameter, it could find every element with -some other attribute also) and replaces the content of those elements with the hashref -value. +Now, what this function does is super-destructive. It finds every +element in the tree with an attribute named id (since 'id' is a +parameter, it could find every element with some other attribute also) +and replaces the content of those elements with the hashref value. -So, in the case above, the +So, in the case above, the - <span id="name">?</span> + <span id="name">?</span> would come out as - <span id="name"></span> + <span id="name"></span> -(it would be blank) - because there is nothing in the hash with that value, so it substituted +(it would be blank) - because there is nothing in the hash with that +value, so it substituted - $ref->{name} + $ref->{name} which was blank and emptied the contents. -Now, let's assume we want to protect name from being auto-assigned. Here is what you do: +Now, let's assume we want to protect name from being auto-assigned. +Here is what you do: $tree->hashmap(id => $ref, ['name']); -That last array ref is an exclusion list. +That last array ref is an exclusion list. -But wouldnt it be nice if you could do a hashmap, but only assigned things which are defined -in the hashref? C<< defmap() >> to the rescue: +But wouldnt it be nice if you could do a hashmap, but only assigned +things which are defined in the hashref? C<< defmap() >> to the +rescue: $tree->defmap(id => $ref); -does just that, so +does just that, so - <span id="name">?</span> + <span id="name">?</span> would be left alone. - =head4 $elem->hashmap($attr_name, \%hashref, \@excluded, $debug) -This method is designed to take a hashref and populate a series of elements. For example: - +This method is designed to take a hashref and populate a series of +elements. For example: <table> <tr sclass="tr" class="alt" align="left" valign="top"> @@ -189,20 +195,23 @@ This method is designed to take a hashref and populate a series of elements. For </tr> </table> -In the table above, there are several attributes named C<< smap >>. If we have a hashref whose keys are the same: +In the table above, there are several attributes named C<< smap >>. If +we have a hashref whose keys are the same: my %data = (people_id => 888, phone => '444-4444', password => 'dont-you-dare-render'); -Then a single API call allows us to populate the HTML while excluding those ones we dont: +Then a single API call allows us to populate the HTML while excluding +those ones we dont: $tree->hashmap(smap => \%data, ['password']); +Note: the other way to prevent rendering some of the hash mapping is +to not give that element the attr you plan to use for hash mapping. -Note: the other way to prevent rendering some of the hash mapping is to not give that element the attr -you plan to use for hash mapping. - -Also note: the function C<< hashmap >> has a simple easy-to-type API. Interally, it calls C<< hash_map >> -(which has a more verbose keyword calling API). Thus, the above call to C<hashmap()> results in this call: +Also note: the function C<< hashmap >> has a simple easy-to-type API. +Interally, it calls C<< hash_map >> (which has a more verbose keyword +calling API). Thus, the above call to C<hashmap()> results in this +call: $tree->hash_map(hash => \%data, to_attr => 'sid', excluding => ['password']); @@ -210,79 +219,81 @@ Also note: the function C<< hashmap >> has a simple easy-to-type API. Interally, C<defmap> was described above. - -=head4 $elem->content_handler(%hashref) - -C<content_handler> is described below. - - =head3 $elem->replace_content(@new_elem) -Replaces all of C<$elem>'s content with C<@new_elem>. +Replaces all of C<$elem>'s content with C<@new_elem>. =head3 $elem->wrap_content($wrapper_element) -Wraps the existing content in the provided element. If the provided element -happens to be a non-element, a push_content is performed instead. +Wraps the existing content in the provided element. If the provided +element happens to be a non-element, a push_content is performed +instead. =head3 $elem->set_child_content(@look_down, $content) - This method looks down $tree using the criteria specified in @look_down using the the HTML::Element look_down() method. +This method looks down $tree using the criteria specified in +@look_down using the the HTML::Element look_down() method. -After finding the node, it detaches the node's content and pushes $content as the node's content. +After finding the node, it detaches the node's content and pushes +$content as the node's content. =head3 $tree->content_handler(%id_content) -This is a convenience method. Because the look_down criteria will often simply be: +This is a convenience method. Because the look_down criteria will +often simply be: - id => 'fixme' + id => 'fixme' to find things like: - <a id=fixme href=http://www.somesite.org>replace_content</a> + <a id=fixme href=http://www.somesite.org>replace_content</a> -You can call this method to shorten your typing a bit. You can simply type +You can call this method to shorten your typing a bit. You can simply +type - $elem->content_handler( fixme => 'new text' ) + $elem->content_handler( fixme => 'new text' ) Instead of typing: - $elem->set_child_content(sid => 'fixme', 'new text') + $elem->set_child_content(sid => 'fixme', 'new text') -ALSO NOTE: you can pass a hash whose keys are C<id>s and whose values are the content you want there and it will perform the replacement on each hash member: +ALSO NOTE: you can pass a hash whose keys are C<id>s and whose values +are the content you want there and it will perform the replacement on +each hash member: - my %id_content = (name => "Terrence Brannon", + my %id_content = (name => "Terrence Brannon", email => 'tbrannon@in.com', - balance => 666, - content => $main_content); - - $tree->content_handler(%id_content); + balance => 666, + content => $main_content); + $tree->content_handler(%id_content); =head3 $tree->highlander($subtree_span_id, $conditionals, @conditionals_args) -This allows for "if-then-else" style processing. Highlander was a movie in -which only one would survive. Well, in terms of a tree when looking at a -structure that you want to process in C<if-then-else> style, only one child -will survive. For example, given this HTML template: - - <span klass="highlander" id="age_dialog"> - <span id="under10"> - Hello, does your mother know you're - using her AOL account? - </span> - <span id="under18"> - Sorry, you're not old enough to enter - (and too dumb to lie about your age) - </span> - <span id="welcome"> - Welcome - </span> - </span> - -We only want one child of the C<span> tag with id C<age_dialog> to remain -based on the age of the person visiting the page. - -So, let's setup a call that will prune the subtree as a function of age: +This allows for "if-then-else" style processing. Highlander was a +movie in which only one would survive. Well, in terms of a tree when +looking at a structure that you want to process in C<if-then-else> +style, only one child will survive. For example, given this HTML +template: + + <span klass="highlander" id="age_dialog"> + <span id="under10"> + Hello, does your mother know you're + using her AOL account? + </span> + <span id="under18"> + Sorry, you're not old enough to enter + (and too dumb to lie about your age) + </span> + <span id="welcome"> + Welcome + </span> + </span> + +We only want one child of the C<span> tag with id C<age_dialog> to +remain based on the age of the person visiting the page. + +So, let's setup a call that will prune the subtree as a function of +age: sub process_page { my $age = shift; @@ -291,36 +302,38 @@ So, let's setup a call that will prune the subtree as a function of age: $tree->highlander (age_dialog => [ - under10 => sub { $_[0] < 10} , - under18 => sub { $_[0] < 18} , + under10 => sub { $_[0] < 10}, + under18 => sub { $_[0] < 18}, welcome => sub { 1 } ], $age ); -And there we have it. If the age is less than 10, then the node with -id C<under10> remains. For age less than 18, the node with id C<under18> -remains. -Otherwise our "else" condition fires and the child with id C<welcome> remains. +And there we have it. If the age is less than 10, then the node with +id C<under10> remains. For age less than 18, the node with id +C<under18> remains. Otherwise our "else" condition fires and the child +with id C<welcome> remains. =head3 $tree->passover(@id_of_element) -In some cases, you know exactly which element(s) should survive. In this case, -you can simply call C<passover> to remove it's (their) siblings. For the HTML -above, you could delete C<under10> and C<welcome> by simply calling: +In some cases, you know exactly which element(s) should survive. In +this case, you can simply call C<passover> to remove it's (their) +siblings. For the HTML above, you could delete C<under10> and +C<welcome> by simply calling: $tree->passover('under18'); -Because passover takes an array, you can specify several children to preserve. +Because passover takes an array, you can specify several children to +preserve. =head3 $tree->highlander2($tree, $conditionals, @conditionals_args) -Right around the same time that C<table2()> came into being, Seamstress -began to tackle tougher and tougher processing problems. It became clear that -a more powerful highlander was needed... one that not only snipped the tree -of the nodes that should not survive, but one that allows for -post-processing of the survivor node. And one that was more flexible with -how to find the nodes to snip. +Right around the same time that C<table2()> came into being, +Seamstress began to tackle tougher and tougher processing problems. It +became clear that a more powerful highlander was needed... one that +not only snipped the tree of the nodes that should not survive, but +one that allows for post-processing of the survivor node. And one that +was more flexible with how to find the nodes to snip. Thus (drum roll) C<highlander2()>. @@ -340,73 +353,70 @@ So let's look at our HTML which requires post-selection processing: </span> </span> -In this case, a branch survives, but it has dummy data in it. We must take -the surviving segment of HTML and rewrite the age C<span> with the age. -Here is how we use C<highlander2()> to do so: +In this case, a branch survives, but it has dummy data in it. We must +take the surviving segment of HTML and rewrite the age C<span> with +the age. Here is how we use C<highlander2()> to do so: - sub replace_age { - my $branch = shift; - my $age = shift; - $branch->look_down(id => 'age')->replace_content($age); - } + sub replace_age { + my $branch = shift; + my $age = shift; + $branch->look_down(id => 'age')->replace_content($age); + } - my $if_then = $tree->look_down(id => 'age_dialog'); + my $if_then = $tree->look_down(id => 'age_dialog'); $if_then->highlander2( cond => [ under10 => [ - sub { $_[0] < 10} , - \&replace_age + sub { $_[0] < 10} , + \&replace_age ], under18 => [ - sub { $_[0] < 18} , - \&replace_age + sub { $_[0] < 18} , + \&replace_age ], welcome => [ - sub { 1 }, - \&replace_age + sub { 1 }, + \&replace_age ] ], cond_arg => [ $age ] - ); + ); -We pass it the tree (C<$if_then>), an arrayref of conditions -(C<cond>) and an arrayref of arguments which are passed to the -C<cond>s and to the replacement subs. +We pass it the tree (C<$if_then>), an arrayref of conditions (C<cond>) +and an arrayref of arguments which are passed to the C<cond>s and to +the replacement subs. The C<under10>, C<under18> and C<welcome> are id attributes in the -tree of the siblings of which only one will survive. However, -should you need to do -more complex look-downs to find the survivor, -then supply an array ref instead of a simple -scalar: - +tree of the siblings of which only one will survive. However, should +you need to do more complex look-downs to find the survivor, then +supply an array ref instead of a simple scalar: $if_then->highlander2( cond => [ [class => 'r12'] => [ - sub { $_[0] < 10} , - \&replace_age + sub { $_[0] < 10} , + \&replace_age ], [class => 'z22'] => [ - sub { $_[0] < 18} , - \&replace_age + sub { $_[0] < 18} , + \&replace_age ], [class => 'w88'] => [ - sub { 1 }, - \&replace_age + sub { 1 }, + \&replace_age ] ], cond_arg => [ $age ] - ); - + ); =head3 $tree->overwrite_attr($mutation_attr => $mutating_closures) -This method is designed for taking a tree and reworking a set of nodes in -a stereotyped fashion. For instance let's say you have 3 remote image -archives, but you don't want to put long URLs in your img src -tags for reasons of abstraction, re-use and brevity. So instead you do this: +This method is designed for taking a tree and reworking a set of nodes +in a stereotyped fashion. For instance let's say you have 3 remote +image archives, but you don't want to put long URLs in your img src +tags for reasons of abstraction, re-use and brevity. So instead you do +this: <img src="/img/smiley-face.jpg" fixup="src lnc"> <img src="/img/hot-babe.jpg" fixup="src playboy"> @@ -430,35 +440,30 @@ and the tags come out modified like so: =head3 $tree->mute_elem($mutation_attr => $mutating_closures, [ $post_hook ] ) -This is a generalization of C<overwrite_attr>. C<overwrite_attr> -assumes the return value of the -closure is supposed overwrite an attribute value and does it for you. -C<mute_elem> is a more general function which does nothing but -hand the closure the element and let it mutate it as it jolly well pleases :) - -In fact, here is the implementation of C<overwrite_attr> -to give you a taste of how C<mute_attr> is used: +This is a generalization of C<overwrite_attr>. C<overwrite_attr> +assumes the return value of the closure is supposed overwrite an +attribute value and does it for you. C<mute_elem> is a more general +function which does nothing but hand the closure the element and let +it mutate it as it jolly well pleases :) - sub overwrite_action { - my ($mute_node, %X) = @_; +In fact, here is the implementation of C<overwrite_attr> to give you a +taste of how C<mute_attr> is used: - $mute_node->attr($X{local_attr}{name} => $X{local_attr}{value}{new}); - } + sub overwrite_action { + my ($mute_node, %X) = @_; - - sub HTML::Element::overwrite_attr { - my $tree = shift; - - $tree->mute_elem(@_, \&overwrite_action); - } + $mute_node->attr($X{local_attr}{name} => $X{local_attr}{value}{new}); + } + sub HTML::Element::overwrite_attr { + my $tree = shift; + $tree->mute_elem(@_, \&overwrite_action); + } =head2 Tree-Building Methods - - =head3 Unrolling an array via a single sample element (<ul> container) This is best described by example. Given this HTML: @@ -478,7 +483,6 @@ We can unroll it like so: To produce this: - <html> <head></head> <body>Here are the things I need from the store: @@ -491,165 +495,153 @@ To produce this: </html> Now, you might be wondering why the API call is: - + $tree->iter($li => @items) instead of: $li->iter(@items) -and there is no good answer. The latter would be more concise and it is what I -should have done. +and there is no good answer. The latter would be more concise and it +is what I should have done. =head3 Unrolling an array via n sample elements (<dl> container) -C<iter()> was fine for awhile, but some things -(e.g. definition lists) need a more general function to make them easy to -do. Hence C<iter2()>. This function will be explained by example of unrolling -a simple definition list. +C<iter()> was fine for awhile, but some things (e.g. definition lists) +need a more general function to make them easy to do. Hence +C<iter2()>. This function will be explained by example of unrolling a +simple definition list. So here's our mock-up HTML from the designer: - <dl class="dual_iter" id="service_plan"> - <dt> - Artist - </dt> - <dd> - A person who draws blood. - </dd> + <dl class="dual_iter" id="service_plan"> + <dt>Artist</dt> + <dd>A person who draws blood.</dd> - <dt> - Musician - </dt> - <dd> - A clone of Iggy Pop. - </dd> + <dt>Musician</dt> + <dd>A clone of Iggy Pop.</dd> - <dt> - Poet - </dt> - <dd> - A relative of Edgar Allan Poe. - </dd> + <dt>Poet</dt> + <dd>A relative of Edgar Allan Poe.</dd> - <dt class="adstyle">sample header</dt> - <dd class="adstyle2">sample data</dd> - - </dl> + <dt class="adstyle">sample header</dt> + <dd class="adstyle2">sample data</dd> +</dl> And we want to unroll our data set: - my @items = ( - ['the pros' => 'never have to worry about service again'], - ['the cons' => 'upfront extra charge on purchase'], - ['our choice' => 'go with the extended service plan'] - ); + my @items = ( + ['the pros' => 'never have to worry about service again'], + ['the cons' => 'upfront extra charge on purchase'], + ['our choice' => 'go with the extended service plan'] + ); -Now, let's make this problem a bit harder to show off the power of C<iter2()>. -Let's assume that we want only the last <dt> and it's accompanying <dd> -(the one with "sample data") to be used as the sample data -for unrolling with our data set. Let's further assume that we want them to -remain in the final output. +Now, let's make this problem a bit harder to show off the power of +C<iter2()>. Let's assume that we want only the last <dt> and it's +accompanying <dd> (the one with "sample data") to be used as the +sample data for unrolling with our data set. Let's further assume that +we want them to remain in the final output. -So now, the API to C<iter2()> will be discussed and we will explain how our -goal of getting our data into HTML fits into the API. +So now, the API to C<iter2()> will be discussed and we will explain +how our goal of getting our data into HTML fits into the API. =over 4 =item * wrapper_ld -This is how to look down and find the container of all the elements we will -be unrolling. The <dl> tag is the container for the dt and dd tags we will be -unrolling. +This is how to look down and find the container of all the elements we +will be unrolling. The <dl> tag is the container for the dt and dd +tags we will be unrolling. -If you pass an anonymous subroutine, then it is presumed that execution of -this subroutine will return the HTML::Element representing the container tag. -If you pass an array ref, then this will be dereferenced and passed to -C<HTML::Element::look_down()>. +If you pass an anonymous subroutine, then it is presumed that +execution of this subroutine will return the HTML::Element +representing the container tag. If you pass an array ref, then this +will be dereferenced and passed to C<HTML::Element::look_down()>. default value: C<< ['_tag' => 'dl'] >> -Based on the mock HTML above, this default is fine for finding our container -tag. So let's move on. +Based on the mock HTML above, this default is fine for finding our +container tag. So let's move on. =item * wrapper_data -This is an array reference of data that we will be putting into the container. -You must supply this. C<@items> above is our C<wrapper_data>. +This is an array reference of data that we will be putting into the +container. You must supply this. C<@items> above is our +C<wrapper_data>. =item * wrapper_proc -After we find the container via C<wrapper_ld>, we may want to pre-process -some aspect of this tree. In our case the first two sets of dt and dd need -to be removed, leaving the last dt and dd. So, we supply a C<wrapper_proc> -which will do this. +After we find the container via C<wrapper_ld>, we may want to +pre-process some aspect of this tree. In our case the first two sets +of dt and dd need to be removed, leaving the last dt and dd. So, we +supply a C<wrapper_proc> which will do this. default: undef =item * item_ld -This anonymous subroutine returns an array ref of C<HTML::Element>s that will -be cloned and populated with item data -(item data is a "row" of C<wrapper_data>). +This anonymous subroutine returns an array ref of C<HTML::Element>s +that will be cloned and populated with item data (item data is a "row" +of C<wrapper_data>). -default: returns an arrayref consisting of the dt and dd element inside the -container. +default: returns an arrayref consisting of the dt and dd element +inside the container. =item * item_data -This is a subroutine that takes C<wrapper_data> and retrieves one "row" -to be "pasted" into the array ref of C<HTML::Element>s found via C<item_ld>. -I hope that makes sense. +This is a subroutine that takes C<wrapper_data> and retrieves one +"row" to be "pasted" into the array ref of C<HTML::Element>s found via +C<item_ld>. I hope that makes sense. default: shifts C<wrapper_data>. =item * item_proc -This is a subroutine that takes the C<item_data> and the C<HTML::Element>s -found via C<item_ld> and produces an arrayref of C<HTML::Element>s which will -eventually be spliced into the container. +This is a subroutine that takes the C<item_data> and the +C<HTML::Element>s found via C<item_ld> and produces an arrayref of +C<HTML::Element>s which will eventually be spliced into the container. -Note that this subroutine MUST return the new items. This is done -So that more items than were passed in can be returned. This is -useful when, for example, you must return 2 dts for an input data item. -And when would you do this? When a single term has multiple spellings -for instance. +Note that this subroutine MUST return the new items. This is done So +that more items than were passed in can be returned. This is useful +when, for example, you must return 2 dts for an input data item. And +when would you do this? When a single term has multiple spellings for +instance. -default: expects C<item_data> to be an arrayref of two elements and -C<item_elems> to be an arrayref of two C<HTML::Element>s. It replaces the -content of the C<HTML::Element>s with the C<item_data>. +default: expects C<item_data> to be an arrayref of two elements and +C<item_elems> to be an arrayref of two C<HTML::Element>s. It replaces +the content of the C<HTML::Element>s with the C<item_data>. =item * splice After building up an array of C<@item_elems>, the subroutine passed as -C<splice> will be given the parent container HTML::Element and the -C<@item_elems>. How the C<@item_elems> end up in the container is up to this -routine: it could put half of them in. It could unshift them or whatever. +C<splice> will be given the parent container HTML::Element and the +C<@item_elems>. How the C<@item_elems> end up in the container is up +to this routine: it could put half of them in. It could unshift them +or whatever. -default: C<< $container->splice_content(0, 2, @item_elems) >> -In other words, kill the 2 sample elements with the newly generated -@item_elems +default: C<< $container->splice_content(0, 2, @item_elems) >> In other +words, kill the 2 sample elements with the newly generated @item_elems =back So now that we have documented the API, let's see the call we need: $tree->iter2( - # default wrapper_ld ok. + # default wrapper_ld ok. wrapper_data => \@items, wrapper_proc => sub { my ($container) = @_; # only keep the last 2 dts and dds my @content_list = $container->content_list; - $container->splice_content(0, @content_list - 2); + $container->splice_content(0, @content_list - 2); }, # default item_ld is fine. # default item_data is fine. - # default item_proc is fine. + # default item_proc is fine. splice => sub { my ($container, @item_elems) = @_; $container->unshift_content(@item_elems); @@ -657,9 +649,6 @@ So now that we have documented the API, let's see the call we need: debug => 1, ); - - - =head3 Select Unrolling The C<unroll_select> method has this API: @@ -669,252 +658,228 @@ The C<unroll_select> method has this API: option_value => $closure, # how to get option value from data row option_content => $closure, # how to get option content from data row option_selected => $closure, # boolean to decide if SELECTED - data => $data # the data to be put into the SELECT - data_iter => $closure # the thing that will get a row of data - debug => $boolean, - append => $boolean, # remove the sample <OPTION> data or append? + data => $data # the data to be put into the SELECT + data_iter => $closure # the thing that will get a row of data + debug => $boolean, + append => $boolean, # remove the sample <OPTION> data or append? ); Here's an example: - $tree->unroll_select( - select_label => 'clan_list', - option_value => sub { my $row = shift; $row->clan_id }, - option_content => sub { my $row = shift; $row->clan_name }, - option_selected => sub { my $row = shift; $row->selected }, - data => \@query_results, - data_iter => sub { my $data = shift; $data->next }, - append => 0, - debug => 0 - ); - - + $tree->unroll_select( + select_label => 'clan_list', + option_value => sub { my $row = shift; $row->clan_id }, + option_content => sub { my $row = shift; $row->clan_name }, + option_selected => sub { my $row = shift; $row->selected }, + data => \@query_results, + data_iter => sub { my $data = shift; $data->next }, + append => 0, + debug => 0 + ); =head2 Tree-Building Methods: Table Generation -Matthew Sisk has a much more intuitive (imperative) -way to generate tables via his module -L<HTML::ElementTable|HTML::ElementTable>. -However, for those with callback fever, the following -method is available. First, we look at a nuts and bolts way to build a table -using only standard L<HTML::Tree> API calls. Then the C<table> method +Matthew Sisk has a much more intuitive (imperative) way to generate +tables via his module L<HTML::ElementTable|HTML::ElementTable>. + +However, for those with callback fever, the following method is +available. First, we look at a nuts and bolts way to build a table +using only standard L<HTML::Tree> API calls. Then the C<table> method available here is discussed. =head3 Sample Model - package Simple::Class; - - use Set::Array; - - my @name = qw(bob bill brian babette bobo bix); - my @age = qw(99 12 44 52 12 43); - my @weight = qw(99 52 80 124 120 230); - - - sub new { - my $this = shift; - bless {}, ref($this) || $this; - } - - sub load_data { - my @data; - - for (0 .. 5) { - push @data, { - age => $age[rand $#age] + int rand 20, - name => shift @name, - weight => $weight[rand $#weight] + int rand 40 - } - } - - Set::Array->new(@data); - } - - - 1; + package Simple::Class; + + use Set::Array; + + my @name = qw(bob bill brian babette bobo bix); + my @age = qw(99 12 44 52 12 43); + my @weight = qw(99 52 80 124 120 230); + + + sub new { + my $this = shift; + bless {}, ref($this) || $this; + } + + sub load_data { + my @data; + + for (0 .. 5) { + push @data, { + age => $age[rand $#age] + int rand 20, + name => shift @name, + weight => $weight[rand $#weight] + int rand 40 + } + } + + Set::Array->new(@data); + } + 1; =head4 Sample Usage: - my $data = Simple::Class->load_data; - ++$_->{age} for @$data + my $data = Simple::Class->load_data; + ++$_->{age} for @$data =head3 Inline Code to Unroll a Table =head4 HTML - <html> - - <table id="load_data"> - - <tr> <th>name</th><th>age</th><th>weight</th> </tr> - - <tr id="iterate"> - - <td id="name"> NATURE BOY RIC FLAIR </td> - <td id="age"> 35 </td> - <td id="weight"> 220 </td> - - </tr> - - </table> - - </html> + <html> + <table id="load_data"> + <tr> <th>name</th><th>age</th><th>weight</th> </tr> + <tr id="iterate"> + <td id="name"> NATURE BOY RIC FLAIR </td> + <td id="age"> 35 </td> + <td id="weight"> 220 </td> + </tr> + </table> + </html> =head4 The manual way (*NOT* recommended) - require 'simple-class.pl'; - use HTML::Seamstress; - - # load the view - my $seamstress = HTML::Seamstress->new_from_file('simple.html'); - - # load the model - my $o = Simple::Class->new; - my $data = $o->load_data; - - # find the <table> and <tr> - my $table_node = $seamstress->look_down('id', 'load_data'); - my $iter_node = $table_node->look_down('id', 'iterate'); - my $table_parent = $table_node->parent; - - - # drop the sample <table> and <tr> from the HTML - # only add them in if there is data in the model - # this is achieved via the $add_table flag - - $table_node->detach; - $iter_node->detach; - my $add_table; - - # Get a row of model data - while (my $row = shift @$data) { - - # We got row data. Set the flag indicating ok to hook the table into the HTML - ++$add_table; - - # clone the sample <tr> - my $new_iter_node = $iter_node->clone; - - # find the tags labeled name age and weight and - # set their content to the row data - $new_iter_node->content_handler($_ => $row->{$_}) + require 'simple-class.pl'; + use HTML::Seamstress; + + # load the view + my $seamstress = HTML::Seamstress->new_from_file('simple.html'); + + # load the model + my $o = Simple::Class->new; + my $data = $o->load_data; + + # find the <table> and <tr> + my $table_node = $seamstress->look_down('id', 'load_data'); + my $iter_node = $table_node->look_down('id', 'iterate'); + my $table_parent = $table_node->parent; + + + # drop the sample <table> and <tr> from the HTML + # only add them in if there is data in the model + # this is achieved via the $add_table flag + + $table_node->detach; + $iter_node->detach; + my $add_table; + + # Get a row of model data + while (my $row = shift @$data) { + + # We got row data. Set the flag indicating ok to hook the table into the HTML + ++$add_table; + + # clone the sample <tr> + my $new_iter_node = $iter_node->clone; + + # find the tags labeled name age and weight and + # set their content to the row data + $new_iter_node->content_handler($_ => $row->{$_}) for qw(name age weight); - - $table_node->push_content($new_iter_node); - - } - - # reattach the table to the HTML tree if we loaded data into some table rows - - $table_parent->push_content($table_node) if $add_table; - - print $seamstress->as_HTML; - + $table_node->push_content($new_iter_node); + + } + + # reattach the table to the HTML tree if we loaded data into some table rows + + $table_parent->push_content($table_node) if $add_table; + + print $seamstress->as_HTML; =head3 $tree->table() : API call to Unroll a Table - require 'simple-class.pl'; - use HTML::Seamstress; - - # load the view - my $seamstress = HTML::Seamstress->new_from_file('simple.html'); - # load the model - my $o = Simple::Class->new; - - $seamstress->table - ( - # tell seamstress where to find the table, via the method call - # ->look_down('id', $gi_table). Seamstress detaches the table from the - # HTML tree automatically if no table rows can be built - - gi_table => 'load_data', - - # tell seamstress where to find the tr. This is a bit useless as - # the <tr> usually can be found as the first child of the parent - - gi_tr => 'iterate', - - # the model data to be pushed into the table - - table_data => $o->load_data, - - # the way to take the model data and obtain one row - # if the table data were a hashref, we would do: - # my $key = (keys %$data)[0]; my $val = $data->{$key}; delete $data->{$key} - - tr_data => sub { my ($self, $data) = @_; - shift(@{$data}) ; - }, - - # the way to take a row of data and fill the <td> tags - - td_data => sub { my ($tr_node, $tr_data) = @_; - $tr_node->content_handler($_ => $tr_data->{$_}) - for qw(name age weight) } - - ); - - - print $seamstress->as_HTML; + require 'simple-class.pl'; + use HTML::Seamstress; + + # load the view + my $seamstress = HTML::Seamstress->new_from_file('simple.html'); + # load the model + my $o = Simple::Class->new; + + $seamstress->table + ( + # tell seamstress where to find the table, via the method call + # ->look_down('id', $gi_table). Seamstress detaches the table from the + # HTML tree automatically if no table rows can be built + + gi_table => 'load_data', + + # tell seamstress where to find the tr. This is a bit useless as + # the <tr> usually can be found as the first child of the parent + gi_tr => 'iterate', + # the model data to be pushed into the table + + table_data => $o->load_data, + + # the way to take the model data and obtain one row + # if the table data were a hashref, we would do: + # my $key = (keys %$data)[0]; my $val = $data->{$key}; delete $data->{$key} + + tr_data => sub { + my ($self, $data) = @_; + shift @{$data} ; + }, + + # the way to take a row of data and fill the <td> tags + + td_data => sub { + my ($tr_node, $tr_data) = @_; + $tr_node->content_handler($_ => $tr_data->{$_}) + for qw(name age weight) + } + ); + + print $seamstress->as_HTML; =head4 Looping over Multiple Sample Rows * HTML - <html> - - <table id="load_data" CELLPADDING=8 BORDER=2> - - <tr> <th>name</th><th>age</th><th>weight</th> </tr> - - <tr id="iterate1" BGCOLOR="white" > - - <td id="name"> NATURE BOY RIC FLAIR </td> - <td id="age"> 35 </td> - <td id="weight"> 220 </td> - - </tr> - <tr id="iterate2" BGCOLOR="#CCCC99"> - - <td id="name"> NATURE BOY RIC FLAIR </td> - <td id="age"> 35 </td> - <td id="weight"> 220 </td> - - </tr> - - </table> - - </html> - + <html> + <table id="load_data" CELLPADDING=8 BORDER=2> + <tr> <th>name</th><th>age</th><th>weight</th> </tr> + <tr id="iterate1" BGCOLOR="white" > + <td id="name"> NATURE BOY RIC FLAIR </td> + <td id="age"> 35 </td> + <td id="weight"> 220 </td> + </tr> + <tr id="iterate2" BGCOLOR="#CCCC99"> + <td id="name"> NATURE BOY RIC FLAIR </td> + <td id="age"> 35 </td> + <td id="weight"> 220 </td> + </tr> + </table> +</html> -* Only one change to last API call. +* Only one change to last API call. This: - gi_tr => 'iterate', + gi_tr => 'iterate', becomes this: - gi_tr => ['iterate1', 'iterate2'] + gi_tr => ['iterate1', 'iterate2'] =head3 $tree->table2() : New API Call to Unroll a Table -After 2 or 3 years with C<table()>, I began to develop -production websites with it and decided it needed a cleaner -interface, particularly in the area of handling the fact that -C<id> tags will be the same after cloning a table row. +After 2 or 3 years with C<table()>, I began to develop production +websites with it and decided it needed a cleaner interface, +particularly in the area of handling the fact that C<id> tags will be +the same after cloning a table row. -First, I will give a dry listing of the function's argument parameters. -This will not be educational most likely. A better way to understand how -to use the function is to read through the incremental unrolling of the -function's interface given in conversational style after the dry listing. -But take your pick. It's the same information given in two different -ways. +First, I will give a dry listing of the function's argument +parameters. This will not be educational most likely. A better way to +understand how to use the function is to read through the incremental +unrolling of the function's interface given in conversational style +after the dry listing. But take your pick. It's the same information +given in two different ways. =head4 Dry/technical parameter documentation @@ -924,7 +889,7 @@ C<< $tree->table2(%param) >> takes the following arguments: =item * C<< table_ld => $look_down >> : optional -How to find the C<table> element in C<$tree>. If C<$look_down> is an +How to find the C<table> element in C<$tree>. If C<$look_down> is an arrayref, then use C<look_down>. If it is a CODE ref, then call it, passing it C<$tree>. @@ -936,16 +901,16 @@ The data to fill the table with. I<Must> be passed in. =item * C<< table_proc => $code_ref >> : not implemented -A subroutine to do something to the table once it is found. -Not currently implemented. Not obviously necessary. Just -created because there is a C<tr_proc> and C<td_proc>. +A subroutine to do something to the table once it is found. Not +currently implemented. Not obviously necessary. Just created because +there is a C<tr_proc> and C<td_proc>. =item * C<< tr_ld => $look_down >> : optional -Same as C<table_ld> but for finding the table row elements. Please note -that the C<tr_ld> is done on the table node that was found I<instead> -of the whole HTML tree. This makes sense. The C<tr>s that you want exist -below the table that was just found. +Same as C<table_ld> but for finding the table row elements. Please +note that the C<tr_ld> is done on the table node that was found +I<instead> of the whole HTML tree. This makes sense. The C<tr>s that +you want exist below the table that was just found. Defaults to C<< ['_tag' => 'tr'] >> if not passed in. @@ -953,93 +918,88 @@ Defaults to C<< ['_tag' => 'tr'] >> if not passed in. How to take the C<table_data> and return a row. Defaults to: - sub { my ($self, $data) = @_; - shift(@{$data}) ; - } - + sub { my ($self, $data) = @_; + shift(@{$data}) ; + } + =item * C<< tr_proc => $code_ref >> : optional -Something to do to the table row we are about to add to the -table we are making. Defaults to a routine which makes the C<id> -attribute unique: +Something to do to the table row we are about to add to the table we +are making. Defaults to a routine which makes the C<id> attribute +unique: - sub { - my ($self, $tr, $tr_data, $tr_base_id, $row_count) = @_; - $tr->attr(id => sprintf "%s_%d", $tr_base_id, $row_count); - } + sub { + my ($self, $tr, $tr_data, $tr_base_id, $row_count) = @_; + $tr->attr(id => sprintf "%s_%d", $tr_base_id, $row_count); + } =item * C<< td_proc => $code_ref >> : required -This coderef will take the row of data and operate on the C<td> cells that -are children of the C<tr>. See C<t/table2.t> for several usage examples. +This coderef will take the row of data and operate on the C<td> cells +that are children of the C<tr>. See C<t/table2.t> for several usage +examples. Here's a sample one: - sub { - my ($tr, $data) = @_; - my @td = $tr->look_down('_tag' => 'td'); - for my $i (0..$#td) { - $td[$i]->splice_content(0, 1, $data->[$i]); - } + sub { + my ($tr, $data) = @_; + my @td = $tr->look_down('_tag' => 'td'); + for my $i (0..$#td) { + $td[$i]->splice_content(0, 1, $data->[$i]); } + } =cut =head4 Conversational parameter documentation -The first thing you need is a table. So we need a look down for that. If you -don't give one, it defaults to +The first thing you need is a table. So we need a look down for that. +If you don't give one, it defaults to ['_tag' => 'table'] -What good is a table to display in without data to display?! -So you must supply a scalar representing your tabular -data source. This scalar might be an array reference, a C<next>able iterator, -a DBI statement handle. Whatever it is, it can be iterated through to build -up rows of table data. -These two required fields (the way to find the table and the data to -display in the table) are C<table_ld> and C<table_data> -respectively. A little more on C<table_ld>. If this happens to be a CODE ref, -then execution -of the code ref is presumed to return the C<HTML::Element> -representing the table in the HTML tree. - -Next, we get the row or rows which serve as sample C<tr> elements by doing -a C<look_down> from the C<table_elem>. While normally one sample row -is enough to unroll a table, consider when you have alternating -table rows. This API call would need one of each row so that it can -cycle through the -sample rows as it loops through the data. -Alternatively, you could always just use one row and -make the necessary changes to the single C<tr> row by -mutating the element in C<tr_proc>, -discussed below. The default C<tr_ld> is -C<< ['_tag' => 'tr'] >> but you can overwrite it. Note well, if you overwrite -it with a subroutine, then it is expected that the subroutine will return -the C<HTML::Element>(s) -which are C<tr> element(s). -The reason a subroutine might be preferred is in the case -that the HTML designers gave you 8 sample C<tr> rows but only one -prototype row is needed. -So you can write a subroutine, to splice out the 7 rows you don't need -and leave the one sample -row remaining so that this API call can clone it and supply it to -the C<tr_proc> and C<td_proc> calls. - -Now, as we move through the table rows with table data, -we need to do two different things on -each table row: +What good is a table to display in without data to display?! So you +must supply a scalar representing your tabular data source. This +scalar might be an array reference, a C<next>able iterator, a DBI +statement handle. Whatever it is, it can be iterated through to build +up rows of table data. These two required fields (the way to find the +table and the data to display in the table) are C<table_ld> and +C<table_data> respectively. A little more on C<table_ld>. If this +happens to be a CODE ref, then execution of the code ref is presumed +to return the C<HTML::Element> representing the table in the HTML +tree. + +Next, we get the row or rows which serve as sample C<tr> elements by +doing a C<look_down> from the C<table_elem>. While normally one sample +row is enough to unroll a table, consider when you have alternating +table rows. This API call would need one of each row so that it can +cycle through the sample rows as it loops through the data. +Alternatively, you could always just use one row and make the +necessary changes to the single C<tr> row by mutating the element in +C<tr_proc>, discussed below. The default C<tr_ld> is C<< ['_tag' => +'tr'] >> but you can overwrite it. Note well, if you overwrite it with +a subroutine, then it is expected that the subroutine will return the +C<HTML::Element>(s) which are C<tr> element(s). The reason a +subroutine might be preferred is in the case that the HTML designers +gave you 8 sample C<tr> rows but only one prototype row is needed. So +you can write a subroutine, to splice out the 7 rows you don't need +and leave the one sample row remaining so that this API call can clone +it and supply it to the C<tr_proc> and C<td_proc> calls. + +Now, as we move through the table rows with table data, we need to do +two different things on each table row: =over 4 =item * get one row of data from the C<table_data> via C<tr_data> -The default procedure assumes the C<table_data> is an array reference and -shifts a row off of it: +The default procedure assumes the C<table_data> is an array reference +and shifts a row off of it: - sub { my ($self, $data) = @_; - shift(@{$data}) ; - } + sub { + my ($self, $data) = @_; + shift @{$data}; + } Your function MUST return undef when there is no more rows to lay out. @@ -1047,16 +1007,16 @@ Your function MUST return undef when there is no more rows to lay out. The default procedure simply makes the id of the table row unique: - sub { my ($self, $tr, $tr_data, $row_count, $root_id) = @_; - $tr->attr(id => sprintf "%s_%d", $root_id, $row_count); - } + sub { + my ($self, $tr, $tr_data, $row_count, $root_id) = @_; + $tr->attr(id => sprintf "%s_%d", $root_id, $row_count); + } =back Now that we have our row of data, we call C<td_proc> so that it can -take the data and the C<td> cells in this C<tr> and process them. -This function I<must> be supplied. - +take the data and the C<td> cells in this C<tr> and process them. This +function I<must> be supplied. =head3 Whither a Table with No Rows @@ -1064,71 +1024,62 @@ Often when a table has no rows, we want to display a message indicating this to the view. Use conditional processing to decide what to display: - <span id=no_data> - <table><tr><td>No Data is Good Data</td></tr></table> - </span> - <span id=load_data> - <html> - - <table id="load_data"> - - <tr> <th>name</th><th>age</th><th>weight</th> </tr> - - <tr id="iterate"> - - <td id="name"> NATURE BOY RIC FLAIR </td> - <td id="age"> 35 </td> - <td id="weight"> 220 </td> - - </tr> - - </table> - - </html> - - </span> - + <span id=no_data> + <table><tr><td>No Data is Good Data</td></tr></table> + </span> + <span id=load_data> + <html> + <table id="load_data"> + <tr> <th>name</th><th>age</th><th>weight</th> </tr> + <tr id="iterate"> + <td id="name"> NATURE BOY RIC FLAIR </td> + <td id="age"> 35 </td> + <td id="weight"> 220 </td> + </tr> + </table> + </html> + </span> =head2 Tree-Killing Methods =head3 $tree->prune -This removes any nodes from the tree which consist of nothing or nothing but whitespace. -See also delete_ignorable_whitespace in L<HTML::Element>. +This removes any nodes from the tree which consist of nothing or +nothing but whitespace. See also delete_ignorable_whitespace in +L<HTML::Element>. =head2 Loltree Functions -A loltree is an arrayref consisting of arrayrefs which is used by -C<< new_from__lol >> in L<HTML::Element> to produce HTML trees. -The CPAN distro L<XML::Element::Tolol> creates such XML trees by parsing XML files, -analagous to L<XML::Toolkit>. The purpose of the functions in this section is to allow -you manipulate a loltree programmatically. +A loltree is an arrayref consisting of arrayrefs which is used by C<< +new_from__lol >> in L<HTML::Element> to produce HTML trees. The CPAN +distro L<XML::Element::Tolol> creates such XML trees by parsing XML +files, analagous to L<XML::Toolkit>. The purpose of the functions in +this section is to allow you manipulate a loltree programmatically. -These could not be methods because if you bless a loltree, then HTML::Tree will barf. +These could not be methods because if you bless a loltree, then +HTML::Tree will barf. =head3 HTML::Element::newchild($lol, $parent_label, @newchild) Given this initial loltree: - my $initial_lol = [ note => [ shopping => [ item => 'sample' ] ] ]; + my $initial_lol = [ note => [ shopping => [ item => 'sample' ] ] ]; This code: - sub shopping_items { - my @shopping_items = map { [ item => _ ] } qw(bread butter beans) ; - @shopping_items; - } + sub shopping_items { + my @shopping_items = map { [ item => _ ] } qw(bread butter beans); + @shopping_items; + } - my $new_lol = HTML::Element::newnode($initial_lol, item => shopping_items()); + my $new_lol = HTML::Element::newnode($initial_lol, item => shopping_items()); will replace the single sample with a list of shopping items: - [ 'note', [ 'shopping', - [ 'item', 'bread' @@ -1153,25 +1104,24 @@ http://www.perlmonks.org/?node_id=912416 =head2 L<HTML::Tree> -A perl package for creating and manipulating HTML trees. +A perl package for creating and manipulating HTML trees. =head2 L<HTML::ElementTable> An L<HTML::Tree> - based module which allows for manipulation of HTML -trees using cartesian coordinations. +trees using cartesian coordinations. =head2 L<HTML::Seamstress> -An L<HTML::Tree> - based module inspired by -XMLC (L<http://xmlc.enhydra.org>), allowing for dynamic -HTML generation via tree rewriting. +An L<HTML::Tree> - based module inspired by XMLC +(L<http://xmlc.enhydra.org>), allowing for dynamic HTML generation via +tree rewriting. =head2 Push-style templating systems -A comprehensive cross-language +A comprehensive cross-language L<list of push-style templating systems|http://perlmonks.org/?node_id=674225>. - =head1 TODO =over @@ -1182,56 +1132,48 @@ currently the API expects the subtrees to survive or be pruned to be identified by id: $if_then->highlander2([ - under10 => sub { $_[0] < 10} , + under10 => sub { $_[0] < 10} , under18 => sub { $_[0] < 18} , welcome => [ sub { 1 }, - sub { - my $branch = shift; - $branch->look_down(id => 'age')->replace_content($age); + sub { + my $branch = shift; + $branch->look_down(id => 'age')->replace_content($age); } ] - ], - $age - ); + ], $age); but, it should be more flexible. the C<under10>, and C<under18> are -expected to be ids in the tree... but it is not hard to have a check to -see if this field is an array reference and if it, then to do a look -down instead: +expected to be ids in the tree... but it is not hard to have a check +to see if this field is an array reference and if it, then to do a +look down instead: $if_then->highlander2([ - [class => 'under10'] => sub { $_[0] < 10} , + [class => 'under10'] => sub { $_[0] < 10} , [class => 'under18'] => sub { $_[0] < 18} , [class => 'welcome'] => [ sub { 1 }, - sub { - my $branch = shift; - $branch->look_down(id => 'age')->replace_content($age); + sub { + my $branch = shift; + $branch->look_down(id => 'age')->replace_content($age); } ] - ], - $age - ); - - - -=cut - + ], $age); =head1 AUTHOR and ACKS Terrence Brannon, E<lt>tbone@cpan.orgE<gt> -I appreciate the feedback from M. David Moussa Leo Keita regarding some issues with the -test suite, namely (1) CRLF leading to test breakage in F<t/crunch.t> and (2) using the -wrong module in F<t/prune.t> thus not having the right functionality available. +I appreciate the feedback from M. David Moussa Leo Keita regarding +some issues with the test suite, namely (1) CRLF leading to test +breakage in F<t/crunch.t> and (2) using the wrong module in +F<t/prune.t> thus not having the right functionality available. Many thanks to BARBIE for his RT bug report. Many thanks to perlmonk kcott for his work on array rewriting: -L<http://www.perlmonks.org/?node_id=912416>. -It was crucial in the development of newchild. +L<http://www.perlmonks.org/?node_id=912416>. It was crucial in the +development of newchild. =head2 Source Repo -- 2.39.5