From 1a48ee7ffa0db08c3c5af68b365ee274acbd485d Mon Sep 17 00:00:00 2001 From: Don Armstrong Date: Thu, 20 Jan 2011 00:32:01 +0000 Subject: [PATCH] [svn-upgrade] Tagging libhtml-calendarmonth-perl (1.25) --- 1.25/Changes | 141 ++ 1.25/LICENSE | 377 +++++ 1.25/MANIFEST | 36 + 1.25/MANIFEST.SKIP | 4 + 1.25/META.json | 48 + 1.25/Makefile.PL | 65 + 1.25/README | 71 + 1.25/dist.ini | 34 + 1.25/lib/HTML/CalendarMonth.pm | 1407 +++++++++++++++++ 1.25/lib/HTML/CalendarMonth/DateTool.pm | 478 ++++++ 1.25/lib/HTML/CalendarMonth/DateTool/Cal.pm | 37 + .../HTML/CalendarMonth/DateTool/DateCalc.pm | 68 + .../HTML/CalendarMonth/DateTool/DateManip.pm | 73 + .../HTML/CalendarMonth/DateTool/DateTime.pm | 85 + 1.25/lib/HTML/CalendarMonth/DateTool/Ncal.pm | 126 ++ .../HTML/CalendarMonth/DateTool/TimeLocal.pm | 39 + 1.25/lib/HTML/CalendarMonth/Locale.pm | 441 ++++++ 1.25/t/00_basic.t | 6 + 1.25/t/01_autodetect.t | 24 + 1.25/t/02_timelocal.t | 23 + 1.25/t/03_datetime.t | 24 + 1.25/t/04_datemanip.t | 24 + 1.25/t/05_datecalc.t | 24 + 1.25/t/06_cal.t | 26 + 1.25/t/07_ncal.t | 27 + 1.25/t/20_i8n.t | 18 + 1.25/t/21_narrow.t | 16 + 1.25/t/author-critic.t | 19 + 1.25/t/dat/bulk.dat | 288 ++++ 1.25/t/dat/i8n.dat | 14 + 1.25/t/dat/narrow.dat | 12 + 1.25/t/dat/odd.dat | 16 + 1.25/t/dat/woy.dat | 4 + 1.25/t/release-pod-coverage.t | 21 + 1.25/t/release-pod-syntax.t | 15 + 1.25/t/testload.pm | 239 +++ 36 files changed, 4370 insertions(+) create mode 100644 1.25/Changes create mode 100644 1.25/LICENSE create mode 100644 1.25/MANIFEST create mode 100644 1.25/MANIFEST.SKIP create mode 100644 1.25/META.json create mode 100644 1.25/Makefile.PL create mode 100644 1.25/README create mode 100644 1.25/dist.ini create mode 100644 1.25/lib/HTML/CalendarMonth.pm create mode 100644 1.25/lib/HTML/CalendarMonth/DateTool.pm create mode 100644 1.25/lib/HTML/CalendarMonth/DateTool/Cal.pm create mode 100644 1.25/lib/HTML/CalendarMonth/DateTool/DateCalc.pm create mode 100644 1.25/lib/HTML/CalendarMonth/DateTool/DateManip.pm create mode 100644 1.25/lib/HTML/CalendarMonth/DateTool/DateTime.pm create mode 100644 1.25/lib/HTML/CalendarMonth/DateTool/Ncal.pm create mode 100644 1.25/lib/HTML/CalendarMonth/DateTool/TimeLocal.pm create mode 100644 1.25/lib/HTML/CalendarMonth/Locale.pm create mode 100755 1.25/t/00_basic.t create mode 100755 1.25/t/01_autodetect.t create mode 100755 1.25/t/02_timelocal.t create mode 100755 1.25/t/03_datetime.t create mode 100755 1.25/t/04_datemanip.t create mode 100755 1.25/t/05_datecalc.t create mode 100755 1.25/t/06_cal.t create mode 100644 1.25/t/07_ncal.t create mode 100755 1.25/t/20_i8n.t create mode 100644 1.25/t/21_narrow.t create mode 100644 1.25/t/author-critic.t create mode 100644 1.25/t/dat/bulk.dat create mode 100644 1.25/t/dat/i8n.dat create mode 100644 1.25/t/dat/narrow.dat create mode 100644 1.25/t/dat/odd.dat create mode 100644 1.25/t/dat/woy.dat create mode 100644 1.25/t/release-pod-coverage.t create mode 100644 1.25/t/release-pod-syntax.t create mode 100644 1.25/t/testload.pm diff --git a/1.25/Changes b/1.25/Changes new file mode 100644 index 0000000..6d946d9 --- /dev/null +++ b/1.25/Changes @@ -0,0 +1,141 @@ +Revision history for HTML-CalendarMonth + +1.25 Fri Sep 24 03:09:38 EDT 2010 + - Switched to File::Which for finding cal/ncal + - Added some sanity checks for the cal/ncal output + +1.23 Sat Jun 12 21:12:45 EDT 2010 + - Updated interface with DateTime::Locale (will eventually + require another update when Locale::CLDR is released + - Deprecated offsets; too much complexity for little gain + - Fixed week-of-year bug in end-of-year edge cases (first + week has higher number than the next) RT #53795 + - Made row globbing optimize on row elements if possible + - Updated default HTML style to be more CSS friendly (inspired + by RT #37548) + - Added option for semantic CSS classes on cells (past, present, + future) ala RT #37549 + - Updated test data + - Improved date tool auto detect + - Fixed Date::Manip parse error for negative day deltas + - Doc updates + - Test updates + - Added linux 'ncal' harness + +1.19 Sat Mar 15 00:47:26 EDT 2008 + - Fixed longstanding test failure due to HTML::Tree (properly) + deciding to put quotes around numeric attributes in tags. + - Also changed i8n test to Zulu rather than Basque since the + DateTime::Local::eu (Basque) module no longer has + abbreviated day names + - Some of the DateTool modules had a minor bug in add_days() not + checking for defined vs 0 + - I released a calendar-related module update on the Ides of + March. I'm just sayin'. + +1.18 Fri Feb 24 15:53:41 EST 2006 + - Fixed some scoping issues in DateTool/DateCalc.pm (thanks + Carl Franks) + - Fixed a Win32 test module location issue (File::Spec tricks) + (thanks Carl Franks) + +1.17 Fri Jan 6 16:09:46 EST 2006 + - Updated tests with more recent test cases + +1.16 Fri Oct 21 16:23:48 EDT 2005 + - Polished tests + - Fixed a Date::Calc testing procedure + +1.15 Fri Apr 1 12:43:09 EST 2005 + - Split out tests + - Version roll hopefully ironed out some cpan tester + dependency issues + +1.14 Mon Mar 28 15:32:54 EST 2005 + - forced dependency on HTML::ElementTable 1.13 or greater + - minor brush ups + +1.13 Mon Feb 28 16:02:31 EST 2005 + - Streamlined accessor/mutator logic. Uses Class::Accessor now. + - Fixed a week of year bug introduced in the recent changes. + - General cleanup + - Added more tests (including one i8n test) + +1.12 Mon Feb 28 00:31:16 EST 2005 + - Fixed auto-select bug that slipped through tests. :( + - Fixed tests. + +1.11 Sun Feb 27 23:58:04 EST 2005 + - No reason to reinvent the wheel. Language support has now been + entirely replaced with full locale support as provided by + DateTime::Locale (does not require installation of entire + DateTime suite, if that's an issue) + - Calendrical calculations have now been fully abstracted out to + a back end interface. Calendars can be generated given the + presence of any one of the following and subject to the + circumstances of the request: + + * native Time::Local (but limited to dates between 1970 and + 2038) + * Date::Calc + * DateTime + * Date::Manip + * unix 'cal' command + +1.10 Sat Feb 26 00:47:37 EST 2005 + - Added more robust language support. Currently supports en, + de, and fr. + +1.09 Tue Mar 26 05:21:59 CST 2002 + - Fixed obscure bug that caused March 31 2002 + to be dropped; related to a localtime/gmtime + issue with DST effects. + - Added tests for calendars over 1-year span + plus special cases such as the aforementioned + March 31 2002 instance. + +1.08 Mon Jan 8 19:15:16 CST 2001 + - Added Date::Manip fallback from Date::Calc, + so a C compiler is not strictly necessary + for folks wanting week-of-year numbering + or exotic dates. + +1.07 Wed Nov 8 01:42:40 CST 2000 + - Day-of-week bug REALLY fixed. Should now work + properly with all perumutations of calendar + pecularities and concepts of what the first + day of the week should be. + +1.06 Wed Oct 4 13:37:31 CDT 2000 + - Day-of-week bug fixed for cases where Sunday is + the first day of the month (such as Oct, 2000), + or last day of the month (such as Dec, 2000), + over various configurations of what is considered + the first day of the week. + +1.04 Sun Sep 17 12:13:40 CDT 2000 + - Documentation tweaks and corrections. + +1.03 Wed Apr 26 12:06:23 CDT 2000 + - Added HTML::ElementTable dependency check in Makefile.PL + - Various bug fixes, under less common circumstances. + - Code syntax tweaks. + +1.02 Tue Jan 25 20:05:05 CST 2000 + - Cleaned up -w noise + - Added mailing list information + +1.01 Thu Sep 16 15:33:41 CDT 1999 + - Distribution patch + - Purged erroneus Date::Manip references + +1.00 Tue Jul 27 21:55:43 CDT 1999 + - abstracted item/coord translations to cell refs + rather than redundant coord lookups + - initial release + +0.09 Thu Jul 8 19:02:39 CDT 1999 + - added week counts and arbitrary 1st DOW + +0.08 Fri Jul 10 19:58:28 1998 + - first public version diff --git a/1.25/LICENSE b/1.25/LICENSE new file mode 100644 index 0000000..e26392a --- /dev/null +++ b/1.25/LICENSE @@ -0,0 +1,377 @@ +This software is copyright (c) 2010 by Matthew Sisk. + +This is free software; you can redistribute it and/or modify it under +the same terms as the Perl 5 programming language system itself. + +Terms of the Perl programming language system itself + +a) the GNU General Public License as published by the Free + Software Foundation; either version 1, or (at your option) any + later version, or +b) the "Artistic License" + +--- The GNU General Public License, Version 1, February 1989 --- + +This software is Copyright (c) 2010 by Matthew Sisk. + +This is free software, licensed under: + + The GNU General Public License, Version 1, February 1989 + + GNU GENERAL PUBLIC LICENSE + Version 1, February 1989 + + Copyright (C) 1989 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 license agreements of most software companies try to keep users +at the mercy of those companies. By contrast, our 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. The +General Public License applies to the Free Software Foundation's +software and to any other program whose authors commit to using it. +You can use it for your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Specifically, the General Public License is designed to make +sure that you have the freedom to give away or sell copies of free +software, 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 a 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 tell them 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. + + 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 Agreement 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 work containing the +Program or a portion of it, either verbatim or with modifications. Each +licensee is addressed as "you". + + 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 +General Public License and to the absence of any warranty; and give any +other recipients of the Program a copy of this General Public License +along with the Program. You may charge a fee for the physical act of +transferring a copy. + + 2. You may modify your copy or copies of the Program or any portion of +it, and copy and distribute such modifications under the terms of Paragraph +1 above, provided that you also do the following: + + a) cause the modified files to carry prominent notices stating that + you changed the files and the date of any change; and + + b) cause the whole of any work that you distribute or publish, that + in whole or in part contains the Program or any part thereof, either + with or without modifications, to be licensed at no charge to all + third parties under the terms of this General Public License (except + that you may choose to grant warranty protection to some or all + third parties, at your option). + + c) If the modified program normally reads commands interactively when + run, you must cause it, when started running for such interactive use + in the simplest and most usual 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 General + Public License. + + d) 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. + +Mere aggregation of another independent work with the Program (or its +derivative) on a volume of a storage or distribution medium does not bring +the other work under the scope of these terms. + + 3. You may copy and distribute the Program (or a portion or derivative of +it, under Paragraph 2) in object code or executable form under the terms of +Paragraphs 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 + Paragraphs 1 and 2 above; or, + + b) accompany it with a written offer, valid for at least three + years, to give any third party free (except for a nominal charge + for the cost of distribution) a complete machine-readable copy of the + corresponding source code, to be distributed under the terms of + Paragraphs 1 and 2 above; or, + + c) accompany it with the information you received as to where the + corresponding source code may be obtained. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form alone.) + +Source code for a work means the preferred form of the work for making +modifications to it. For an executable file, complete source code means +all the source code for all modules it contains; but, as a special +exception, it need not include source code for modules which are standard +libraries that accompany the operating system on which the executable +file runs, or for standard header files or definitions files that +accompany that operating system. + + 4. You may not copy, modify, sublicense, distribute or transfer the +Program except as expressly provided under this General Public License. +Any attempt otherwise to copy, modify, sublicense, distribute or transfer +the Program is void, and will automatically terminate your rights to use +the Program under this License. However, parties who have received +copies, or rights to use copies, from you under this General Public +License will not have their licenses terminated so long as such parties +remain in full compliance. + + 5. By copying, distributing or modifying 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. + + 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. + + 7. 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 the 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 +the license, you may choose any version ever published by the Free Software +Foundation. + + 8. 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 + + 9. 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. + + 10. 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 + + Appendix: 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 humanity, 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 1, 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) 19xx 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 a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + program `Gnomovision' (a program to direct compilers to make passes + at assemblers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +That's all there is to it! + + +--- The Artistic License 1.0 --- + +This software is Copyright (c) 2010 by Matthew Sisk. + +This is free software, licensed under: + + The Artistic License 1.0 + +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. + - "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 ftp.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) accompany any non-standard executables with their corresponding Standard + Version executables, giving the non-standard executables non-standard + names, and clearly documenting 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. + +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 whomever generated them, and may be sold +commercially, and may be aggregated with this Package. + +7. C or perl subroutines supplied by you and linked into this Package shall not +be considered part of this Package. + +8. The name of the Copyright Holder may not be used to endorse or promote +products derived from this software without specific prior written permission. + +9. 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 + diff --git a/1.25/MANIFEST b/1.25/MANIFEST new file mode 100644 index 0000000..54556bf --- /dev/null +++ b/1.25/MANIFEST @@ -0,0 +1,36 @@ +Changes +LICENSE +MANIFEST +MANIFEST.SKIP +META.json +Makefile.PL +README +dist.ini +lib/HTML/CalendarMonth.pm +lib/HTML/CalendarMonth/DateTool.pm +lib/HTML/CalendarMonth/DateTool/Cal.pm +lib/HTML/CalendarMonth/DateTool/DateCalc.pm +lib/HTML/CalendarMonth/DateTool/DateManip.pm +lib/HTML/CalendarMonth/DateTool/DateTime.pm +lib/HTML/CalendarMonth/DateTool/Ncal.pm +lib/HTML/CalendarMonth/DateTool/TimeLocal.pm +lib/HTML/CalendarMonth/Locale.pm +t/00_basic.t +t/01_autodetect.t +t/02_timelocal.t +t/03_datetime.t +t/04_datemanip.t +t/05_datecalc.t +t/06_cal.t +t/07_ncal.t +t/20_i8n.t +t/21_narrow.t +t/author-critic.t +t/dat/bulk.dat +t/dat/i8n.dat +t/dat/narrow.dat +t/dat/odd.dat +t/dat/woy.dat +t/release-pod-coverage.t +t/release-pod-syntax.t +t/testload.pm diff --git a/1.25/MANIFEST.SKIP b/1.25/MANIFEST.SKIP new file mode 100644 index 0000000..8d5c2de --- /dev/null +++ b/1.25/MANIFEST.SKIP @@ -0,0 +1,4 @@ +\.pl$ +\.out$ +\.old$ +\.bak$ diff --git a/1.25/META.json b/1.25/META.json new file mode 100644 index 0000000..6b466b3 --- /dev/null +++ b/1.25/META.json @@ -0,0 +1,48 @@ +{ + "abstract" : "Generate and manipulate HTML calendar months", + "author" : [ + "Matthew P. Sisk " + ], + "dynamic_config" : 0, + "generated_by" : "Dist::Zilla version 4.101612, CPAN::Meta::Converter version 2.101610", + "license" : [ + "perl_5" + ], + "meta-spec" : { + "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec", + "version" : "2" + }, + "name" : "HTML-CalendarMonth", + "prereqs" : { + "configure" : { + "requires" : { + "ExtUtils::MakeMaker" : "6.31" + } + }, + "runtime" : { + "requires" : { + "Carp" : 0, + "Class::Accessor" : 0, + "DateTime::Locale" : "0.45", + "File::Which" : 0, + "HTML::ElementTable" : "1.18", + "Time::Local" : 0, + "constant" : 0 + } + }, + "test" : { + "requires" : { + "Cwd" : 0, + "English" : 0, + "Exporter" : 0, + "File::Spec" : 0, + "FindBin" : 0, + "Test::More" : 0, + "vars" : 0 + } + } + }, + "release_status" : "stable", + "version" : "1.25" +} + diff --git a/1.25/Makefile.PL b/1.25/Makefile.PL new file mode 100644 index 0000000..dbaf014 --- /dev/null +++ b/1.25/Makefile.PL @@ -0,0 +1,65 @@ + +use strict; +use warnings; + + + +use ExtUtils::MakeMaker 6.31; + + + +my %WriteMakefileArgs = ( + 'ABSTRACT' => 'Generate and manipulate HTML calendar months', + 'AUTHOR' => 'Matthew P. Sisk ', + 'BUILD_REQUIRES' => { + 'Cwd' => '0', + 'English' => '0', + 'Exporter' => '0', + 'File::Spec' => '0', + 'FindBin' => '0', + 'Test::More' => '0', + 'vars' => '0' + }, + 'CONFIGURE_REQUIRES' => { + 'ExtUtils::MakeMaker' => '6.31' + }, + 'DISTNAME' => 'HTML-CalendarMonth', + 'EXE_FILES' => [], + 'LICENSE' => 'perl', + 'NAME' => 'HTML::CalendarMonth', + 'PREREQ_PM' => { + 'Carp' => '0', + 'Class::Accessor' => '0', + 'DateTime::Locale' => '0.45', + 'File::Which' => '0', + 'HTML::ElementTable' => '1.18', + 'Time::Local' => '0', + 'constant' => '0' + }, + 'VERSION' => '1.25', + 'test' => { + 'TESTS' => 't/*.t' + } +); + + +unless ( eval { ExtUtils::MakeMaker->VERSION(6.56) } ) { + my $br = delete $WriteMakefileArgs{BUILD_REQUIRES}; + my $pp = $WriteMakefileArgs{PREREQ_PM}; + for my $mod ( keys %$br ) { + if ( exists $pp->{$mod} ) { + $pp->{$mod} = $br->{$mod} if $br->{$mod} > $pp->{$mod}; + } + else { + $pp->{$mod} = $br->{$mod}; + } + } +} + +delete $WriteMakefileArgs{CONFIGURE_REQUIRES} + unless eval { ExtUtils::MakeMaker->VERSION(6.52) }; + +WriteMakefile(%WriteMakefileArgs); + + + diff --git a/1.25/README b/1.25/README new file mode 100644 index 0000000..d64588d --- /dev/null +++ b/1.25/README @@ -0,0 +1,71 @@ +HTML-CalendarMonth +------------------- + +HTML::CalendarMonth is a module that simplifies the rendering of a +calendar month in HTML. It is NOT a scheduling system. + +Calendars are represented as HTML::Element based structures, derived +from the HTML::ElementTable class. + +The module includes support for 'week of the year' numbering, arbitrary +1st day of the week definitions, and locale support. + +If you wish to use 'week of the year' numbering, or want to explore +dates beyond the capability of the internal perl time functions, then +you will need Date::Calc, DateTime, or Date::Manip. + +INSTALLATION + +You install HTML-Calendar, as you would install any perl module library, +by running these commands: + + perl Makefile.PL + make + make test + make install + +DOCUMENTATION + +See HTML/CalendarMonth.pm for the code. See Changes for recent changes. +POD style documentation is included in the module. This is normally +converted to a manual page and installed as part of the "make install" +process. You should also be able to use the 'perldoc' utility to extract +and read documentation from the module directly. + +Some examples can be found here: + + http://www.mojotoad.com/sisk/projects/HTML-CalendarMonth/examples.html + +SUPPORT + +There is a mailing list for HTML::Calendar. To subscribe or view past +messages, please visit the following URL: + + http://lists.sourceforge.net/mailman/listinfo/html-calmonth-general + +Questions and comments may also be directed to Matt Sisk + + +AVAILABILITY + +The package is available from CPAN: + + http://www.cpan.org/authors/id/M/MS/MSISK/ + +The package is also available at the Toadstool: + + http://www.mojotoad.com/sisk/projects/HTML-CalendarMonth/ + +ACKNOWLEDGMENTS + +Thanks to William R. Ward for some conceptual nudging. Thanks to Fabian +Aichele, Jarkko Hietaniemi, Wolfgang Jürgensen, and David 'Sniper' +Rigaudiere for some suggestions on global calendar customs. Thanks to +Gael Marziou, Raul Rivero, Ricardo Signes, T. Bugra Uytun, and Philipp +W. for some helpful bug spotting. + +COPYRIGHT + +Copyright (c) 1999-2010 Matthew P. Sisk. All rights reserved. All wrongs +revenged. This program is free software; you can redistribute it and/or +modify it under the same terms as Perl itself. diff --git a/1.25/dist.ini b/1.25/dist.ini new file mode 100644 index 0000000..11692d6 --- /dev/null +++ b/1.25/dist.ini @@ -0,0 +1,34 @@ +name = HTML-CalendarMonth +author = Matthew P. Sisk +license = Perl_5 +copyright_holder = Matthew Sisk + +[VersionFromModule] + +[NextRelease] +format = %-5v %{eee LLL dd HH:MM:ss zzz yyyy}d + +[@Git] + +[GatherDir] +[ManifestSkip] +[PruneCruft] +[MetaJSON] +[MakeMaker] +[License] + +[ExtraTests] +[CriticTests] +[PodSyntaxTests] +[PodCoverageTests] + +[PkgVersion] + +[AutoPrereq] +skip = ^testload|Date::Calc|Date::Manip|DateTime$ + +[Manifest] + +[TestRelease] +[ConfirmRelease] +[UploadToCPAN] diff --git a/1.25/lib/HTML/CalendarMonth.pm b/1.25/lib/HTML/CalendarMonth.pm new file mode 100644 index 0000000..0e66eb8 --- /dev/null +++ b/1.25/lib/HTML/CalendarMonth.pm @@ -0,0 +1,1407 @@ +package HTML::CalendarMonth; +BEGIN { + $HTML::CalendarMonth::VERSION = '1.25'; +} + +use strict; +use warnings; +use Carp; + +BEGIN { $HTML::CalendarMonth::VERSION = 1.25 } + +use HTML::ElementTable 1.18; +use HTML::CalendarMonth::Locale; +use HTML::CalendarMonth::DateTool; + +use base qw( Class::Accessor HTML::ElementTable ); + +my %Objects; + +# default complex attributes +my %Calmonth_Attrs = ( + head_m => 1, # month heading mode + head_y => 1, # year heading mode + head_dow => 1, # DOW heading mode + head_week => 0, # weak of year + year_span => 2, # default col span of year + + today => undef, # DOM, if not now + week_begin => 1, # what DOW (1-7) is the 1st DOW? + + historic => 1, # if able to choose, use ncal/cal + # rather than Date::Calc, which + # blindly extrapolates Gregorian + + alias => {}, # what gets displayed if not + # the default item + + month => undef, # these will get initialized + year => undef, + + locale => 'en_US', + full_days => 0, + full_months => 1, + + datetool => undef, + + enable_css => 1, + semantic_css => 0, + + # internal muckety muck + _cal => undef, + _itoch => {}, + _ctoih => {}, + _caltool => undef, + _weeknums => undef, + _today => undef, + + dow1st => undef, + lastday => undef, + loc => undef, + + # deprecated + row_offset => undef, + col_offset => undef, +); + +__PACKAGE__->mk_accessors(keys %Calmonth_Attrs); + +# Class::Accessor overrides + +sub set { + my($self, $key) = splice(@_, 0, 2); + if (@_ == 1) { + $Objects{$self}{$key} = $_[0]; + } + elsif (@_ > 1) { + $Objects{$self}{$key} = [@_]; + } + else { + Carp::confess("wrong number of arguments received"); + } +} + +sub get { + my $self = shift; + if (@_ == 1) { + return $Objects{$self}{$_[0]}; + } + elsif ( @_ > 1 ) { + return @{$Objects{$self}{@_}}; + } + else { + Carp::confess("wrong number of arguments received."); + } +} + +sub _is_calmonth_attr { shift; exists $Calmonth_Attrs{shift()} } + +sub _set_defaults { + my $self = shift; + foreach (keys %Calmonth_Attrs) { + $self->$_($Calmonth_Attrs{$_}); + } + $self; +} + +sub DESTROY { delete $Objects{shift()} } + +# last dow col, first week row + +use constant LDC => 6; +use constant FWR => 2; + +# alias + +sub item_alias { + my($self, $item) = splice(@_, 0, 2); + defined $item or croak "item name required"; + $self->alias->{$item} = shift if @_; + $self->alias->{$item} || $item; +} + +sub item_aliased { + my($self, $item) = splice(@_, 0, 2); + defined $item or croak "item name required.\n"; + defined $self->alias->{$item}; +} + +# header toggles + +sub _head { + # Set/test entire heading (month,year,and dow headers) (does not + # affect week number column). Return true if either heading active. + my $self = shift; + $self->head_m(@_) && $self->head_dow(@_) if @_; + $self->_head_my || $self->head_dow; +} + +sub _head_my { + # Set/test month and year header mode + my($self, $mode) = splice(@_, 0, 2); + $self->head_m($mode) && $self->head_y($mode) if defined $mode; + $self->head_m || $self->head_y; +} + +sub _initialized { + my $self = shift; + @_ ? $self->{_initialized} = shift : $self->{_initialized}; +} + +# circa interface + +sub _date { + # set target month, year + my $self = shift; + if (@_) { + my ($month, $year) = @_; + $month && defined $year || croak "date method requires month and year"; + croak "Date already set" if $self->_initialized(); + + # get rid of possible leading 0's + $month += 0; + $year += 0; + + $month <= 12 && $month >= 1 or croak "Month $month out of range (1-12)\n"; + $year > 0 or croak "Negative years are unacceptable\n"; + + $self->month($self->monthname($month)); + $self->year($year); + $month = $self->monthnum($month); + + # trigger _gencal...this should be the only place where this occurs + $self->_gencal; + } + return($self->month, $self->year); +} + +# class factory access + +use constant CLASS_HET => 'HTML::ElementTable'; +use constant CLASS_DATETOOL => 'HTML::CalendarMonth::DateTool'; +use constant CLASS_LOCALE => 'HTML::CalendarMonth::Locale'; + +sub _gencal { + # generate internal calendar representation + my $self = shift; + + # new calendar...clobber day-specific settings + my $itoc = $self->_itoch({}); + my $ctoi = $self->_ctoih({}); + + # figure out dow of 1st day of the month as well as last day of the + # month (uses date calculator backends) + $self->_anchor_month(); + + # row count for weeks in grid + my $wcnt = 0; + + my ($dowc) = $self->dow1st; + my $skips = $self->_caltool->_skips; + + # for each day + foreach (1 .. $self->lastday) { + next if $skips->{$_}; + my $r = $wcnt + FWR; + my $c = $dowc; + # this is a bootstrap until we know the number of rows in the month. + $itoc->{$_} = [$r, $c]; + $dowc = ++$dowc % 7; + ++$wcnt unless $dowc || $_ == $self->lastday; + } + + $self->{_week_rows} = $wcnt; + + my $row_extent = $wcnt + FWR; + my $col_extent = LDC; + $col_extent += 1 if $self->head_week; + + $self->SUPER::extent($row_extent, $col_extent); + + # table can contain the days now, so replace our bootstrap coordinates + # with references to the actual elements. + foreach (keys %$itoc) { + my $cellref = $self->cell(@{$itoc->{$_}}); + $self->_itoc($_, $cellref); + $self->_ctoi($cellref, $_); + } + + # week num affects month/year spans + my $width = $self->head_week ? 8 : 7; + + # month/year headers + my $cellref = $self->cell(0, 0); + $self->_itoc($self->month, $cellref); + $self->_ctoi($cellref, $self->month); + $cellref = $self->cell(0, $width - $self->year_span); + $self->_itoc($self->year, $cellref); + $self->_ctoi($cellref, $self->year); + + $self->item($self->month)->replace_content($self->item_alias($self->month)); + $self->item($self->year)->replace_content($self->item_alias($self->year)); + + if ($self->_head_my) { + if ($self->head_m) { + $self->item($self->month)->attr('colspan',$width - $self->year_span); + } + else { + $self->item($self->month)->mask(1); + $self->item($self->year)->attr('colspan', $width); + } + if ($self->head_y) { + $self->item($self->year)->attr('colspan',$self->year_span); + } + else { + $self->item($self->year)->mask(1); + $self->item($self->month)->attr('colspan', $width); + } + } + else { + $self->row(0)->mask(1); + } + + # DOW headers + my $trans; + my $days = $self->loc->days; + foreach (0..$#$days) { + # Transform for week_begin 1..7 + $trans = ($_ + $self->week_begin - 1) % 7; + my $cellref = $self->cell(1, $_); + $self->_itoc($days->[$trans], $cellref); + $self->_ctoi($cellref, $days->[$trans]); + } + if ($self->head_dow) { + grep($self->item($_)->replace_content($self->item_alias($_)), @$days); + } + else { + $self->row(1)->mask(1); + } + + # week number column + if ($self->head_week) { + # week nums can collide with days. Use "w" in front of the number + # for uniqueness, and automatically alias to just the number (unless + # already aliased, of course). + $self->_gen_week_nums(); + my $ws; + my $row_count = FWR; + foreach ($self->_numeric_week_nums) { + $ws = "w$_"; + $self->item_alias($ws, $_) unless $self->item_aliased($ws); + my $cellref = $self->cell($row_count, $self->last_col); + $self->_itoc($ws, $cellref); + $self->_ctoi($cellref, $ws); + $self->item($ws)->replace_content($self->item_alias($ws)); + ++$row_count; + } + } + + # fill in days of the month + my $i; + foreach my $r (FWR .. $self->last_row) { + foreach my $c (0 .. LDC) { + $self->cell($r,$c)->replace_content($self->item_alias($i)) + if ($i = $self->item_at($r,$c)); + } + } + + # css classes + if ($self->enable_css) { + $self ->push_attr(class => 'hcm-table' ); + $self->item_row($self->dayheaders)->push_attr(class => 'hcm-day-head' ); + $self->item ($self->year) ->push_attr(class => 'hcm-year-head' ); + $self->item ($self->month) ->push_attr(class => 'hcm-month-head'); + $self->item ($self->week_nums) ->push_attr(class => 'hcm-week-head' ) + if $self->head_week; + } + + if ($self->semantic_css) { + my $today = $self->today; + if ($today < 0) { + $self->item($self->days)->push_attr(class => 'hcm-past'); + } + elsif ($today == 0) { + $self->item($self->days)->push_attr(class => 'hcm-future'); + } + else { + for my $d ($self->days) { + if ($d < $today) { + $self->item($d)->push_attr(class => 'hcm-past'); + } + elsif ($d > $today) { + $self->item($d)->push_attr(class => 'hcm-future'); + } + else { + $self->item($d)->push_attr(class => 'hcm-today'); + } + } + } + } + + $self; +} + +sub default_css { + my $hbgc = '#DDDDDD'; + my $bc = '#888888'; + + my $str = <<__CSS; + +__CSS + +} + +sub _datetool { + my $self = shift; + my $ct; + if (! ($ct = $self->_caltool)) { + $ct = $self->_caltool(CLASS_DATETOOL->new( + year => $self->year, + month => $self->month, + weeknum => $self->head_week, + historic => $self->historic, + datetool => $self->datetool, + )); + } + $ct; +} + +sub _anchor_month { + # Figure out what our month grid looks like. + # Let HTML::CalendarMonth::DateTool determine which method is + # appropriate. + my $self = shift; + + my $month = $self->monthnum($self->month); + my $year = $self->year; + + my $tool = $self->_datetool; + + my $dow1st = $tool->dow1st; # 0..6, starting with Sun + my $lastday = $tool->lastday; + + # week_begin given as 1..7 starting with Sun + $dow1st = ($dow1st - ($self->week_begin - 1)) % 7; + + $self->dow1st($dow1st); + $self->lastday($lastday); + + $self; +} + +sub _gen_week_nums { + # Generate week-of-the-year numbers. The first week is generally + # agreed upon to be the week that contains the 4th of January. + # + # For purposes of shenanigans with 'week_begin', we anchor the week + # number off of Thursday in each row. + + my $self = shift; + + my($year, $month, $lastday) = ($self->year, $self->monthnum, $self->lastday); + + my $tool = $self->_caltool; + croak "Oops. " . ref $tool . " not set up for week of year calculations.\n" + unless $tool->can('week_of_year'); + + my $fdow = $self->dow1st; + my $delta = 4 - $fdow; + if ($delta < 0) { + $delta += 7; + } + my @ft = $tool->add_days($delta, 1); + + my $ldow = $tool->dow($lastday); + $delta = 4 - $ldow; + if ($delta > 0) { + $delta -= 7; + } + my @lt = $tool->add_days($delta, $lastday); + + my $fweek = $tool->week_of_year(@ft); + my $lweek = $tool->week_of_year(@lt); + my @wnums = $fweek > $lweek ? ($fweek, 1 .. $lweek) : ($fweek .. $lweek); + + # do we have days above our first Thursday? + if ($self->row_of($ft[0]) != FWR) { + unshift(@wnums, $wnums[0] -1); + } + + # do we have days below our last Thursday? + if ($self->row_of($lt[0]) != $self->last_row) { + push(@wnums, $wnums[-1] + 1); + } + + # first visible week is from last year + if ($wnums[0] == 0) { + $wnums[0] = $tool->week_of_year($tool->add_days(-7, $ft[0])); + } + + # last visible week is from subsequent year + if ($wnums[-1] > $lweek) { + $wnums[-1] = $tool->week_of_year($tool->add_days(7, $lt[0])); + } + + $self->_weeknums(\@wnums); +} + +# month hooks + +sub row_items { + # given a list of items, return all items in rows shared by the + # provided items. + my $self = shift; + my %items; + foreach my $item (@_) { + my $row = ($self->coords_of($item))[0]; + foreach my $col (0 .. $self->last_col) { + my $i = $self->item_at($row, $col) || next; + ++$items{$i}; + } + } + keys %items > 1 ? keys %items : (keys %items)[0]; +} + +sub col_items { + # return all item cells in the columns occupied by the provided list + # of items. + my $self = shift; + $self->_col_items(0, $self->last_row, @_); +} + +sub daycol_items { + # same as col_items(), but excludes header cells. + my $self = shift; + $self->_col_items(FWR, $self->last_row, @_); +} + +sub _col_items { + # given row bounds and a list of items, return all item elements + # in the columns occupied by the provided items. Does not return + # empty cells. + my($self, $rfirst, $rlast) = splice(@_, 0, 3); + my %items; + my($item, $row, $col, %i); + foreach my $item (@_) { + my $col = ($self->coords_of($item))[1]; + foreach my $row ($rfirst .. $rlast) { + my $i = $self->item_at($row,$col) || next; + ++$items{$i}; + } + } + keys %items > 1 ? keys %items : (keys %items)[0]; +} + +sub daytime { + # return seconds since epoch for a given day + my($self, $day) = splice(@_, 0, 2); + $day or croak "must specify day of month"; + croak "day does not exist" unless $self->_daycheck($day); + $self->_caltool->day_epoch($day); +} + +sub week_nums { + # return list of all week number labels + my @wnums = map("w$_", shift->_numeric_week_nums); + wantarray ? @wnums : \@wnums; +} + +sub _numeric_week_nums { + # return list of all week numbers as numbers + my $self = shift; + return unless $self->head_week; + wantarray ? @{$self->_weeknums} : $self->_weeknums; +} + +sub days { + # return list of all days of the month (1..$c->lastday). + my $self = shift; + my $skips = $self->_caltool->_skips; + my @days = grep { !$skips->{$_} } (1 .. $self->lastday); + wantarray ? @days : \@days; +} + +sub dayheaders { + # return list of all day headers (Su..Sa). + shift->loc->days; +} + +sub headers { + # return list of all headers (month,year,dayheaders) + my $self = shift; + wantarray ? ($self->year, $self->month, $self->dayheaders) + : [$self->year, $self->month, $self->dayheaders]; +} + +sub items { + # return list of all items (days, headers) + my $self = shift; + wantarray ? ($self->headers, $self->days) + : [$self->headers, $self->days]; +} + +sub last_col { + # what's the max col of the calendar? + my $self = shift; + $self->head_week ? LDC + 1 : LDC; +} + +sub last_day_col { LDC } + +sub last_row { + # last row of the calendar + my $self = shift; + return ($self->coords_of($self->lastday))[0]; +} + +*last_week_row = \&last_row; + +sub first_week_row { FWR }; + +sub past_days { + my $self = shift; + my $today = $self->_today; + if ($today < 0) { + return $self->days; + } + elsif ($today == 0) { + return; + } + return(1 .. $today); +} + +sub future_days { + my $self = shift; + my $today = $self->_today; + if ($today < 0) { + return; + } + elsif ($today == 0) { + return $self->days; + } + return($today .. $self->last_day); +} + +# custom glob interfaces + +sub item { + # return TD elements containing items + my $self = shift; + @_ || croak "item(s) must be provided"; + $self->cell(grep(defined $_, map($self->coords_of($_), @_))); +} + +sub item_row { + # return a glob of the rows of a list of items, including empty cells. + my $self = shift; + $self->row(map { $self->row_of($_) } @_); +} + +sub item_day_row { + # same as item_row, but excludes possible week number cells + my $self = shift; + return $self->item_row(@_) unless $self->head_week; + my(%rows, @coords); + for my $r (map { $self->row_of($_) } @_) { + next if ++$rows{$r} > 1; + for my $c (0 .. 6) { + push(@coords, ($r, $c)); + } + } + $self->cell(@coords); +} + +sub item_week_nums { + # glob of all week numbers + my $self = shift; + $self->item($self->week_nums); +} + +sub item_col { + # return a glob of the cols of a list of items, including empty cells. + my $self = shift; + $self->_item_col(0, $self->last_row, @_); +} + +sub item_daycol { + # same as item_col(), but excludes header cells. + my $self = shift; + $self->_item_col(2, $self->last_row, @_); +} + +sub _item_col { + # given row bounds and a list of items, return a glob representing + # the cells in the columns occupied by the provided items, including + # empty cells. + my($self, $rfirst, $rlast) = splice(@_, 0, 3); + defined $rfirst && defined $rlast or Carp::confess "No items provided"; + my(%seen, @coords); + foreach my $col (map { $self->col_of($_) } @_) { + next if ++$seen{$col} > 1; + foreach my $row ($rfirst .. $rlast) { + push(@coords, $row, $col); + } + } + $self->cell(@coords); +} + +sub item_box { + # return a glob of the box defined by two items + my($self, $item1, $item2) = splice(@_, 0, 3); + defined $item1 && defined $item2 or croak "Two items required"; + $self->box($self->coords_of($item1), $self->coords_of($item2)); +} + +sub all { + # return a glob of all calendar cells, including empty cells. + my $self = shift; + $self->box( 0,0 => $self->last_row, $self->last_col ); +} + +sub alldays { + # return a glob of all cells other than header cells + my $self = shift; + $self->box( 2, 0 => $self->last_row, 6 ); +} + +sub allheaders { + # return a glob of all header cells + my $self = shift; + $self->item($self->headers); +} + +# transformation Methods + +sub coords_of { + # convert an item into grid coordinates + my $self = shift; + croak "undefined value passed to coords_of()" if @_ && ! defined $_[0]; + my $ref = $self->_itoc(@_); + my @pos = ref $ref ? $ref->position : (); + @pos ? (@pos[$#pos - 1, $#pos]) : (); +} + +sub item_at { + # convert grid coords into item + my $self = shift; + $self->_ctoi($self->cell(@_)); +} + +sub _itoc { + # item to grid + my($self, $item, $ref) = splice(@_, 0, 3); + defined $item or croak "item required"; + my $itoc = $self->_itoch; + if ($ref) { + croak "Reference required" unless ref $ref; + $itoc->{$item} = $ref; + } + $itoc->{$item}; +} + +sub _ctoi { + # cell reference to item + my($self, $refstring, $item) = splice(@_, 0, 3); + defined $refstring or croak "cell id required"; + my $ctoi = $self->_ctoih; + if (defined $item) { + $ctoi->{$refstring} = $item; + } + $ctoi->{$refstring}; +} + +sub row_of { + my $self = shift; + ($self->coords_of(@_))[0]; +} + +sub col_of { + my $self = shift; + ($self->coords_of(@_))[1]; +} + +sub monthname { + # check/return month...returns name. Accepts month number or string. + my $self = shift; + return $self->month unless @_; + my $loc = $self->loc; + my @names; + for my $m (@_) { + $m = ($m - 1) % 12 if $m && $m =~ /^\d+$/; + $m = $loc->monthname($m) || croak "month not found " . join(', ', @_); + return $m if @_ == 1; + push(@names, $m); + } + @names; +} + +sub monthnum { + # check/return month, returns number. Accepts month number or string. + my $self = shift; + my @months = @_ ? @_ : $self->month; + my $loc = $self->loc; + my @nums; + for my $m (@months) { + $m = ($m - 1) % 12 if $m && $m =~ /^\d+$/; + $m = $loc->monthnum($m); + croak "month not found ", join(', ', @_) unless defined $m; + $m += 1; + return $m if @_ == 1; + push(@nums, $m); + } + @nums; +} + +sub dayname { + # check/return day...returns name. Accepts 1..7, or Su..Sa + my $self = shift; + @_ || croak "day string or num required"; + my $loc = $self->loc; + my @names; + for my $d (@_) { + if ($d =~ /^\d+$/) { + $d = (($d - 1) % 7) + $self->week_begin - 1; + } + $d = $loc->dayname($d) || croak "day not found ", join(', ', @_); + return $d if @_ == 1; + push(@names, $d); + } + @names; +} + +sub daynum { + # check/return day number 1..7, returns number. Accepts 1..7, + # or Su..Sa + my $self = shift; + @_ || croak "day string or num required"; + my $loc = $self->loc; + my @nums; + for my $d (@_) { + if ($d =~ /^\d+$/) { + $d = (($d - 1) % 7) + $self->week_begin - 1; + } + $d = $loc->daynum($d); + croak "day not found ", join(', ', @_) unless defined $d; + $d += 1; + return $d if @_ == 1; + push(@nums, $d); + } + @nums; +} + +# tests-n-checks + +sub _dayheadcheck { + # test day head names + my($self, $name) = splice(@_, 0, 2); + $name or croak "name missing"; + return if $name =~ /^\d+$/; + $self->daynum($name); +} + +sub _daycheck { + # check if an item is a day of the month (1..31) + my($self, $item) = splice(@_, 0, 2); + croak "item required" unless $item; + # can't just invert _headcheck because coords_of() needs _daycheck, + # and _headcheck uses coords_of() + $item =~ /^\d{1,2}$/ && $item <= 31; +} + +sub _headcheck { + # check if an item is a header + !_daycheck(@_); +} + +# constructors/destructors + +sub new { + my $class = shift; + my %parms = @_; + my(%attrs, %tattrs); + foreach (keys %parms) { + if (__PACKAGE__->_is_calmonth_attr($_)) { + $attrs{$_} = $parms{$_}; + } + else { + $tattrs{$_} = $parms{$_}; + } + } + + my $self = CLASS_HET->new(%tattrs); + bless $self, $class; + + # set defaults + $self->_set_defaults; + + my $month = delete $attrs{month}; + my $year = delete $attrs{year}; + if (!$month || !$year) { + my ($nmonth,$nyear) = (localtime(time))[4,5]; + ++$nmonth; $nyear += 1900; + $month ||= $nmonth; + $year ||= $nyear; + } + $self->month($month); + $self->year($year); + + # set overrides + for my $k (keys %attrs) { + $self->$k($attrs{$k}) if defined $attrs{$k}; + } + + my $loc = CLASS_LOCALE->new( + id => $self->locale, + full_days => $self->full_days, + full_months => $self->full_months, + ) or croak "Problem creating locale " . $self->locale . "\n"; + $self->loc($loc); + + my $dt = CLASS_DATETOOL->new( + year => $self->year, + month => $self->month, + weeknum => $self->head_week, + historic => $self->historic, + datetool => $self->datetool, + ); + $self->_caltool($dt); + + $self->week_begin($loc->first_day_of_week + 1) + unless defined $attrs{week_begin}; + + my $dom_now = defined $attrs{today} ? $dt->_dom_now(delete $attrs{today}) + : $dt->_dom_now; + $self->_today($dom_now); + $self->today($dom_now) if $dom_now > 0; + + my $alias = $attrs{alias} || {}; + if ($self->full_days < 0) { + my @full = $self->loc->days; + my @narrow = $self->loc->narrow_days; + for my $i (0 .. $#narrow) { + $alias->{$full[$i]} = $narrow[$i]; + } + } + if ($self->full_months < 0) { + my @full = $self->loc->months; + my @narrow = $self->loc->narrow_months; + for my $i (0 .. $#narrow) { + $alias->{$full[$i]} = $narrow[$i]; + } + } + $self->alias($alias) if keys %$alias; + + # for now, this is the only time this will every happen for this + # object. It is now 'initialized'. + $self->_date($month, $year); + + $self; +} + +### overrides (our table is static) + +sub extent { } +sub maxrow { shift->SUPER::maxrow } +sub maxcol { shift->SUPER::maxcol } + +### deprecated + +use constant row_offset => 0; +use constant col_offset => 0; +use constant first_col => 0; +use constant first_row => 0; +use constant first_week_col => 0; +use constant last_week_col => 6; + +### + +1; + +__END__ + +=head1 NAME + +HTML::CalendarMonth - Generate and manipulate HTML calendar months + +=head1 SYNOPSIS + + use HTML::CalendarMonth; + + # Using regular HTML::Element creation + my $c = HTML::CalendarMonth->new( month => 8, year => 2010 ); + print $c->as_HTML; + + # Full locale support via DateTime::Locale + my $c2 = HTML::CalendarMonth->new( + month => 8, + year => 2010, + locale => 'zu_ZA' + ); + print $c2->as_HTML; + + # HTML-Tree integration + my $tree = HTML::TreeBuilder->parse_file('cal.html'); + $tree->find_by_attribute(class => 'hcm-calendar')->replace_with($c); + print $tree->as_HTML; + + # clean up if you're not done, HTML::Element structures must be + # manually destroyed + $c->delete; $c2->delete; + +=head1 DESCRIPTION + +HTML::CalendarMonth is a subclass of HTML::ElementTable. See +L for how that class works, for it affects this +module on many levels. Like HTML::ElementTable, HTML::CalendarMonth is +an enhanced HTML::Element with methods added to facilitate the +manipulation of the calendar table elements as a whole. + +The primary interaction with HTML::CalendarMonth is through I +rather than cell coordinates like HTML::ElementTable uses. An I is +merely a string that represents the content of the cell of interest +within the calendar. For instance, the element representing the 14th day +of the month would be returned by C<$c-Eitem(14)>. Similarly, the +element representing the header for Monday would be returned by C<$c- +Eitem('Mo')>. If the year happened to by 2010, then C<$c- +Eitem(2010)> would return the cell representing the year. Since +years and particular months change frequently, it is probably more +useful to take advantage of the C and C methods, which +return their respective values. The following is therefore the same as +explicitely referencing the year: C<$c-Eitem($c- Eyear())>. + +Multiple cells of the calendar can be manipulated as if they were a +single element. For instance, C<$c-Eitem(15)-Eattr(class =E +'fancyday')> would alter the class of the cell representing the 15th. By +the same token, C<$c-Eitem(15, 16, 17, +23)-Eattr(class =E 'fancyday')> would do the same thing for all +cells containing the days passed to the C method. + +Underneath, the calendar is still nothing more than a table structure, +the same as provided by the HTML::ElementTable class. In addition to the +I based access methods above, calendar cells can still be accessed +using row and column grid coordinates using the C method +provided by the table class. All coordinate-based methods in the table +class are accessible to the calendar class. + +The module includes support for week-of-the-year numbering, arbitrary +1st day of the week definitions, and locale support. + +Dates that are beyond the range of the built-in time functions of perl +are handled either by the ncal/cal command, Date::Calc, DateTime, or +Date::Manip. The presence of any one of these utilities and modules will +suffice for these far flung date calculations. One of these utilities +(with the exception of 'cal') is also required if you want to use week-of- +year numbering. + +Full locale support is offered via DateTime::Locale. For a full list of +supported locale id's, look at HTML::CalendarMonth::Locale->locales(). + +=head1 METHODS + +All arguments appearing in [brackets] are optional, and do not represent +anonymous array references. + +=head2 Constructor + +=over + +=item new() + +With no arguments, the constructor will return a calendar object +representing the current month with a default appearance. The initial +configuration of the calendar is controlled by special attributes. Non- +calendar related attributes are passed along to HTML::ElementTable. Any +non-table related attributes left after that are passed to HTML::Element +while constructing the EtableE tag. See L if +you are interested in attributes that can be passed along to that class. + +Special Attributes for HTML::CalendarMonth: + +=over + +=item month + +1-12, or Jan-Dec. Defaults to current month. + +=item year + +Four digit representation. Defaults to current year. + +=item head_m + +Specifies whether to display the month header. Default 1. + +=item head_y + +Specifies whether to display the year header. Default 1. + +=item head_dow + +Specifies whether to display days of the week header. Default 1. + +=item locale + +Specifies the id of the locale in which to render the calendar. Default +is 'en_US'. By default, this will also control determine which day is +considered to be the first day of the week. See +L for more information. If for some reason +you prefer to use different labels than those provided by C, see +the C attribute below. + +=item full_days + +Specifies whether or not to use full day names or their abbreviated +names. Default is 0, use abbreviated names. Use -1 for 'narrow' mode, +the shortest (not guaranteed to be unique) abbreviations. + +=item full_months + +Specifies whether or not to use full month names or their abbreviated +names. Default is 1, use full names. Use -1 for 'narrow' mode, the +shortest (not guaranteed to be unique) abbreviations. + +=item alias + +Takes a hash reference mapping labels provided by C to any +custom label you prefer. Lookups, such as C, will still use +the locale string, but when the calendar is rendered the aliased value +will appear. + +=item head_week + +Specifies whether to display the week-of-year numbering. Default 0. + +=item week_begin + +Specify first day of the week, which can be 1..7, starting with Sunday. +In order to specify Monday, set this to 2, and so on. By default, this +is determined based on the locale. + +=item enable_css + +Set some handy CSS class attributes on elements, enabled by default. +Currently the classes are: + + hcm-table Set on the table tag of the calendar + hcm-day-head Set on the day-of-week tr or td tags + hcm-year-head Set on the td tag for the year + hcm-month-head Set on the td tag for the month + hcm-week-head Set on the td tags for the week-of-year + +=item semantic_css + +Sets some additional CSS class attributes on elements, disabled by +default. The notion of 'today' is taken either from the system clock +(default) or from the 'today' parameter as provided to new(). Currently +these classes are: + + hcm-today Set on the td tag for today, if present + hcm-past Set on the td tags for prior days, if present + hcm-future Set on the td tags for subsequent days, if present + +=item today + +Specify the value for 'today' if different from the local time as +reported by the system clock (the default). If specified as two or less +digits, it is assumed to be one of the days of the month in the current +calendar. If more than two digits, it is assumed to be a epoch time in +seconds. Otherwise it must be given as a string of the form 'YYYY-mm- +dd'. Note that the default value as determined by the system clock uses +localtime rather than gmtime. + +=item historic + +This option is ignored for dates that do not exceed the range of the built- +in perl time functions. For dates that B exceed these ranges, this +option specifies the default calculation method. When set, if the 'ncal' +or 'cal' command is available on your system, that will be used rather +than the Date::Calc or Date::Manip modules. This can be an issue since +the date modules blindly extrapolate the Gregorian calendar, whereas +ncal/cal will revert to the Julian calendar during September 1752. If +either ncal or cal are not available on your system, this attribute is +meaningless. Defaults to 1. + +=back + +=back + +=head2 Item Query Methods + +The following methods return lists of item *symbols* (28, 29, 'Thu', +...) that are related in some way to the provided list of items. The +returned symbols may then be used as arguments to the glob methods +detailed further below. + +=over + +=item row_items(item1, [item2, ...]) + +Returns all item symbols in rows shared by the provided item symbols. + +=item col_items(item1, [item2, ...]) + +Returns all item symbols in columns shared by the provided item symbols. + +=item daycol_items(col_item1, [col_item2, ...]) + +Same as col_items(), but the returned item symbols are limited to those +that are not header items (month, year, day-of-week). + +=item row_of(item1, [item2, ...]) + +Returns the row indices of rows containing the provided item symbols. + +=item col_of(item1, [item2, ...]) + +Returns the column indices of columns containing the provided +item symbols. + +=item lastday() + +Returns the day number (symbol) of the last day of the month. + +=item dow1st() + +Returns the column index for the first day of the month. + +=item days() + +Returns a list of all days of the month as numbers. + +=item week_nums() + +Returns a list of week-of-year numbers for this month. + +=item dayheaders() + +Returns a list of all day headers (Su..Sa) + +=item headers() + +Returns a list of all headers (month, year, dayheaders) + +=item items() + +Returns a list of all item symbols (day number, header values) in +the calendar. + +=item last_col() + +Returns the index of the last column of the calendar (note that this +could be the week-of-year column if head_week is enabled). + +=item last_day_col() + +Returns the index of the last column of the calendar containing days of +the month (same as last_col() unless week-of-year is enabled). + +=item first_week_row() + +Returns the index of the first row of the calendar containing day items +(ie, the first week). + +=item last_row() + +Returns the index of the last row of the calendar. + +=item today() + +Returns the day of month for 'today', if present in the current +calendar. + +=item past_days() + +Returns a list of days prior to 'today'. If 'today' is in a future +month, all days are returned. If 'today' is in a past month, no days +are returned. + +=item future_days() + +Returns a list of days after 'today'. If 'today' is in a past +month, all days are returned. If 'today' is in a future month, no +days are returned. + +=back + +=head2 Glob Methods + +Glob methods return references that are functionally equivalent to an +individual calendar cell. Mostly, they provide item based analogues to +the glob methods provided in HTML::ElementTable. In methods dealing with +rows, columns, and boxes, the globs include empty calendar cells (which +would otherwise need to be accessed through native HTML::ElementTable +methods). The row and column numbers returned by the item methods above +are compatible with the grid based methods in HTML::ElementTable. + +For details on how these globs work, check out L and +L. + +=over + +=item item(item1, [item2, ...]) + +Returns all cells containing the provided item symbols. + +=item item_row(item1, [item2, ...]) + +Returns all cells in all rows occupied by the provided item symbols. + +=item item_day_row(item1, [item2, ...]) + +Same as item_row() except excludes week-of-year cells, if present. + +=item item_col(item1, [item2, ...]) + +Returns all cells in all columns occupied by the provided item symbols. + +=item item_daycol(item1, [item2, ...]) + +Same as item_col() except limits the cells to non header cells. + +=item item_week_nums() + +Returns all week-of-year cells, if present. + +=item item_box(item1a, item1b, [item2a, item2b, ...]) + +Returns all cells in the boxes defined by the item pairs provided. + +=item allheaders() + +Returns all header cells. + +=item alldays() + +Returns all non header cells, including empty cells. + +=item all() + +Returns all cells in the calendar, including empty cells. + +=back + +=head2 Transformation Methods + +The following methods provide ways of translating between various item +symbols, coordinates, and other representations. + +=over + +=item coords_of(item) + +Returns the row and column coordinates of the provided item symbol, for +use with the grid based methods in HTML::ElementTable. + +=item item_at(row,column) + +Returns the item symbol of the item at the provided coordinates, for use +with the item based methods of HTML::CalendarMonth. + +=item monthname(monthnum) + +Returns the name (item symbol) of the month number provided, where +I can be 1..12. + +=item monthnum(monthname) + +Returns the number (1..12) of the month name provided. Only a minimal +case-insensitive match on the month name is necessary; the proper item +symbol for the month will be determined from this match. + +=item dayname(daynum) + +Returns the name (item symbol) of the day of week header for a number of +a day of the week, where I is 1..7. + +=item daynum(dayname) + +Returns the number of the day of the week given the symbolic name for +that day (Su..Sa). + +=item daytime(day) + +Returns the number in seconds since the epoch for a given day. The day +must be present in the current calendar. + +=back + +=head2 Other Methods + +=over + +=item default_css() + +Returns a simple style sheet as a string that can be used in an HTML +document in conjunction with the classes assigned to elements when css +is enabled. + +=back + +=head1 REQUIRES + +HTML::ElementTable + +=head1 OPTIONAL + +Date::Calc, DateTime, or Date::Manip (only if you want week-of- +year numbering or non-contemporary dates on a system without the +I command) + +=head1 AUTHOR + +Matthew P. Sisk, EFE + +=head1 COPYRIGHT + +Copyright (c) 1998-2010 Matthew P. Sisk. All rights reserved. All wrongs +revenged. This program is free software; you can redistribute it and/or +modify it under the same terms as Perl itself. + +=head1 SEE ALSO + +A useful page of examples can be found at +http://www.mojotoad.com/sisk/projects/HTML-CalendarMonth. + +For information on iso639 standards for abbreviations for language +names, see http://www.loc.gov/standards/iso639-2/englangn.html + +HTML::ElementTable(3), HTML::Element(3), perl(1) + +=for Pod::Coverage col_offset row_offset item_alias item_aliased last_week_row diff --git a/1.25/lib/HTML/CalendarMonth/DateTool.pm b/1.25/lib/HTML/CalendarMonth/DateTool.pm new file mode 100644 index 0000000..91df572 --- /dev/null +++ b/1.25/lib/HTML/CalendarMonth/DateTool.pm @@ -0,0 +1,478 @@ +package HTML::CalendarMonth::DateTool; +BEGIN { + $HTML::CalendarMonth::DateTool::VERSION = '1.25'; +} + +# Base class for determining what date calculation package to use. + +use strict; +use warnings; +use Carp; + +use File::Which qw( which ); + +my %Toolmap = ( + 'Time::Local' => 'TimeLocal', + 'Date::Calc' => 'DateCalc', + 'DateTime' => 'DateTime', + 'Date::Manip' => 'DateManip', + 'ncal' => 'Ncal', + 'cal' => 'Cal', +); + +my %Classmap; +$Classmap{lc $Toolmap{$_}} = $_ foreach keys %Toolmap; + +my($Cal_Cmd, $Ncal_Cmd); + +sub _toolmap { + shift; + my $str = shift; + my $tool = $Toolmap{$str}; + unless ($tool) { + foreach (values %Toolmap) { + if ($str =~ /^$_$/i) { + $tool = $_; + last; + } + } + } + return unless $tool; + join('::', __PACKAGE__, $tool); +} + +sub new { + my $class = shift; + my $self = {}; + bless $self, $class; + my %parms = @_; + $self->{year} = $parms{year}; + $self->{month} = $parms{month}; + $self->{weeknum} = $parms{weeknum}; + $self->{historic} = $parms{historic}; + if (! $self->{year}) { + my @dmy = $self->_dmy_now; + $self->{year} = $dmy[2]; + $self->{month} ||= $dmy[1]; + } + $self->{month} ||= 1; + if ($parms{datetool}) { + $self->{datetool} = $self->_toolmap($parms{datetool}) + or croak "Sorry, didn't find a tool for datetool '$parms{datetool}'\n"; + } + my $dc = $self->_summon_date_class; + unless (eval "require $dc") { + croak "Problem loading $dc ($@)\n"; + } + # rebless into new class + bless $self, $dc; +} + +sub year { shift->{year} } +sub month { shift->{month} } +sub weeknum { shift->{weeknum} } +sub historic { shift->{historic} } +sub datetool { shift->{datetool} } + +sub _name { + my $class = shift; + $class = ref $class || $class; + lc((split(/::/, $class))[-1]); +} + +sub _cal_cmd { + my $self = shift; + if (! defined $Cal_Cmd) { + $Cal_Cmd = which('cal') || ''; + if ($Cal_Cmd) { + my @out = grep { ! /^\s*$/ } `$Cal_Cmd 9 1752`; + # September 1752 + #Su Mo Tu We Th Fr Sa + # 1 2 14 15 16 + #17 18 19 20 21 22 23 + #24 25 26 27 28 29 30 + my @pat = ( + qr/^\s*\S+\s+\d+$/, + qr/^\s*\S+\s+\S+\s+\S+\s+\S+\s+\S+\s+\S+\s+\S+\s*$/, + qr/^\s*\d+\s+\d+\s+\d+\s+\d+\s+\d+\s*$/, + qr/^\s*\d+\s+\d+\s+\d+\s+\d+\s+\d+\s+\d+\s+\d+\s*$/, + qr/^\s*\d+\s+\d+\s+\d+\s+\d+\s+\d+\s+\d+\s+\d+\s*$/, + ); + if (@out == @pat) { + for my $i (0 .. $#out) { + if ($out[$i] !~ $pat[$i]) { + $Cal_Cmd = ''; + last; + } + } + } + else { + $Cal_Cmd = ''; + } + } + } + $Cal_Cmd; +} + +sub _ncal_cmd { + my $self = shift; + if (! defined $Ncal_Cmd) { + $Ncal_Cmd = which('ncal') || ''; + if ($Ncal_Cmd) { + my @out = grep { ! /^\s*$/ } map { s/^\s*//; $_ } `$Ncal_Cmd 9 1752`; + # September 1752 + #Mo 18 25 + #Tu 1 19 26 + #We 2 20 27 + #Th 14 21 28 + #Fr 15 22 29 + #Sa 16 23 30 + #Su 17 24 + my @pat = ( + qr/^\s*\S+\s+\d+$/, + qr/^\s*\S+\s+\d+\s+\d+\s*$/, + qr/^\s*\S+\s+\d+\s+\d+\s+\d+\s*$/, + qr/^\s*\S+\s+\d+\s+\d+\s+\d+\s*$/, + qr/^\s*\S+\s+\d+\s+\d+\s+\d+\s*$/, + qr/^\s*\S+\s+\d+\s+\d+\s+\d+\s*$/, + qr/^\s*\S+\s+\d+\s+\d+\s+\d+\s*$/, + qr/^\s*\S+\s+\d+\s+\d+\s*$/, + ); + if (@out == @pat) { + for my $i (0 .. $#out) { + if ($out[$i] !~ $pat[$i]) { + $Ncal_Cmd = ''; + last; + } + } + } + else { + $Ncal_Cmd = ''; + } + } + } + $Ncal_Cmd; +} + +sub day_epoch { + # in case our subclasses are lazy + my($self, $day, $month, $year) = @_; + $month ||= $self->month; + $year ||= $self->year; + Time::Local::timegm(0,0,0,1,$month,$year); +} + +sub _skips { + my $self = shift; + @_ ? $self->{skips} = shift : $self->{skips}; +} + +sub dow1st { (shift->dow1st_and_lastday)[0] } + +sub lastday { (shift->dow1st_and_lastday)[1] } + +sub _dmy_now { + my $self = shift; + my $ts = @_ ? shift : time; + my($d, $m, $y) = (localtime($ts))[3,4,5]; + ++$m; $y += 1900; + ($d, $m, $y); +} + +sub _dom_now { + my $self = shift; + my $ts = @_ ? shift : time; + my($d, $m, $y); + if ($ts =~ /^\d+$/) { + if (length $ts <= 2) { + ($d, $m, $y) = ($ts, $self->month, $self->year); + croak "invalid day of month (1 .. " . $self->lastday . ") '$ts'" + unless $ts >= 1 && $ts <= $self->lastday; + } + else { + ($d, $m, $y) = $self->_dmy_now($ts); + } + } + else { + ($y, $m, $d) = $ts =~ m{^(\d+)/(\d\d)/(\d\d)$}; + croak "invalid yyyy/mm/dd date string '$ts'" unless defined $d; + } + my($cy, $cm) = ($self->year, $self->month); + my $first = sprintf("%04d/%02d/%02d", $cy, $cm, 1); + my $last = sprintf("%04d/%02d/%02d", $cy, $cm, $self->lastday); + my $pivot = sprintf("%04d/%02d/%02d", $y, $m, $d); + return -1 if $pivot gt $last; + return 0 if $pivot lt $first; + $d; +} + +sub _summon_date_class { + my $self = shift; + my @tools; + if (my $c = $self->datetool) { + @tools = $c->_name; + } + else { + @tools = qw( timelocal datecalc datetime datemanip ncal cal ); + } + my($dc, @fails); + for my $tool (@tools) { + my $method = join('_', '', lc($tool), 'fails'); + if (my $f = $self->$method) { + push(@fails, [$tool, $f]); + } + else { + $dc = $self->_toolmap($tool); + last; + } + } + return $dc if $dc; + if (@tools == 1) { + croak "invalid date tool " . join(': ', @{$fails[0]}) if @tools == 1; + } + else { + croak join("\n", + "no valid date tool found:", + map(sprintf("%11s: %s", @$_), @fails), + "\n" + ); + } +} + +sub _dump_tests { + my $self = shift; + print "Time::Local : ", $self->_timelocal_fails || 1, "\n"; + print " Date::Calc : ", $self->_datecalc_fails || 1, "\n"; + print " DateTime : ", $self->_datetime_fails || 1, "\n"; + print "Date::Manip : ", $self->_datemanip_fails || 1, "\n"; + print " ncal : ", $self->_ncal_fails || 1, "\n"; + print " cal : ", $self->_cal_fails || 1, "\n"; +} + +sub _is_julian { + my $self = shift; + my $y = $self->year; + $y < 1752 || ($y == 1752 && $self->month <= 9); +} + +sub _timelocal_fails { + my $self = shift; + return "not installed" unless $self->_timelocal_present; + return "week-of-year numbering unsupported" if $self->weeknum; + my $y = $self->year; + return "only years between 1970 and 2038 supported" + if $y < 1970 || $y >= 2038; + return; +} + +sub _ncal_fails { + my $self = shift; + return "command not found" unless $self->_ncal_present; + return "week-of-year numbering not supported prior to 1752/09" + if $self->weeknum && $self->_is_julian; + return; +} + +sub _cal_fails { + my $self = shift; + return "command not found" unless $self->_cal_present; + return "week-of-year numbering not supported" if $self->weeknum; + return; +} + +sub _datecalc_fails { + my $self = shift; + return "not installed" unless $self->_datecalc_present; + return "historic mode prior to 1752/09 not supported" + if $self->historic && $self->_is_julian; + return; +} + +sub _datetime_fails { + my $self = shift; + return "not installed" unless $self->_datetime_present; + return "historic mode prior to 1752/09 not supported" + if $self->historic && $self->_is_julian; + return; +} + +sub _datemanip_fails { + my $self = shift; + return "not installed" unless $self->_datemanip_present; + return "historic mode prior to 1752/09 not supported" + if $self->historic && $self->_is_julian; + return; +} + +sub _timelocal_present { eval "require Time::Local"; return !$@ } +sub _datecalc_present { eval "require Date::Calc"; return !$@ } +sub _datetime_present { eval "require DateTime"; return !$@ } +sub _datemanip_present { eval "require Date::Manip"; return !$@ } +sub _ncal_present { shift->_ncal_cmd } +sub _cal_present { shift->_cal_cmd }; + +1; + +__END__ + +=head1 NAME + +HTML::CalendarMonth::DateTool - Base class for determining which date package to use for calendrical calculations. + +=head1 SYNOPSIS + + my $date_tool = HTML::CalendarMonth::DateTool->new( + year => $YYYY_year, + month => $one_thru_12_month, + weeknum => $weeknum_mode, + historic => $historic_mode, + datetool => $specific_datetool_if_desired, + ); + +=head1 DESCRIPTION + +This module attempts to utilize the best date calculation package +available on the current system. For most contemporary dates this +usually ends up being the internal Time::Local package of perl. For more +exotic dates, or when week number of the years are desired, other +methods are attempted including DateTime, Date::Calc, Date::Manip, and +the linux/unix 'ncal' or 'cal' commands. Each of these has a specific +subclass of this module offering the same utility methods needed by +HTML::CalendarMonth. + +=head1 METHODS + +=over + +=item new() + +Constructor. Takes the following parameters: + +=over + +=item year + +Year of calendar in question (required). If you are rendering exotic +dates (i.e. dates outside of 1970 to 2038) then something besides +Time::Local will be used for calendrical calculations. + +=item month + +Month of calendar in question (required). 1 through 12. + +=item weeknum + +Optional. When specified, will limit class excursions to those that are +currently set up for week of year calculations. + +=item historic + +Optional. If the the ncal or cal commands are available, use one of them +rather than other available date modules since these utilities +accurately handle some specific historical artifacts such as the +transition from Julian to Gregorian. + +=item datetool + +Optional. Mostly for debugging, this option can be used to indicate a +specific HTML::CalendarMonth::DateTool subclass for instantiation. The +value can be either the actual utility class, e.g., Date::Calc, or the +name of the CalendarMonth handler leaf class, e.g. DateCalc. Use 'ncal' +or 'cal', respectively, for the wrappers around those commands. + +=back + +=back + +There are number of methods automatically available: + +=over + +=item month() + +=item year() + +=item weeknum() + +=item historical() + +=item datetool() + +Accessors for the parameters provided to C above. + +=item dow1st() + +Returns the day of week number for the 1st of the C and C +specified during the call to C. Relies on the presence of +C. Should be 0..6 starting with Sun. + +=item lastday() + +Returns the last day of the month for the C and C specified +during the call to C. Relies on the presence of +C. + +=back + +=head1 Overridden methods + +Subclasses of this module must provide at least the C and +C methods. + +=over + +=item dow1st_and_lastday() + +Required. Provides a list containing the day of the week of the first +day of the month (0..6 starting with Sun) along with the last day of +the month. + +=item day_epoch() + +Optional unless interested in epoch values for wacky dates. For a given +day, and optionally C and C if they are different from +those specified in C, provide the unix epoch in seconds for that +day at midnight. + +=back + +If the subclass is expected to provide week of year numbers, three more +methods are necessary: + +=over + +=item dow() + +For a given day, and optionally C and C if they are +different from those specified in C, provide the day of week +number. (1=Sunday, 7=Saturday). + +=item add_days($days, $delta, $day, [$month], [$year]) + +For a given day, and optionally C and C if they are +different from those specified in C, provide a list of year, +month, and day once C days have been added. + +=item week_of_year($day, [$month], [$year]) + +For a given day, and optionally C and C if they are +different from those specified in C, provide a list with the week +number of the year along with the year. (some days of a particular year +can end up belonging to the prior or following years). + +=back + +=head1 AUTHOR + +Matthew P. Sisk, EFE + +=head1 COPYRIGHT + +Copyright (c) 2010 Matthew P. Sisk. All rights reserved. All wrongs +revenged. This program is free software; you can redistribute it and/or +modify it under the same terms as Perl itself. + +=head1 SEE ALSO + +HTML::CalendarMonth(3), Time::Local(3), DateTime(3), Date::Calc(3), +Date::Manip(3), cal(1) diff --git a/1.25/lib/HTML/CalendarMonth/DateTool/Cal.pm b/1.25/lib/HTML/CalendarMonth/DateTool/Cal.pm new file mode 100644 index 0000000..2d63e00 --- /dev/null +++ b/1.25/lib/HTML/CalendarMonth/DateTool/Cal.pm @@ -0,0 +1,37 @@ +package HTML::CalendarMonth::DateTool::Cal; +BEGIN { + $HTML::CalendarMonth::DateTool::Cal::VERSION = '1.25'; +} + +# Interface to unix 'cal' command + +use strict; +use warnings; +use Carp; + +use base qw( HTML::CalendarMonth::DateTool ); + +sub dow1st_and_lastday { + my($self, $month, $year) = @_; + $month ||= $self->month; + $year ||= $self->year; + my $cmd = $self->_cal_cmd or croak "cal command not found\n"; + + my @cal = grep(!/^\s*$/,`$cmd $month $year`); + chomp @cal; + my @days = grep(/\d+/,split(/\s+/,$cal[2])); + my $dow1st = 6 - $#days; + my($lastday) = $cal[$#cal] =~ /(\d+)\s*$/; + # With dow1st and lastday, one builds a calendar sequentially. + # Historically, in particular Sep 1752, days have been skipped. Here's + # the chance to catch that. + $self->_skips(undef); + if ($month == 9 && $year == 1752) { + my %skips; + grep(++$skips{$_}, 3 .. 13); + $self->_skips(\%skips); + } + ($dow1st, $lastday); +} + +1; diff --git a/1.25/lib/HTML/CalendarMonth/DateTool/DateCalc.pm b/1.25/lib/HTML/CalendarMonth/DateTool/DateCalc.pm new file mode 100644 index 0000000..38cbcbb --- /dev/null +++ b/1.25/lib/HTML/CalendarMonth/DateTool/DateCalc.pm @@ -0,0 +1,68 @@ +package HTML::CalendarMonth::DateTool::DateCalc; +BEGIN { + $HTML::CalendarMonth::DateTool::DateCalc::VERSION = '1.25'; +} + +# Interface to Date::Calc + +use strict; +use warnings; +use Carp; + +use base qw( HTML::CalendarMonth::DateTool ); + +use Date::Calc qw( + Days_in_Month + Day_of_Week + Add_Delta_Days + Weeks_in_Year + Week_of_Year + Week_Number + Mktime +); + +sub dow1st_and_lastday { + my($self, $month, $year) = @_; + $month ||= $self->month; + $year ||= $self->year; + ($self->dow(1), Days_in_Month($year, $month)); +} + +sub day_epoch { + my($self, $day, $month, $year) = @_; + $month ||= $self->month; + $year ||= $self->year; + Mktime($year, $month, $day, 0, 0, 0); +} + +sub dow { + my($self, $day, $month, $year) = @_; + $day || croak "day required.\n"; + $month ||= $self->month; + $year ||= $self->year; + # Date::Calc uses 1..7 as indicies in the week, starting with Monday. + # Convert to 0..6, starting with Sunday. + Day_of_Week($year, $month, $day) % 7; +} + +sub add_days { + my($self, $delta, $day, $month, $year) = @_; + defined $delta || croak "delta (in days) required.\n"; + $day || croak "day required.\n"; + $month ||= $self->month; + $year ||= $self->year; + my($y, $m, $d) = Add_Delta_Days($year, $month, $day, $delta); + ($d, $m, $y); +} + +sub week_of_year { + my($self, $day, $month, $year) = @_; + $day || croak "day required.\n"; + $month ||= $self->month; + $year ||= $self->year; + my $week; + ($week, $year) = Week_of_Year($year, $month, $day); + ($year, $week); +} + +1; diff --git a/1.25/lib/HTML/CalendarMonth/DateTool/DateManip.pm b/1.25/lib/HTML/CalendarMonth/DateTool/DateManip.pm new file mode 100644 index 0000000..d13283a --- /dev/null +++ b/1.25/lib/HTML/CalendarMonth/DateTool/DateManip.pm @@ -0,0 +1,73 @@ +package HTML::CalendarMonth::DateTool::DateManip; +BEGIN { + $HTML::CalendarMonth::DateTool::DateManip::VERSION = '1.25'; +} + +# Interface to Date::Manip + +use strict; +use warnings; +use Carp; + +use base qw( HTML::CalendarMonth::DateTool ); + +use Date::Manip qw( + Date_DaysInMonth + Date_DayOfWeek + DateCalc + UnixDate + Date_SecsSince1970 + ParseDateDelta +); + +sub dow1st_and_lastday { + my($self, $month, $year) = @_; + $month ||= $self->month; + $year ||= $self->year; + ($self->dow(1), Date_DaysInMonth($month, $year)); +} + +sub day_epoch { + my($self, $day, $month, $year) = @_; + $day || croak "day required.\n"; + $month ||= $self->month; + $year ||= $self->year; + Date_SecsSince1970($month, $day, $year, 0, 0, 0); +} + +sub dow { + # Date::Manip uses 1..7 as indicies in the week, starting with Monday. + # Convert to 0..6 starting with Sunday. + my($self, $day, $month, $year) = @_; + $day || croak "day required.\n"; + $month ||= $self->month; + $year ||= $self->year; + Date_DayOfWeek($month, $day, $year) % 7; +} + +sub add_days { + my($self, $delta, $day, $month, $year) = @_; + defined $delta || croak "delta (in days) required.\n"; + $day || croak "day required.\n"; + $month ||= $self->month; + $year ||= $self->year; + my $date = DateCalc( + sprintf("%04d%02d%02d", $year, $month, $day), + "$delta days" + ); + my($y, $m, $d) = $date =~ /^(\d{4})(\d\d)(\d\d)/; + $_ += 0 foreach ($y, $m, $d); + ($d, $m, $y); +} + +sub week_of_year { + my($self, $day, $month, $year) = @_; + $day || croak "day required.\n"; + $month ||= $self->month; + $year ||= $self->year; + my $week = UnixDate(sprintf("%04d%02d%02d", $year, $month, $day), '%U'); + $week += 0; + ($year, $week); +} + +1; diff --git a/1.25/lib/HTML/CalendarMonth/DateTool/DateTime.pm b/1.25/lib/HTML/CalendarMonth/DateTool/DateTime.pm new file mode 100644 index 0000000..a0b98b3 --- /dev/null +++ b/1.25/lib/HTML/CalendarMonth/DateTool/DateTime.pm @@ -0,0 +1,85 @@ +package HTML::CalendarMonth::DateTool::DateTime; +BEGIN { + $HTML::CalendarMonth::DateTool::DateTime::VERSION = '1.25'; +} + +# Interface to DateTime + +use strict; +use warnings; +use Carp; + +use base qw( HTML::CalendarMonth::DateTool ); + +use DateTime; + +sub dow1st_and_lastday { + my($self, $month, $year) = @_; + $month ||= $self->month; + $year ||= $self->year; + my $lastday = $self->_last_dom_dt($year, $month); + my $dow1st = $self->dow(1); + ($dow1st, $lastday->day); +} + +sub day_epoch { + my($self, $day, $month, $year) = @_; + $day || croak "day required.\n"; + $month ||= $self->month; + $year ||= $self->year; + my $dt = $self->_new_dt($year, $month, $day); + $dt->epoch; +} + +sub dow { + my($self, $day, $month, $year) = @_; + $day || croak "day required.\n"; + $month ||= $self->month; + $year ||= $self->year; + my $dt = $self->_new_dt($year, $month, $day); + # convert from 1..7, starting with Mon, to 0..6, starting with Sun + $dt->dow % 7; +} + +sub add_days { + my($self, $delta, $day, $month, $year) = @_; + defined $delta || croak "delta (in days) required.\n"; + $day || croak "day required.\n"; + $month ||= $self->month; + $year ||= $self->year; + my $dt = $self->_new_dt($year, $month, $day); + $dt->add(days => $delta); + ($dt->day, $dt->month, $dt->year); +} + +sub week_of_year { + my($self, $day, $month, $year) = @_; + $day || croak "day required.\n"; + $month ||= $self->month; + $year ||= $self->year; + my $dt = $self->_new_dt($year, $month, $day); + # returns ($year, $week) + $dt->week; +} + +sub _new_dt { + my $self = shift; + my($year, $month, $day) = @_; + $year or croak "year and month required\n"; + my %parms = (year => $year); + $parms{month} = $month if $month; + $parms{day} = $day if $day; + $parms{hour} = 0; + $parms{minute} = 0; + $parms{second} = 0; + DateTime->new(%parms); +} + +sub _last_dom_dt { + my $self = shift; + my($year, $month) = @_; + $year && $month or croak "year and month required.\n"; + DateTime->last_day_of_month(year => $year, month => $month); +} + +1; diff --git a/1.25/lib/HTML/CalendarMonth/DateTool/Ncal.pm b/1.25/lib/HTML/CalendarMonth/DateTool/Ncal.pm new file mode 100644 index 0000000..22fff0f --- /dev/null +++ b/1.25/lib/HTML/CalendarMonth/DateTool/Ncal.pm @@ -0,0 +1,126 @@ +package HTML::CalendarMonth::DateTool::Ncal; +BEGIN { + $HTML::CalendarMonth::DateTool::Ncal::VERSION = '1.25'; +} + +# Interface to linux 'ncal' command + +use strict; +use warnings; +use Carp; + +use base qw( HTML::CalendarMonth::DateTool ); + +sub dow1st_and_lastday { + my($self, $month, $year) = @_; + $month ||= $self->month; + $year ||= $self->year; + if (my $r = $self->{_res}{$year}{$month}) { + return(@$r); + } + my $cmd = $self->_ncal_cmd or croak "ncal command not found\n"; + my @cal = grep(!/^\s*$/,`$cmd -w $month $year`); + shift @cal if $cal[0] =~ /\D+/; + my @woy; + if ($cal[-1] =~ /^\s*\d+/) { + @woy = (pop @cal) =~ /(\d+)/g; + } + my($dow1st, %woy, %dow); + my $last_day = 0; + for my $di (0 .. $#cal) { + my $dow_row = $cal[$di]; + $dow_row =~ s/^\s+//; + $dow_row =~ s/\s+$//; + $dow_row =~ s/\s{3,}/ 0 /g; + $dow_row =~ s/\D+/ /g; + $dow_row =~ s/^\s+//; + my @days = split(/\s+/, $dow_row); + $dow1st = ($di + 1) % 7 if !$dow1st && $days[0]; + for my $i (0 .. $#days) { + my $d = $days[$i] || next; + $last_day = $d if $d > $last_day; + $woy{$d} = $woy[$i]; + $dow{$d} = $di; + } + } + # catch switchover from Julian to Gregorian + $self->_skips(undef); + if ($month == 9 && $year == 1752) { + my %skips; + grep(++$skips{$_}, 3 .. 13); + $self->_skips(\%skips); + } + delete $self->{_woy}; + delete $self->{_dow}; + delete $self->{_res}; + $self->{_woy}{$year}{$month} = \%woy if %woy; + $self->{_dow}{$year}{$month} = \%dow if %dow; + $self->{_res}{$year}{$month} = [$dow1st, $last_day]; + ($dow1st, $last_day); +} + +sub week_of_year { + my($self, $day, $month, $year) = @_; + $month ||= $self->month; + $year ||= $self->year; + croak "week of year not supported by ncal prior to 10/1752" + if $year < 1752 || ($year == 1752 && $month < 10); + $self->dow1st_and_lastday unless $self->{_woy}{$year}{$month}; + $self->{_woy}{$year}{$month}{$day}; +} + +sub dow { + my($self, $day, $month, $year) = @_; + $month ||= $self->month; + $year ||= $self->year; + $self->dow1st_and_lastday unless $self->{_dow}{$year}{$month}; + $self->{_dow}{$year}{$month}{$day}; +} + +sub add_days { + my($self, $delta, $day, $month, $year) = @_; + $month ||= $self->month; + $year ||= $self->year; + if ($delta <= 0) { + $delta = abs($delta); + if ($delta < $day) { + return($day - $delta, $month, $year); + } + else { + my @days = reverse 1 .. $day; + while (@days < $delta) { + --$month; + if ($month <= 0) { + --$year; $month = 12; + } + my($dow1st, $last_day) = $self->dow1st_and_lastday($month, $year); + push(@days, reverse 1 .. $last_day); + } + return($days[$delta], $month, $year); + } + } + else { + my $last_day; + if (my $res = $self->{_res}{$year}{$month}) { + $last_day = $res->[1]; + } + else { + $last_day = ($self->dow1st_and_lastday($month, $year))[1]; + } + if ($delta + $day <= $last_day) { + return($day + $delta, $month, $year); + } + my @days = $day .. $last_day; + while (@days < $delta) { + ++$month; + if ($month > 12) { + ++$year; $month = 1; + } + my($dow1st, $last_day) = $self->dow1st_and_lastday($month, $year); + push(@days, 1 .. $last_day); + } + return($days[$delta], $month, $year); + } +} + +1; diff --git a/1.25/lib/HTML/CalendarMonth/DateTool/TimeLocal.pm b/1.25/lib/HTML/CalendarMonth/DateTool/TimeLocal.pm new file mode 100644 index 0000000..e04321b --- /dev/null +++ b/1.25/lib/HTML/CalendarMonth/DateTool/TimeLocal.pm @@ -0,0 +1,39 @@ +package HTML::CalendarMonth::DateTool::TimeLocal; +BEGIN { + $HTML::CalendarMonth::DateTool::TimeLocal::VERSION = '1.25'; +} + +# Interface to Time::Local + +use strict; +use warnings; +use Carp; + +use base qw( HTML::CalendarMonth::DateTool ); + +use Time::Local; + +sub dow1st_and_lastday { + my($self, $month, $year) = @_; + $month ||= $self->month; + $year ||= $self->year; + # map month to 0-12 + --$month; + # years since 1900...hooh-rah for POSIX... + $year -= 1900; + my $nmonth = $month + 1; + my $nyear = $year; + if ($nmonth > 11) { + # Happy new year + $nmonth = 0; + ++$nyear; + } + # Leave dow of 1st in 0-based format + my $dow1st = (gmtime(Time::Local::timegm(0,0,0,1,$month,$year)))[6]; + # Last day is one day prior to 1st of month after + my $lastday = (gmtime(Time::Local::timegm(0,0,0,1,$nmonth,$nyear) + - 60*60*24))[3]; + ($dow1st, $lastday); +} + +1; diff --git a/1.25/lib/HTML/CalendarMonth/Locale.pm b/1.25/lib/HTML/CalendarMonth/Locale.pm new file mode 100644 index 0000000..248a90c --- /dev/null +++ b/1.25/lib/HTML/CalendarMonth/Locale.pm @@ -0,0 +1,441 @@ +package HTML::CalendarMonth::Locale; +BEGIN { + $HTML::CalendarMonth::Locale::VERSION = '1.25'; +} + +# Front end class around DateTime::Locale. In addition to providing +# access to the DT::Locale class and locale-specific instance, this +# class prepares some other hashes and lookups utilized by +# HTML::CalendarMonth. + +use strict; +use warnings; +use Carp; + +use DateTime::Locale 0.45; + +my %Register; + +sub new { + my $class = shift; + my $self = {}; + bless $self, $class; + my %parms = @_; + my $id = $parms{id} or croak "Locale id required (eg 'en_US')\n"; + $self->{id} = $id; + $self->{full_days} = defined $parms{full_days} ? $parms{full_days} : 0; + $self->{full_months} = defined $parms{full_months} ? $parms{full_months} : 1; + unless ($Register{$id}) { + $Register{$id} = $self->locale->load($id) + or croak "Problem loading locale '$id'\n"; + } + $self; +} + +sub locale { 'DateTime::Locale' } + +sub loc { $Register{shift->id} } + +sub locales { shift->locale->ids } + +sub id { shift->{id} } +sub full_days { shift->{full_days} } +sub full_months { shift->{full_months} } + +sub first_day_of_week { shift->loc->first_day_of_week % 7 } + +sub days { + my $self = shift; + my $id = $self->id; + unless ($Register{$id}{days}) { + my $method = $self->full_days > 0 ? 'day_stand_alone_wide' + : 'day_stand_alone_abbreviated'; + # adjust to H::CM standard expectation, 1st day Sun + # Sunday is first, regardless of what the calendar considers to be + # the first day of the week + my @days = @{$self->loc->$method}; + unshift(@days, pop @days); + $Register{$id}{days} = \@days; + } + wantarray ? @{$Register{$id}{days}} : $Register{$id}{days}; +} + +sub narrow_days { + my $self = shift; + my $id = $self->id; + unless ($Register{$id}{narrow_days}) { + # Sunday is first, regardless of what the calendar considers to be + # the first day of the week + my @days = @{ $self->loc->day_stand_alone_narrow }; + unshift(@days, pop @days); + $Register{$id}{narrow_days} = \@days; + } + wantarray ? @{$Register{$id}{narrow_days}} : $Register{$id}{narrow_days}; +} + +sub months { + my $self = shift; + my $id = $self->id; + unless ($Register{$id}{months}) { + my $method = $self->full_months > 0 ? 'month_stand_alone_wide' + : 'month_stand_alone_abbreviated'; + $Register{$id}{months} = [@{$self->loc->$method}]; + } + wantarray ? @{$Register{$id}{months}} : $Register{$id}{months}; +} + +sub narrow_months { + my $self = shift; + my $id = $self->id; + $Register{$id}{narrow_months} ||= [$self->loc->month_stand_alone_narrow]; + wantarray ? @{$Register{$id}{narrow_months}} : $Register{$id}{narrow_months}; +} + +sub days_minmatch { + my $self = shift; + $Register{$self->id}{days_mm} + ||= $self->lc_minmatch_hash($self->days); +} +*minmatch = \&days_minmatch; + +sub _days_minmatch_pattern { + my $dmm = shift->days_minmatch; + join('|', sort keys %$dmm); +} +*minmatch_pattern = \&_days_minmatch_pattern; + + +sub months_minmatch { + my $self = shift; + $Register{$self->id}{months_mm} + ||= $self->lc_minmatch_hash($self->months); +} + +sub _months_minmatch_pattern { + my $mmm = shift->months_minmatch; + join('|', sort keys %$mmm); +} + +sub daynums { + my $self = shift; + my $id = $self->id; + unless ($Register{$id}{daynum}) { + my %daynum; + my $days = $self->days; + $daynum{$days->[$_]} = $_ foreach 0 .. $#$days; + $Register{$id}{daynum} = \%daynum; + } + $Register{$id}{daynum}; +} + +sub _daymatch { + my($self, $day) = @_; + return unless defined $day; + if ($day =~ /^\d+$/) { + $day %= 7; + return($day, $self->days->[$day]); + } + my $p = $self->_days_minmatch_pattern; + if ($day =~ /^($p)/i) { + $day = $self->days_minmatch->{lc $1}; + return($self->daynums->{$day}, $day); + } + return (); +} + +sub daynum { (shift->_daymatch(@_))[0] } +sub dayname { (shift->_daymatch(@_))[1] } + +sub monthnums { + my $self = shift; + my $id = $self->id; + unless ($Register{$id}{monthnum}) { + my %monthnum; + my $months = $self->months; + $monthnum{$months->[$_]} = $_ foreach 0 .. $#$months; + $Register{$id}{monthnum} = \%monthnum; + } + $Register{$id}{monthnum}; +} + +sub _monthmatch { + my($self, $mon) = @_; + return unless defined $mon; + if ($mon =~ /^\d+$/) { + $mon %= 12; + return($mon, $self->months->[$mon]); + } + my $p = $self->_months_minmatch_pattern; + if ($mon =~ /^($p)/i) { + $mon = $self->months_minmatch->{lc $1}; + return($self->monthnums->{$mon}, $mon); + } + return (); +} + +sub monthnum { (shift->_monthmatch(@_))[0] } +sub monthname { (shift->_monthmatch(@_))[1] } + +### + +sub locale_map { + my $self = shift; + my %map; + foreach my $id ($self->locales) { + $map{$id} = $self->locale->load($id)->name; + } + wantarray ? %map : \%map; +} + +### + +sub lc_minmatch_hash { + # given a list, provide a reverse lookup of case-insensitive minimal + # values for each label in the list + my $whatever = shift; + my @orig_labels = @_; + my @labels = map { lc $_ } @orig_labels; + my $cc = 1; + my %minmatch; + while (@labels) { + my %scratch; + foreach my $i (0 .. $#labels) { + my $str = $labels[$i]; + my $chrs = substr($str, 0, $cc); + $scratch{$chrs} ||= []; + push(@{$scratch{$chrs}}, $i); + } + my @keep_i; + foreach (keys %scratch) { + if (@{$scratch{$_}} == 1) { + $minmatch{$_} = $orig_labels[$scratch{$_}[0]]; + } + else { + push(@keep_i, @{$scratch{$_}}); + } + } + @labels = @labels[@keep_i]; + @orig_labels = @orig_labels[@keep_i]; + ++$cc; + } + \%minmatch; +} + +sub minmatch_hash { + # given a list, provide a reverse lookup of minimal values for each + # label in the list + my $whatever = shift; + my @labels = @_; + my $cc = 1; + my %minmatch; + while (@labels) { + my %scratch; + foreach my $i (0 .. $#labels) { + my $str = $labels[$i]; + my $chrs = substr($str, 0, $cc); + $scratch{$chrs} ||= []; + push(@{$scratch{$chrs}}, $i); + } + my @keep_i; + foreach (keys %scratch) { + if (@{$scratch{$_}} == 1) { + $minmatch{$_} = $labels[$scratch{$_}[0]]; + } + else { + push(@keep_i, @{$scratch{$_}}); + } + } + @labels = @labels[@keep_i]; + ++$cc; + } + \%minmatch; +} + +1; + +__END__ + +=head1 NAME + +HTML::CalendarMonth::Locale - Front end class for DateTime::Locale + +=head1 SYNOPSIS + + use HTML::CalendarMonth::Locale; + + my $loc = HTML::CalendarMonth::Locale->new( id => 'en_US' ); + + # list of days of the week for locale + my @days = $loc->days; + + # list of months of the year for locale + my @months = $loc->months; + + # the name of the current locale, as supplied the id parameter to + # new() + my $locale_name = $loc->id; + + # the actual DateTime::Locale object + my $loc = $loc->loc; + + 1; + +=head1 DESCRIPTION + +HTML::CalendarMonth utilizes the powerful locale capabilities of +DateTime::Locale for rendering its calendars. The default locale is +'en_US' but many others are available. To see this list, invoke the +class method HTML::CalendarMonth::Locale->locales() which in turn +invokes DateTime::Locale::ids(). + +This module is mostly intended for internal usage within +HTML::CalendarMonth, but some of its functionality may be of use for +developers: + +=head1 METHODS + +=over + +=item new() + +Constructor. Takes the following parameters: + +=over + +=item id + +Locale id, e.g. 'en_US'. + +=item full_days + +Specifies whether full day names or their abbreviations are desired. +Default 0, use abbreviated days. + +=item full_months + +Specifies whether full month names or their abbreviations are desired. +Default 1, use full months. + +=back + +=item id() + +Returns the locale id used during object construction. + +=item locale() + +Accessor method for the DateTime::Locale class, which in turn offers +several class methods of specific interest. See L. + +=item locale_map() + +Returns a hash of all available locales, mapping their id to their +full name. + +=item loc() + +Accessor method for the DateTime::Locale instance as specified by C. +See L. + +=item locales() + +Lists all available locale ids. Equivalent to locale()->ids(), or +DateTime::Locale->ids(). + +=item days() + +Returns a list of days of the week, Sunday first. These are the actual +unique day strings used for rendering calendars, so depending on which +attributes were provided to C, this list will either be +abbreviations or full names. The default uses abbreviated day names. +Returns a list in list context or an array ref in scalar context. + +=item narrow_days() + +Returns a list of short day abbreviations, beginning with Sunday. The +narrow abbreviations are not guaranteed to be unique (i.e. 'S' for both +Sat and Sun). + +=item days_minmatch() + +Provides a hash reference containing minimal case-insensitive match +strings for each day of the week, e.g., 'sa' for Saturday, 'm' for +Monday, etc. + +=item months() + +Returns a list of months of the year, beginning with January. Depending +on which attributes were provided to C, this list will either be +full names or abbreviations. The default uses full names. Returns a list +in list context or an array ref in scalar context. + +=item narrow_months() + +Returns a list of short month abbreviations, beginning with January. The +narrow abbreviations are not guaranteed to be unique. + +=item months_minmatch() + +Provides a hash reference containing minimal case-insensitive match +strings for each month of the year, e.g., 'n' for November, 'ja' for +January, 'jul' for July, 'jun' for June, etc. + +=item daynums() + +Provides a hash reference containing day of week indices for each fully +qualified day name as returned by days(). + +=item daynum($day) + +Provides the day of week index for a particular day name. + +=item dayname($day) + +Provides the fully qualified day name for a given string or day index. + +=item monthnums() + +Provides a hash reference containing month of year indices for each +fully qualified month name as returned by months(). + +=item monthnum($month) + +Provides the month of year index for a particular month name. + +=item monthname($month) + +Provides the month name for a given string or month index. + +=item minmatch_hash(@list) + +This is the method used to generate the case-insensitive minimal match +hash referenced above. Given an arbitrary list, a hash reference will +be returned with minimal match strings as keys and the original strings +as values. + +=item lc_minmatch_hash(@list) + +Same as minmatch_hash, except keys are forced to lower case. + +=item first_day_of_week() + +Returns a number from 0 to 6 representing the first day of the week for +this locale, where 0 represents Sunday. + +=back + +=head1 AUTHOR + +Matthew P. Sisk, EFE + +=head1 COPYRIGHT + +Copyright (c) 2010 Matthew P. Sisk. All rights reserved. All wrongs +revenged. This program is free software; you can redistribute it and/or +modify it under the same terms as Perl itself. + +=head1 SEE ALSO + +HTML::CalendarMonth(3), DateTime::Locale(3) + +=for Pod::Coverage minmatch minmatch_pattern diff --git a/1.25/t/00_basic.t b/1.25/t/00_basic.t new file mode 100755 index 0000000..4034ae6 --- /dev/null +++ b/1.25/t/00_basic.t @@ -0,0 +1,6 @@ +use Test::More tests => 3; +BEGIN { + use_ok('HTML::CalendarMonth'); + use_ok('HTML::CalendarMonth::Locale'); + use_ok('HTML::CalendarMonth::DateTool'); +} diff --git a/1.25/t/01_autodetect.t b/1.25/t/01_autodetect.t new file mode 100755 index 0000000..3ecc0cf --- /dev/null +++ b/1.25/t/01_autodetect.t @@ -0,0 +1,24 @@ +#!/usr/bin/perl + +use strict; +use FindBin; +use lib $FindBin::RealBin; + +use testload; + +use HTML::CalendarMonth::DateTool; + +my($test_count, $detected); +BEGIN { + $test_count = bulk_count() + 1; + eval { $detected = HTML::CalendarMonth::DateTool->new }; +} + +use Test::More tests => $test_count; + +ok($detected, 'auto-detected a datetool'); + +SKIP: { + skip("no datetools installed", $test_count - 1) unless $detected; + check_bulk_with_datetool(); +} diff --git a/1.25/t/02_timelocal.t b/1.25/t/02_timelocal.t new file mode 100755 index 0000000..4611847 --- /dev/null +++ b/1.25/t/02_timelocal.t @@ -0,0 +1,23 @@ +#!/usr/bin/perl + +use strict; +use FindBin; +use lib $FindBin::RealBin; + +use testload; + +my($test_count, $method); +BEGIN { + $method = 'Time::Local'; + $test_count = bulk_count() + odd_count() + 2; +} + +use Test::More tests => $test_count; + +SKIP: { + eval "use $method"; + skip("$method not installed", $test_count) if $@; + check_datetool($method); + check_bulk_with_datetool($method); + check_odd_with_datetool($method); +} diff --git a/1.25/t/03_datetime.t b/1.25/t/03_datetime.t new file mode 100755 index 0000000..d152381 --- /dev/null +++ b/1.25/t/03_datetime.t @@ -0,0 +1,24 @@ +#!/usr/bin/perl + +use strict; +use FindBin; +use lib $FindBin::RealBin; + +use testload; + +my($test_count, $method); +BEGIN { + $method = 'DateTime'; + $test_count = bulk_count() + odd_count() + woy_count() + 2; +} + +use Test::More tests => $test_count; + +SKIP: { + eval "use $method"; + skip("$method not installed", $test_count) if $@; + check_datetool($method); + check_bulk_with_datetool($method); + check_odd_with_datetool($method); + check_woy_with_datetool($method); +} diff --git a/1.25/t/04_datemanip.t b/1.25/t/04_datemanip.t new file mode 100755 index 0000000..dd6046f --- /dev/null +++ b/1.25/t/04_datemanip.t @@ -0,0 +1,24 @@ +#!/usr/bin/perl + +use strict; +use FindBin; +use lib $FindBin::RealBin; + +use testload; + +my($test_count, $method); +BEGIN { + $method = 'Date::Manip'; + $test_count = bulk_count() + odd_count() + woy_count() + 2; +} + +use Test::More tests => $test_count; + +SKIP: { + eval "use $method"; + skip("$method not installed", $test_count) if $@; + check_datetool($method); + check_bulk_with_datetool($method); + check_odd_with_datetool($method); + check_woy_with_datetool($method); +} diff --git a/1.25/t/05_datecalc.t b/1.25/t/05_datecalc.t new file mode 100755 index 0000000..c4e3ca9 --- /dev/null +++ b/1.25/t/05_datecalc.t @@ -0,0 +1,24 @@ +#!/usr/bin/perl + +use strict; +use FindBin; +use lib $FindBin::RealBin; + +use testload; + +my($test_count, $method); +BEGIN { + $method = 'Date::Calc'; + $test_count = bulk_count() + odd_count() + woy_count() + 2; +} + +use Test::More tests => $test_count; + +SKIP: { + eval "use $method"; + skip("$method not installed", $test_count) if $@; + check_datetool($method); + check_bulk_with_datetool($method); + check_odd_with_datetool($method); + check_woy_with_datetool($method); +} diff --git a/1.25/t/06_cal.t b/1.25/t/06_cal.t new file mode 100755 index 0000000..b2807a9 --- /dev/null +++ b/1.25/t/06_cal.t @@ -0,0 +1,26 @@ +#!/usr/bin/perl + +use strict; +use FindBin; +use lib $FindBin::RealBin; + +use testload; + +my($test_count, $method); +BEGIN { + $method = 'cal'; + $test_count = bulk_count() + odd_count() + 3; +} + +use Test::More tests => $test_count; + +use constant DTC => 'HTML::CalendarMonth::DateTool'; + +use_ok(DTC); + +SKIP: { + skip("$method not installed", $test_count - 1) unless DTC->_cal_cmd; + check_datetool($method); + check_bulk_with_datetool($method); + check_odd_with_datetool($method); +} diff --git a/1.25/t/07_ncal.t b/1.25/t/07_ncal.t new file mode 100644 index 0000000..f5ef15b --- /dev/null +++ b/1.25/t/07_ncal.t @@ -0,0 +1,27 @@ +#!/usr/bin/perl + +use strict; +use FindBin; +use lib $FindBin::RealBin; + +use testload; + +my($test_count, $method); +BEGIN { + $method = 'ncal'; + $test_count = bulk_count() + odd_count() + woy_count() + 3; +} + +use Test::More tests => $test_count; + +use constant DTC => 'HTML::CalendarMonth::DateTool'; + +use_ok(DTC); + +SKIP: { + skip("$method not installed", $test_count - 1) unless DTC->_ncal_cmd; + check_datetool($method); + check_bulk_with_datetool($method); + check_odd_with_datetool($method); + check_woy_with_datetool($method); +} diff --git a/1.25/t/20_i8n.t b/1.25/t/20_i8n.t new file mode 100755 index 0000000..9631c65 --- /dev/null +++ b/1.25/t/20_i8n.t @@ -0,0 +1,18 @@ +#!/usr/bin/perl + +use strict; +use FindBin; +use lib $FindBin::RealBin; + +use testload; + +my $test_count; +BEGIN { $test_count = i8n_count() + 1 } + +use Test::More tests => $test_count; + +use HTML::CalendarMonth::Locale; + +my @stoof = HTML::CalendarMonth::Locale->locales; +ok(@stoof > 20, 'i8n: ' . scalar @stoof . ' locale ids retreived'); +check_i8n(); diff --git a/1.25/t/21_narrow.t b/1.25/t/21_narrow.t new file mode 100644 index 0000000..0857e61 --- /dev/null +++ b/1.25/t/21_narrow.t @@ -0,0 +1,16 @@ +#!/usr/bin/perl + +use strict; +use FindBin; +use lib $FindBin::RealBin; + +use testload; + +my $test_count; +BEGIN { $test_count = narrow_count() } + +use Test::More tests => $test_count; + +use HTML::CalendarMonth::Locale; + +check_narrow(); diff --git a/1.25/t/author-critic.t b/1.25/t/author-critic.t new file mode 100644 index 0000000..7f47387 --- /dev/null +++ b/1.25/t/author-critic.t @@ -0,0 +1,19 @@ +#!perl + +BEGIN { + unless ($ENV{AUTHOR_TESTING}) { + require Test::More; + Test::More::plan(skip_all => 'these tests are for testing by the author'); + } +} + + +use strict; +use warnings; + +use Test::More; +use English qw(-no_match_vars); + +eval "use Test::Perl::Critic"; +plan skip_all => 'Test::Perl::Critic required to criticise code' if $@; +all_critic_ok(); diff --git a/1.25/t/dat/bulk.dat b/1.25/t/dat/bulk.dat new file mode 100644 index 0000000..92f50d0 --- /dev/null +++ b/1.25/t/dat/bulk.dat @@ -0,0 +1,288 @@ +2010/01 1 +
January2010
SunMonTueWedThuFriSat
12
3456789
10111213141516
17181920212223
24252627282930
31
+2010/01 2 +
January2010
MonTueWedThuFriSatSun
123
45678910
11121314151617
18192021222324
25262728293031
+2010/02 1 +
February2010
SunMonTueWedThuFriSat
123456
78910111213
14151617181920
21222324252627
28
+2010/02 2 +
February2010
MonTueWedThuFriSatSun
1234567
891011121314
15161718192021
22232425262728
+2010/03 1 +
March2010
SunMonTueWedThuFriSat
123456
78910111213
14151617181920
21222324252627
28293031
+2010/03 2 +
March2010
MonTueWedThuFriSatSun
1234567
891011121314
15161718192021
22232425262728
293031
+2010/04 1 +
April2010
SunMonTueWedThuFriSat
123
45678910
11121314151617
18192021222324
252627282930
+2010/04 2 +
April2010
MonTueWedThuFriSatSun
1234
567891011
12131415161718
19202122232425
2627282930
+2010/05 1 +
May2010
SunMonTueWedThuFriSat
1
2345678
9101112131415
16171819202122
23242526272829
3031
+2010/05 2 +
May2010
MonTueWedThuFriSatSun
12
3456789
10111213141516
17181920212223
24252627282930
31
+2010/06 1 +
June2010
SunMonTueWedThuFriSat
12345
6789101112
13141516171819
20212223242526
27282930
+2010/06 2 +
June2010
MonTueWedThuFriSatSun
123456
78910111213
14151617181920
21222324252627
282930
+2010/07 1 +
July2010
SunMonTueWedThuFriSat
123
45678910
11121314151617
18192021222324
25262728293031
+2010/07 2 +
July2010
MonTueWedThuFriSatSun
1234
567891011
12131415161718
19202122232425
262728293031
+2010/08 1 +
August2010
SunMonTueWedThuFriSat
1234567
891011121314
15161718192021
22232425262728
293031
+2010/08 2 +
August2010
MonTueWedThuFriSatSun
1
2345678
9101112131415
16171819202122
23242526272829
3031
+2010/09 1 +
September2010
SunMonTueWedThuFriSat
1234
567891011
12131415161718
19202122232425
2627282930
+2010/09 2 +
September2010
MonTueWedThuFriSatSun
12345
6789101112
13141516171819
20212223242526
27282930
+2010/10 1 +
October2010
SunMonTueWedThuFriSat
12
3456789
10111213141516
17181920212223
24252627282930
31
+2010/10 2 +
October2010
MonTueWedThuFriSatSun
123
45678910
11121314151617
18192021222324
25262728293031
+2010/11 1 +
November2010
SunMonTueWedThuFriSat
123456
78910111213
14151617181920
21222324252627
282930
+2010/11 2 +
November2010
MonTueWedThuFriSatSun
1234567
891011121314
15161718192021
22232425262728
2930
+2010/12 1 +
December2010
SunMonTueWedThuFriSat
1234
567891011
12131415161718
19202122232425
262728293031
+2010/12 2 +
December2010
MonTueWedThuFriSatSun
12345
6789101112
13141516171819
20212223242526
2728293031
+2011/01 1 +
January2011
SunMonTueWedThuFriSat
1
2345678
9101112131415
16171819202122
23242526272829
3031
+2011/01 2 +
January2011
MonTueWedThuFriSatSun
12
3456789
10111213141516
17181920212223
24252627282930
31
+2011/02 1 +
February2011
SunMonTueWedThuFriSat
12345
6789101112
13141516171819
20212223242526
2728
+2011/02 2 +
February2011
MonTueWedThuFriSatSun
123456
78910111213
14151617181920
21222324252627
28
+2011/03 1 +
March2011
SunMonTueWedThuFriSat
12345
6789101112
13141516171819
20212223242526
2728293031
+2011/03 2 +
March2011
MonTueWedThuFriSatSun
123456
78910111213
14151617181920
21222324252627
28293031
+2011/04 1 +
April2011
SunMonTueWedThuFriSat
12
3456789
10111213141516
17181920212223
24252627282930
+2011/04 2 +
April2011
MonTueWedThuFriSatSun
123
45678910
11121314151617
18192021222324
252627282930
+2011/05 1 +
May2011
SunMonTueWedThuFriSat
1234567
891011121314
15161718192021
22232425262728
293031
+2011/05 2 +
May2011
MonTueWedThuFriSatSun
1
2345678
9101112131415
16171819202122
23242526272829
3031
+2011/06 1 +
June2011
SunMonTueWedThuFriSat
1234
567891011
12131415161718
19202122232425
2627282930
+2011/06 2 +
June2011
MonTueWedThuFriSatSun
12345
6789101112
13141516171819
20212223242526
27282930
+2011/07 1 +
July2011
SunMonTueWedThuFriSat
12
3456789
10111213141516
17181920212223
24252627282930
31
+2011/07 2 +
July2011
MonTueWedThuFriSatSun
123
45678910
11121314151617
18192021222324
25262728293031
+2011/08 1 +
August2011
SunMonTueWedThuFriSat
123456
78910111213
14151617181920
21222324252627
28293031
+2011/08 2 +
August2011
MonTueWedThuFriSatSun
1234567
891011121314
15161718192021
22232425262728
293031
+2011/09 1 +
September2011
SunMonTueWedThuFriSat
123
45678910
11121314151617
18192021222324
252627282930
+2011/09 2 +
September2011
MonTueWedThuFriSatSun
1234
567891011
12131415161718
19202122232425
2627282930
+2011/10 1 +
October2011
SunMonTueWedThuFriSat
1
2345678
9101112131415
16171819202122
23242526272829
3031
+2011/10 2 +
October2011
MonTueWedThuFriSatSun
12
3456789
10111213141516
17181920212223
24252627282930
31
+2011/11 1 +
November2011
SunMonTueWedThuFriSat
12345
6789101112
13141516171819
20212223242526
27282930
+2011/11 2 +
November2011
MonTueWedThuFriSatSun
123456
78910111213
14151617181920
21222324252627
282930
+2011/12 1 +
December2011
SunMonTueWedThuFriSat
123
45678910
11121314151617
18192021222324
25262728293031
+2011/12 2 +
December2011
MonTueWedThuFriSatSun
1234
567891011
12131415161718
19202122232425
262728293031
+2012/01 1 +
January2012
SunMonTueWedThuFriSat
1234567
891011121314
15161718192021
22232425262728
293031
+2012/01 2 +
January2012
MonTueWedThuFriSatSun
1
2345678
9101112131415
16171819202122
23242526272829
3031
+2012/02 1 +
February2012
SunMonTueWedThuFriSat
1234
567891011
12131415161718
19202122232425
26272829
+2012/02 2 +
February2012
MonTueWedThuFriSatSun
12345
6789101112
13141516171819
20212223242526
272829
+2012/03 1 +
March2012
SunMonTueWedThuFriSat
123
45678910
11121314151617
18192021222324
25262728293031
+2012/03 2 +
March2012
MonTueWedThuFriSatSun
1234
567891011
12131415161718
19202122232425
262728293031
+2012/04 1 +
April2012
SunMonTueWedThuFriSat
1234567
891011121314
15161718192021
22232425262728
2930
+2012/04 2 +
April2012
MonTueWedThuFriSatSun
1
2345678
9101112131415
16171819202122
23242526272829
30
+2012/05 1 +
May2012
SunMonTueWedThuFriSat
12345
6789101112
13141516171819
20212223242526
2728293031
+2012/05 2 +
May2012
MonTueWedThuFriSatSun
123456
78910111213
14151617181920
21222324252627
28293031
+2012/06 1 +
June2012
SunMonTueWedThuFriSat
12
3456789
10111213141516
17181920212223
24252627282930
+2012/06 2 +
June2012
MonTueWedThuFriSatSun
123
45678910
11121314151617
18192021222324
252627282930
+2012/07 1 +
July2012
SunMonTueWedThuFriSat
1234567
891011121314
15161718192021
22232425262728
293031
+2012/07 2 +
July2012
MonTueWedThuFriSatSun
1
2345678
9101112131415
16171819202122
23242526272829
3031
+2012/08 1 +
August2012
SunMonTueWedThuFriSat
1234
567891011
12131415161718
19202122232425
262728293031
+2012/08 2 +
August2012
MonTueWedThuFriSatSun
12345
6789101112
13141516171819
20212223242526
2728293031
+2012/09 1 +
September2012
SunMonTueWedThuFriSat
1
2345678
9101112131415
16171819202122
23242526272829
30
+2012/09 2 +
September2012
MonTueWedThuFriSatSun
12
3456789
10111213141516
17181920212223
24252627282930
+2012/10 1 +
October2012
SunMonTueWedThuFriSat
123456
78910111213
14151617181920
21222324252627
28293031
+2012/10 2 +
October2012
MonTueWedThuFriSatSun
1234567
891011121314
15161718192021
22232425262728
293031
+2012/11 1 +
November2012
SunMonTueWedThuFriSat
123
45678910
11121314151617
18192021222324
252627282930
+2012/11 2 +
November2012
MonTueWedThuFriSatSun
1234
567891011
12131415161718
19202122232425
2627282930
+2012/12 1 +
December2012
SunMonTueWedThuFriSat
1
2345678
9101112131415
16171819202122
23242526272829
3031
+2012/12 2 +
December2012
MonTueWedThuFriSatSun
12
3456789
10111213141516
17181920212223
24252627282930
31
+2013/01 1 +
January2013
SunMonTueWedThuFriSat
12345
6789101112
13141516171819
20212223242526
2728293031
+2013/01 2 +
January2013
MonTueWedThuFriSatSun
123456
78910111213
14151617181920
21222324252627
28293031
+2013/02 1 +
February2013
SunMonTueWedThuFriSat
12
3456789
10111213141516
17181920212223
2425262728
+2013/02 2 +
February2013
MonTueWedThuFriSatSun
123
45678910
11121314151617
18192021222324
25262728
+2013/03 1 +
March2013
SunMonTueWedThuFriSat
12
3456789
10111213141516
17181920212223
24252627282930
31
+2013/03 2 +
March2013
MonTueWedThuFriSatSun
123
45678910
11121314151617
18192021222324
25262728293031
+2013/04 1 +
April2013
SunMonTueWedThuFriSat
123456
78910111213
14151617181920
21222324252627
282930
+2013/04 2 +
April2013
MonTueWedThuFriSatSun
1234567
891011121314
15161718192021
22232425262728
2930
+2013/05 1 +
May2013
SunMonTueWedThuFriSat
1234
567891011
12131415161718
19202122232425
262728293031
+2013/05 2 +
May2013
MonTueWedThuFriSatSun
12345
6789101112
13141516171819
20212223242526
2728293031
+2013/06 1 +
June2013
SunMonTueWedThuFriSat
1
2345678
9101112131415
16171819202122
23242526272829
30
+2013/06 2 +
June2013
MonTueWedThuFriSatSun
12
3456789
10111213141516
17181920212223
24252627282930
+2013/07 1 +
July2013
SunMonTueWedThuFriSat
123456
78910111213
14151617181920
21222324252627
28293031
+2013/07 2 +
July2013
MonTueWedThuFriSatSun
1234567
891011121314
15161718192021
22232425262728
293031
+2013/08 1 +
August2013
SunMonTueWedThuFriSat
123
45678910
11121314151617
18192021222324
25262728293031
+2013/08 2 +
August2013
MonTueWedThuFriSatSun
1234
567891011
12131415161718
19202122232425
262728293031
+2013/09 1 +
September2013
SunMonTueWedThuFriSat
1234567
891011121314
15161718192021
22232425262728
2930
+2013/09 2 +
September2013
MonTueWedThuFriSatSun
1
2345678
9101112131415
16171819202122
23242526272829
30
+2013/10 1 +
October2013
SunMonTueWedThuFriSat
12345
6789101112
13141516171819
20212223242526
2728293031
+2013/10 2 +
October2013
MonTueWedThuFriSatSun
123456
78910111213
14151617181920
21222324252627
28293031
+2013/11 1 +
November2013
SunMonTueWedThuFriSat
12
3456789
10111213141516
17181920212223
24252627282930
+2013/11 2 +
November2013
MonTueWedThuFriSatSun
123
45678910
11121314151617
18192021222324
252627282930
+2013/12 1 +
December2013
SunMonTueWedThuFriSat
1234567
891011121314
15161718192021
22232425262728
293031
+2013/12 2 +
December2013
MonTueWedThuFriSatSun
1
2345678
9101112131415
16171819202122
23242526272829
3031
+2014/01 1 +
January2014
SunMonTueWedThuFriSat
1234
567891011
12131415161718
19202122232425
262728293031
+2014/01 2 +
January2014
MonTueWedThuFriSatSun
12345
6789101112
13141516171819
20212223242526
2728293031
+2014/02 1 +
February2014
SunMonTueWedThuFriSat
1
2345678
9101112131415
16171819202122
232425262728
+2014/02 2 +
February2014
MonTueWedThuFriSatSun
12
3456789
10111213141516
17181920212223
2425262728
+2014/03 1 +
March2014
SunMonTueWedThuFriSat
1
2345678
9101112131415
16171819202122
23242526272829
3031
+2014/03 2 +
March2014
MonTueWedThuFriSatSun
12
3456789
10111213141516
17181920212223
24252627282930
31
+2014/04 1 +
April2014
SunMonTueWedThuFriSat
12345
6789101112
13141516171819
20212223242526
27282930
+2014/04 2 +
April2014
MonTueWedThuFriSatSun
123456
78910111213
14151617181920
21222324252627
282930
+2014/05 1 +
May2014
SunMonTueWedThuFriSat
123
45678910
11121314151617
18192021222324
25262728293031
+2014/05 2 +
May2014
MonTueWedThuFriSatSun
1234
567891011
12131415161718
19202122232425
262728293031
+2014/06 1 +
June2014
SunMonTueWedThuFriSat
1234567
891011121314
15161718192021
22232425262728
2930
+2014/06 2 +
June2014
MonTueWedThuFriSatSun
1
2345678
9101112131415
16171819202122
23242526272829
30
+2014/07 1 +
July2014
SunMonTueWedThuFriSat
12345
6789101112
13141516171819
20212223242526
2728293031
+2014/07 2 +
July2014
MonTueWedThuFriSatSun
123456
78910111213
14151617181920
21222324252627
28293031
+2014/08 1 +
August2014
SunMonTueWedThuFriSat
12
3456789
10111213141516
17181920212223
24252627282930
31
+2014/08 2 +
August2014
MonTueWedThuFriSatSun
123
45678910
11121314151617
18192021222324
25262728293031
+2014/09 1 +
September2014
SunMonTueWedThuFriSat
123456
78910111213
14151617181920
21222324252627
282930
+2014/09 2 +
September2014
MonTueWedThuFriSatSun
1234567
891011121314
15161718192021
22232425262728
2930
+2014/10 1 +
October2014
SunMonTueWedThuFriSat
1234
567891011
12131415161718
19202122232425
262728293031
+2014/10 2 +
October2014
MonTueWedThuFriSatSun
12345
6789101112
13141516171819
20212223242526
2728293031
+2014/11 1 +
November2014
SunMonTueWedThuFriSat
1
2345678
9101112131415
16171819202122
23242526272829
30
+2014/11 2 +
November2014
MonTueWedThuFriSatSun
12
3456789
10111213141516
17181920212223
24252627282930
+2014/12 1 +
December2014
SunMonTueWedThuFriSat
123456
78910111213
14151617181920
21222324252627
28293031
+2014/12 2 +
December2014
MonTueWedThuFriSatSun
1234567
891011121314
15161718192021
22232425262728
293031
+2015/01 1 +
January2015
SunMonTueWedThuFriSat
123
45678910
11121314151617
18192021222324
25262728293031
+2015/01 2 +
January2015
MonTueWedThuFriSatSun
1234
567891011
12131415161718
19202122232425
262728293031
+2015/02 1 +
February2015
SunMonTueWedThuFriSat
1234567
891011121314
15161718192021
22232425262728
+2015/02 2 +
February2015
MonTueWedThuFriSatSun
1
2345678
9101112131415
16171819202122
232425262728
+2015/03 1 +
March2015
SunMonTueWedThuFriSat
1234567
891011121314
15161718192021
22232425262728
293031
+2015/03 2 +
March2015
MonTueWedThuFriSatSun
1
2345678
9101112131415
16171819202122
23242526272829
3031
+2015/04 1 +
April2015
SunMonTueWedThuFriSat
1234
567891011
12131415161718
19202122232425
2627282930
+2015/04 2 +
April2015
MonTueWedThuFriSatSun
12345
6789101112
13141516171819
20212223242526
27282930
+2015/05 1 +
May2015
SunMonTueWedThuFriSat
12
3456789
10111213141516
17181920212223
24252627282930
31
+2015/05 2 +
May2015
MonTueWedThuFriSatSun
123
45678910
11121314151617
18192021222324
25262728293031
+2015/06 1 +
June2015
SunMonTueWedThuFriSat
123456
78910111213
14151617181920
21222324252627
282930
+2015/06 2 +
June2015
MonTueWedThuFriSatSun
1234567
891011121314
15161718192021
22232425262728
2930
+2015/07 1 +
July2015
SunMonTueWedThuFriSat
1234
567891011
12131415161718
19202122232425
262728293031
+2015/07 2 +
July2015
MonTueWedThuFriSatSun
12345
6789101112
13141516171819
20212223242526
2728293031
+2015/08 1 +
August2015
SunMonTueWedThuFriSat
1
2345678
9101112131415
16171819202122
23242526272829
3031
+2015/08 2 +
August2015
MonTueWedThuFriSatSun
12
3456789
10111213141516
17181920212223
24252627282930
31
+2015/09 1 +
September2015
SunMonTueWedThuFriSat
12345
6789101112
13141516171819
20212223242526
27282930
+2015/09 2 +
September2015
MonTueWedThuFriSatSun
123456
78910111213
14151617181920
21222324252627
282930
+2015/10 1 +
October2015
SunMonTueWedThuFriSat
123
45678910
11121314151617
18192021222324
25262728293031
+2015/10 2 +
October2015
MonTueWedThuFriSatSun
1234
567891011
12131415161718
19202122232425
262728293031
+2015/11 1 +
November2015
SunMonTueWedThuFriSat
1234567
891011121314
15161718192021
22232425262728
2930
+2015/11 2 +
November2015
MonTueWedThuFriSatSun
1
2345678
9101112131415
16171819202122
23242526272829
30
+2015/12 1 +
December2015
SunMonTueWedThuFriSat
12345
6789101112
13141516171819
20212223242526
2728293031
+2015/12 2 +
December2015
MonTueWedThuFriSatSun
123456
78910111213
14151617181920
21222324252627
28293031
diff --git a/1.25/t/dat/i8n.dat b/1.25/t/dat/i8n.dat new file mode 100644 index 0000000..336f2d1 --- /dev/null +++ b/1.25/t/dat/i8n.dat @@ -0,0 +1,14 @@ +2010/03 ga_IE +
Márta2010
DomhLuanMáirtCéadDéarAoineSath
123456
78910111213
14151617181920
21222324252627
28293031
+2010/03 es_MX +
marzo2010
lunmarmiéjueviesábdom
1234567
891011121314
15161718192021
22232425262728
293031
+2010/03 fr_FR +
mars2010
lun.mar.mer.jeu.ven.sam.dim.
1234567
891011121314
15161718192021
22232425262728
293031
+2010/03 de_DE +
März2010
Mo.Di.Mi.Do.Fr.Sa.So.
1234567
891011121314
15161718192021
22232425262728
293031
+2010/03 ru_RU +
Март2010
ПнВтСрЧтПтСбВс
1234567
891011121314
15161718192021
22232425262728
293031
+2010/03 pt_BR +
março2010
segterquaquisexsábdom
1234567
891011121314
15161718192021
22232425262728
293031
+2010/03 zu_ZA +
uMashi2010
MsoBilThaSinHlaMgqSon
1234567
891011121314
15161718192021
22232425262728
293031
diff --git a/1.25/t/dat/narrow.dat b/1.25/t/dat/narrow.dat new file mode 100644 index 0000000..9c6479a --- /dev/null +++ b/1.25/t/dat/narrow.dat @@ -0,0 +1,12 @@ +2010/08 1 +
August2010
SMTWTFS
1234567
891011121314
15161718192021
22232425262728
293031
+2010/08 2 +
August2010
MTWTFSS
1
2345678
9101112131415
16171819202122
23242526272829
3031
+2010/09 1 +
September2010
SMTWTFS
1234
567891011
12131415161718
19202122232425
2627282930
+2010/09 2 +
September2010
MTWTFSS
12345
6789101112
13141516171819
20212223242526
27282930
+2010/10 1 +
October2010
SMTWTFS
12
3456789
10111213141516
17181920212223
24252627282930
31
+2010/10 2 +
October2010
MTWTFSS
123
45678910
11121314151617
18192021222324
25262728293031
diff --git a/1.25/t/dat/odd.dat b/1.25/t/dat/odd.dat new file mode 100644 index 0000000..366c0c3 --- /dev/null +++ b/1.25/t/dat/odd.dat @@ -0,0 +1,16 @@ +2000/10 1 +
October2000
SunMonTueWedThuFriSat
1234567
891011121314
15161718192021
22232425262728
293031
+2000/10 2 +
October2000
MonTueWedThuFriSatSun
1
2345678
9101112131415
16171819202122
23242526272829
3031
+2000/12 1 +
December2000
SunMonTueWedThuFriSat
12
3456789
10111213141516
17181920212223
24252627282930
31
+2000/12 2 +
December2000
MonTueWedThuFriSatSun
123
45678910
11121314151617
18192021222324
25262728293031
+2002/03 1 +
March2002
SunMonTueWedThuFriSat
12
3456789
10111213141516
17181920212223
24252627282930
31
+2002/03 2 +
March2002
MonTueWedThuFriSatSun
123
45678910
11121314151617
18192021222324
25262728293031
+1752/09 1 +
September1752
SunMonTueWedThuFriSat
12141516
17181920212223
24252627282930
+1752/09 2 +
September1752
MonTueWedThuFriSatSun
1214151617
18192021222324
252627282930
diff --git a/1.25/t/dat/woy.dat b/1.25/t/dat/woy.dat new file mode 100644 index 0000000..a88da87 --- /dev/null +++ b/1.25/t/dat/woy.dat @@ -0,0 +1,4 @@ +2000/01 +
January2000
SunMonTueWedThuFriSat
152
23456781
91011121314152
161718192021223
232425262728294
30315
+2000/12 +
December2000
SunMonTueWedThuFriSat
1248
345678949
1011121314151650
1718192021222351
2425262728293052
311
diff --git a/1.25/t/release-pod-coverage.t b/1.25/t/release-pod-coverage.t new file mode 100644 index 0000000..3a81849 --- /dev/null +++ b/1.25/t/release-pod-coverage.t @@ -0,0 +1,21 @@ +#!perl + +BEGIN { + unless ($ENV{RELEASE_TESTING}) { + require Test::More; + Test::More::plan(skip_all => 'these tests are for release candidate testing'); + } +} + + +use Test::More; + +eval "use Test::Pod::Coverage 1.08"; +plan skip_all => "Test::Pod::Coverage 1.08 required for testing POD coverage" + if $@; + +eval "use Pod::Coverage::TrustPod"; +plan skip_all => "Pod::Coverage::TrustPod required for testing POD coverage" + if $@; + +all_pod_coverage_ok({ coverage_class => 'Pod::Coverage::TrustPod' }); diff --git a/1.25/t/release-pod-syntax.t b/1.25/t/release-pod-syntax.t new file mode 100644 index 0000000..d46a955 --- /dev/null +++ b/1.25/t/release-pod-syntax.t @@ -0,0 +1,15 @@ +#!perl + +BEGIN { + unless ($ENV{RELEASE_TESTING}) { + require Test::More; + Test::More::plan(skip_all => 'these tests are for release candidate testing'); + } +} + +use Test::More; + +eval "use Test::Pod 1.41"; +plan skip_all => "Test::Pod 1.41 required for testing POD" if $@; + +all_pod_files_ok(); diff --git a/1.25/t/testload.pm b/1.25/t/testload.pm new file mode 100644 index 0000000..1c30d0f --- /dev/null +++ b/1.25/t/testload.pm @@ -0,0 +1,239 @@ +package testload; + +use vars qw( @ISA @EXPORT $Dat_Dir ); + +use strict; +use warnings; +use Test::More; + +use Cwd qw( abs_path ); + +my $DEBUG = 0; + +require Exporter; +@ISA = qw(Exporter); + +use vars qw( + $Dat_Dir + $Bulk_File + $Odd_File + $Woy_File + $I8N_File + $Narrow_File +); + +@EXPORT = qw( + $Dat_Dir + $Bulk_File $Odd_File $Woy_File $I8N_File $Narrow_File + check_datetool + check_bulk_with_datetool + check_odd_with_datetool + check_woy_with_datetool + check_i8n + check_narrow + + bulk_count + odd_count + woy_count + i8n_count + narrow_count + + clean +); + +use File::Spec; + +use HTML::CalendarMonth; +use HTML::CalendarMonth::DateTool; + +BEGIN { + my($vol, $dir, $file) = File::Spec->splitpath(abs_path(__FILE__)); + $dir = File::Spec->catdir($dir, 'dat'); + $Dat_Dir = File::Spec->catpath($vol, $dir, ''); +} + +$Bulk_File = File::Spec->catdir($Dat_Dir, 'bulk.dat'); +$Odd_File = File::Spec->catdir($Dat_Dir, 'odd.dat'); +$Woy_File = File::Spec->catdir($Dat_Dir, 'woy.dat'); +$I8N_File = File::Spec->catdir($Dat_Dir, 'i8n.dat'); +$Narrow_File = File::Spec->catdir($Dat_Dir, 'narrow.dat'); + +my(@Bulk, @Odd, @Woy, @I8N, @Nar); + +sub _load_file { + my $f = shift; + my $cal = shift || []; + local(*F); + return unless open(F, '<', $f); + while (my $h = ) { + chomp $h; + my($d, $wb) = split(/\s+/, $h); + my($y, $m) = split(/\//, $d); + my $c = ; + chomp $c; + push(@$cal, [$d, $y, $m, $wb, clean($c)]); + } + $cal; +} + +_load_file($Bulk_File, \@Bulk ); +_load_file($Odd_File, \@Odd ); +_load_file($Woy_File, \@Woy ); +_load_file($I8N_File, \@I8N ); +_load_file($Narrow_File, \@Nar); + +sub bulk_count { scalar @Bulk } +sub odd_count { scalar @Odd } +sub woy_count { scalar @Woy } +sub i8n_count { scalar @I8N } +sub narrow_count { scalar @Nar } + +# Today's date +my($month, $year) = (localtime(time))[4,5]; +++$month; +$year += 1900; + +my $today = sprintf("%d/%02d", $year, $month); +my $year_from_now = sprintf("%d/%02d", $year+1, $month); + +# keep the next year +@Bulk = grep { $_ ge $today && $_->[0] le $year_from_now } @Bulk; + +### + +sub clean { + my $str = shift || Carp::confess "string required"; + $str =~ s/^\s*//; $str =~ s/\s*$//; + # guard against HTML::Tree starting to quote numeric attrs as of + # v3.19_02 + $str =~ s/\"(\d+)\"/$1/g; + $str; +} + +sub check_datetool { + my $datetool = shift; + my $module = HTML::CalendarMonth::DateTool->_toolmap($datetool); + ok($module, "toolmap($datetool) : $module"); + require_ok($module); +} + +sub check_bulk_with_datetool { + my $datetool = shift; + my @days; + foreach (@Bulk) { + my($d, $y, $m, $wb, $tc) = @$_; + my $c = HTML::CalendarMonth->new( + year => $y, + month => $m, + week_begin => $wb, + datetool => $datetool, + ); + @days = $c->dayheaders unless @days; + my $day1 = $days[$wb - 1]; + my $method = $c->_caltool->_name; + $method = "auto-select ($method)" unless $datetool; + my $msg = sprintf( + "(%d/%02d %s 1st day) using %s", + $y, $m, $day1, $method + ); + cmp_ok(clean($c->as_HTML), 'eq', $tc, $msg); + } +} + +sub check_odd_with_datetool { + my $datetool = shift; + my @days; + foreach (@Odd) { + my($d, $y, $m, $wb, $tc) = @$_; + SKIP: { + my $c; + eval { + $c = HTML::CalendarMonth->new( + year => $y, + month => $m, + week_begin => $wb, + datetool => $datetool, + ); + }; + if ($@ || !$c) { + croak $@ unless $@ =~ /(no|in)\s*valid date tool/i; + skip("$datetool skip odd $y/$m", 1); + } + @days = $c->dayheaders unless @days; + my $day1 = $days[$wb - 1]; + my $method = $c->_caltool->_name; + $method = "auto-select ($method)" unless $datetool; + my $msg = sprintf( + "(%d/%02d %s 1st day) using %s", + $y, $m, $day1, $method + ); + cmp_ok(clean($c->as_HTML), 'eq', $tc, $msg); + } + } +} + +sub check_woy_with_datetool { + my $datetool = shift; + foreach (@Woy) { + my($d, $y, $m, $wb, $tc) = @$_; + my $c = HTML::CalendarMonth->new( + year => $y, + month => $m, + head_week => 1, + datetool => $datetool, + ); + my $msg = sprintf("(%d/%02d week of year) using %s", $y, $m, $datetool); + cmp_ok(clean($c->as_HTML), 'eq', $tc, $msg); + } +} + +sub check_i8n { + foreach (@I8N) { + my($d, $y, $m, $id, $tc) = @$_; + my $c = HTML::CalendarMonth->new( + year => $y, + month => $m, + locale => $id, + ); + my $name = $c->loc->loc->name; + my $msg = sprintf( + "(%d/%02d i8n) %s (wb:%d) using auto-detect", + $y, $m, $name, $c->week_begin + ); + cmp_ok(clean($c->as_HTML), 'eq', $tc, $msg); + } +} + +sub check_narrow { + my @days; + foreach (@Nar) { + my($d, $y, $m, $wb, $tc) = @$_; + my $c = HTML::CalendarMonth->new( + year => $y, + month => $m, + week_begin => $wb, + full_days => -1, + ); + @days = $c->dayheaders unless @days; + my $day1 = $days[$wb - 1]; + my $msg = sprintf( + "(%d/%02d %s/%s 1st day) narrow/alias using auto-detect", + $y, $m, $day1, $c->item_alias($day1) + ); + cmp_ok(clean($c->as_HTML), 'eq', $tc, $msg); + } +} + +sub debug_dump { + my($l1, $str1, $l2, $str2) = @_; + local(*DUMP); + open(DUMP, ">$DEBUG") or die "Could not dump to $DEBUG: $!\n"; + print DUMP "
$l1$l2
\n"; + print DUMP "$str1\n\n"; + print DUMP "$str2\n
\n"; + close(DUMP); + print STDERR "\nDumped tables to $DEBUG. Aborting test.\n"; + exit; +} + +1; -- 2.39.2