HTML-Template-Pluggable-0.22000755001750001750 014236676171 15256 5ustar00rhesarhesa000000000000HTML-Template-Pluggable-0.22/.gitignore000444001750001750 17414236676171 17365 0ustar00rhesarhesa000000000000blib* MANIFEST* META* Makefile* Makefile.old Build _build* pm_to_blib* *.tar.gz .lwpcookies HTML-Template-* cover_db .git* HTML-Template-Pluggable-0.22/ARTISTIC000444001750001750 1373714236676171 16613 0ustar00rhesarhesa000000000000 The "Artistic License" Preamble The intent of this document is to state the conditions under which a Package may be copied, such that the Copyright Holder maintains some semblance of artistic control over the development of the package, while giving the users of the package the right to use and distribute the Package in a more-or-less customary fashion, plus the right to make reasonable modifications. Definitions: "Package" refers to the collection of files distributed by the Copyright Holder, and derivatives of that collection of files created through textual modification. "Standard Version" refers to such a Package if it has not been modified, or has been modified in accordance with the wishes of the Copyright Holder as specified below. "Copyright Holder" is whoever is named in the copyright or copyrights for the package. "You" is you, if you're thinking about copying or distributing this Package. "Reasonable copying fee" is whatever you can justify on the basis of media cost, duplication charges, time of people involved, and so on. (You will not be required to justify it to the Copyright Holder, but only to the computing community at large as a market that must bear the fee.) "Freely Available" means that no fee is charged for the item itself, though there may be fees involved in handling the item. It also means that recipients of the item may redistribute it under the same conditions they received it. 1. You may make and give away verbatim copies of the source form of the Standard Version of this Package without restriction, provided that you duplicate all of the original copyright notices and associated disclaimers. 2. You may apply bug fixes, portability fixes and other modifications derived from the Public Domain or from the Copyright Holder. A Package modified in such a way shall still be considered the Standard Version. 3. You may otherwise modify your copy of this Package in any way, provided that you insert a prominent notice in each changed file stating how and when you changed that file, and provided that you do at least ONE of the following: a) place your modifications in the Public Domain or otherwise make them Freely Available, such as by posting said modifications to Usenet or an equivalent medium, or placing the modifications on a major archive site such as uunet.uu.net, or by allowing the Copyright Holder to include your modifications in the Standard Version of the Package. b) use the modified Package only within your corporation or organization. c) rename any non-standard executables so the names do not conflict with standard executables, which must also be provided, and provide a separate manual page for each non-standard executable that clearly documents how it differs from the Standard Version. d) make other distribution arrangements with the Copyright Holder. 4. You may distribute the programs of this Package in object code or executable form, provided that you do at least ONE of the following: a) distribute a Standard Version of the executables and library files, together with instructions (in the manual page or equivalent) on where to get the Standard Version. b) accompany the distribution with the machine-readable source of the Package with your modifications. c) give non-standard executables non-standard names, and clearly document the differences in manual pages (or equivalent), together with instructions on where to get the Standard Version. d) make other distribution arrangements with the Copyright Holder. 5. You may charge a reasonable copying fee for any distribution of this Package. You may charge any fee you choose for support of this Package. You may not charge a fee for this Package itself. However, you may distribute this Package in aggregate with other (possibly commercial) programs as part of a larger (possibly commercial) software distribution provided that you do not advertise this Package as a product of your own. You may embed this Package's interpreter within an executable of yours (by linking); this shall be construed as a mere form of aggregation, provided that the complete Standard Version of the interpreter is so embedded. 6. The scripts and library files supplied as input to or produced as output from the programs of this Package do not automatically fall under the copyright of this Package, but belong to whoever generated them, and may be sold commercially, and may be aggregated with this Package. If such scripts or library files are aggregated with this Package via the so-called "undump" or "unexec" methods of producing a binary executable image, then distribution of such an image shall neither be construed as a distribution of this Package nor shall it fall under the restrictions of Paragraphs 3 and 4, provided that you do not represent such an executable image as a Standard Version of this Package. 7. C subroutines (or comparably compiled subroutines in other languages) supplied by you and linked into this Package in order to emulate subroutines and variables of the language defined by this Package shall not be considered part of this Package, but are the equivalent of input as in Paragraph 6, provided these subroutines do not change the language in any way that would cause it to fail the regression tests for the language. 8. Aggregation of this Package with a commercial distribution is always permitted provided that the use of this Package is embedded; that is, when no overt attempt is made to make this Package's interfaces visible to the end user of the commercial distribution. Such use shall not be construed as a distribution of this Package. 9. The name of the Copyright Holder may not be used to endorse or promote products derived from this software without specific prior written permission. 10. THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. The End HTML-Template-Pluggable-0.22/Build.PL000444001750001750 141614236676171 16711 0ustar00rhesarhesa000000000000use strict; use warnings; use Module::Build; my $builder = Module::Build->new( module_name => 'HTML::Template::Pluggable', license => 'perl', dist_author => 'Mark Stosberg ', dist_version_from => 'lib/HTML/Template/Pluggable.pm', requires => { 'Test::More' => 0, # Required because about every test uses it. 'Test::MockObject' => 1, 'HTML::Template' => 2.7, 'Regexp::Common' => 0, 'Scalar::Util' => 0, 'Class::Trigger' => 0, 'CGI' => 3.06, }, add_to_cleanup => [ 'HTML-Template-Pluggable-*' ], create_makefile_pl => 'traditional', create_readme => 1, ); $builder->create_build_script(); HTML-Template-Pluggable-0.22/Changes000444001750001750 643414236676171 16715 0ustar00rhesarhesa000000000000Revision history for HTML-Template-Pluggable 0.21 2022-05-04 Rhesa Rozendaal * fix all the test failures: * make number formatting test locale-independent * add back support for AUTOLOADed methods 0.20 2022-05-03 Rhesa Rozendaal * add prereq for CGI since this is no longer bundled with perl core 0.18 2009-12-26 Rhesa Rozendaal * fixed RT #40714 to the extent that H::T allows * fixed RT #49123 by checking can('AUTOLOAD') * imported CPAN history into git, and published on github 0.17 2007-05-15 Rhesa Rozendaal - ::Dot now handles exceptions on method calls differently: * if the option die_on_bad_params is on, it will rethrow the exception * if die_on_bad_params is off, it will emit a warning and produce no output for that param 0.16 2007-03-28 Rhesa Rozendaal - removed test dependency on CGI::Application 0.15 2006-03-28 Rhesa Rozendaal - argh! removed dependency on CAP::AutoRunmode from test suite 0.14 2006-03-27 Rhesa Rozendaal - bugfixes in ::Dot: - switched to using blessed() instead of UNIVERSAL::can as a function. this breaks with using a CGI object for versions older than 3.06, since CGI didn't have a working can() method. - made nested calls to the same object work, so you can now do: Both issues were reported by Dan Horne. 0.13 2005-10-04 Rhesa Rozendaal - bug fixes in ::Dot: - using obj.loop in a or now returns the number of elements; this is a slight incompatibility with H::T, but makes the if's work - single char method names in nested calls work properly now - added pod tests to improve kwalitee... 0.12 2005-08-26 Rhesa Rozendaal - added before_output hook 0.08 Wed Aug 17 02:30:37 CEST 2005 Rhesa Rozendaal - fixed bug with global_vars => 1 - made sure all original HTML::Template tests pass with ::Pluggable and ::Dot 0.07 Tue Aug 16 16:19:50 CEST 2005 Rhesa Rozendaal - bug fix in tmpl_loop stuff. Only get array on final method call 0.06 Mon Aug 15 19:56:24 CEST 2005 Rhesa Rozendaal - implemented tmpl_loops in ::Dot! 0.05 Sun Aug 14 23:36:55 CEST 2005 Rhesa Rozendaal - Added tests against side effects (where avoidable). Extended the docs for ::Dot - renamed 'pre_param' trigger location to 'middle_param' 0.04 Sat Aug 13 03:09:54 CEST 2005 Rhesa Rozendaal - Thanks to Michael Graham, it's now possible to reference plain old tmpl_vars in argument lists 0.03 Fri Aug 12 16:16:29 CEST 2005 Rhesa Rozendaal - Added more docs to ::Dot, and more tests 0.02 Thu Aug 11 01:09:21 CEST 2005 Mark Stosberg - minor doc formatting tweaks 0.01 Wed Aug 10 16:21:03 CEST 2005 Rhesa Rozendaal - Initial release on CPAN HTML-Template-Pluggable-0.22/GPL000444001750001750 4312714236676171 16007 0ustar00rhesarhesa000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 19yy This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) 19yy name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. HTML-Template-Pluggable-0.22/MANIFEST000444001750001750 70214236676171 16523 0ustar00rhesarhesa000000000000ARTISTIC Build.PL Changes GPL lib/HTML/Template/Pluggable.pm lib/HTML/Template/Plugin/Dot.pm Makefile.PL MANIFEST This list of files MANIFEST.SKIP META.yml README t/RT40714-1.t t/RT40714-2.t t/RT49123.t t/before_output.t t/dot_can.t t/dot_for_loops.t t/dot_loop.t t/dot_nested.t t/dot_notation.t t/dot_notation_methods_with_args.t t/dot_notation_mixnmatch.t t/dot_notation_recursive.t t/pod-coverage.t t/pod.t t/side_effects.t META.json .gitignore HTML-Template-Pluggable-0.22/MANIFEST.SKIP000444001750001750 60414236676171 17271 0ustar00rhesarhesa000000000000# This is a list of regular expressions of files to skip when rebuilding # the MANIFEST file. See the documention for the ExtUtils::Manifest module for more detail. -mls \bCVS\b ^MANIFEST\.bak$ ^Makefile$ ~$ \.old$ \.bak$ ^blib/ ^pm_to_blib$ ^MakeMaker-\d .tar.gz$ ^notes ^releases \.tgz$ \.tmp$ \.swp$ \.swm$ \.swn$ \.swo$ \.patch$ \.orig$ \.diff$ _darcs _build ^Build$ ^\.git$ ^\.git/ HTML-Template-Pluggable-0.22/META.json000444001750001750 243714236676171 17042 0ustar00rhesarhesa000000000000{ "abstract" : "Extends HTML::Template with plugin support", "author" : [ "Mark Stosberg " ], "dynamic_config" : 1, "generated_by" : "Module::Build version 0.4231", "license" : [ "perl_5" ], "meta-spec" : { "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec", "version" : 2 }, "name" : "HTML-Template-Pluggable", "prereqs" : { "configure" : { "requires" : { "Module::Build" : "0.42" } }, "runtime" : { "requires" : { "CGI" : "3.06", "Class::Trigger" : "0", "HTML::Template" : "2.7", "Regexp::Common" : "0", "Scalar::Util" : "0", "Test::MockObject" : "1", "Test::More" : "0" } } }, "provides" : { "HTML::Template::Pluggable" : { "file" : "lib/HTML/Template/Pluggable.pm", "version" : "0.22" }, "HTML::Template::Plugin::Dot" : { "file" : "lib/HTML/Template/Plugin/Dot.pm", "version" : "1.04" } }, "release_status" : "stable", "resources" : { "license" : [ "http://dev.perl.org/licenses/" ] }, "version" : "0.22", "x_serialization_backend" : "JSON::PP version 4.04" } HTML-Template-Pluggable-0.22/META.yml000444001750001750 156414236676171 16672 0ustar00rhesarhesa000000000000--- abstract: 'Extends HTML::Template with plugin support' author: - 'Mark Stosberg ' build_requires: {} configure_requires: Module::Build: '0.42' dynamic_config: 1 generated_by: 'Module::Build version 0.4231, CPAN::Meta::Converter version 2.150010' license: perl meta-spec: url: http://module-build.sourceforge.net/META-spec-v1.4.html version: '1.4' name: HTML-Template-Pluggable provides: HTML::Template::Pluggable: file: lib/HTML/Template/Pluggable.pm version: '0.22' HTML::Template::Plugin::Dot: file: lib/HTML/Template/Plugin/Dot.pm version: '1.04' requires: CGI: '3.06' Class::Trigger: '0' HTML::Template: '2.7' Regexp::Common: '0' Scalar::Util: '0' Test::MockObject: '1' Test::More: '0' resources: license: http://dev.perl.org/licenses/ version: '0.22' x_serialization_backend: 'CPAN::Meta::YAML version 0.018' HTML-Template-Pluggable-0.22/Makefile.PL000444001750001750 114214236676171 17363 0ustar00rhesarhesa000000000000# Note: this file was auto-generated by Module::Build::Compat version 0.4231 use ExtUtils::MakeMaker; WriteMakefile ( 'NAME' => 'HTML::Template::Pluggable', 'VERSION_FROM' => 'lib/HTML/Template/Pluggable.pm', 'PREREQ_PM' => { 'CGI' => '3.06', 'Class::Trigger' => 0, 'HTML::Template' => '2.7', 'Regexp::Common' => 0, 'Scalar::Util' => 0, 'Test::MockObject' => 1, 'Test::More' => 0 }, 'INSTALLDIRS' => 'site', 'EXE_FILES' => [], 'PL_FILES' => {} ) ; HTML-Template-Pluggable-0.22/README000444001750001750 747114236676171 16304 0ustar00rhesarhesa000000000000NAME HTML::Template::Pluggable - Extends HTML::Template with plugin support SYNOPSIS Just use this module instead of HTML::Template, then use any plugins, and go on with life. use HTML::Template::Pluggable; use HTML::Template::Plugin::Dot; # Everything works the same, except for functionality that plugins add. my $t = HTML::Template::Pluggable->new(); THE GOAL Ideally we'd like to see this functionality merged into HTML::Template, and turn this into a null sub-class. STATUS The design of the plugin system is still in progress. Right now we have just two triggers, in param and output. The name and function of this may change, and we would like to add triggers in new() and other methods when the need arises. All we promise for now is to keep HTML::Template::Plugin::Dot compatible. Please get in touch if you have suggestions with feedback on designing the plugin system if you would like to contribute. WRITING PLUGINS HTML::Template offers a plugin system which allows developers to extend the functionality in significant ways without creating a creating a sub-class, which might be impossible to use in combination with another sub-class extension. Currently, two triggers have been made available to alter how the values of TMPL_VARs are set. If more hooks are needed to implement your own plugin idea, it may be feasible to add them-- check the FAQ then ask about it on the list. Class::Trigger is used to provide plugins. Basically, you can just: HTML::Template->add_trigger('middle_param', \&trigger); A good place to add one is in your plugin's import subroutine: package HTML::Template::Plugin::MyPlugin; use base 'Exporter'; sub import { HTML::Template->add_trigger('middle_param', \&dot_notation); goto &Exporter::import; } TRIGGER LOCATIONS param We have added one trigger location to this method, named middle_param. # in a Plugin's import() routine. HTML::Template->add_trigger('middle_param', \&_set_tmpl_var_with_dot ); This sets a callback which is executed in param() with all of the same arguments. It is only useful for altering how /setting/ params works. The logic to read a param is unaffected. It can set any TMPL_VAR values before the normal param logic kicks in. To do this, $self->{param_map} is modified as can be seen from source in HTML::Template::param(). However, it must obey the following convention of setting $self->{param_map_done}{$param_name} for each param that is set. $param_name would be a key from $self->{param_map}. This notifies the other plugins and the core param() routine to skip trying to set this value. $self->{param_map_done} is reset with each call to param(), so that like with a hash, you have the option to reset a param later with the same name. output One trigger location here: before_output. HTML::Template->add_trigger('before_output', \&_last_chance_params ); This sets a callback which is executed right before output is generated. SEE ALSO o HTML::Template::Plugin::Dot - Add Template Toolkit's magic dot notation to HTML::Template. AUTHOR Mark Stosberg, BUGS Please report any bugs or feature requests to bug-html-template-pluggable@rt.cpan.org, or through the web interface at http://rt.cpan.org. I will be notified, and then you'll automatically be notified of progress on your bug as I make changes. Copyright & License Copyright 2006 Mark Stosberg, All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. HTML-Template-Pluggable-0.22/lib000755001750001750 014236676171 16024 5ustar00rhesarhesa000000000000HTML-Template-Pluggable-0.22/lib/HTML000755001750001750 014236676171 16570 5ustar00rhesarhesa000000000000HTML-Template-Pluggable-0.22/lib/HTML/Template000755001750001750 014236676171 20343 5ustar00rhesarhesa000000000000HTML-Template-Pluggable-0.22/lib/HTML/Template/Pluggable.pm000444001750001750 1612614236676171 22766 0ustar00rhesarhesa000000000000package HTML::Template::Pluggable; use base 'HTML::Template'; use Class::Trigger; use vars (qw/$VERSION/); $VERSION = '0.22'; use warnings; use strict; use Carp; =head1 NAME HTML::Template::Pluggable - Extends HTML::Template with plugin support =cut =head1 SYNOPSIS Just use this module instead of HTML::Template, then use any plugins, and go on with life. use HTML::Template::Pluggable; use HTML::Template::Plugin::Dot; # Everything works the same, except for functionality that plugins add. my $t = HTML::Template::Pluggable->new(); =head1 THE GOAL Ideally we'd like to see this functionality merged into HTML::Template, and turn this into a null sub-class. =head1 STATUS The design of the plugin system is still in progress. Right now we have just two triggers, in param and output. The name and function of this may change, and we would like to add triggers in new() and other methods when the need arises. All we promise for now is to keep L compatible. Please get in touch if you have suggestions with feedback on designing the plugin system if you would like to contribute. =cut sub param { my $self = shift; my $options = $self->{options}; my $param_map = $self->{param_map}; # the no-parameter case - return list of parameters in the template. return keys(%$param_map) unless scalar(@_); my $first = shift; my $type = ref $first; # the one-parameter case - could be a parameter value request or a # hash-ref. if (!scalar(@_) and !length($type)) { my $param = $options->{case_sensitive} ? $first : lc $first; # check for parameter existence $options->{die_on_bad_params} and !exists($param_map->{$param}) and croak("HTML::Template : Attempt to get nonexistent parameter '$param' - this parameter name doesn't match any declarations in the template file : (die_on_bad_params set => 1)"); return undef unless (exists($param_map->{$param}) and defined($param_map->{$param})); return ${$param_map->{$param}} if (ref($param_map->{$param}) eq 'HTML::Template::VAR'); return $param_map->{$param}[HTML::Template::LOOP::PARAM_SET]; } if (!scalar(@_)) { croak("HTML::Template->param() : Single reference arg to param() must be a hash-ref! You gave me a $type.") unless $type eq 'HASH' or (ref($first) and UNIVERSAL::isa($first, 'HASH')); push(@_, %$first); } else { unshift(@_, $first); } croak("HTML::Template->param() : You gave me an odd number of parameters to param()!") unless ((@_ % 2) == 0); $self->call_trigger('middle_param', @_); # strangely, changing this to a "while(@_) { shift, shift }" type # loop causes perl 5.004_04 to die with some nonsense about a # read-only value. for (my $x = 0; $x <= $#_; $x += 2) { my $param = $options->{case_sensitive} ? $_[$x] : lc $_[$x]; my $value = $_[($x + 1)]; # necessary to cooperate with plugin system next if $self->{param_map_done}{$param}; # check that this param exists in the template $options->{die_on_bad_params} and !exists($param_map->{$param}) and croak("HTML::Template : Attempt to set nonexistent parameter '$param' - this parameter name doesn't match any declarations in the template file : (die_on_bad_params => 1)"); # if we're not going to die from bad param names, we need to ignore # them... next unless (exists($param_map->{$param})); # figure out what we've got, taking special care to allow for # objects that are compatible underneath. my $value_type = ref($value); if (defined($value_type) and length($value_type) and ($value_type eq 'ARRAY' or ((ref($value) !~ /^(CODE)|(HASH)|(SCALAR)$/) and $value->isa('ARRAY')))) { (ref($param_map->{$param}) eq 'HTML::Template::LOOP') or croak("HTML::Template::param() : attempt to set parameter '$param' with an array ref - parameter is not a TMPL_LOOP!"); $param_map->{$param}[HTML::Template::LOOP::PARAM_SET] = [@{$value}]; } else { (ref($param_map->{$param}) eq 'HTML::Template::VAR') or croak("HTML::Template::param() : attempt to set parameter '$param' with a scalar - parameter is not a TMPL_VAR!"); ${$param_map->{$param}} = $value; } } } sub output { my $self = shift; $self->call_trigger('before_output', @_); $self->SUPER::output(@_); } =head1 WRITING PLUGINS HTML::Template offers a plugin system which allows developers to extend the functionality in significant ways without creating a creating a sub-class, which might be impossible to use in combination with another sub-class extension. Currently, two triggers have been made available to alter how the values of TMPL_VARs are set. If more hooks are needed to implement your own plugin idea, it may be feasible to add them-- check the FAQ then ask about it on the list. L is used to provide plugins. Basically, you can just: HTML::Template->add_trigger('middle_param', \&trigger); A good place to add one is in your plugin's C subroutine: package HTML::Template::Plugin::MyPlugin; use base 'Exporter'; sub import { HTML::Template->add_trigger('middle_param', \&dot_notation); goto &Exporter::import; } =head2 TRIGGER LOCATIONS =over 4 =item param We have added one trigger location to this method, named C. # in a Plugin's import() routine. HTML::Template->add_trigger('middle_param', \&_set_tmpl_var_with_dot ); This sets a callback which is executed in param() with all of the same arguments. It is only useful for altering how /setting/ params works. The logic to read a param is unaffected. It can set any TMPL_VAR values before the normal param logic kicks in. To do this, C<$self-E{param_map}> is modified as can be seen from source in HTML::Template::param(). However, it must obey the following convention of setting $self->{param_map_done}{$param_name} for each param that is set. C<$param_name> would be a key from C<$self-E{param_map}>. This notifies the other plugins and the core param() routine to skip trying to set this value. $self->{param_map_done} is reset with each call to param(), so that like with a hash, you have the option to reset a param later with the same name. =item output One trigger location here: C. HTML::Template->add_trigger('before_output', \&_last_chance_params ); This sets a callback which is executed right before output is generated. =back =head1 SEE ALSO =over 4 =item o L - Add Template Toolkit's magic dot notation to HTML::Template. =back =head1 AUTHOR Mark Stosberg, C<< >> =head1 BUGS Please report any bugs or feature requests to C, or through the web interface at L. I will be notified, and then you'll automatically be notified of progress on your bug as I make changes. =head1 Copyright & License Copyright 2006 Mark Stosberg, All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut 1; # End of HTML::Template::Pluggable HTML-Template-Pluggable-0.22/lib/HTML/Template/Plugin000755001750001750 014236676171 21601 5ustar00rhesarhesa000000000000HTML-Template-Pluggable-0.22/lib/HTML/Template/Plugin/Dot.pm000444001750001750 4652714236676171 23060 0ustar00rhesarhesa000000000000package HTML::Template::Plugin::Dot; use vars qw/$VERSION/; $VERSION = '1.04'; use strict; use Carp; use Data::Dumper; use Regexp::Common qw/ RE_balanced RE_delimited RE_num_real /; use Scalar::Util qw/blessed reftype/; use base 'Exporter'; # prefetch regexps for speed our $RE_balanced = RE_balanced(); our $RE_delimited = RE_delimited(-delim=>q{'"`}); our $RE_num_real = RE_num_real(); use constant DEBUG => 0; sub import { # my $caller = scalar(caller); HTML::Template::Pluggable->add_trigger('middle_param', \&_dot_notation); goto &Exporter::import; } sub _dot_notation { my $self = shift; my $options = $self->{options}; my $param_map = $self->{param_map}; # @_ has already been setup for us by the time we're called. my %input; for (my $x = 0; $x <= $#_; $x += 2) { my $param = $options->{case_sensitive} ? $_[$x] : lc $_[$x]; my $value = $_[($x + 1)]; $input{$param} = $value; } DEBUG and carp("dot_notation called for $_[0]"); DEBUG and carp("param map: ", Dumper($param_map)); DEBUG and carp("input: ", Dumper(\%input)); while (my ($param, $value) = each %input) { # necessary to cooperate with plugin system next if ($self->{param_map_done}{$param} and not $self->{num_vars_left_in_loop}); my ($exists,@dot_matches) = _exists_in_tmpl($self, $param); # We don't have to worry about "die on bad params", because that will be handled # by HTML::Template's param(). DEBUG and carp("exists: $exists, dot matches: @dot_matches, param: $param"); next unless $exists; my $value_type = ref($value); if(@dot_matches) { for my $dot_match (@dot_matches) { my $value_for_tmpl = _param_to_tmpl($self,$dot_match,$param,$value, \%input); my $dot_value_type = ref($value_for_tmpl); unless (defined($dot_value_type) and length($dot_value_type) and ($dot_value_type eq 'ARRAY' or (ref($value_for_tmpl) and (ref($value_for_tmpl) !~ /^(CODE)|(HASH)|(SCALAR)$/) and $value_for_tmpl->isa('ARRAY')))) { (ref($param_map->{$dot_match}) eq 'HTML::Template::VAR') or croak("HTML::Template::param() : attempt to set parameter '$param' with a scalar - parameter is not a TMPL_VAR!"); ${$param_map->{$dot_match}} = $value_for_tmpl; } else { (ref($param_map->{$dot_match}) eq 'HTML::Template::LOOP') or croak("HTML::Template::param() : attempt to set parameter '$param' with an array ref - parameter is not a TMPL_LOOP!"); $param_map->{$dot_match}[HTML::Template::LOOP::PARAM_SET()] = $value_for_tmpl; } # Necessary for plugin system compatibility $self->{num_vars_left_in_loop} -= 1; $self->{param_map_done}{$param} = $value; # store the object for future reference } } # We still need to care about tmpl_loops that aren't dot matches so we can adjust their loops elsif (defined($value_type) and length($value_type) and ($value_type eq 'ARRAY' or ((ref($value) !~ /^(CODE)|(HASH)|(SCALAR)$/) and $value->isa('ARRAY')))) { (ref($param_map->{$param}) eq 'HTML::Template::LOOP') or croak("HTML::Template::param() : attempt to set parameter '$param' with an array ref - parameter is not a TMPL_LOOP!"); # TODO: Use constant names instead of "0" $self->{num_vars_left_in_loop} += keys %{ $param_map->{$param}[HTML::Template::LOOP::TEMPLATE_HASH()]{'0'}{'param_map'} } if exists $param_map->{$param}[HTML::Template::LOOP::TEMPLATE_HASH()]{'0'}; } else { (ref($param_map->{$param}) eq 'HTML::Template::VAR') or croak("HTML::Template::param() : attempt to set parameter '$param' with a scalar - parameter is not a TMPL_VAR!"); # intetionally /don't/ set the values for non-dot notation params, # and don't mark them as done, just that they exist. # but only if there actually are dot params in the template. if there aren't, # this property needs to stay undefined (to fix test 6 in t/RT40714-1.t). $self->{num_vars_left_in_loop} -= 1 if exists $self->{num_vars_left_in_loop}; } } } # Check to see if a param exists in the template, with support for dot notation # returns an an array # - bool for any matches # - array of keys with dot notation that matched. sub _exists_in_tmpl { my $self = shift; my ($param) = @_; my $param_map = $self->{param_map}; return 1 if exists $param_map->{$param}; return @{$self->{_seen_exists_in_tmpl}{$param}} if exists $self->{_seen_exists_in_tmpl} and exists $self->{_seen_exists_in_tmpl}{$param}; if (my @matching_dot_tokens = grep { /^$param\./ } keys %$param_map) { $self->{_seen_exists_in_tmpl}{$param} = [1, @matching_dot_tokens]; return @{$self->{_seen_exists_in_tmpl}{$param}}; } else { $self->{_seen_exists_in_tmpl}{$param} = []; return; } } # =head2 _param_to_tmpl() # # my $result = _param_to_tmpl($pluggable,$tmpl_token_name,$param_name,$param_value); # # Returns the right thing to put in the template given a token name, a param name # and a param value. Returns undef if this template token name and param name # don't match. # # The template token name supports the dot notation, which means that method # calls and nested hashes are expanded. # # However, first we check for a literal match, for backwards compatibility with # HTML::Template. # # =cut sub _param_to_tmpl { my ($self, $token_name, $param_name, $param_value, $input) = @_; # This clause may not be needed because the non-dot-notation # cases are handled elsewhere. if ($token_name eq $param_name) { return $param_value; } my ($one, $the_rest) = split /\./, $token_name, 2; length $the_rest or return undef; $one eq $param_name or return undef; my $loopmap_name = 'this'; # default for mapping array elements for loop vars $loopmap_name = $1 if $the_rest =~ s/\s*:\s*([_a-z]\w*)\s*$//; # Rhesa (Thu Aug 4 18:33:30 CEST 2005) # Patch for mixing method calls and attribute access mixing, # and optional parameter lists! # # First we're setting $ref to $param_value # # We're going to loop over $the_rest by finding anything that matches # - a valid identifier $id ( [_a-z]\w* ) # - optionally followed by something resembling an argument list $data # - optionally followed by a dot or $ # then we're checking if # - $ref is an object # - if we can call $id on it # - in this case we further parse the argument list for strings # or numbers or references to other h-t params # - or if it's an attribute # - or a hashref and we have no $data # We'll use the result of that operation for $ref as long as there are dots # followed by an identifier my $ref = $param_value; $self->{param_map_done}{$one} ||= $ref; my $want_loop = ref($self->{param_map}{$token_name}) eq 'HTML::Template::LOOP'; my(@results); # keeps return values from dot operations THE_REST: while ($the_rest =~ s/^ ([_a-z]\w*) # an identifier ($RE_balanced)? # optional param list (?:\.|$) # dot or end of string //xi ) { my ($id, $data) = ($1, $2); if (blessed($ref)) { if ($ref->can($id) or ($ref->can('AUTOLOAD') && !$ref->isa("Test::MockObject"))) { my @args = (); if ($data) { $data =~ s/^\(// and $data =~ s/\)$//; while ($data) { if ($data =~ s/ ^\s* ( $RE_delimited # a string | $RE_num_real # or a number ) (?:,\s*)? //xi ) { my $m = $1; $m =~ s/^["'`]//; $m =~ s/["'`]$//; push @args, $m; } elsif ($data =~ s/ ^\s* ( # ($1) a sub-expression of the form "object.method(args)" ([_a-z]\w*) # ($2) the object in question (?: \. [_a-z]\w* # method name $RE_balanced? # optional argument list )* ) (?:,\s*)? //xi ) { my ($m, $o) = ($1, $2); DEBUG and carp("found subexpression '$m' with '$o'"); DEBUG and carp Dumper($self->{param_map}), Dumper($self->{param_map_done}); if (exists($self->{param_map}{$m})) { my $prev = exists $input->{$m} ? $input->{$m} : $self->param($m); DEBUG and carp("found '$prev' for '$m' in param_map"); push @args, $prev; } elsif (exists($self->{param_map_done}{$o})) { my $prev = _param_to_tmpl($self, $m, $o, $self->{param_map_done}{$o}, $input); DEBUG and carp("found '$prev' for '$o' in param_map_done"); push @args, $prev; } elsif (exists($input->{$o})) { $self->{param_map}{$o} = HTML::Template::VAR->new(); my $prev = _param_to_tmpl($self, $m, $o, $input->{$o}, $input); DEBUG and carp("found '$prev' through recursion"); push @args, $prev; } else { croak("Attempt to reference nonexisting parameter '$m' in argument list to '$id' in dot expression '$token_name': $m is not a TMPL_VAR!"); } } else { last; } } croak("Bare word '$data' not allowed in argument list to '$id' in dot expression '$token_name'") if $data; } eval { if($the_rest or !$want_loop) { $one .= ".$id"; $ref = $ref->$id(@args); $self->{param_map_done}{$one} ||= $ref; } else { @results = $ref->$id(@args); } }; if($@) { if( $self->{options}{die_on_bad_params} ) { croak("Error invoking $ref->$id(@args): $@"); } else { carp("Error invoking $ref->$id(@args): $@"); @results = (); $ref = $self->{param_map_done}{$one} = ''; $the_rest = ''; last THE_REST; } } } elsif(reftype($ref) eq 'HASH') { croak("Can't access hash key '$id' with a parameter list! ($data)") if $data; if($the_rest or !$want_loop) { $ref = exists( $ref->{$id} ) ? $ref->{$id} : undef; } else { @results = exists( $ref->{$id} ) ? $ref->{$id} : (); } } else { croak("Don't know what to do with reference '$ref', identifier '$id' and data '$data', giving up."); } } elsif(ref($ref) eq 'HASH') { if($the_rest or !$want_loop) { $ref = exists( $ref->{$id} ) ? $ref->{$id} : undef; } else { @results = exists( $ref->{$id} ) ? $ref->{$id} : (); } } } if(!$the_rest and $want_loop) { $ref = ($#results==0 and ref($results[0]) eq 'ARRAY') ? $results[0] : \@results; } croak("Trailing characters '$the_rest' in dot expression '$token_name'") if $the_rest; if($want_loop) { # fixup the array to a conformant data structure my @arr = (reftype($ref) eq 'ARRAY') ? @$ref : ($ref); return [ map { {$loopmap_name => $_} } @arr ]; } else { $ref = scalar(@$ref) if ref($ref) eq 'ARRAY'; return $ref; } } 1; __END__ =head1 NAME HTML::Template::Plugin::Dot - Add Magic Dot notation to HTML::Template =head1 SYNOPSIS use HTML::Template::Pluggable; use HTML::Template::Plugin::Dot; my $t = HTML::Template::Pluggable->new(...); Now you can use chained accessor calls and nested hashrefs as params, and access them with a dot notation. You can even pass arguments to the methods. For example, in your code: $t->param( my_complex_struct => $struct ); And then in your template you can reference specific values in the structure: my_complex_struct.key.obj.accessor('hash') my_complex_struct.other_key =head1 DESCRIPTION By adding support for this dot notation to L, the programmers' job of sending data to the template is easier, and designers have easier access to more data to display in the template, without learning any more tag syntax. =head2 EXAMPLES =head2 Class::DBI integration L accessors can be used in the template. If the accessor is never called in the template, that data doesn't have to be loaded. In the code: $t->param ( my_row => $class_dbi_obj ); In the template: my_row.last_name This extends to related objects or inflated columns (commonly used for date fields). Here's an example with a date column that's inflated into a DateTime object: my_row.my_date.mdy('/') my_row.my_date.strftime('%D') Of course, if date formatting strings look scary to the designer, you can keep them in the application, or even a database layer to insure consistency in all presentations. (Note: for the latter example to work correctly, you should set the option "case_sensitive" to a true value.) Here's an example with related objects. Suppose you have a Customer object, that has_a BillingAddress object attached to it. Then you could say something like this: ... =head2 More complex uses The dot notation allows you to pass arguments to method calls (as in the C example above). In fact, you can pass other objects in the template as well, and this enables more complex usage. Imagine we had a (fictional) Formatter object which could perform some basic string formatting functions. This could be used in e.g. currencies, or dates. In your code: $t->param( Formatter => Formatter->new, order => $order_obj ); In your template: Amount: (hint: see L) This even extends to references to plain tmpl_vars in your template: $t->param( Formatter => Formatter->new, plain => 'Jane' ); is backwards Note: for "nested" parameters to work correctly, you should supply both params at the same time: # for this template snippet, # this works $t->param( o1 => $o1, o2 => $o2); # but this doesn't $t->param( o1 => $o1 ); $t->param( o2 => $o2 ); # and neither would swapping the two lines. # if your template has another, separate reference to the inner param, # then it works, provided you specify o2 before o1 $t->param( o2 => $o2 ); $t->param( o1 => $o1 ); =head2 TMPL_LOOPs As of version 0.94, the dot notation is also supported on TMPL_LOOP tags (but see the L section). Given an object method (or a hash key) that returns an array or a reference to an array, we will unwrap that array for use in the loop. Individual array elements are mapped to a hash C<< { 'this' => $elt } >>, so that you can refer to them in TMPL_VARs as "this.something". An example might help. Let's use the canonical Class::DBI example for our data. Suppose you have an $artist object, which has_many CDs. You can now pass just the $artist object, and handle the loops in the template: $t->param( artist => $artist ); The template: has released these albums: - As you can see, each element from the artist.cds() array is called "this" by default. You can supply your own name by appending ': name' like this: ... That's not the end of it! You can even nest these loops, displaying the Tracks for each CD like so: - ( ) =head2 LIMITATIONS =over 4 =item * Casing of parameter names Casing of parameter names follows the option C of HTML::Template. If you do not use that option, all parameter names are converted to lower case. I suggest turning this option on to avoid confusion. =item * Quotes and spaces Because of the way HTML::Template parses parameter names (which follows the rules of HTML attributes), you have to be careful when your expressions contain spaces or quote characters. You can say C<< >>, but not C<< >>. You can use single or double quotes around your entire expression, and then use the other one inside: C<< >> This is the recommended way to write your expressions. (Note: within expressions, the characters in C<< [`'"] >> are recognised as quote characters. So if you need to pass literal quotes to a method, you could do it like this: C<< >>. ) =back =head2 PERFORMANCE No attempt to even measure performance has been made. For now the focus is on usability and stability. If you carry out benchmarks, or have suggestions for performance improvements, be sure to let us know! =head1 CONTRIBUTING Patches, questions and feedback are welcome. This project is managed using the darcs source control system ( http://www.darcs.net/ ). A public darcs archive is here: http://cgiapp.erlbaum.net/darcs_hive/ht-pluggable/ =head1 AUTHORS Mark Stosberg, Emark@summersault.comE; Rhesa Rozendaal, Erhesa@cpan.orgE =head1 Copyright & License Parts copyright 2006 Mark Stosberg Parts copyright 2006 Rhesa Rozendaal This program is free software; you can redistribute it and/or modify it under the same terms as perl itself. =cut HTML-Template-Pluggable-0.22/t000755001750001750 014236676171 15521 5ustar00rhesarhesa000000000000HTML-Template-Pluggable-0.22/t/RT40714-1.t000444001750001750 311114236676171 17122 0ustar00rhesarhesa000000000000use Test::More tests => 7; use HTML::Template::Pluggable; use HTML::Template::Plugin::Dot; use Carp 'croak'; sub render { my( $template, @vars ) = @_; my $t = HTML::Template::Pluggable->new( scalarref => \$template ); eval { $t->param( @vars ) }; return $t->output; } my $out; $out = render( "", testobj => testclass->new() ); is( $out, 'attribute_value' ); $out = render( "", testobj => testclass->new() ); is( $out, 'hello' ); $out = render( "", testobj => testclass->new() ); is( $out, '1' ); $out = render( "", testobj => testclass->new(), somevar => 'somevalue4' ); is( $out, 'somevalue4' ); $out = render( "", testobj => testclass->new(), somevar => 'somevalue5' ); # contribution expected 'somevalue5', but since test() isn't # a method of testclass, this should return nothing. is( $out, '' ); $out = render( "", testobj => testclass->new(), somevar => 'somevalue' ); is( $out, 'somevaluesomevalue' ); $out = render( "", somevar => 'somevalue6', testobj => testclass->new(), nope => 42, ); is( $out, 'somevalue6' ); package testclass; sub new { my $class = shift; my $self = { attribute => 'attribute_value' }; return bless $self, $class; } sub echo { shift; return join(', ', @_); } sub hello { return 'hello'; } __END__ HTML-Template-Pluggable-0.22/t/RT40714-2.t000444001750001750 213614236676171 17131 0ustar00rhesarhesa000000000000use Test::More; use HTML::Template::Pluggable; use HTML::Template::Plugin::Dot; eval "use Number::Format;"; plan skip_all => 'Number::Format required for these tests' if $@; plan tests => 3; sub render { my( $template, %vars ) = @_; my $result; eval { my $t = new HTML::Template::Pluggable( scalarref => \$template, case_sensitive => 1, ); $t->param( %vars ); $result = $t->output; }; diag $@ if $@; return $result; } my $out; $out = render( "Amount: ", order => { total_amount => 12.2 } ); is( $out, 'Amount: 12.2', 'Substitute value from hashref' ); my $formatter = new Number::Format; ok( $formatter && $formatter->isa('Number::Format'), 'Instantiate Number::Format' ); $out = render( q{Amount: }, Formatter => $formatter, order => { total_amount => 12.2 } ); is( $out, 'Amount: ' . $formatter->format_price(12.20, 2, 'USD ') ); __END__ 1..0 # SKIP Number::Format required for these tests HTML-Template-Pluggable-0.22/t/RT49123.t000444001750001750 132114236676171 16770 0ustar00rhesarhesa000000000000 use strict; use warnings; use Test::More 'no_plan'; use HTML::Template::Pluggable; use HTML::Template::Plugin::Dot; { package My::Auto; sub new { bless {}, shift } sub foo { "foo" } sub AUTOLOAD { "bar" } } sub render { my ($str, @params) = @_; my $t = HTML::Template::Pluggable->new( scalarref => \$str, die_on_bad_params => 0 ); $t->param( @params ); return $t->output; } my $obj = My::Auto->new; my $x = render(q{}, auto => $obj); is $x, 'foo', 'can("foo")'; is $obj->quux, "bar", "object can autoload"; my $y = render(q{}, auto => $obj); is $y, 'bar', 'can("AUTOLOAD")'; __END__ ok 1 - can("foo") ok 2 - can("AUTOLOAD") 1..2 HTML-Template-Pluggable-0.22/t/before_output.t000444001750001750 121214236676171 20721 0ustar00rhesarhesa000000000000use Test::More; use Data::Dumper; use strict; plan tests => 1 # use_ok + 2 # my tests ; use_ok('HTML::Template::Pluggable'); { my $t = HTML::Template::Pluggable->new( scalarref => \q{nothing}, debug => 0, ); $t->add_trigger('before_output', sub { diag("trigger called with @_") if $_[0]->{options}->{debug} } ); ok($t->output eq 'nothing'); } { my $t = HTML::Template::Pluggable->new( scalarref => \q{}, debug => 0, ); $t->add_trigger('before_output', sub { my $self = shift; $self->param('before_output' => 'before output'); } ); ok($t->output eq 'before output'); } __END__ HTML-Template-Pluggable-0.22/t/dot_can.t000444001750001750 256314236676171 17460 0ustar00rhesarhesa000000000000# use Carp qw(verbose); use Test::More qw/ no_plan /; SKIP: { # tests the new object test supplied by Dan Horne (RT #18129) # specifically with CGI. # Note that CGI.pm prior to version 3.06 does not have a sane # can() method, so we skip this test if your version is older. require CGI; skip "Your CGI.pm ($CGI::VERSION) does not have a sane can() method. Upgrade to at least 3.06 if you want to run this test." if $CGI::VERSION lt '3.06'; BEGIN { $ENV{QUERY_STRING} = 'foo=bar'; $ENV{HTTP_HOST} = 'hiero'; $ENV{CGI_APP_RETURN_ONLY} = 1; } my $t = T2->new; $t->start_mode('foo'); my $out = $t->run; like ($out, qr/Start Mode: foo/); package T2; use warnings; use HTML::Template::Pluggable; use HTML::Template::Plugin::Dot; sub new { bless {}, +shift; } sub run { my $self = shift; my $m = $self->{start_mode}; $self->$m(); } sub start_mode { my $self = shift; $self->{start_mode} = shift if @_; $self->{start_mode} } sub query { my $self = shift; $self->{cgi} ||= CGI->new; $self->{cgi}; } sub foo { my $self = shift; my $t = HTML::Template::Pluggable->new(scalarref => \q{ Start Mode: }); $t->param(c => $self); return $t->output; } } __END__ HTML-Template-Pluggable-0.22/t/dot_for_loops.t000444001750001750 1202614236676171 20734 0ustar00rhesarhesa000000000000use Test::More; use Test::MockObject; use Data::Dumper; use lib 'lib'; use strict; my $tests = 14; plan tests => 3 # use_ok + $tests # my tests ; use_ok('HTML::Template::Pluggable'); use_ok('HTML::Template::Plugin::Dot'); use_ok('Test::MockObject'); my $mock = Test::MockObject->new(); $mock->mock( 'name', sub { 'mock' } ); $mock->mock( 'that_returns_loopdata', sub { my ($self, $count) = @_; $count ||= 5; return $self->ar($count); } ); $mock->mock( 'ar', sub { my ($self, $count) = @_; my @ret = (); for( 1.. $count) { push @ret, { a => $_, b => $_*10, }; } return @ret; } ); $mock->mock( 'arrayref', sub { my ($self, $count) = @_; $count ||= 5; return [ $self->ar($count) ]; } ); $mock->mock( empty_Loop => sub { return [] } ); $mock->mock( 'nested', sub { my ($self, $count) = @_; $count ||= 2; my @ret; for (1..$count) { push @ret, { a => $_, b => [ map { { c=>$_*3 } } (1..$_) ], }; } return @ret; } ); my $hashref = { loop => $mock->arrayref }; my ($tag, $out); $tag = q{ : , . }; $out = get_output($tag, $mock); SKIP: { skip "HTML::Template subclassing bug for tmpl_loop support. See: http://rt.cpan.org/NoAuth/Bug.html?id=14037", $tests if $@; like($out, qr/1, 10/, 'Wrapped loops work with implicit "this" mapping'); $tag = q{ , . }; $out = get_output($tag, $mock); like($out, qr/1, 10/, 'Wrapped loops work with explicit "that" mapping'); $tag = q{ , . }; $out = get_output($tag, $mock); like($out, qr/1, 10/, 'Wrapped loops work with arrayrefs'); $tag = q{ no , . data }; $out = get_output($tag, $mock); like($out, qr/no\s+data/, 'Wrapped loops work with no data'); $tag = q{ no , . data }; $out = get_output($tag, $mock, 'non_object.empty_loop' => []); like($out, qr/no\s+data/, 'Wrapped loops work with no object and no data'); $tag = q{ , (). }; $out = get_output($tag, $mock); like($out, qr/\Q3, (3)(6)(9)./, 'Wrapped nested loops work with arrayrefs'); $tag = q{ , (). }; $out = get_output($tag, $mock); like($out, qr/\Q3, (3)(6)(9)./, 'Wrapped nested loops work with arrayrefs and explicit "inner" mapping'); $tag = q{ , (). }; $out = get_output($tag, $mock); like($out, qr/\Q1, (3)./, 'Wrapped nested loops work with arrayrefs and implicit mapping everywhere (single return value)'); $tag = q{ , (). }; $out = get_output($tag, $mock); like($out, qr/\Q3, (3)(6)(9)./, 'Wrapped nested loops work with arrayrefs and implicit mapping everywhere'); $tag = q{ , . }; $out = get_output($tag, $hashref); like($out, qr/\Q3, 30./, 'simple hashref with an arrayref'); $tag = q{ , . }; $out = get_output($tag, $hashref); like($out, qr/\Q3, 30./, 'simple hashref with an arrayref, which is tested in a tmpl_if'); $tag = q{ :: , . }; $out = get_output($tag, $hashref); like($out, qr/\Q3, 30./, 'simple hashref with an arrayref, which is used as a var'); $hashref={loop=>[]}; $tag = q{ , . }; $out = get_output($tag, $hashref); like($out, qr/^ $/, 'simple hashref with an emtpy arrayref'); $hashref={loop=>[]}; $tag = q{ , . }; $out = get_output($tag, $hashref); like($out, qr/^ $/, 'simple hashref with an emtpy arrayref, used in a tmpl_if'); } sub get_output { my ($tag, @data) = @_; my ( $output ); # diag(""); my $t = HTML::Template::Pluggable->new( scalarref => \$tag, global_vars => 0, debug => 0, die_on_bad_params => 1, ); eval { $t->param( object => @data ); $output = $t->output; }; #diag("template tag is $tag"); #diag("output is $output"); #diag("exception is $@") if $@; return $output; } # vi: filetype=perl __END__ HTML-Template-Pluggable-0.22/t/dot_loop.t000444001750001750 210114236676171 17654 0ustar00rhesarhesa000000000000use Test::More qw(no_plan); use strict; use_ok('HTML::Template::Pluggable'); use_ok('HTML::Template::Plugin::Dot'); use_ok('Test::MockObject'); my $mock = Test::MockObject->new(); $mock->mock( 'some', sub { $mock } ); $mock->mock( 'method', sub { "chained methods work inside tmpl_loop" } ); my $mock2 = Test::MockObject->new(); $mock2->mock( 'some', sub { $mock2 } ); $mock2->mock( 'method', sub { "chained methods work inside a loop twice" } ); my ($output, $template, $result); $template = qq{}; # test a simple template my $t = HTML::Template::Pluggable->new( scalarref => \$template, debug => 0 ); eval { $t->param('deloop',[ {should_be => $mock, num => 1}, {should_be => $mock2, num => 2} ]); $output = $t->output; }; SKIP: { skip "HTML::Template subclassing bug for tmpl_loop support. See: http://rt.cpan.org/NoAuth/Bug.html?id=14037", 2 if $@; like($output ,qr/chained methods work inside tmpl_loop/); like($output ,qr/chained methods work inside a loop twice/); } __END__ HTML-Template-Pluggable-0.22/t/dot_nested.t000444001750001750 147614236676171 20203 0ustar00rhesarhesa000000000000# use Carp qw(verbose); use Test::More qw/ no_plan /; { # submitted by Dan Horne package T1; use strict; sub name { my $self = shift; $self->{name} ||= shift; return $self->{name}; } sub greeting { my $self = shift; my $name = shift; return "hello $name"; } sub new { my $class = shift; bless {}, $class; } 1; } use HTML::Template::Pluggable; use HTML::Template::Plugin::Dot; my $text = ''; my $test = T1->new(); $test->name('bob'); is "hello bob", $test->greeting('bob'); eval { my $template = HTML::Template::Pluggable->new(scalarref => \$text); $template->param('t' => $test); my $out = $template->output; is($out, T1->greeting("bob")); } or warn $@; __END__ HTML-Template-Pluggable-0.22/t/dot_notation.t000444001750001750 232014236676171 20541 0ustar00rhesarhesa000000000000use strict; use Test::More tests => 8; use Test::MockObject; use strict; use_ok('HTML::Template::Pluggable'); use_ok('HTML::Template::Plugin::Dot'); use_ok('Test::MockObject'); my $mock = Test::MockObject->new(); $mock->mock( 'some', sub { $mock } ); $mock->mock( 'method', sub { "chained methods work" } ); my ($output, $template, $result); # test a simple template my $t = HTML::Template::Pluggable->new( scalarref => \ qq{ tmpl_ifs work \n}, debug => 0 ); $t->param('wants.to_be.literal', "Literals tokens with dots work"); $t->param('desires', { to_be => { hashref => "nested hashrefs work" } }); $t->param('should_be',$mock); $output = $t->output; like($output ,qr/Literals tokens with dots work/); like($output ,qr/nested hashrefs work/); like($output ,qr/chained methods work/); like($output ,qr/chained methods work.*chained methods work/, "using a dot var more than once works" ); like($output ,qr/tmpl_ifs work/); # vi: filetype=perl __END__ HTML-Template-Pluggable-0.22/t/dot_notation_methods_with_args.t000444001750001750 503514236676171 24341 0ustar00rhesarhesa000000000000use Test::More; use Test::MockObject; use strict; # setup tags to test. # the tag name is "should_be.some.method" . $key, # the expected outcome is the value. # this list should pass my @passing = ( [ q/should_be.some.method/, q/args/, ], [ q/should_be.some.method()/, q/args/, ], [ q/should_be.some.method('with_param')/, q/>with_param1< >2< >3-1.3E+09with.parens()with `quotes`/, ], [ q/should_be.some.method('with `quotes` and ( parens ) and {braces} ')/,q/braces} /, ], [ q/should_be.some.method('something with brackets[1,2,3]')/, q/>something with brackets[1,2,3] 3 # use_ok + scalar(@passing) # tests that should pass + scalar(@failing) # tests that should fail ; use_ok('HTML::Template::Pluggable'); use_ok('HTML::Template::Plugin::Dot'); use_ok('Test::MockObject'); my $mock = Test::MockObject->new(); $mock->mock( 'some', sub { $mock } ); $mock->mock( 'method', sub { shift; # skip object join " ", "args =", map { ">$_<" } @_; } ); foreach my $test ( @passing) { my ($pat, $out) = @$test; my $tag = qq{ }; my ( $output, $template, $result ); my $t = HTML::Template::Pluggable->new( scalarref => \$tag, debug => 0 ); $t->param( should_be => $mock ); $output = $t->output; # diag("template tag is $tag"); # diag("output is $output"); like( $output, qr/\Q$out/i, $pat); } foreach my $test ( @failing) { my ($pat, $out) = @$test; my $tag = qq{ }; my ( $output, $template, $result ); my $t = HTML::Template::Pluggable->new( scalarref => \$tag, debug => 0 ); eval { $t->param( should_be => $mock ); $output = $t->output; }; # diag("template tag is $tag"); # diag("output is $output"); # diag("exception is $@") if $@; like( $@, qr/\Q$out/, $pat); } # vi: filetype=perl __END__ HTML-Template-Pluggable-0.22/t/dot_notation_mixnmatch.t000444001750001750 504514236676171 22620 0ustar00rhesarhesa000000000000use Test::More; use Test::MockObject; use strict; ### Tests mixing method calls and hashkey access. ### ### The objective is to be able to say: ### object.method.hashkey ### or ### hashref.object.method ### ### Wilder patterns should work too. # setup tags to test. # the template var name is $key, # the expected outcome is the $value. my %pats = map { split /\s+=>\s+/ } split $/, < plain hash ref chain hash.obj => Test::MockObject hash.obj.property => direct object property hash.obj.accessor => default accessor value hash.obj.accessor('public') => public object property hash.key.obj.accessor('hash').key.deep => deep hash ref via obj accessor via hash ref obj.property => direct object property obj.accessor => default accessor value obj.accessor('public') => public object property obj.accessor('hash').key.objaccess => hash ref via obj accessor obj._private => private method PATS plan tests => 3 # use_ok + scalar(keys %pats) # method patterns ; use_ok('HTML::Template::Pluggable'); use_ok('HTML::Template::Plugin::Dot'); use_ok('Test::MockObject'); ## setup data structures my $obj = Test::MockObject->new(); my $hash = {}; ### fill them with something useful $hash->{key} = {}; $hash->{obj} = $obj; $hash->{key}->{string} = 'plain hash ref chain'; $hash->{key}->{objaccess} = 'hash ref via obj accessor'; $hash->{key}->{deep} = 'deep hash ref via obj accessor via hash ref'; $hash->{key}->{obj} = $obj; $obj->{ 'property' } = 'direct object property'; $obj->{ 'public' } = 'public object property'; $obj->{ 'hash' } = $hash; $obj->mock('accessor', sub { my ($self, $attr) = @_; return "default accessor value" unless $attr; return $self->{property} if $attr eq 'property'; return $self->{public} if $attr eq 'public'; return $self->{hash} if $attr eq 'hash'; } ); $obj->mock('_private', sub { "private method" }); # dump structures # use Data::Dumper; # diag("hash looks like ", Dumper($hash)); # diag("obj looks like ", Dumper($obj)); my ( $output, $template, $result ); foreach my $pat(sort keys %pats) { my $out = $pats{$pat}; my $tag = qq{ }; # diag("template tag is $tag"); my $t = HTML::Template::Pluggable->new( scalarref => \$tag, debug => 0 ); $t->param( obj => $obj ) if $pat =~ /^obj/; $t->param( hash => $hash ) if $pat =~ /^hash/; $output = $t->output; # diag("output is $output"); like( $output, qr/\Q$out/, $pat); } # vi: filetype=perl __END__ HTML-Template-Pluggable-0.22/t/dot_notation_recursive.t000444001750001750 331614236676171 22636 0ustar00rhesarhesa000000000000use Test::More; use Test::MockObject; use strict; my @tests = ( [q/Formatter.sprintf('%.2f', mock.value)/, q/ 3.20 / ], [q/Formatter.sprintf('%.2f', mock.nested(3.1459).key)/, q/ 3.15 / ], [q/Formatter.sprintf('%20s', mock.nested(bareword, 'literal1', non.bareword).key)/, q/ bare value := / ], [q/Formatter.sprintf('%20s %4s %7s', bareword, 'literal1', non.bareword)/, q/ bare value := / ], # [q/mock.nested(Formatter.sprintf('%.3f', 3.14159)).key/, q/ 3.142 / ], ### eeewww. other way around obviously doesn't work, as it needs the param setting reversed. ); plan tests => 3 # use_ok + scalar(@tests) # recursion tests ; use_ok('HTML::Template::Pluggable'); use_ok('HTML::Template::Plugin::Dot'); use_ok('Test::MockObject'); my $formatter = Test::MockObject->new(); $formatter->mock( 'sprintf' , sub { shift; sprintf(shift(), @_) } ); my $mock = Test::MockObject->new(); $mock->mock( 'name', sub { 'Mock' } ); $mock->mock( 'value', sub { '3.196002' } ); $mock->mock( 'nested', sub { $mock->{key} = $_[1]; $mock } ); foreach my $test(@tests) { my ($pat, $out) = @$test; my ( $output, $template, $result ); my $tag = qq{ := }; # my $t = HTML::Template::Pluggable->new( scalarref => \$tag, debug => 0 ); # diag("template tag is $tag"); $t->param( bareword => 'bare value' ); $t->param('non.bareword' => 'non bare value' ); $t->param( mock => $mock ); $t->param( Formatter => $formatter ); $output = $t->output; like( $output, qr/$out/, $pat); # diag("output is $output"); # diag("mock is ", $t->param('mock')); } # vi: filetype=perl __END__ HTML-Template-Pluggable-0.22/t/pod-coverage.t000444001750001750 25414236676171 20377 0ustar00rhesarhesa000000000000#!perl -T use Test::More; eval "use Test::Pod::Coverage 1.04"; plan skip_all => "Test::Pod::Coverage 1.04 required for testing POD coverage" if $@; all_pod_coverage_ok(); HTML-Template-Pluggable-0.22/t/pod.t000444001750001750 21414236676171 16602 0ustar00rhesarhesa000000000000#!perl -T use Test::More; eval "use Test::Pod 1.14"; plan skip_all => "Test::Pod 1.14 required for testing POD" if $@; all_pod_files_ok(); HTML-Template-Pluggable-0.22/t/side_effects.t000444001750001750 517714236676171 20500 0ustar00rhesarhesa000000000000use Test::More; use Test::MockObject; use strict; plan tests => 3 # use_ok + 12 # hash keys, dying methods ; use_ok 'HTML::Template::Pluggable'; use_ok 'HTML::Template::Plugin::Dot'; use_ok 'Test::MockObject'; my $mock = Test::MockObject->new(); $mock->mock( 'method_that_dies' => sub { die "horribly..." } ); $mock->mock( 'nested' => sub { $_[0] } ); # methods that die { my $ex = get_output( '', $mock, { die_on_bad_params => 1 }, ); like $@, qr/horribly... at /, "method calls die loudly with die_on_bad_params off"; unlike $ex, qr/0x/, "exception doesn't leave a stringified object behind"; } { my $ex = get_output( '', $mock, { die_on_bad_params => 1 }, ); like $@, qr/horribly... at /, "nested method calls die loudly with die_on_bad_params off"; unlike $ex, qr/0x/, "exception doesn't leave a stringified object behind"; } { my $warning; local $SIG{__WARN__} = sub { $warning = shift; }; my $ex = get_output( '', $mock, { die_on_bad_params => 0 }, ); is $@, '', "method calls fail silently with die_on_bad_params off"; is $ex, '', "exception doesn't leave a stringified object behind"; like $warning, qr/horribly/, 'but emits a warning'; $ex = get_output( '', $mock, { die_on_bad_params => 0 }, ); is $@, '', "nested method calls fail silently with die_on_bad_params off"; is $ex, '', "exception doesn't leave a stringified object behind"; like $warning, qr/horribly/, 'but emits a warning'; } # accessing non-existent hash keys my %in = ( a => 1, b => 2 ); get_output( '', \%in, ); is_deeply(\%in, { a=>1, b=>2 }, 'No side effects on hashes'); # accessing non-existent object properties $mock->{old_key} = 'old value'; get_output( '', $mock, ); ok(!exists($mock->{new_key}), 'No side effects on object properties'); sub get_output { my ($tag, $data, $params) = @_; my $output = ''; my $t = HTML::Template::Pluggable->new( scalarref => \$tag, debug => 0, %$params, ); eval { $t->param( object => $data ); $output = $t->output; }; # diag("template tag is $tag"); # diag("output is $output"); # diag("exception is $@") if $@; return $output; } # vi: filetype=perl __END__