Path-Dispatcher-1.08000755000766000024 013702474074 14026 5ustar00etherstaff000000000000README100644000766000024 56113702474074 14751 0ustar00etherstaff000000000000Path-Dispatcher-1.08This archive contains the distribution Path-Dispatcher, version 1.08: Flexible and extensible dispatch This software is copyright (c) 2020 by Shawn M Moore. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. This README file was generated by Dist::Zilla::Plugin::Readme v6.015. Changes100640000766000024 1721313702474074 15422 0ustar00etherstaff000000000000Path-Dispatcher-1.08Revision history for Path-Dispatcher 1.08 2020-07-12 02:40:52Z - add abstracts to modules that were missing them (RT#132909) - add MooX::TypeTiny for optimized type checks 1.07 2020-02-29 20:55:07Z - Switch from Any::Moose to Moo and Types::Standard based on PRs from chresomanci and hashbangperl 1.06 2015-02-18 Switch packaging system to Dist::Zilla (David Pottage) https://github.com/sartak/path-dispatcher/pull/1 Thanks to the CPAN Pull Request Challenge :) 1.05 2013-03-14 eval q{$'} before regex match when needed to soothe bleadperl Thanks Dave Mitchell! http://www.nntp.perl.org/group/perl.perl5.porters/2013/03/msg200156.html 1.04 2011-09-01 Explicitly depend on Test::Fatal (reported by Jérôme Quelin [rt.cpan.org #70666]) Convert all tests from Test::Exception to Test::Fatal 1.03 2011-08-30 Provisional support for arbitrary payloads, not just code blocks, as results See https://github.com/sartak/path-dispatcher/blob/master/t/200-payload.t Eventually blocks will be deprecated, but not for a while. Internally blocks are rewritten as payloads so if you're doing deep magic with PD you may be exposed to that implementation detail. 1.02 2010-11-02 Various improvements to the handling of $match->leftover with undef 1.01 2010-10-24 Skip t/026-named-captures.t if you don't have 5.10.1 Give matches a ->parent for inspecting an Under prefix rule's captures etc 1.00 2010-10-17 Bump to 1.0 to indicate back compat breakage Add match->named($key) for pulling out a named capture Use Try::Tiny to avoid swallowing exceptions (rafl) 0.16 2010-10-17 ** BACKWARDS INCOMPATIBLE CHANGE: Pass the match object into rule ** blocks rather than assigning $1, $2, $3. Use ->pos(1), (2), (3), ** etc. instead. This cleans up the code a lot and makes ** Path-Dispatcher more flexible. Add support for named captures Make all attributes read-only. If you need something to be read-write, I am open to such a change. Just let me know! Make _dispatcher_rule private Remove trace/readable_attribute/name support. This wants to be implemented in a different, better, more comprehensive way. Add documentation for shell tab completion Plenty other updated documentation 0.15 2010-03-16 09:40:40Z ** Factored Path-Dispatcher-Declarative into its own distribution ** Be sure to update your dependency lists! Implement ->complete for Rule::Dispatch Add Path::Dispatcher::Rule::Alternation Implement case insensitivity for Rule::Eq Add Path::Dispatcher::Rule::Sequence - like Rule::Tokens but better! Add Path::Dispatcher::Rule::Enum Path autoboxing has been factored out into a private method for more overridability A few documentation improvements as usual :) 0.14 2009-12-31 13:18:19Z Add Path::Dispatcher->complete for tab-completion Handle delimiters better in Path::Dispatcher::Rule::Tokens Factor out a _prefix method for rules to simplify their logic 0.13 2009-08-09 13:38:19Z Add unshift_rule to classes that do Role::Rules Several distribution improvements 0.12 2009-04-17 03:21:05Z Fix a bug with undefined capture variables being converted to the empty string and throwing warnings (reported by obra) Give Path::Dispatcher::Rule::Dispatch a "rules" method 0.11 2009-04-15 02:47:50Z Fix some misnamed keys caused by de-AttributeHelper-ing Stop using some deprecated Moose features Doc fixes (Sartak and confound) 0.10 2009-03-06 23:40:42Z The way you specify token_delimiter and case_sensitive_tokens has changed! You now say: use Path::Dispatcher::Declarative -base, -defaults => { token_delimiter => '/', case_sensitive_tokens => 0, }; Added Path::Dispatcher::Cookbook (grink) Added Path::Dispatcher::Builder which now backs Path::Dispatcher::Declarative (grink) then {} rule which is an "always" with that uses next_rule (grink) chain {} rule which is like Catalyst's chain (grink) Remove the last vestiges of stages (Sartak) Many minor fixes (Sartak) 0.09 2009-02-09 21:12:18Z Avoid using method modifiers since it's potentially another dep. 0.08 2009-02-05 12:15:38Z Inline uses of MooseX::AttributeHelpers. Now use "Any::Moose" (basically Squirrel done right) 0.07 2009-01-28 01:39:37Z Paths are now boxed with the new Path::Dispatcher::Path. New rule type "Intersection" which matches only when each of its subrules match. New rule type "Metadata" which matches the optional metadata (a hash) of the path. The sugar for this is: on { foo => "bar" } New rule type "Eq" which just does basic string equality. Rules can now be named. In Path::Dispatcher::Declarative, each rule is named with its dispatcher's name and the file:line where the rule was defined. Dispatch tracing output, for debugging. Set environment variable PATH_DISPATCHER_TRACE to a number. The higher the number, the more output will be generated. The current maximum value of 10 will dump code references. 0.06 2008-11-15 21:02:29Z New rule type "Empty" which matches only the empty path. Declarative: on '' now matches only the empty path. 0.05 2008-11-15 16:36:41Z Improve test coverage New rule type "Always" which always matches. Match: ends_dispatch is now an attribute Rule::Tokens: Support for case insensitive matching Fix for tokens' type constraint Dispatcher: Allow rules to be specified in the constructor (a typo prevented it) Dispatch: first_match, has_match methods which do what you'd expect The run method will now collect return values and return them Declarative: redispatch_to sugar which adds a Dispatch rule "on '' => sub" as a special case will match all paths 0.04 2008-10-28 17:56:41Z Dist fixes 0.03 2008-10-28 17:42:47Z "rewrite" rules Super dispatchers are GONE! Yay. New Rule::Dispatch which just takes some other dispatcher. nothingmuch++ Rule::Tokens: Fix for always matching just a prefix whether you wanted to or not Make tokenization and untokenization into methods for overriding Declarative: -base is required, otherwise unrelated modules using your dispatcher would get their @ISA set! 0.02 2008-10-20 14:10:12Z Documentation! Prefix matches "under" rules Remove stages until they're actually needed Rule: The codeblock is no longer required Empty tokens are ignored The token attribute is now 'delimiter' instead of 'splitter' Allow regexes and alternations in the token rules Match: No longer Dispatch::Match Created by the Rule instead of the Dispatcher Declarative: You now must subclass Path::Dispatcher::Declarative Allow overriding the token delimiter 0.01 2008-08-27 11:04:18Z Initial release LICENSE100644000766000024 4366013702474074 15145 0ustar00etherstaff000000000000Path-Dispatcher-1.08This software is copyright (c) 2020 by Shawn M Moore. 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) 2020 by Shawn M Moore. 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. 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 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) 2020 by Shawn M Moore. 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 INSTALL100644000766000024 446213702474074 15146 0ustar00etherstaff000000000000Path-Dispatcher-1.08This is the Perl distribution Path-Dispatcher. Installing Path-Dispatcher is straightforward. ## Installation with cpanm If you have cpanm, you only need one line: % cpanm Path::Dispatcher If it does not have permission to install modules to the current perl, cpanm will automatically set up and install to a local::lib in your home directory. See the local::lib documentation (https://metacpan.org/pod/local::lib) for details on enabling it in your environment. ## Installing with the CPAN shell Alternatively, if your CPAN shell is set up, you should just be able to do: % cpan Path::Dispatcher ## Manual installation As a last resort, you can manually install it. Download the tarball, untar it, install configure prerequisites (see below), then build it: % perl Build.PL % ./Build && ./Build test Then install it: % ./Build install Or the more portable variation: % perl Build.PL % perl Build % perl Build test % perl Build install If your perl is system-managed, you can create a local::lib in your home directory to install modules to. For details, see the local::lib documentation: https://metacpan.org/pod/local::lib The prerequisites of this distribution will also have to be installed manually. The prerequisites are listed in one of the files: `MYMETA.yml` or `MYMETA.json` generated by running the manual build process described above. ## Configure Prerequisites This distribution requires other modules to be installed before this distribution's installer can be run. They can be found under the "configure_requires" key of META.yml or the "{prereqs}{configure}{requires}" key of META.json. ## Other Prerequisites This distribution may require additional modules to be installed after running Build.PL or Makefile.PL. Look for prerequisites in the following phases: * to run ./Build or make, PHASE = build * to use the module code itself, PHASE = runtime * to run tests, PHASE = test They can all be found in the "PHASE_requires" key of MYMETA.yml or the "{prereqs}{PHASE}{requires}" key of MYMETA.json. ## Documentation Path-Dispatcher documentation is available as POD. You can run `perldoc` from a shell to read the documentation: % perldoc Path::Dispatcher For more information on installing Perl modules via CPAN, please see: https://www.cpan.org/modules/INSTALL.html dist.ini100640000766000024 123713702474074 15552 0ustar00etherstaff000000000000Path-Dispatcher-1.08name = Path-Dispatcher author = Shawn M Moore, C<< >> license = Perl_5 copyright_holder = Shawn M Moore [FileFinder::Filter / all_files_but_using_5.10_features] finder = :TestFiles skip = t/026-named-captures.t [@Author::ETHER] :version = 0.119 authority = cpan:SARTAK MinimumPerl.test_finder = all_files_but_using_5.10_features Test::MinimumVersion.max_target_perl = 5.008003 -remove = Test::PodSpelling ; TODO -remove = PodCoverageTests ; TODO -remove = Test::CleanNamespaces ; TODO [Substitute] file = xt/author/minimum-version.t code = s!^(all_minimum_version_ok\([^)]+)(\s*\);)!$1, { skip => ['t/026-named-captures.t'] }$2! META.yml100644000766000024 7164213702474074 15412 0ustar00etherstaff000000000000Path-Dispatcher-1.08--- abstract: 'Flexible and extensible dispatch' author: - 'Shawn M Moore, C<< >>' build_requires: File::Spec: '0' Module::Metadata: '0' Test::Fatal: '0' Test::More: '0' perl: '5.008001' strict: '0' warnings: '0' configure_requires: ExtUtils::MakeMaker: '0' Module::Build::Tiny: '0.034' perl: '5.008001' dynamic_config: 0 generated_by: 'Dist::Zilla version 6.015, CPAN::Meta::Converter version 2.150010' license: perl meta-spec: url: http://module-build.sourceforge.net/META-spec-v1.4.html version: '1.4' name: Path-Dispatcher no_index: directory: - t - xt provides: Path::Dispatcher: file: lib/Path/Dispatcher.pm version: '1.08' Path::Dispatcher::Dispatch: file: lib/Path/Dispatcher/Dispatch.pm version: '1.08' Path::Dispatcher::Match: file: lib/Path/Dispatcher/Match.pm version: '1.08' Path::Dispatcher::Path: file: lib/Path/Dispatcher/Path.pm version: '1.08' Path::Dispatcher::Role::Rules: file: lib/Path/Dispatcher/Role/Rules.pm version: '1.08' Path::Dispatcher::Rule: file: lib/Path/Dispatcher/Rule.pm version: '1.08' Path::Dispatcher::Rule::Alternation: file: lib/Path/Dispatcher/Rule/Alternation.pm version: '1.08' Path::Dispatcher::Rule::Always: file: lib/Path/Dispatcher/Rule/Always.pm version: '1.08' Path::Dispatcher::Rule::Chain: file: lib/Path/Dispatcher/Rule/Chain.pm version: '1.08' Path::Dispatcher::Rule::CodeRef: file: lib/Path/Dispatcher/Rule/CodeRef.pm version: '1.08' Path::Dispatcher::Rule::Dispatch: file: lib/Path/Dispatcher/Rule/Dispatch.pm version: '1.08' Path::Dispatcher::Rule::Empty: file: lib/Path/Dispatcher/Rule/Empty.pm version: '1.08' Path::Dispatcher::Rule::Enum: file: lib/Path/Dispatcher/Rule/Enum.pm version: '1.08' Path::Dispatcher::Rule::Eq: file: lib/Path/Dispatcher/Rule/Eq.pm version: '1.08' Path::Dispatcher::Rule::Intersection: file: lib/Path/Dispatcher/Rule/Intersection.pm version: '1.08' Path::Dispatcher::Rule::Metadata: file: lib/Path/Dispatcher/Rule/Metadata.pm version: '1.08' Path::Dispatcher::Rule::Regex: file: lib/Path/Dispatcher/Rule/Regex.pm version: '1.08' Path::Dispatcher::Rule::Sequence: file: lib/Path/Dispatcher/Rule/Sequence.pm version: '1.08' Path::Dispatcher::Rule::Tokens: file: lib/Path/Dispatcher/Rule/Tokens.pm version: '1.08' Path::Dispatcher::Rule::Under: file: lib/Path/Dispatcher/Rule/Under.pm version: '1.08' requires: Carp: '0' Moo: '0' Moo::Role: '0' MooX::TypeTiny: '0' Scalar::Util: '0' Try::Tiny: '0' Type::Tiny: '0' Type::Utils: '0' Types::Standard: '0' constant: '0' overload: '0' perl: '5.008001' resources: bugtracker: https://rt.cpan.org/Public/Dist/Display.html?Name=Path-Dispatcher homepage: https://github.com/karenetheridge/Path-Dispatcher repository: https://github.com/karenetheridge/Path-Dispatcher.git version: '1.08' x_Dist_Zilla: perl: version: '5.032000' plugins: - class: Dist::Zilla::Plugin::FileFinder::Filter name: all_files_but_using_5.10_features version: '6.015' - class: Dist::Zilla::Plugin::Prereqs config: Dist::Zilla::Plugin::Prereqs: phase: develop type: recommends name: '@Author::ETHER/pluginbundle version' version: '6.015' - class: Dist::Zilla::Plugin::PromptIfStale config: Dist::Zilla::Plugin::PromptIfStale: check_all_plugins: 0 check_all_prereqs: 0 modules: - Dist::Zilla::PluginBundle::Author::ETHER phase: build run_under_travis: 0 skip: [] name: '@Author::ETHER/stale modules, build' version: '0.057' - class: Dist::Zilla::Plugin::FileFinder::ByName name: '@Author::ETHER/Examples' version: '6.015' - class: Dist::Zilla::Plugin::Git::GatherDir config: Dist::Zilla::Plugin::GatherDir: exclude_filename: - CONTRIBUTING - INSTALL - LICENSE - README.pod exclude_match: [] follow_symlinks: 0 include_dotfiles: 0 prefix: '' prune_directory: [] root: . Dist::Zilla::Plugin::Git::GatherDir: include_untracked: 0 name: '@Author::ETHER/Git::GatherDir' version: '2.046' - class: Dist::Zilla::Plugin::MetaYAML name: '@Author::ETHER/MetaYAML' version: '6.015' - class: Dist::Zilla::Plugin::MetaJSON name: '@Author::ETHER/MetaJSON' version: '6.015' - class: Dist::Zilla::Plugin::Readme name: '@Author::ETHER/Readme' version: '6.015' - class: Dist::Zilla::Plugin::Manifest name: '@Author::ETHER/Manifest' version: '6.015' - class: Dist::Zilla::Plugin::License name: '@Author::ETHER/License' version: '6.015' - class: Dist::Zilla::Plugin::GenerateFile::FromShareDir config: Dist::Zilla::Plugin::GenerateFile::FromShareDir: destination_filename: CONTRIBUTING dist: Dist-Zilla-PluginBundle-Author-ETHER encoding: UTF-8 has_xs: 0 location: build source_filename: CONTRIBUTING Dist::Zilla::Role::RepoFileInjector: allow_overwrite: 1 repo_root: . version: '0.009' name: '@Author::ETHER/generate CONTRIBUTING' version: '0.014' - class: Dist::Zilla::Plugin::InstallGuide config: Dist::Zilla::Role::ModuleMetadata: Module::Metadata: '1.000037' version: '0.006' name: '@Author::ETHER/InstallGuide' version: '1.200013' - class: Dist::Zilla::Plugin::Test::Compile config: Dist::Zilla::Plugin::Test::Compile: bail_out_on_fail: '1' fail_on_warning: author fake_home: 0 filename: xt/author/00-compile.t module_finder: - ':InstallModules' needs_display: 0 phase: develop script_finder: - ':PerlExecFiles' - '@Author::ETHER/Examples' skips: [] switch: [] name: '@Author::ETHER/Test::Compile' version: '2.058' - class: Dist::Zilla::Plugin::Test::NoTabs config: Dist::Zilla::Plugin::Test::NoTabs: filename: xt/author/no-tabs.t finder: - ':InstallModules' - ':ExecFiles' - '@Author::ETHER/Examples' - ':TestFiles' - ':ExtraTestFiles' name: '@Author::ETHER/Test::NoTabs' version: '0.15' - class: Dist::Zilla::Plugin::Test::EOL config: Dist::Zilla::Plugin::Test::EOL: filename: xt/author/eol.t finder: - ':ExecFiles' - ':ExtraTestFiles' - ':InstallModules' - ':TestFiles' - '@Author::ETHER/Examples' trailing_whitespace: 1 name: '@Author::ETHER/Test::EOL' version: '0.19' - class: Dist::Zilla::Plugin::MetaTests name: '@Author::ETHER/MetaTests' version: '6.015' - class: Dist::Zilla::Plugin::Test::CPAN::Changes config: Dist::Zilla::Plugin::Test::CPAN::Changes: changelog: Changes name: '@Author::ETHER/Test::CPAN::Changes' version: '0.012' - class: Dist::Zilla::Plugin::GenerateFile::FromShareDir config: Dist::Zilla::Plugin::GenerateFile::FromShareDir: destination_filename: xt/author/changes_has_content.t dist: Dist-Zilla-PluginBundle-Author-ETHER encoding: UTF-8 location: build source_filename: changes_has_content.t Dist::Zilla::Role::RepoFileInjector: allow_overwrite: 1 repo_root: . version: '0.009' name: '@Author::ETHER/generate xt/author/changes_has_content.t' version: '0.014' - class: Dist::Zilla::Plugin::Test::ChangesHasContent name: '@Author::ETHER/Test::ChangesHasContent' version: '0.011' - class: Dist::Zilla::Plugin::Test::MinimumVersion config: Dist::Zilla::Plugin::Test::MinimumVersion: max_target_perl: '5.008003' name: '@Author::ETHER/Test::MinimumVersion' version: '2.000010' - class: Dist::Zilla::Plugin::PodSyntaxTests name: '@Author::ETHER/PodSyntaxTests' version: '6.015' - class: Dist::Zilla::Plugin::Test::Pod::No404s name: '@Author::ETHER/Test::Pod::No404s' version: '1.004' - class: Dist::Zilla::Plugin::Test::Kwalitee config: Dist::Zilla::Plugin::Test::Kwalitee: filename: xt/author/kwalitee.t skiptest: [] name: '@Author::ETHER/Test::Kwalitee' version: '2.12' - class: Dist::Zilla::Plugin::MojibakeTests name: '@Author::ETHER/MojibakeTests' version: '0.8' - class: Dist::Zilla::Plugin::Test::ReportPrereqs name: '@Author::ETHER/Test::ReportPrereqs' version: '0.027' - class: Dist::Zilla::Plugin::Test::Portability config: Dist::Zilla::Plugin::Test::Portability: options: '' name: '@Author::ETHER/Test::Portability' version: '2.001000' - class: Dist::Zilla::Plugin::Git::Describe name: '@Author::ETHER/Git::Describe' version: '0.007' - class: Dist::Zilla::Plugin::PodWeaver config: Dist::Zilla::Plugin::PodWeaver: config_plugins: - '@Author::ETHER' finder: - ':InstallModules' - ':ExecFiles' plugins: - class: Pod::Weaver::Plugin::EnsurePod5 name: '@Author::ETHER/EnsurePod5' version: '4.015' - class: Pod::Weaver::Plugin::H1Nester name: '@Author::ETHER/H1Nester' version: '4.015' - class: Pod::Weaver::Plugin::SingleEncoding name: '@Author::ETHER/SingleEncoding' version: '4.015' - class: Pod::Weaver::Plugin::Transformer name: '@Author::ETHER/List' version: '4.015' - class: Pod::Weaver::Plugin::Transformer name: '@Author::ETHER/Verbatim' version: '4.015' - class: Pod::Weaver::Section::Region name: '@Author::ETHER/header' version: '4.015' - class: Pod::Weaver::Section::Name name: '@Author::ETHER/Name' version: '4.015' - class: Pod::Weaver::Section::Version name: '@Author::ETHER/Version' version: '4.015' - class: Pod::Weaver::Section::Region name: '@Author::ETHER/prelude' version: '4.015' - class: Pod::Weaver::Section::Generic name: SYNOPSIS version: '4.015' - class: Pod::Weaver::Section::Generic name: DESCRIPTION version: '4.015' - class: Pod::Weaver::Section::Generic name: OVERVIEW version: '4.015' - class: Pod::Weaver::Section::Collect name: ATTRIBUTES version: '4.015' - class: Pod::Weaver::Section::Collect name: METHODS version: '4.015' - class: Pod::Weaver::Section::Collect name: FUNCTIONS version: '4.015' - class: Pod::Weaver::Section::Collect name: TYPES version: '4.015' - class: Pod::Weaver::Section::Leftovers name: '@Author::ETHER/Leftovers' version: '4.015' - class: Pod::Weaver::Section::Region name: '@Author::ETHER/postlude' version: '4.015' - class: Pod::Weaver::Section::GenerateSection name: '@Author::ETHER/generate SUPPORT' version: '1.06' - class: Pod::Weaver::Section::AllowOverride name: '@Author::ETHER/allow override SUPPORT' version: '0.05' - class: Pod::Weaver::Section::Authors name: '@Author::ETHER/Authors' version: '4.015' - class: Pod::Weaver::Section::AllowOverride name: '@Author::ETHER/allow override AUTHOR' version: '0.05' - class: Pod::Weaver::Section::Contributors name: '@Author::ETHER/Contributors' version: '0.009' - class: Pod::Weaver::Section::Legal name: '@Author::ETHER/Legal' version: '4.015' - class: Pod::Weaver::Section::Region name: '@Author::ETHER/footer' version: '4.015' name: '@Author::ETHER/PodWeaver' version: '4.008' - class: Dist::Zilla::Plugin::GithubMeta name: '@Author::ETHER/GithubMeta' version: '0.58' - class: Dist::Zilla::Plugin::AutoMetaResources name: '@Author::ETHER/AutoMetaResources' version: '1.21' - class: Dist::Zilla::Plugin::Authority name: '@Author::ETHER/Authority' version: '1.009' - class: Dist::Zilla::Plugin::MetaNoIndex name: '@Author::ETHER/MetaNoIndex' version: '6.015' - class: Dist::Zilla::Plugin::MetaProvides::Package config: Dist::Zilla::Plugin::MetaProvides::Package: finder: - ':InstallModules' finder_objects: - class: Dist::Zilla::Plugin::FinderCode name: ':InstallModules' version: '6.015' include_underscores: 0 Dist::Zilla::Role::MetaProvider::Provider: $Dist::Zilla::Role::MetaProvider::Provider::VERSION: '2.002004' inherit_missing: '0' inherit_version: '0' meta_noindex: '1' Dist::Zilla::Role::ModuleMetadata: Module::Metadata: '1.000037' version: '0.006' name: '@Author::ETHER/MetaProvides::Package' version: '2.004003' - class: Dist::Zilla::Plugin::MetaConfig name: '@Author::ETHER/MetaConfig' version: '6.015' - class: Dist::Zilla::Plugin::Keywords config: Dist::Zilla::Plugin::Keywords: keywords: [] name: '@Author::ETHER/Keywords' version: '0.007' - class: Dist::Zilla::Plugin::UseUnsafeInc config: Dist::Zilla::Plugin::UseUnsafeInc: dot_in_INC: 0 name: '@Author::ETHER/UseUnsafeInc' version: '0.001' - class: Dist::Zilla::Plugin::AutoPrereqs name: '@Author::ETHER/AutoPrereqs' version: '6.015' - class: Dist::Zilla::Plugin::Prereqs::AuthorDeps name: '@Author::ETHER/Prereqs::AuthorDeps' version: '0.007' - class: Dist::Zilla::Plugin::MinimumPerl name: '@Author::ETHER/MinimumPerl' version: '1.006' - class: Dist::Zilla::Plugin::MakeMaker::Fallback config: Dist::Zilla::Plugin::MakeMaker: make_path: make version: '6.015' Dist::Zilla::Plugin::MakeMaker::Awesome: version: '0.48' Dist::Zilla::Plugin::MakeMaker::Fallback: skip_release_testing: 0 Dist::Zilla::Role::TestRunner: default_jobs: 9 version: '6.015' name: '@Author::ETHER/MakeMaker::Fallback' version: '0.030' - class: Dist::Zilla::Plugin::ModuleBuildTiny::Fallback config: Dist::Zilla::Plugin::ModuleBuildTiny::Fallback: mb_version: '0.28' plugins: - class: Dist::Zilla::Plugin::ModuleBuild config: Dist::Zilla::Role::TestRunner: default_jobs: 9 name: 'ModuleBuild, via ModuleBuildTiny::Fallback' version: '6.015' - class: Dist::Zilla::Plugin::ModuleBuildTiny config: Dist::Zilla::Role::TestRunner: default_jobs: 9 name: 'ModuleBuildTiny, via ModuleBuildTiny::Fallback' version: '0.015' Dist::Zilla::Role::TestRunner: default_jobs: 9 name: '@Author::ETHER/ModuleBuildTiny::Fallback' version: '0.025' - class: Dist::Zilla::Plugin::Git::Contributors config: Dist::Zilla::Plugin::Git::Contributors: git_version: 2.25.0 include_authors: 0 include_releaser: 1 order_by: commits paths: [] name: '@Author::ETHER/Git::Contributors' version: '0.035' - class: Dist::Zilla::Plugin::StaticInstall config: Dist::Zilla::Plugin::StaticInstall: dry_run: 1 mode: auto name: '@Author::ETHER/StaticInstall' version: '0.012' - class: Dist::Zilla::Plugin::RunExtraTests config: Dist::Zilla::Role::TestRunner: default_jobs: 9 name: '@Author::ETHER/RunExtraTests' version: '0.029' - class: Dist::Zilla::Plugin::CheckSelfDependency config: Dist::Zilla::Plugin::CheckSelfDependency: finder: - ':InstallModules' Dist::Zilla::Role::ModuleMetadata: Module::Metadata: '1.000037' version: '0.006' name: '@Author::ETHER/CheckSelfDependency' version: '0.011' - class: Dist::Zilla::Plugin::Run::AfterBuild config: Dist::Zilla::Plugin::Run::Role::Runner: fatal_errors: 1 quiet: 1 run: - "bash -c \"test -e .ackrc && grep -q -- '--ignore-dir=.latest' .ackrc || echo '--ignore-dir=.latest' >> .ackrc; if [[ `dirname '%d'` != .build ]]; then test -e .ackrc && grep -q -- '--ignore-dir=%d' .ackrc || echo '--ignore-dir=%d' >> .ackrc; fi\"" version: '0.048' name: '@Author::ETHER/.ackrc' version: '0.048' - class: Dist::Zilla::Plugin::Run::AfterBuild config: Dist::Zilla::Plugin::Run::Role::Runner: eval: - "if ('%d' =~ /^%n-[.[:xdigit:]]+$/) { unlink '.latest'; symlink '%d', '.latest'; }" fatal_errors: 0 quiet: 1 version: '0.048' name: '@Author::ETHER/.latest' version: '0.048' - class: Dist::Zilla::Plugin::CheckStrictVersion name: '@Author::ETHER/CheckStrictVersion' version: '0.001' - class: Dist::Zilla::Plugin::CheckMetaResources name: '@Author::ETHER/CheckMetaResources' version: '0.001' - class: Dist::Zilla::Plugin::EnsureLatestPerl config: Dist::Zilla::Plugin::EnsureLatestPerl: Module::CoreList: '5.20200620' name: '@Author::ETHER/EnsureLatestPerl' version: '0.008' - class: Dist::Zilla::Plugin::PromptIfStale config: Dist::Zilla::Plugin::PromptIfStale: check_all_plugins: 1 check_all_prereqs: 1 modules: [] phase: release run_under_travis: 0 skip: [] name: '@Author::ETHER/stale modules, release' version: '0.057' - class: Dist::Zilla::Plugin::Git::Check config: Dist::Zilla::Plugin::Git::Check: untracked_files: die Dist::Zilla::Role::Git::DirtyFiles: allow_dirty: [] allow_dirty_match: [] changelog: Changes Dist::Zilla::Role::Git::Repo: git_version: 2.25.0 repo_root: . name: '@Author::ETHER/initial check' version: '2.046' - class: Dist::Zilla::Plugin::Git::CheckFor::MergeConflicts config: Dist::Zilla::Role::Git::Repo: git_version: 2.25.0 repo_root: . name: '@Author::ETHER/Git::CheckFor::MergeConflicts' version: '0.014' - class: Dist::Zilla::Plugin::Git::CheckFor::CorrectBranch config: Dist::Zilla::Role::Git::Repo: git_version: 2.25.0 repo_root: . name: '@Author::ETHER/Git::CheckFor::CorrectBranch' version: '0.014' - class: Dist::Zilla::Plugin::Git::Remote::Check name: '@Author::ETHER/Git::Remote::Check' version: 0.1.2 - class: Dist::Zilla::Plugin::CheckPrereqsIndexed name: '@Author::ETHER/CheckPrereqsIndexed' version: '0.020' - class: Dist::Zilla::Plugin::TestRelease name: '@Author::ETHER/TestRelease' version: '6.015' - class: Dist::Zilla::Plugin::Git::Check config: Dist::Zilla::Plugin::Git::Check: untracked_files: die Dist::Zilla::Role::Git::DirtyFiles: allow_dirty: [] allow_dirty_match: [] changelog: Changes Dist::Zilla::Role::Git::Repo: git_version: 2.25.0 repo_root: . name: '@Author::ETHER/after tests' version: '2.046' - class: Dist::Zilla::Plugin::CheckIssues name: '@Author::ETHER/CheckIssues' version: '0.011' - class: Dist::Zilla::Plugin::UploadToCPAN name: '@Author::ETHER/UploadToCPAN' version: '6.015' - class: Dist::Zilla::Plugin::CopyFilesFromRelease config: Dist::Zilla::Plugin::CopyFilesFromRelease: filename: - CONTRIBUTING - INSTALL - LICENCE - LICENSE - ppport.h match: [] name: '@Author::ETHER/copy generated files' version: '0.006' - class: Dist::Zilla::Plugin::ReadmeAnyFromPod config: Dist::Zilla::Role::FileWatcher: version: '0.006' name: '@Author::ETHER/ReadmeAnyFromPod' version: '0.163250' - class: Dist::Zilla::Plugin::Prereqs config: Dist::Zilla::Plugin::Prereqs: phase: develop type: recommends name: '@Author::ETHER/@Git::VersionManager/pluginbundle version' version: '6.015' - class: Dist::Zilla::Plugin::RewriteVersion::Transitional config: Dist::Zilla::Plugin::RewriteVersion: add_tarball_name: 0 finders: - ':ExecFiles' - ':InstallModules' global: 1 skip_version_provider: 0 Dist::Zilla::Plugin::RewriteVersion::Transitional: {} name: '@Author::ETHER/@Git::VersionManager/RewriteVersion::Transitional' version: '0.009' - class: Dist::Zilla::Plugin::MetaProvides::Update name: '@Author::ETHER/@Git::VersionManager/MetaProvides::Update' version: '0.007' - class: Dist::Zilla::Plugin::CopyFilesFromRelease config: Dist::Zilla::Plugin::CopyFilesFromRelease: filename: - Changes match: [] name: '@Author::ETHER/@Git::VersionManager/CopyFilesFromRelease' version: '0.006' - class: Dist::Zilla::Plugin::Git::Commit config: Dist::Zilla::Plugin::Git::Commit: add_files_in: - . commit_msg: '%N-%v%t%n%n%c' Dist::Zilla::Role::Git::DirtyFiles: allow_dirty: - CONTRIBUTING - Changes - INSTALL - LICENSE - README.pod allow_dirty_match: [] changelog: Changes Dist::Zilla::Role::Git::Repo: git_version: 2.25.0 repo_root: . Dist::Zilla::Role::Git::StringFormatter: time_zone: local name: '@Author::ETHER/@Git::VersionManager/release snapshot' version: '2.046' - class: Dist::Zilla::Plugin::Git::Tag config: Dist::Zilla::Plugin::Git::Tag: branch: ~ changelog: Changes signed: 0 tag: v1.08 tag_format: v%V tag_message: v%v%t Dist::Zilla::Role::Git::Repo: git_version: 2.25.0 repo_root: . Dist::Zilla::Role::Git::StringFormatter: time_zone: local name: '@Author::ETHER/@Git::VersionManager/Git::Tag' version: '2.046' - class: Dist::Zilla::Plugin::BumpVersionAfterRelease::Transitional config: Dist::Zilla::Plugin::BumpVersionAfterRelease: finders: - ':ExecFiles' - ':InstallModules' global: 1 munge_makefile_pl: 1 Dist::Zilla::Plugin::BumpVersionAfterRelease::Transitional: {} name: '@Author::ETHER/@Git::VersionManager/BumpVersionAfterRelease::Transitional' version: '0.009' - class: Dist::Zilla::Plugin::NextRelease name: '@Author::ETHER/@Git::VersionManager/NextRelease' version: '6.015' - class: Dist::Zilla::Plugin::Git::Commit config: Dist::Zilla::Plugin::Git::Commit: add_files_in: [] commit_msg: 'increment $VERSION after %v release' Dist::Zilla::Role::Git::DirtyFiles: allow_dirty: - Build.PL - Changes - Makefile.PL allow_dirty_match: - (?^:^lib/.*\.pm$) changelog: Changes Dist::Zilla::Role::Git::Repo: git_version: 2.25.0 repo_root: . Dist::Zilla::Role::Git::StringFormatter: time_zone: local name: '@Author::ETHER/@Git::VersionManager/post-release commit' version: '2.046' - class: Dist::Zilla::Plugin::Prereqs config: Dist::Zilla::Plugin::Prereqs: phase: x_Dist_Zilla type: requires name: '@Author::ETHER/@Git::VersionManager/prereqs for @Git::VersionManager' version: '6.015' - class: Dist::Zilla::Plugin::Git::Push config: Dist::Zilla::Plugin::Git::Push: push_to: - origin remotes_must_exist: 1 Dist::Zilla::Role::Git::Repo: git_version: 2.25.0 repo_root: . name: '@Author::ETHER/Git::Push' version: '2.046' - class: Dist::Zilla::Plugin::GitHub::Update config: Dist::Zilla::Plugin::GitHub::Update: metacpan: 1 name: '@Author::ETHER/GitHub::Update' version: '0.47' - class: Dist::Zilla::Plugin::Run::AfterRelease config: Dist::Zilla::Plugin::Run::Role::Runner: fatal_errors: 0 quiet: 0 run: - REDACTED version: '0.048' name: '@Author::ETHER/install release' version: '0.048' - class: Dist::Zilla::Plugin::Run::AfterRelease config: Dist::Zilla::Plugin::Run::Role::Runner: eval: - 'print "release complete!\xa"' fatal_errors: 1 quiet: 1 version: '0.048' name: '@Author::ETHER/release complete' version: '0.048' - class: Dist::Zilla::Plugin::ConfirmRelease name: '@Author::ETHER/ConfirmRelease' version: '6.015' - class: Dist::Zilla::Plugin::Prereqs config: Dist::Zilla::Plugin::Prereqs: phase: x_Dist_Zilla type: requires name: '@Author::ETHER/prereqs for @Author::ETHER' version: '6.015' - class: Dist::Zilla::Plugin::Substitute name: Substitute version: '0.006' - class: Dist::Zilla::Plugin::FinderCode name: ':InstallModules' version: '6.015' - class: Dist::Zilla::Plugin::FinderCode name: ':IncModules' version: '6.015' - class: Dist::Zilla::Plugin::FinderCode name: ':TestFiles' version: '6.015' - class: Dist::Zilla::Plugin::FinderCode name: ':ExtraTestFiles' version: '6.015' - class: Dist::Zilla::Plugin::FinderCode name: ':ExecFiles' version: '6.015' - class: Dist::Zilla::Plugin::FinderCode name: ':PerlExecFiles' version: '6.015' - class: Dist::Zilla::Plugin::FinderCode name: ':ShareFiles' version: '6.015' - class: Dist::Zilla::Plugin::FinderCode name: ':MainModule' version: '6.015' - class: Dist::Zilla::Plugin::FinderCode name: ':AllFiles' version: '6.015' - class: Dist::Zilla::Plugin::FinderCode name: ':NoFiles' version: '6.015' - class: Dist::Zilla::Plugin::VerifyPhases name: '@Author::ETHER/PHASE VERIFICATION' version: '0.016' zilla: class: Dist::Zilla::Dist::Builder config: is_trial: '0' version: '6.015' x_authority: cpan:SARTAK x_contributors: - 'sartak ' - 'Shawn M Moore ' - 'Shawn M Moore ' - 'Karen Etheridge ' - 'robertkrimen ' - 'Aaron Trevena ' - 'David Pottage ' - 'Shawn M Moore ' - 'Shawn M Moore ' - 'Florian Ragwitz ' - 'Shawn M Moore ' - 'clkao ' x_generated_by_perl: v5.32.0 x_serialization_backend: 'YAML::Tiny version 1.73' x_spdx_expression: 'Artistic-1.0-Perl OR GPL-1.0-or-later' x_use_unsafe_inc: 0 MANIFEST100644000766000024 347613702474074 15252 0ustar00etherstaff000000000000Path-Dispatcher-1.08# This file was automatically generated by Dist::Zilla::Plugin::Manifest v6.015. Build.PL CONTRIBUTING Changes INSTALL LICENSE MANIFEST META.json META.yml Makefile.PL README dist.ini lib/Path/Dispatcher.pm lib/Path/Dispatcher/Cookbook.pod lib/Path/Dispatcher/Dispatch.pm lib/Path/Dispatcher/Match.pm lib/Path/Dispatcher/Path.pm lib/Path/Dispatcher/Role/Rules.pm lib/Path/Dispatcher/Rule.pm lib/Path/Dispatcher/Rule/Alternation.pm lib/Path/Dispatcher/Rule/Always.pm lib/Path/Dispatcher/Rule/Chain.pm lib/Path/Dispatcher/Rule/CodeRef.pm lib/Path/Dispatcher/Rule/Dispatch.pm lib/Path/Dispatcher/Rule/Empty.pm lib/Path/Dispatcher/Rule/Enum.pm lib/Path/Dispatcher/Rule/Eq.pm lib/Path/Dispatcher/Rule/Intersection.pm lib/Path/Dispatcher/Rule/Metadata.pm lib/Path/Dispatcher/Rule/Regex.pm lib/Path/Dispatcher/Rule/Sequence.pm lib/Path/Dispatcher/Rule/Tokens.pm lib/Path/Dispatcher/Rule/Under.pm t/00-report-prereqs.dd t/00-report-prereqs.t t/000-compile.t t/001-api.t t/002-rule.t t/003-404.t t/004-run.t t/005-multi-rule.t t/006-abort.t t/007-coderef-matcher.t t/009-args.t t/010-return.t t/011-next-rule.t t/012-under.t t/013-tokens.t t/014-tokens-prefix.t t/015-regex-prefix.t t/017-intersection.t t/018-metadata.t t/019-intersection-metadata.t t/022-numbers-undef.t t/023-alternation.t t/024-sequence.t t/025-sequence-custom-rule.t t/026-named-captures.t t/027-custom-named-captures.t t/030-exceptions.t t/031-structured-match.t t/032-multiple-delimiter.t t/033-chain.t t/100-match-object.t t/200-payload.t t/901-return-values.t t/902-coderef.t xt/author/00-compile.t xt/author/changes_has_content.t xt/author/eol.t xt/author/kwalitee.t xt/author/minimum-version.t xt/author/mojibake.t xt/author/no-tabs.t xt/author/pod-no404s.t xt/author/pod-syntax.t xt/author/portability.t xt/release/changes_has_content.t xt/release/cpan-changes.t xt/release/distmeta.t Build.PL100644000766000024 752513702474074 15414 0ustar00etherstaff000000000000Path-Dispatcher-1.08# This Build.PL for Path-Dispatcher was generated by # Dist::Zilla::Plugin::ModuleBuildTiny::Fallback 0.025 use strict; use warnings; my %configure_requires = ( 'ExtUtils::MakeMaker' => '0', 'Module::Build::Tiny' => '0.034', ); my %errors = map { eval "require $_; $_->VERSION($configure_requires{$_}); 1"; $_ => $@, } keys %configure_requires; if (!grep { $_ } values %errors) { # This section for Path-Dispatcher was generated by Dist::Zilla::Plugin::ModuleBuildTiny 0.015. use strict; use warnings; use 5.008001; # use Module::Build::Tiny 0.034; Module::Build::Tiny::Build_PL(); } else { if (not $ENV{PERL_MB_FALLBACK_SILENCE_WARNING}) { warn <<'EOW' *** WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING *** If you're seeing this warning, your toolchain is really, really old* and you'll almost certainly have problems installing CPAN modules from this century. But never fear, dear user, for we have the technology to fix this! If you're using CPAN.pm to install things, then you can upgrade it using: cpan CPAN If you're using CPANPLUS to install things, then you can upgrade it using: cpanp CPANPLUS If you're using cpanminus, you shouldn't be seeing this message in the first place, so please file an issue on github. This public service announcement was brought to you by the Perl Toolchain Gang, the irc.perl.org #toolchain IRC channel, and the number 42. ---- * Alternatively, you are running this file manually, in which case you need to learn to first fulfill all configure requires prerequisites listed in META.yml or META.json -- or use a cpan client to install this distribution. You can also silence this warning for future installations by setting the PERL_MB_FALLBACK_SILENCE_WARNING environment variable, but please don't do that until you fix your toolchain as described above. Errors from configure prereqs: EOW . do { require Data::Dumper; Data::Dumper->new([ \%errors ])->Indent(2)->Terse(1)->Sortkeys(1)->Dump; }; sleep 10 if -t STDIN && (-t STDOUT || !(-f STDOUT || -c STDOUT)); } # This section was automatically generated by Dist::Zilla::Plugin::ModuleBuild v6.015. use strict; use warnings; require Module::Build; Module::Build->VERSION(0.28); my %module_build_args = ( "configure_requires" => { "ExtUtils::MakeMaker" => 0, "Module::Build::Tiny" => "0.034", "perl" => "5.008001" }, "dist_abstract" => "Flexible and extensible dispatch", "dist_author" => [ "Shawn M Moore, C<< >>" ], "dist_name" => "Path-Dispatcher", "dist_version" => "1.08", "license" => "perl", "module_name" => "Path::Dispatcher", "recursive_test_files" => 1, "requires" => { "Carp" => 0, "Moo" => 0, "Moo::Role" => 0, "MooX::TypeTiny" => 0, "Scalar::Util" => 0, "Try::Tiny" => 0, "Type::Tiny" => 0, "Type::Utils" => 0, "Types::Standard" => 0, "constant" => 0, "overload" => 0, "perl" => "5.008001" }, "test_requires" => { "File::Spec" => 0, "Module::Metadata" => 0, "Test::Fatal" => 0, "Test::More" => 0, "perl" => "5.008001", "strict" => 0, "warnings" => 0 } ); my %fallback_build_requires = ( "File::Spec" => 0, "Module::Metadata" => 0, "Test::Fatal" => 0, "Test::More" => 0, "perl" => "5.008001", "strict" => 0, "warnings" => 0 ); unless ( eval { Module::Build->VERSION(0.4004) } ) { delete $module_build_args{test_requires}; $module_build_args{build_requires} = \%fallback_build_requires; } my $build = Module::Build->new(%module_build_args); $build->create_build_script; } META.json100644000766000024 14122513702474074 15575 0ustar00etherstaff000000000000Path-Dispatcher-1.08{ "abstract" : "Flexible and extensible dispatch", "author" : [ "Shawn M Moore, C<< >>" ], "dynamic_config" : 0, "generated_by" : "Dist::Zilla version 6.015, CPAN::Meta::Converter version 2.150010", "license" : [ "perl_5" ], "meta-spec" : { "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec", "version" : 2 }, "name" : "Path-Dispatcher", "no_index" : { "directory" : [ "t", "xt" ] }, "prereqs" : { "configure" : { "requires" : { "ExtUtils::MakeMaker" : "0", "Module::Build::Tiny" : "0.034", "perl" : "5.008001" } }, "develop" : { "recommends" : { "Dist::Zilla::PluginBundle::Author::ETHER" : "0.158", "Dist::Zilla::PluginBundle::Git::VersionManager" : "0.007" }, "requires" : { "Encode" : "0", "File::Spec" : "0", "IO::Handle" : "0", "IPC::Open3" : "0", "Test::CPAN::Changes" : "0.19", "Test::CPAN::Meta" : "0", "Test::EOL" : "0", "Test::Kwalitee" : "1.21", "Test::MinimumVersion" : "0", "Test::Mojibake" : "0", "Test::More" : "0.96", "Test::NoTabs" : "0", "Test::Pod" : "1.41", "Test::Pod::No404s" : "0", "Test::Portability::Files" : "0", "strict" : "0", "warnings" : "0" } }, "runtime" : { "requires" : { "Carp" : "0", "Moo" : "0", "Moo::Role" : "0", "MooX::TypeTiny" : "0", "Scalar::Util" : "0", "Try::Tiny" : "0", "Type::Tiny" : "0", "Type::Utils" : "0", "Types::Standard" : "0", "constant" : "0", "overload" : "0", "perl" : "5.008001" } }, "test" : { "recommends" : { "CPAN::Meta" : "2.120900" }, "requires" : { "File::Spec" : "0", "Module::Metadata" : "0", "Test::Fatal" : "0", "Test::More" : "0", "perl" : "5.008001", "strict" : "0", "warnings" : "0" } }, "x_Dist_Zilla" : { "requires" : { "Dist::Zilla" : "5", "Dist::Zilla::Plugin::Authority" : "1.009", "Dist::Zilla::Plugin::AutoMetaResources" : "0", "Dist::Zilla::Plugin::AutoPrereqs" : "5.038", "Dist::Zilla::Plugin::BumpVersionAfterRelease::Transitional" : "0.004", "Dist::Zilla::Plugin::CheckIssues" : "0", "Dist::Zilla::Plugin::CheckMetaResources" : "0", "Dist::Zilla::Plugin::CheckPrereqsIndexed" : "0.019", "Dist::Zilla::Plugin::CheckSelfDependency" : "0", "Dist::Zilla::Plugin::CheckStrictVersion" : "0", "Dist::Zilla::Plugin::ConfirmRelease" : "0", "Dist::Zilla::Plugin::CopyFilesFromRelease" : "0", "Dist::Zilla::Plugin::EnsureLatestPerl" : "0", "Dist::Zilla::Plugin::FileFinder::ByName" : "0", "Dist::Zilla::Plugin::FileFinder::Filter" : "0", "Dist::Zilla::Plugin::GenerateFile::FromShareDir" : "0", "Dist::Zilla::Plugin::Git::Check" : "0", "Dist::Zilla::Plugin::Git::CheckFor::CorrectBranch" : "0.004", "Dist::Zilla::Plugin::Git::CheckFor::MergeConflicts" : "0", "Dist::Zilla::Plugin::Git::Commit" : "2.020", "Dist::Zilla::Plugin::Git::Contributors" : "0.029", "Dist::Zilla::Plugin::Git::Describe" : "0.004", "Dist::Zilla::Plugin::Git::GatherDir" : "2.016", "Dist::Zilla::Plugin::Git::Push" : "0", "Dist::Zilla::Plugin::Git::Remote::Check" : "0", "Dist::Zilla::Plugin::Git::Tag" : "0", "Dist::Zilla::Plugin::GitHub::Update" : "0.40", "Dist::Zilla::Plugin::GithubMeta" : "0.54", "Dist::Zilla::Plugin::InstallGuide" : "1.200005", "Dist::Zilla::Plugin::Keywords" : "0.004", "Dist::Zilla::Plugin::License" : "5.038", "Dist::Zilla::Plugin::MakeMaker::Fallback" : "0.029", "Dist::Zilla::Plugin::Manifest" : "0", "Dist::Zilla::Plugin::MetaConfig" : "0", "Dist::Zilla::Plugin::MetaJSON" : "0", "Dist::Zilla::Plugin::MetaNoIndex" : "0", "Dist::Zilla::Plugin::MetaProvides::Package" : "1.15000002", "Dist::Zilla::Plugin::MetaTests" : "0", "Dist::Zilla::Plugin::MetaYAML" : "0", "Dist::Zilla::Plugin::MinimumPerl" : "1.006", "Dist::Zilla::Plugin::ModuleBuildTiny::Fallback" : "0.018", "Dist::Zilla::Plugin::MojibakeTests" : "0.8", "Dist::Zilla::Plugin::NextRelease" : "5.033", "Dist::Zilla::Plugin::PodSyntaxTests" : "5.040", "Dist::Zilla::Plugin::PodWeaver" : "4.008", "Dist::Zilla::Plugin::Prereqs" : "0", "Dist::Zilla::Plugin::Prereqs::AuthorDeps" : "0.006", "Dist::Zilla::Plugin::PromptIfStale" : "0", "Dist::Zilla::Plugin::Readme" : "0", "Dist::Zilla::Plugin::ReadmeAnyFromPod" : "0.142180", "Dist::Zilla::Plugin::RewriteVersion::Transitional" : "0.006", "Dist::Zilla::Plugin::Run::AfterBuild" : "0.041", "Dist::Zilla::Plugin::Run::AfterRelease" : "0.038", "Dist::Zilla::Plugin::RunExtraTests" : "0.024", "Dist::Zilla::Plugin::StaticInstall" : "0.005", "Dist::Zilla::Plugin::Substitute" : "0", "Dist::Zilla::Plugin::Test::CPAN::Changes" : "0.012", "Dist::Zilla::Plugin::Test::ChangesHasContent" : "0", "Dist::Zilla::Plugin::Test::Compile" : "2.039", "Dist::Zilla::Plugin::Test::EOL" : "0.17", "Dist::Zilla::Plugin::Test::Kwalitee" : "2.10", "Dist::Zilla::Plugin::Test::MinimumVersion" : "2.000010", "Dist::Zilla::Plugin::Test::NoTabs" : "0.08", "Dist::Zilla::Plugin::Test::Pod::No404s" : "1.003", "Dist::Zilla::Plugin::Test::Portability" : "2.000007", "Dist::Zilla::Plugin::Test::ReportPrereqs" : "0.022", "Dist::Zilla::Plugin::TestRelease" : "0", "Dist::Zilla::Plugin::UploadToCPAN" : "0", "Dist::Zilla::Plugin::UseUnsafeInc" : "0", "Dist::Zilla::PluginBundle::Author::ETHER" : "0.119", "Dist::Zilla::PluginBundle::Git::VersionManager" : "0.007", "Software::License::Perl_5" : "0" } } }, "provides" : { "Path::Dispatcher" : { "file" : "lib/Path/Dispatcher.pm", "version" : "1.08" }, "Path::Dispatcher::Dispatch" : { "file" : "lib/Path/Dispatcher/Dispatch.pm", "version" : "1.08" }, "Path::Dispatcher::Match" : { "file" : "lib/Path/Dispatcher/Match.pm", "version" : "1.08" }, "Path::Dispatcher::Path" : { "file" : "lib/Path/Dispatcher/Path.pm", "version" : "1.08" }, "Path::Dispatcher::Role::Rules" : { "file" : "lib/Path/Dispatcher/Role/Rules.pm", "version" : "1.08" }, "Path::Dispatcher::Rule" : { "file" : "lib/Path/Dispatcher/Rule.pm", "version" : "1.08" }, "Path::Dispatcher::Rule::Alternation" : { "file" : "lib/Path/Dispatcher/Rule/Alternation.pm", "version" : "1.08" }, "Path::Dispatcher::Rule::Always" : { "file" : "lib/Path/Dispatcher/Rule/Always.pm", "version" : "1.08" }, "Path::Dispatcher::Rule::Chain" : { "file" : "lib/Path/Dispatcher/Rule/Chain.pm", "version" : "1.08" }, "Path::Dispatcher::Rule::CodeRef" : { "file" : "lib/Path/Dispatcher/Rule/CodeRef.pm", "version" : "1.08" }, "Path::Dispatcher::Rule::Dispatch" : { "file" : "lib/Path/Dispatcher/Rule/Dispatch.pm", "version" : "1.08" }, "Path::Dispatcher::Rule::Empty" : { "file" : "lib/Path/Dispatcher/Rule/Empty.pm", "version" : "1.08" }, "Path::Dispatcher::Rule::Enum" : { "file" : "lib/Path/Dispatcher/Rule/Enum.pm", "version" : "1.08" }, "Path::Dispatcher::Rule::Eq" : { "file" : "lib/Path/Dispatcher/Rule/Eq.pm", "version" : "1.08" }, "Path::Dispatcher::Rule::Intersection" : { "file" : "lib/Path/Dispatcher/Rule/Intersection.pm", "version" : "1.08" }, "Path::Dispatcher::Rule::Metadata" : { "file" : "lib/Path/Dispatcher/Rule/Metadata.pm", "version" : "1.08" }, "Path::Dispatcher::Rule::Regex" : { "file" : "lib/Path/Dispatcher/Rule/Regex.pm", "version" : "1.08" }, "Path::Dispatcher::Rule::Sequence" : { "file" : "lib/Path/Dispatcher/Rule/Sequence.pm", "version" : "1.08" }, "Path::Dispatcher::Rule::Tokens" : { "file" : "lib/Path/Dispatcher/Rule/Tokens.pm", "version" : "1.08" }, "Path::Dispatcher::Rule::Under" : { "file" : "lib/Path/Dispatcher/Rule/Under.pm", "version" : "1.08" } }, "release_status" : "stable", "resources" : { "bugtracker" : { "mailto" : "bug-Path-Dispatcher@rt.cpan.org", "web" : "https://rt.cpan.org/Public/Dist/Display.html?Name=Path-Dispatcher" }, "homepage" : "https://github.com/karenetheridge/Path-Dispatcher", "repository" : { "type" : "git", "url" : "https://github.com/karenetheridge/Path-Dispatcher.git", "web" : "https://github.com/karenetheridge/Path-Dispatcher" } }, "version" : "1.08", "x_Dist_Zilla" : { "perl" : { "version" : "5.032000" }, "plugins" : [ { "class" : "Dist::Zilla::Plugin::FileFinder::Filter", "name" : "all_files_but_using_5.10_features", "version" : "6.015" }, { "class" : "Dist::Zilla::Plugin::Prereqs", "config" : { "Dist::Zilla::Plugin::Prereqs" : { "phase" : "develop", "type" : "recommends" } }, "name" : "@Author::ETHER/pluginbundle version", "version" : "6.015" }, { "class" : "Dist::Zilla::Plugin::PromptIfStale", "config" : { "Dist::Zilla::Plugin::PromptIfStale" : { "check_all_plugins" : 0, "check_all_prereqs" : 0, "modules" : [ "Dist::Zilla::PluginBundle::Author::ETHER" ], "phase" : "build", "run_under_travis" : 0, "skip" : [] } }, "name" : "@Author::ETHER/stale modules, build", "version" : "0.057" }, { "class" : "Dist::Zilla::Plugin::FileFinder::ByName", "name" : "@Author::ETHER/Examples", "version" : "6.015" }, { "class" : "Dist::Zilla::Plugin::Git::GatherDir", "config" : { "Dist::Zilla::Plugin::GatherDir" : { "exclude_filename" : [ "CONTRIBUTING", "INSTALL", "LICENSE", "README.pod" ], "exclude_match" : [], "follow_symlinks" : 0, "include_dotfiles" : 0, "prefix" : "", "prune_directory" : [], "root" : "." }, "Dist::Zilla::Plugin::Git::GatherDir" : { "include_untracked" : 0 } }, "name" : "@Author::ETHER/Git::GatherDir", "version" : "2.046" }, { "class" : "Dist::Zilla::Plugin::MetaYAML", "name" : "@Author::ETHER/MetaYAML", "version" : "6.015" }, { "class" : "Dist::Zilla::Plugin::MetaJSON", "name" : "@Author::ETHER/MetaJSON", "version" : "6.015" }, { "class" : "Dist::Zilla::Plugin::Readme", "name" : "@Author::ETHER/Readme", "version" : "6.015" }, { "class" : "Dist::Zilla::Plugin::Manifest", "name" : "@Author::ETHER/Manifest", "version" : "6.015" }, { "class" : "Dist::Zilla::Plugin::License", "name" : "@Author::ETHER/License", "version" : "6.015" }, { "class" : "Dist::Zilla::Plugin::GenerateFile::FromShareDir", "config" : { "Dist::Zilla::Plugin::GenerateFile::FromShareDir" : { "destination_filename" : "CONTRIBUTING", "dist" : "Dist-Zilla-PluginBundle-Author-ETHER", "encoding" : "UTF-8", "has_xs" : 0, "location" : "build", "source_filename" : "CONTRIBUTING" }, "Dist::Zilla::Role::RepoFileInjector" : { "allow_overwrite" : 1, "repo_root" : ".", "version" : "0.009" } }, "name" : "@Author::ETHER/generate CONTRIBUTING", "version" : "0.014" }, { "class" : "Dist::Zilla::Plugin::InstallGuide", "config" : { "Dist::Zilla::Role::ModuleMetadata" : { "Module::Metadata" : "1.000037", "version" : "0.006" } }, "name" : "@Author::ETHER/InstallGuide", "version" : "1.200013" }, { "class" : "Dist::Zilla::Plugin::Test::Compile", "config" : { "Dist::Zilla::Plugin::Test::Compile" : { "bail_out_on_fail" : 1, "fail_on_warning" : "author", "fake_home" : 0, "filename" : "xt/author/00-compile.t", "module_finder" : [ ":InstallModules" ], "needs_display" : 0, "phase" : "develop", "script_finder" : [ ":PerlExecFiles", "@Author::ETHER/Examples" ], "skips" : [], "switch" : [] } }, "name" : "@Author::ETHER/Test::Compile", "version" : "2.058" }, { "class" : "Dist::Zilla::Plugin::Test::NoTabs", "config" : { "Dist::Zilla::Plugin::Test::NoTabs" : { "filename" : "xt/author/no-tabs.t", "finder" : [ ":InstallModules", ":ExecFiles", "@Author::ETHER/Examples", ":TestFiles", ":ExtraTestFiles" ] } }, "name" : "@Author::ETHER/Test::NoTabs", "version" : "0.15" }, { "class" : "Dist::Zilla::Plugin::Test::EOL", "config" : { "Dist::Zilla::Plugin::Test::EOL" : { "filename" : "xt/author/eol.t", "finder" : [ ":ExecFiles", ":ExtraTestFiles", ":InstallModules", ":TestFiles", "@Author::ETHER/Examples" ], "trailing_whitespace" : 1 } }, "name" : "@Author::ETHER/Test::EOL", "version" : "0.19" }, { "class" : "Dist::Zilla::Plugin::MetaTests", "name" : "@Author::ETHER/MetaTests", "version" : "6.015" }, { "class" : "Dist::Zilla::Plugin::Test::CPAN::Changes", "config" : { "Dist::Zilla::Plugin::Test::CPAN::Changes" : { "changelog" : "Changes" } }, "name" : "@Author::ETHER/Test::CPAN::Changes", "version" : "0.012" }, { "class" : "Dist::Zilla::Plugin::GenerateFile::FromShareDir", "config" : { "Dist::Zilla::Plugin::GenerateFile::FromShareDir" : { "destination_filename" : "xt/author/changes_has_content.t", "dist" : "Dist-Zilla-PluginBundle-Author-ETHER", "encoding" : "UTF-8", "location" : "build", "source_filename" : "changes_has_content.t" }, "Dist::Zilla::Role::RepoFileInjector" : { "allow_overwrite" : 1, "repo_root" : ".", "version" : "0.009" } }, "name" : "@Author::ETHER/generate xt/author/changes_has_content.t", "version" : "0.014" }, { "class" : "Dist::Zilla::Plugin::Test::ChangesHasContent", "name" : "@Author::ETHER/Test::ChangesHasContent", "version" : "0.011" }, { "class" : "Dist::Zilla::Plugin::Test::MinimumVersion", "config" : { "Dist::Zilla::Plugin::Test::MinimumVersion" : { "max_target_perl" : 5.008003 } }, "name" : "@Author::ETHER/Test::MinimumVersion", "version" : "2.000010" }, { "class" : "Dist::Zilla::Plugin::PodSyntaxTests", "name" : "@Author::ETHER/PodSyntaxTests", "version" : "6.015" }, { "class" : "Dist::Zilla::Plugin::Test::Pod::No404s", "name" : "@Author::ETHER/Test::Pod::No404s", "version" : "1.004" }, { "class" : "Dist::Zilla::Plugin::Test::Kwalitee", "config" : { "Dist::Zilla::Plugin::Test::Kwalitee" : { "filename" : "xt/author/kwalitee.t", "skiptest" : [] } }, "name" : "@Author::ETHER/Test::Kwalitee", "version" : "2.12" }, { "class" : "Dist::Zilla::Plugin::MojibakeTests", "name" : "@Author::ETHER/MojibakeTests", "version" : "0.8" }, { "class" : "Dist::Zilla::Plugin::Test::ReportPrereqs", "name" : "@Author::ETHER/Test::ReportPrereqs", "version" : "0.027" }, { "class" : "Dist::Zilla::Plugin::Test::Portability", "config" : { "Dist::Zilla::Plugin::Test::Portability" : { "options" : "" } }, "name" : "@Author::ETHER/Test::Portability", "version" : "2.001000" }, { "class" : "Dist::Zilla::Plugin::Git::Describe", "name" : "@Author::ETHER/Git::Describe", "version" : "0.007" }, { "class" : "Dist::Zilla::Plugin::PodWeaver", "config" : { "Dist::Zilla::Plugin::PodWeaver" : { "config_plugins" : [ "@Author::ETHER" ], "finder" : [ ":InstallModules", ":ExecFiles" ], "plugins" : [ { "class" : "Pod::Weaver::Plugin::EnsurePod5", "name" : "@Author::ETHER/EnsurePod5", "version" : "4.015" }, { "class" : "Pod::Weaver::Plugin::H1Nester", "name" : "@Author::ETHER/H1Nester", "version" : "4.015" }, { "class" : "Pod::Weaver::Plugin::SingleEncoding", "name" : "@Author::ETHER/SingleEncoding", "version" : "4.015" }, { "class" : "Pod::Weaver::Plugin::Transformer", "name" : "@Author::ETHER/List", "version" : "4.015" }, { "class" : "Pod::Weaver::Plugin::Transformer", "name" : "@Author::ETHER/Verbatim", "version" : "4.015" }, { "class" : "Pod::Weaver::Section::Region", "name" : "@Author::ETHER/header", "version" : "4.015" }, { "class" : "Pod::Weaver::Section::Name", "name" : "@Author::ETHER/Name", "version" : "4.015" }, { "class" : "Pod::Weaver::Section::Version", "name" : "@Author::ETHER/Version", "version" : "4.015" }, { "class" : "Pod::Weaver::Section::Region", "name" : "@Author::ETHER/prelude", "version" : "4.015" }, { "class" : "Pod::Weaver::Section::Generic", "name" : "SYNOPSIS", "version" : "4.015" }, { "class" : "Pod::Weaver::Section::Generic", "name" : "DESCRIPTION", "version" : "4.015" }, { "class" : "Pod::Weaver::Section::Generic", "name" : "OVERVIEW", "version" : "4.015" }, { "class" : "Pod::Weaver::Section::Collect", "name" : "ATTRIBUTES", "version" : "4.015" }, { "class" : "Pod::Weaver::Section::Collect", "name" : "METHODS", "version" : "4.015" }, { "class" : "Pod::Weaver::Section::Collect", "name" : "FUNCTIONS", "version" : "4.015" }, { "class" : "Pod::Weaver::Section::Collect", "name" : "TYPES", "version" : "4.015" }, { "class" : "Pod::Weaver::Section::Leftovers", "name" : "@Author::ETHER/Leftovers", "version" : "4.015" }, { "class" : "Pod::Weaver::Section::Region", "name" : "@Author::ETHER/postlude", "version" : "4.015" }, { "class" : "Pod::Weaver::Section::GenerateSection", "name" : "@Author::ETHER/generate SUPPORT", "version" : "1.06" }, { "class" : "Pod::Weaver::Section::AllowOverride", "name" : "@Author::ETHER/allow override SUPPORT", "version" : "0.05" }, { "class" : "Pod::Weaver::Section::Authors", "name" : "@Author::ETHER/Authors", "version" : "4.015" }, { "class" : "Pod::Weaver::Section::AllowOverride", "name" : "@Author::ETHER/allow override AUTHOR", "version" : "0.05" }, { "class" : "Pod::Weaver::Section::Contributors", "name" : "@Author::ETHER/Contributors", "version" : "0.009" }, { "class" : "Pod::Weaver::Section::Legal", "name" : "@Author::ETHER/Legal", "version" : "4.015" }, { "class" : "Pod::Weaver::Section::Region", "name" : "@Author::ETHER/footer", "version" : "4.015" } ] } }, "name" : "@Author::ETHER/PodWeaver", "version" : "4.008" }, { "class" : "Dist::Zilla::Plugin::GithubMeta", "name" : "@Author::ETHER/GithubMeta", "version" : "0.58" }, { "class" : "Dist::Zilla::Plugin::AutoMetaResources", "name" : "@Author::ETHER/AutoMetaResources", "version" : "1.21" }, { "class" : "Dist::Zilla::Plugin::Authority", "name" : "@Author::ETHER/Authority", "version" : "1.009" }, { "class" : "Dist::Zilla::Plugin::MetaNoIndex", "name" : "@Author::ETHER/MetaNoIndex", "version" : "6.015" }, { "class" : "Dist::Zilla::Plugin::MetaProvides::Package", "config" : { "Dist::Zilla::Plugin::MetaProvides::Package" : { "finder" : [ ":InstallModules" ], "finder_objects" : [ { "class" : "Dist::Zilla::Plugin::FinderCode", "name" : ":InstallModules", "version" : "6.015" } ], "include_underscores" : 0 }, "Dist::Zilla::Role::MetaProvider::Provider" : { "$Dist::Zilla::Role::MetaProvider::Provider::VERSION" : "2.002004", "inherit_missing" : 0, "inherit_version" : 0, "meta_noindex" : 1 }, "Dist::Zilla::Role::ModuleMetadata" : { "Module::Metadata" : "1.000037", "version" : "0.006" } }, "name" : "@Author::ETHER/MetaProvides::Package", "version" : "2.004003" }, { "class" : "Dist::Zilla::Plugin::MetaConfig", "name" : "@Author::ETHER/MetaConfig", "version" : "6.015" }, { "class" : "Dist::Zilla::Plugin::Keywords", "config" : { "Dist::Zilla::Plugin::Keywords" : { "keywords" : [] } }, "name" : "@Author::ETHER/Keywords", "version" : "0.007" }, { "class" : "Dist::Zilla::Plugin::UseUnsafeInc", "config" : { "Dist::Zilla::Plugin::UseUnsafeInc" : { "dot_in_INC" : 0 } }, "name" : "@Author::ETHER/UseUnsafeInc", "version" : "0.001" }, { "class" : "Dist::Zilla::Plugin::AutoPrereqs", "name" : "@Author::ETHER/AutoPrereqs", "version" : "6.015" }, { "class" : "Dist::Zilla::Plugin::Prereqs::AuthorDeps", "name" : "@Author::ETHER/Prereqs::AuthorDeps", "version" : "0.007" }, { "class" : "Dist::Zilla::Plugin::MinimumPerl", "name" : "@Author::ETHER/MinimumPerl", "version" : "1.006" }, { "class" : "Dist::Zilla::Plugin::MakeMaker::Fallback", "config" : { "Dist::Zilla::Plugin::MakeMaker" : { "make_path" : "make", "version" : "6.015" }, "Dist::Zilla::Plugin::MakeMaker::Awesome" : { "version" : "0.48" }, "Dist::Zilla::Plugin::MakeMaker::Fallback" : { "skip_release_testing" : 0 }, "Dist::Zilla::Role::TestRunner" : { "default_jobs" : 9, "version" : "6.015" } }, "name" : "@Author::ETHER/MakeMaker::Fallback", "version" : "0.030" }, { "class" : "Dist::Zilla::Plugin::ModuleBuildTiny::Fallback", "config" : { "Dist::Zilla::Plugin::ModuleBuildTiny::Fallback" : { "mb_version" : "0.28", "plugins" : [ { "class" : "Dist::Zilla::Plugin::ModuleBuild", "config" : { "Dist::Zilla::Role::TestRunner" : { "default_jobs" : 9 } }, "name" : "ModuleBuild, via ModuleBuildTiny::Fallback", "version" : "6.015" }, { "class" : "Dist::Zilla::Plugin::ModuleBuildTiny", "config" : { "Dist::Zilla::Role::TestRunner" : { "default_jobs" : 9 } }, "name" : "ModuleBuildTiny, via ModuleBuildTiny::Fallback", "version" : "0.015" } ] }, "Dist::Zilla::Role::TestRunner" : { "default_jobs" : 9 } }, "name" : "@Author::ETHER/ModuleBuildTiny::Fallback", "version" : "0.025" }, { "class" : "Dist::Zilla::Plugin::Git::Contributors", "config" : { "Dist::Zilla::Plugin::Git::Contributors" : { "git_version" : "2.25.0", "include_authors" : 0, "include_releaser" : 1, "order_by" : "commits", "paths" : [] } }, "name" : "@Author::ETHER/Git::Contributors", "version" : "0.035" }, { "class" : "Dist::Zilla::Plugin::StaticInstall", "config" : { "Dist::Zilla::Plugin::StaticInstall" : { "dry_run" : 1, "mode" : "auto" } }, "name" : "@Author::ETHER/StaticInstall", "version" : "0.012" }, { "class" : "Dist::Zilla::Plugin::RunExtraTests", "config" : { "Dist::Zilla::Role::TestRunner" : { "default_jobs" : 9 } }, "name" : "@Author::ETHER/RunExtraTests", "version" : "0.029" }, { "class" : "Dist::Zilla::Plugin::CheckSelfDependency", "config" : { "Dist::Zilla::Plugin::CheckSelfDependency" : { "finder" : [ ":InstallModules" ] }, "Dist::Zilla::Role::ModuleMetadata" : { "Module::Metadata" : "1.000037", "version" : "0.006" } }, "name" : "@Author::ETHER/CheckSelfDependency", "version" : "0.011" }, { "class" : "Dist::Zilla::Plugin::Run::AfterBuild", "config" : { "Dist::Zilla::Plugin::Run::Role::Runner" : { "fatal_errors" : 1, "quiet" : 1, "run" : [ "bash -c \"test -e .ackrc && grep -q -- '--ignore-dir=.latest' .ackrc || echo '--ignore-dir=.latest' >> .ackrc; if [[ `dirname '%d'` != .build ]]; then test -e .ackrc && grep -q -- '--ignore-dir=%d' .ackrc || echo '--ignore-dir=%d' >> .ackrc; fi\"" ], "version" : "0.048" } }, "name" : "@Author::ETHER/.ackrc", "version" : "0.048" }, { "class" : "Dist::Zilla::Plugin::Run::AfterBuild", "config" : { "Dist::Zilla::Plugin::Run::Role::Runner" : { "eval" : [ "if ('%d' =~ /^%n-[.[:xdigit:]]+$/) { unlink '.latest'; symlink '%d', '.latest'; }" ], "fatal_errors" : 0, "quiet" : 1, "version" : "0.048" } }, "name" : "@Author::ETHER/.latest", "version" : "0.048" }, { "class" : "Dist::Zilla::Plugin::CheckStrictVersion", "name" : "@Author::ETHER/CheckStrictVersion", "version" : "0.001" }, { "class" : "Dist::Zilla::Plugin::CheckMetaResources", "name" : "@Author::ETHER/CheckMetaResources", "version" : "0.001" }, { "class" : "Dist::Zilla::Plugin::EnsureLatestPerl", "config" : { "Dist::Zilla::Plugin::EnsureLatestPerl" : { "Module::CoreList" : "5.20200620" } }, "name" : "@Author::ETHER/EnsureLatestPerl", "version" : "0.008" }, { "class" : "Dist::Zilla::Plugin::PromptIfStale", "config" : { "Dist::Zilla::Plugin::PromptIfStale" : { "check_all_plugins" : 1, "check_all_prereqs" : 1, "modules" : [], "phase" : "release", "run_under_travis" : 0, "skip" : [] } }, "name" : "@Author::ETHER/stale modules, release", "version" : "0.057" }, { "class" : "Dist::Zilla::Plugin::Git::Check", "config" : { "Dist::Zilla::Plugin::Git::Check" : { "untracked_files" : "die" }, "Dist::Zilla::Role::Git::DirtyFiles" : { "allow_dirty" : [], "allow_dirty_match" : [], "changelog" : "Changes" }, "Dist::Zilla::Role::Git::Repo" : { "git_version" : "2.25.0", "repo_root" : "." } }, "name" : "@Author::ETHER/initial check", "version" : "2.046" }, { "class" : "Dist::Zilla::Plugin::Git::CheckFor::MergeConflicts", "config" : { "Dist::Zilla::Role::Git::Repo" : { "git_version" : "2.25.0", "repo_root" : "." } }, "name" : "@Author::ETHER/Git::CheckFor::MergeConflicts", "version" : "0.014" }, { "class" : "Dist::Zilla::Plugin::Git::CheckFor::CorrectBranch", "config" : { "Dist::Zilla::Role::Git::Repo" : { "git_version" : "2.25.0", "repo_root" : "." } }, "name" : "@Author::ETHER/Git::CheckFor::CorrectBranch", "version" : "0.014" }, { "class" : "Dist::Zilla::Plugin::Git::Remote::Check", "name" : "@Author::ETHER/Git::Remote::Check", "version" : "0.1.2" }, { "class" : "Dist::Zilla::Plugin::CheckPrereqsIndexed", "name" : "@Author::ETHER/CheckPrereqsIndexed", "version" : "0.020" }, { "class" : "Dist::Zilla::Plugin::TestRelease", "name" : "@Author::ETHER/TestRelease", "version" : "6.015" }, { "class" : "Dist::Zilla::Plugin::Git::Check", "config" : { "Dist::Zilla::Plugin::Git::Check" : { "untracked_files" : "die" }, "Dist::Zilla::Role::Git::DirtyFiles" : { "allow_dirty" : [], "allow_dirty_match" : [], "changelog" : "Changes" }, "Dist::Zilla::Role::Git::Repo" : { "git_version" : "2.25.0", "repo_root" : "." } }, "name" : "@Author::ETHER/after tests", "version" : "2.046" }, { "class" : "Dist::Zilla::Plugin::CheckIssues", "name" : "@Author::ETHER/CheckIssues", "version" : "0.011" }, { "class" : "Dist::Zilla::Plugin::UploadToCPAN", "name" : "@Author::ETHER/UploadToCPAN", "version" : "6.015" }, { "class" : "Dist::Zilla::Plugin::CopyFilesFromRelease", "config" : { "Dist::Zilla::Plugin::CopyFilesFromRelease" : { "filename" : [ "CONTRIBUTING", "INSTALL", "LICENCE", "LICENSE", "ppport.h" ], "match" : [] } }, "name" : "@Author::ETHER/copy generated files", "version" : "0.006" }, { "class" : "Dist::Zilla::Plugin::ReadmeAnyFromPod", "config" : { "Dist::Zilla::Role::FileWatcher" : { "version" : "0.006" } }, "name" : "@Author::ETHER/ReadmeAnyFromPod", "version" : "0.163250" }, { "class" : "Dist::Zilla::Plugin::Prereqs", "config" : { "Dist::Zilla::Plugin::Prereqs" : { "phase" : "develop", "type" : "recommends" } }, "name" : "@Author::ETHER/@Git::VersionManager/pluginbundle version", "version" : "6.015" }, { "class" : "Dist::Zilla::Plugin::RewriteVersion::Transitional", "config" : { "Dist::Zilla::Plugin::RewriteVersion" : { "add_tarball_name" : 0, "finders" : [ ":ExecFiles", ":InstallModules" ], "global" : 1, "skip_version_provider" : 0 }, "Dist::Zilla::Plugin::RewriteVersion::Transitional" : {} }, "name" : "@Author::ETHER/@Git::VersionManager/RewriteVersion::Transitional", "version" : "0.009" }, { "class" : "Dist::Zilla::Plugin::MetaProvides::Update", "name" : "@Author::ETHER/@Git::VersionManager/MetaProvides::Update", "version" : "0.007" }, { "class" : "Dist::Zilla::Plugin::CopyFilesFromRelease", "config" : { "Dist::Zilla::Plugin::CopyFilesFromRelease" : { "filename" : [ "Changes" ], "match" : [] } }, "name" : "@Author::ETHER/@Git::VersionManager/CopyFilesFromRelease", "version" : "0.006" }, { "class" : "Dist::Zilla::Plugin::Git::Commit", "config" : { "Dist::Zilla::Plugin::Git::Commit" : { "add_files_in" : [ "." ], "commit_msg" : "%N-%v%t%n%n%c" }, "Dist::Zilla::Role::Git::DirtyFiles" : { "allow_dirty" : [ "CONTRIBUTING", "Changes", "INSTALL", "LICENSE", "README.pod" ], "allow_dirty_match" : [], "changelog" : "Changes" }, "Dist::Zilla::Role::Git::Repo" : { "git_version" : "2.25.0", "repo_root" : "." }, "Dist::Zilla::Role::Git::StringFormatter" : { "time_zone" : "local" } }, "name" : "@Author::ETHER/@Git::VersionManager/release snapshot", "version" : "2.046" }, { "class" : "Dist::Zilla::Plugin::Git::Tag", "config" : { "Dist::Zilla::Plugin::Git::Tag" : { "branch" : null, "changelog" : "Changes", "signed" : 0, "tag" : "v1.08", "tag_format" : "v%V", "tag_message" : "v%v%t" }, "Dist::Zilla::Role::Git::Repo" : { "git_version" : "2.25.0", "repo_root" : "." }, "Dist::Zilla::Role::Git::StringFormatter" : { "time_zone" : "local" } }, "name" : "@Author::ETHER/@Git::VersionManager/Git::Tag", "version" : "2.046" }, { "class" : "Dist::Zilla::Plugin::BumpVersionAfterRelease::Transitional", "config" : { "Dist::Zilla::Plugin::BumpVersionAfterRelease" : { "finders" : [ ":ExecFiles", ":InstallModules" ], "global" : 1, "munge_makefile_pl" : 1 }, "Dist::Zilla::Plugin::BumpVersionAfterRelease::Transitional" : {} }, "name" : "@Author::ETHER/@Git::VersionManager/BumpVersionAfterRelease::Transitional", "version" : "0.009" }, { "class" : "Dist::Zilla::Plugin::NextRelease", "name" : "@Author::ETHER/@Git::VersionManager/NextRelease", "version" : "6.015" }, { "class" : "Dist::Zilla::Plugin::Git::Commit", "config" : { "Dist::Zilla::Plugin::Git::Commit" : { "add_files_in" : [], "commit_msg" : "increment $VERSION after %v release" }, "Dist::Zilla::Role::Git::DirtyFiles" : { "allow_dirty" : [ "Build.PL", "Changes", "Makefile.PL" ], "allow_dirty_match" : [ "(?^:^lib/.*\\.pm$)" ], "changelog" : "Changes" }, "Dist::Zilla::Role::Git::Repo" : { "git_version" : "2.25.0", "repo_root" : "." }, "Dist::Zilla::Role::Git::StringFormatter" : { "time_zone" : "local" } }, "name" : "@Author::ETHER/@Git::VersionManager/post-release commit", "version" : "2.046" }, { "class" : "Dist::Zilla::Plugin::Prereqs", "config" : { "Dist::Zilla::Plugin::Prereqs" : { "phase" : "x_Dist_Zilla", "type" : "requires" } }, "name" : "@Author::ETHER/@Git::VersionManager/prereqs for @Git::VersionManager", "version" : "6.015" }, { "class" : "Dist::Zilla::Plugin::Git::Push", "config" : { "Dist::Zilla::Plugin::Git::Push" : { "push_to" : [ "origin" ], "remotes_must_exist" : 1 }, "Dist::Zilla::Role::Git::Repo" : { "git_version" : "2.25.0", "repo_root" : "." } }, "name" : "@Author::ETHER/Git::Push", "version" : "2.046" }, { "class" : "Dist::Zilla::Plugin::GitHub::Update", "config" : { "Dist::Zilla::Plugin::GitHub::Update" : { "metacpan" : 1 } }, "name" : "@Author::ETHER/GitHub::Update", "version" : "0.47" }, { "class" : "Dist::Zilla::Plugin::Run::AfterRelease", "config" : { "Dist::Zilla::Plugin::Run::Role::Runner" : { "fatal_errors" : 0, "quiet" : 0, "run" : [ "REDACTED" ], "version" : "0.048" } }, "name" : "@Author::ETHER/install release", "version" : "0.048" }, { "class" : "Dist::Zilla::Plugin::Run::AfterRelease", "config" : { "Dist::Zilla::Plugin::Run::Role::Runner" : { "eval" : [ "print \"release complete!\\xa\"" ], "fatal_errors" : 1, "quiet" : 1, "version" : "0.048" } }, "name" : "@Author::ETHER/release complete", "version" : "0.048" }, { "class" : "Dist::Zilla::Plugin::ConfirmRelease", "name" : "@Author::ETHER/ConfirmRelease", "version" : "6.015" }, { "class" : "Dist::Zilla::Plugin::Prereqs", "config" : { "Dist::Zilla::Plugin::Prereqs" : { "phase" : "x_Dist_Zilla", "type" : "requires" } }, "name" : "@Author::ETHER/prereqs for @Author::ETHER", "version" : "6.015" }, { "class" : "Dist::Zilla::Plugin::Substitute", "name" : "Substitute", "version" : "0.006" }, { "class" : "Dist::Zilla::Plugin::FinderCode", "name" : ":InstallModules", "version" : "6.015" }, { "class" : "Dist::Zilla::Plugin::FinderCode", "name" : ":IncModules", "version" : "6.015" }, { "class" : "Dist::Zilla::Plugin::FinderCode", "name" : ":TestFiles", "version" : "6.015" }, { "class" : "Dist::Zilla::Plugin::FinderCode", "name" : ":ExtraTestFiles", "version" : "6.015" }, { "class" : "Dist::Zilla::Plugin::FinderCode", "name" : ":ExecFiles", "version" : "6.015" }, { "class" : "Dist::Zilla::Plugin::FinderCode", "name" : ":PerlExecFiles", "version" : "6.015" }, { "class" : "Dist::Zilla::Plugin::FinderCode", "name" : ":ShareFiles", "version" : "6.015" }, { "class" : "Dist::Zilla::Plugin::FinderCode", "name" : ":MainModule", "version" : "6.015" }, { "class" : "Dist::Zilla::Plugin::FinderCode", "name" : ":AllFiles", "version" : "6.015" }, { "class" : "Dist::Zilla::Plugin::FinderCode", "name" : ":NoFiles", "version" : "6.015" }, { "class" : "Dist::Zilla::Plugin::VerifyPhases", "name" : "@Author::ETHER/PHASE VERIFICATION", "version" : "0.016" } ], "zilla" : { "class" : "Dist::Zilla::Dist::Builder", "config" : { "is_trial" : 0 }, "version" : "6.015" } }, "x_authority" : "cpan:SARTAK", "x_contributors" : [ "sartak ", "Shawn M Moore ", "Shawn M Moore ", "Karen Etheridge ", "robertkrimen ", "Aaron Trevena ", "David Pottage ", "Shawn M Moore ", "Shawn M Moore ", "Florian Ragwitz ", "Shawn M Moore ", "clkao " ], "x_generated_by_perl" : "v5.32.0", "x_serialization_backend" : "Cpanel::JSON::XS version 4.19", "x_spdx_expression" : "Artistic-1.0-Perl OR GPL-1.0-or-later", "x_use_unsafe_inc" : 0 } t000755000766000024 013702474074 14212 5ustar00etherstaff000000000000Path-Dispatcher-1.08001-api.t100640000766000024 303713702474074 15605 0ustar00etherstaff000000000000Path-Dispatcher-1.08/tuse strict; use warnings; use Test::More; use Path::Dispatcher; my @calls; my $dispatcher = Path::Dispatcher->new; $dispatcher->add_rule( Path::Dispatcher::Rule::Regex->new( regex => qr/foo/, block => sub { my $match = shift; push @calls, [@_]; }, ), ); is_deeply([splice @calls], [], "no calls to the rule block yet"); my $dispatch = $dispatcher->dispatch('foo'); is_deeply([splice @calls], [], "no calls to the rule block yet"); isa_ok($dispatch, 'Path::Dispatcher::Dispatch'); $dispatch->run; is_deeply([splice @calls], [ [] ], "finally invoked the rule block"); $dispatcher->run('foo'); is_deeply([splice @calls], [ [] ], "invoked the rule block on 'run'"); $dispatcher->add_rule( Path::Dispatcher::Rule::Regex->new( regex => qr/(bar)/, block => sub { my $match = shift; push @calls, $match->positional_captures; }, ), ); is_deeply([splice @calls], [], "no calls to the rule block yet"); $dispatch = $dispatcher->dispatch('bar'); is_deeply([splice @calls], [], "no calls to the rule block yet"); isa_ok($dispatch, 'Path::Dispatcher::Dispatch'); $dispatch->run; is_deeply([splice @calls], [ ['bar'] ], "finally invoked the rule block"); $dispatcher->run('bar'); is_deeply([splice @calls], [ ['bar'] ], "invoked the rule block on 'run'"); isa_ok($dispatch, 'Path::Dispatcher::Dispatch'); $dispatch->run; is_deeply([splice @calls], [ ['bar'] ], "invoked the rule block on 'run', makes sure ->pos etc are still correctly set"); done_testing; 003-404.t100640000766000024 105613702474074 15344 0ustar00etherstaff000000000000Path-Dispatcher-1.08/tuse strict; use warnings; use Test::More; use Path::Dispatcher; my @calls; my $dispatcher = Path::Dispatcher->new; $dispatcher->add_rule( Path::Dispatcher::Rule::Regex->new( regex => qr/foo/, block => sub { push @calls, [@_] }, ), ); my $dispatch = $dispatcher->dispatch('bar'); is_deeply([splice @calls], [], "no calls to the rule block yet"); isa_ok($dispatch, 'Path::Dispatcher::Dispatch'); is($dispatch->matches, 0, "no matches"); $dispatch->run; is_deeply([splice @calls], [], "no calls to the rule block"); done_testing; 004-run.t100640000766000024 137513702474074 15646 0ustar00etherstaff000000000000Path-Dispatcher-1.08/tuse strict; use warnings; use Test::More; use Path::Dispatcher; my $dispatcher = Path::Dispatcher->new( rules => [ Path::Dispatcher::Rule::Regex->new( regex => qr/^foobar/, block => sub { "foobar matched" }, ), ], ); my $result = $dispatcher->run("foobar"); is($result, "foobar matched"); $dispatcher->add_rule( Path::Dispatcher::Rule::Regex->new( regex => qr/^foo/, block => sub { "foo matched" }, ), ); $result = $dispatcher->run("foobar"); is($result, "foobar matched"); my $dispatch = $dispatcher->dispatch("foobar"); $result = $dispatch->run("foobar"); is($result, "foobar matched"); my @results = $dispatch->run("foobar"); is_deeply(\@results, ["foobar matched"]); done_testing; Makefile.PL100644000766000024 740013702474074 16062 0ustar00etherstaff000000000000Path-Dispatcher-1.08# This Makefile.PL for Path-Dispatcher was generated by # Dist::Zilla::Plugin::MakeMaker::Fallback 0.030 # and Dist::Zilla::Plugin::MakeMaker::Awesome 0.48. # Don't edit it but the dist.ini and plugins used to construct it. use strict; use warnings; use 5.008001; use ExtUtils::MakeMaker; BEGIN { my %configure_requires = ( 'ExtUtils::MakeMaker' => '0', 'Module::Build::Tiny' => '0.034', ); my %errors = map { eval "require $_; $_->VERSION($configure_requires{$_}); 1"; $_ => $@, } keys %configure_requires; if (grep { $_ } values %errors) { warn "Errors from configure prereqs:\n" . do { require Data::Dumper; Data::Dumper->new([ \%errors ])->Indent(2)->Terse(1)->Sortkeys(1)->Dump; }; } if (not $ENV{PERL_MM_FALLBACK_SILENCE_WARNING}) { warn <<'EOW'; *** WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING *** If you're seeing this warning, your toolchain is really, really old* and you'll almost certainly have problems installing CPAN modules from this century. But never fear, dear user, for we have the technology to fix this! If you're using CPAN.pm to install things, then you can upgrade it using: cpan CPAN If you're using CPANPLUS to install things, then you can upgrade it using: cpanp CPANPLUS If you're using cpanminus, you shouldn't be seeing this message in the first place, so please file an issue on github. If you're using a packaging tool through a unix distribution, this issue should be reported to the package manager. If you're installing manually, please retrain your fingers to run Build.PL when present instead of Makefile.PL. This public service announcement was brought to you by the Perl Toolchain Gang, the irc.perl.org #toolchain IRC channel, and the number 42. ---- * Alternatively, you are doing something overly clever, in which case you should consider setting the 'prefer_installer' config option in CPAN.pm, or 'prefer_makefile' in CPANPLUS, to 'mb" and '0' respectively. You can also silence this warning for future installations by setting the PERL_MM_FALLBACK_SILENCE_WARNING environment variable. EOW sleep 10 if -t STDIN && (-t STDOUT || !(-f STDOUT || -c STDOUT)); } } # end BEGIN my %WriteMakefileArgs = ( "ABSTRACT" => "Flexible and extensible dispatch", "AUTHOR" => "Shawn M Moore, C<< >>", "CONFIGURE_REQUIRES" => { "ExtUtils::MakeMaker" => 0, "Module::Build::Tiny" => "0.034" }, "DISTNAME" => "Path-Dispatcher", "LICENSE" => "perl", "MIN_PERL_VERSION" => "5.008001", "NAME" => "Path::Dispatcher", "PL_FILES" => {}, "PREREQ_PM" => { "Carp" => 0, "Moo" => 0, "Moo::Role" => 0, "MooX::TypeTiny" => 0, "Scalar::Util" => 0, "Try::Tiny" => 0, "Type::Tiny" => 0, "Type::Utils" => 0, "Types::Standard" => 0, "constant" => 0, "overload" => 0 }, "TEST_REQUIRES" => { "File::Spec" => 0, "Module::Metadata" => 0, "Test::Fatal" => 0, "Test::More" => 0, "strict" => 0, "warnings" => 0 }, "VERSION" => "1.08", "test" => { "TESTS" => "t/*.t" } ); my %FallbackPrereqs = ( "Carp" => 0, "File::Spec" => 0, "Module::Metadata" => 0, "Moo" => 0, "Moo::Role" => 0, "MooX::TypeTiny" => 0, "Scalar::Util" => 0, "Test::Fatal" => 0, "Test::More" => 0, "Try::Tiny" => 0, "Type::Tiny" => 0, "Type::Utils" => 0, "Types::Standard" => 0, "constant" => 0, "overload" => 0, "strict" => 0, "warnings" => 0 ); unless ( eval { ExtUtils::MakeMaker->VERSION('6.63_03') } ) { delete $WriteMakefileArgs{TEST_REQUIRES}; delete $WriteMakefileArgs{BUILD_REQUIRES}; $WriteMakefileArgs{PREREQ_PM} = \%FallbackPrereqs; } delete $WriteMakefileArgs{CONFIGURE_REQUIRES} unless eval { ExtUtils::MakeMaker->VERSION(6.52) }; WriteMakefile(%WriteMakefileArgs); 002-rule.t100640000766000024 152413702474074 16003 0ustar00etherstaff000000000000Path-Dispatcher-1.08/tuse strict; use warnings; use Test::More; use Path::Dispatcher; my @calls; my $rule = Path::Dispatcher::Rule::Regex->new( regex => qr/^(..)(..)/, block => sub { push @calls, { vars => [$1, $2, $3], args => [@_], } }, ); my $match = $rule->match(Path::Dispatcher::Path->new('foobar')); isa_ok($match, 'Path::Dispatcher::Match'); is_deeply($match->positional_captures, ['fo', 'ob']); is_deeply([splice @calls], [], "block not called on match"); $rule->run; is_deeply([splice @calls], [{ vars => [undef, undef, undef], args => [], }], "block called on ->run"); my $no_block = Path::Dispatcher::Rule::Regex->new( regex => qr/^(.{32})/, ); ok($no_block); ok(!$no_block->has_block); ok(!$no_block->has_payload); is($no_block->block, undef); is($no_block->payload, undef); done_testing; 009-args.t100640000766000024 73713702474074 15764 0ustar00etherstaff000000000000Path-Dispatcher-1.08/tuse strict; use warnings; use Test::More; use Path::Dispatcher; my @calls; my $dispatcher = Path::Dispatcher->new; $dispatcher->add_rule( Path::Dispatcher::Rule::Regex->new( regex => qr/foo/, block => sub { my $match = shift; push @calls, [@_] }, ), ); $dispatcher->run('foo', 42); is_deeply([splice @calls], [ [42], ]); my $dispatch = $dispatcher->dispatch('foo'); $dispatch->run(24); is_deeply([splice @calls], [ [24], ]); done_testing; CONTRIBUTING100644000766000024 773113702474074 15751 0ustar00etherstaff000000000000Path-Dispatcher-1.08 CONTRIBUTING Thank you for considering contributing to this distribution. This file contains instructions that will help you work with the source code. PLEASE NOTE that if you have any questions or difficulties, you can reach the maintainer(s) through the bug queue described later in this document (preferred), or by emailing the releaser directly. You are not required to follow any of the steps in this document to submit a patch or bug report; these are just recommendations, intended to help you (and help us help you faster). The distribution is managed with Dist::Zilla (https://metacpan.org/release/Dist-Zilla). This means than many of the usual files you might expect are not in the repository, but are generated at release time (e.g. Makefile.PL). However, you can run tests directly using the 'prove' tool: $ prove -l $ prove -lv t/some_test_file.t $ prove -lvr t/ In most cases, 'prove' is entirely sufficient for you to test any patches you have. You may need to satisfy some dependencies. The easiest way to satisfy dependencies is to install the last release -- this is available at https://metacpan.org/release/Path-Dispatcher If you use cpanminus, you can do it without downloading the tarball first: $ cpanm --reinstall --installdeps --with-recommends Path::Dispatcher Dist::Zilla is a very powerful authoring tool, but requires a number of author-specific plugins. If you would like to use it for contributing, install it from CPAN, then run one of the following commands, depending on your CPAN client: $ cpan `dzil authordeps --missing` or $ dzil authordeps --missing | cpanm You should then also install any additional requirements not needed by the dzil build but may be needed by tests or other development: $ cpan `dzil listdeps --author --missing` or $ dzil listdeps --author --missing | cpanm Or, you can use the 'dzil stale' command to install all requirements at once: $ cpan Dist::Zilla::App::Command::stale $ cpan `dzil stale --all` or $ cpanm Dist::Zilla::App::Command::stale $ dzil stale --all | cpanm You can also do this via cpanm directly: $ cpanm --reinstall --installdeps --with-develop --with-recommends Path::Dispatcher Once installed, here are some dzil commands you might try: $ dzil build $ dzil test $ dzil test --release $ dzil xtest $ dzil listdeps --json $ dzil build --notgz You can learn more about Dist::Zilla at http://dzil.org/. The code for this distribution is hosted at GitHub. The repository is: https://github.com/karenetheridge/Path-Dispatcher You can submit code changes by forking the repository, pushing your code changes to your clone, and then submitting a pull request. Please include a suitable end-user-oriented entry in the Changes file describing your change. Detailed instructions for doing that is available here: https://help.github.com/articles/creating-a-pull-request All pull requests for this distribution will be automatically tested on Linux by Travis at: https://travis-ci.com/karenetheridge/Path-Dispatcher Results will be visible in the pull request on GitHub. Follow the appropriate links for details when tests fail. Changes will not be mergeable until all tests pass. If you have found a bug, but do not have an accompanying patch to fix it, you can submit an issue report here: https://rt.cpan.org/Public/Dist/Display.html?Name=Path-Dispatcher or via email: bug-Path-Dispatcher@rt.cpan.org This is a good place to send your questions about the usage of this distribution. If you send me a patch or pull request, your name and email address will be included in the documentation as a contributor (using the attribution on the commit or patch), unless you specifically request for it not to be. If you wish to be listed under a different name or address, you should submit a pull request to the .mailmap file to contain the correct mapping. This file was generated via Dist::Zilla::Plugin::GenerateFile::FromShareDir 0.014 from a template file originating in Dist-Zilla-PluginBundle-Author-ETHER-0.158. 006-abort.t100640000766000024 214313702474074 16145 0ustar00etherstaff000000000000Path-Dispatcher-1.08/tuse strict; use warnings; use Test::More; use Test::Fatal; use Path::Dispatcher; my @calls; my $dispatcher = Path::Dispatcher->new; $dispatcher->add_rule( Path::Dispatcher::Rule::Regex->new( regex => qr/foo/, block => sub { push @calls, "on"; die "Path::Dispatcher abort\n"; }, ), ); $dispatcher->add_rule( Path::Dispatcher::Rule::Regex->new( regex => qr/foo/, block => sub { push @calls, "last"; }, ), ); my $dispatch = $dispatcher->dispatch('foo'); is_deeply([splice @calls], [], "no blocks called yet of course"); $dispatch->run; is_deeply([splice @calls], ['on'], "correctly aborted the entire dispatch"); $dispatcher->add_rule( Path::Dispatcher::Rule::Regex->new( regex => qr/bar/, block => sub { push @calls, "bar: before"; my $x = {}->(); push @calls, "bar: last"; }, ), ); like(exception { $dispatcher->run('bar'); }, qr/Not a CODE reference/); is_deeply([splice @calls], ['bar: before'], "regular dies pass through"); done_testing; 012-under.t100640000766000024 411513702474074 16151 0ustar00etherstaff000000000000Path-Dispatcher-1.08/tuse strict; use warnings; use Test::More; use Path::Dispatcher; my $predicate = Path::Dispatcher::Rule::Tokens->new( tokens => ['ticket'], prefix => 1, ); my $create = Path::Dispatcher::Rule::Tokens->new( tokens => ['create'], ); my $update = Path::Dispatcher::Rule::Tokens->new( tokens => ['update'], prefix => 1, ); my $under = Path::Dispatcher::Rule::Under->new( predicate => $predicate, rules => [$create, $update], ); my %tests = ( "ticket create" => {}, "ticket update" => {}, " ticket update " => { name => "whitespace doesn't matter for token-based rules", }, "ticket update foo" => { name => "'ticket update' rule is prefix", }, "ticket create foo" => { fail => 1, catchall => 1, name => "did not match 'ticket create foo' because it's not a suffix", }, "comment create" => { fail => 1, name => "did not match 'comment create' because the prefix is ticket", }, "ticket delete" => { fail => 1, catchall => 1, name => "did not match 'ticket delete' because delete is not a suffix", }, ); for my $path (keys %tests) { my $data = $tests{$path}; my $name = $data->{name} || $path; my $match = $under->match(Path::Dispatcher::Path->new($path)); $match = !$match if $data->{fail}; ok($match, $name); } my $catchall = Path::Dispatcher::Rule::Regex->new( regex => qr/()/, ); $under->add_rule($catchall); for my $path (keys %tests) { my $data = $tests{$path}; my $name = $data->{name} || $path; my $match = $under->match(Path::Dispatcher::Path->new($path)); $match = !$match if $data->{fail} && !$data->{catchall}; ok($match, $name); } # ensure that the predicate MUST be a prefix eval { local $SIG{__DIE__}; Path::Dispatcher::Rule::Under->new( predicate => Path::Dispatcher::Rule::Tokens->new( tokens => ['foo'], prefix => 0, ), ); }; like($@, qr/This rule \(.*?\) does not match just prefixes/, "predicate MUST match just a prefix"); done_testing; 033-chain.t100640000766000024 244513702474074 16125 0ustar00etherstaff000000000000Path-Dispatcher-1.08/tuse strict; use warnings; use Test::More; use Path::Dispatcher; my @calls; my $dispatcher = Path::Dispatcher->new( rules => [ Path::Dispatcher::Rule::Under->new( predicate => Path::Dispatcher::Rule::Tokens->new( tokens => ['show'], prefix => 1, ), rules => [ Path::Dispatcher::Rule::Chain->new( block => sub { push @calls, 'chain' }, ), Path::Dispatcher::Rule::Tokens->new( tokens => ['inventory'], block => sub { push @calls, 'inventory' }, ), Path::Dispatcher::Rule::Tokens->new( tokens => ['score'], block => sub { push @calls, 'score' }, ), ], ), ], ); $dispatcher->run("show inventory"); is_deeply([splice @calls], [ 'chain', 'inventory' ]); $dispatcher->run("show score"); is_deeply([splice @calls], [ 'chain', 'score' ]); $dispatcher->run("show nothing"); is_deeply([splice @calls], [ ]); $dispatcher->run("do nothing"); is_deeply([splice @calls], [ ]); $dispatcher->run("do inventory"); is_deeply([splice @calls], [ ]); $dispatcher->run("do score"); is_deeply([splice @calls], [ ]); done_testing; 010-return.t100640000766000024 131413702474074 16347 0ustar00etherstaff000000000000Path-Dispatcher-1.08/tuse strict; use warnings; use Test::More; use Path::Dispatcher; # we currently have no defined return strategy :/ my $dispatcher = Path::Dispatcher->new; $dispatcher->add_rule( Path::Dispatcher::Rule::Regex->new( regex => qr/foo/, block => sub { "foo" }, ), ); is_deeply([$dispatcher->run('foo', 42)], ["foo"]); my $dispatch = $dispatcher->dispatch('foo'); is_deeply([$dispatch->run(24)], ["foo"]); $dispatcher->add_rule( Path::Dispatcher::Rule::Regex->new( regex => qr/foo/, block => sub { "jinkies" }, ), ); is_deeply([$dispatcher->run('foo', 42)], ["foo"]); $dispatch = $dispatcher->dispatch('foo'); is_deeply([$dispatch->run(24)], ["foo"]); done_testing; 013-tokens.t100640000766000024 413713702474074 16344 0ustar00etherstaff000000000000Path-Dispatcher-1.08/tuse strict; use warnings; use Test::More; use Path::Dispatcher; my @calls; my $dispatcher = Path::Dispatcher->new; $dispatcher->add_rule( Path::Dispatcher::Rule::Tokens->new( tokens => ['foo', 'bar'], block => sub { push @calls, shift->positional_captures }, ), ); $dispatcher->run('foo bar'); is_deeply([splice @calls], [ ['foo', 'bar'] ], "correctly populated number vars from [str, str] token rule"); $dispatcher->add_rule( Path::Dispatcher::Rule::Tokens->new( tokens => ['foo', qr/bar/], block => sub { push @calls, shift->positional_captures }, ), ); $dispatcher->run('foo bar'); is_deeply([splice @calls], [ ['foo', 'bar'] ], "ran the first [str, str] rule"); $dispatcher->run('foo barbaz'); is_deeply([splice @calls], [ ['foo', 'barbaz'] ], "ran the second [str, regex] rule"); $dispatcher->run('foo bar baz'); is_deeply([splice @calls], [], "no matches"); $dispatcher->add_rule( Path::Dispatcher::Rule::Tokens->new( tokens => [["Bat", "Super"], "Man"], block => sub { push @calls, shift->positional_captures }, ), ); $dispatcher->run('Super Man'); is_deeply([splice @calls], [ ['Super', 'Man'] ], "ran the [ [Str,Str], Str ] rule"); $dispatcher->run('Bat Man'); is_deeply([splice @calls], [ ['Bat', 'Man'] ], "ran the [ [Str,Str], Str ] rule"); $dispatcher->run('Aqua Man'); is_deeply([splice @calls], [ ], "no match"); $dispatcher->add_rule( Path::Dispatcher::Rule::Tokens->new( tokens => [[[[qr/Deep/]]], "Man"], block => sub { push @calls, shift->positional_captures }, ), ); $dispatcher->run('Deep Man'); is_deeply([splice @calls], [ ['Deep', 'Man'] ], "alternations can be arbitrarily deep"); $dispatcher->run('Not Appearing in this Dispatcher Man'); is_deeply([splice @calls], [ ], "no match"); my $rule = Path::Dispatcher::Rule::Tokens->new( tokens => ['path', 'dispatcher'], delimiter => '::', prefix => 1, case_sensitive => 0, ); my $match = $rule->match(Path::Dispatcher::Path->new('Path::Dispatcher::Rule::Tokens')); is($match->leftover, 'Rule::Tokens'); done_testing; 000-compile.t100640000766000024 12513702474074 16436 0ustar00etherstaff000000000000Path-Dispatcher-1.08/tuse strict; use warnings; use Test::More; use_ok 'Path::Dispatcher'; done_testing; 200-payload.t100640000766000024 127013702474074 16463 0ustar00etherstaff000000000000Path-Dispatcher-1.08/tuse strict; use warnings; use Test::More; use Test::Fatal; use Path::Dispatcher; my $dispatcher = Path::Dispatcher->new( rules => [ Path::Dispatcher::Rule::Regex->new( regex => qr/^(\w+)$/, payload => 'all the money', ), ], ); my $dispatch = $dispatcher->dispatch('hello'); ok($dispatch->has_matches); my $match = $dispatch->first_match; ok($match->rule->isa('Path::Dispatcher::Rule::Regex')); ok($match->rule->payload, 'all the money'); ok($match->payload, 'all the money'); like(exception { $dispatch->run }, qr/Payload is not a coderef/); like(exception { $dispatcher->run('bye') }, qr/Payload is not a coderef/); done_testing; 902-coderef.t100640000766000024 65313702474074 16436 0ustar00etherstaff000000000000Path-Dispatcher-1.08/tuse strict; use warnings; use Test::More; use Test::Fatal; use Path::Dispatcher::Rule::Tokens; my $rule = Path::Dispatcher::Rule::Tokens->new( tokens => ['bus', 'train'], ); like(exception { $rule->run; }, qr/^No codeblock to run/); my $match = $rule->match(Path::Dispatcher::Path->new('bus train')); ok($match, "matched the tokens"); like(exception { $match->run; }, qr/^No codeblock to run/); done_testing; author000755000766000024 013702474074 15704 5ustar00etherstaff000000000000Path-Dispatcher-1.08/xteol.t100644000766000024 450413702474074 17013 0ustar00etherstaff000000000000Path-Dispatcher-1.08/xt/authoruse strict; use warnings; # this test was generated with Dist::Zilla::Plugin::Test::EOL 0.19 use Test::More 0.88; use Test::EOL; my @files = ( 'lib/Path/Dispatcher.pm', 'lib/Path/Dispatcher/Cookbook.pod', 'lib/Path/Dispatcher/Dispatch.pm', 'lib/Path/Dispatcher/Match.pm', 'lib/Path/Dispatcher/Path.pm', 'lib/Path/Dispatcher/Role/Rules.pm', 'lib/Path/Dispatcher/Rule.pm', 'lib/Path/Dispatcher/Rule/Alternation.pm', 'lib/Path/Dispatcher/Rule/Always.pm', 'lib/Path/Dispatcher/Rule/Chain.pm', 'lib/Path/Dispatcher/Rule/CodeRef.pm', 'lib/Path/Dispatcher/Rule/Dispatch.pm', 'lib/Path/Dispatcher/Rule/Empty.pm', 'lib/Path/Dispatcher/Rule/Enum.pm', 'lib/Path/Dispatcher/Rule/Eq.pm', 'lib/Path/Dispatcher/Rule/Intersection.pm', 'lib/Path/Dispatcher/Rule/Metadata.pm', 'lib/Path/Dispatcher/Rule/Regex.pm', 'lib/Path/Dispatcher/Rule/Sequence.pm', 'lib/Path/Dispatcher/Rule/Tokens.pm', 'lib/Path/Dispatcher/Rule/Under.pm', 't/00-report-prereqs.dd', 't/00-report-prereqs.t', 't/000-compile.t', 't/001-api.t', 't/002-rule.t', 't/003-404.t', 't/004-run.t', 't/005-multi-rule.t', 't/006-abort.t', 't/007-coderef-matcher.t', 't/009-args.t', 't/010-return.t', 't/011-next-rule.t', 't/012-under.t', 't/013-tokens.t', 't/014-tokens-prefix.t', 't/015-regex-prefix.t', 't/017-intersection.t', 't/018-metadata.t', 't/019-intersection-metadata.t', 't/022-numbers-undef.t', 't/023-alternation.t', 't/024-sequence.t', 't/025-sequence-custom-rule.t', 't/026-named-captures.t', 't/027-custom-named-captures.t', 't/030-exceptions.t', 't/031-structured-match.t', 't/032-multiple-delimiter.t', 't/033-chain.t', 't/100-match-object.t', 't/200-payload.t', 't/901-return-values.t', 't/902-coderef.t', 'xt/author/00-compile.t', 'xt/author/changes_has_content.t', 'xt/author/eol.t', 'xt/author/kwalitee.t', 'xt/author/minimum-version.t', 'xt/author/mojibake.t', 'xt/author/no-tabs.t', 'xt/author/pod-no404s.t', 'xt/author/pod-syntax.t', 'xt/author/portability.t', 'xt/release/changes_has_content.t', 'xt/release/cpan-changes.t', 'xt/release/distmeta.t' ); eol_unix_ok($_, { trailing_whitespace => 1 }) foreach @files; done_testing; 018-metadata.t100640000766000024 135013702474074 16620 0ustar00etherstaff000000000000Path-Dispatcher-1.08/tuse strict; use warnings; use Test::More; use Path::Dispatcher; my @calls; my $dispatcher = Path::Dispatcher->new( rules => [ Path::Dispatcher::Rule::Metadata->new( field => "http_method", matcher => Path::Dispatcher::Rule::Eq->new(string => "GET"), block => sub { push @calls, $_ }, ), ], ); $dispatcher->run(Path::Dispatcher::Path->new( path => "the path", metadata => { http_method => "GET", }, )); is_deeply([splice @calls], ["the path"]); $dispatcher->run(Path::Dispatcher::Path->new( path => "the path", metadata => { http_method => "POST", }, )); is_deeply([splice @calls], [], "metadata didn't match"); done_testing; 024-sequence.t100640000766000024 736713702474074 16663 0ustar00etherstaff000000000000Path-Dispatcher-1.08/tuse strict; use warnings; use Test::More; use Path::Dispatcher; my @calls; my $dispatcher = Path::Dispatcher->new; $dispatcher->add_rule( Path::Dispatcher::Rule::Sequence->new( rules => [ Path::Dispatcher::Rule::Eq->new( string => 'foo', ), Path::Dispatcher::Rule::Eq->new( string => 'bar', ), ], block => sub { push @calls, shift->positional_captures }, ), ); $dispatcher->run('foo bar'); is_deeply([splice @calls], [ ['foo', 'bar'] ], "correctly populated number vars from [str, str] token rule"); $dispatcher->add_rule( Path::Dispatcher::Rule::Sequence->new( rules => [ Path::Dispatcher::Rule::Eq->new( string => 'foo', ), Path::Dispatcher::Rule::Regex->new( regex => qr/bar/, ), ], block => sub { push @calls, shift->positional_captures }, ), ); $dispatcher->run('foo bar'); is_deeply([splice @calls], [ ['foo', 'bar'] ], "ran the first [str, str] rule"); $dispatcher->run('foo barbaz'); is_deeply([splice @calls], [ ['foo', 'barbaz'] ], "ran the second [str, regex] rule"); $dispatcher->run('foo bar baz'); is_deeply([splice @calls], [ ], "no matches"); $dispatcher->add_rule( Path::Dispatcher::Rule::Sequence->new( rules => [ Path::Dispatcher::Rule::Alternation->new( rules => [ Path::Dispatcher::Rule::Eq->new( string => 'Bat', ), Path::Dispatcher::Rule::Eq->new( string => 'Super', ), ], ), Path::Dispatcher::Rule::Eq->new( string => 'Man', ), ], block => sub { push @calls, shift->positional_captures }, ), ); $dispatcher->run('Super Man'); is_deeply([splice @calls], [ ['Super', 'Man'] ], "ran the [ [Str,Str], Str ] rule"); $dispatcher->run('Bat Man'); is_deeply([splice @calls], [ ['Bat', 'Man'] ], "ran the [ [Str,Str], Str ] rule"); $dispatcher->run('Aqua Man'); is_deeply([splice @calls], [ ], "no match"); $dispatcher->add_rule( Path::Dispatcher::Rule::Sequence->new( rules => [ Path::Dispatcher::Rule::Alternation->new( rules => [ Path::Dispatcher::Rule::Alternation->new( rules => [ Path::Dispatcher::Rule::Alternation->new( rules => [ Path::Dispatcher::Rule::Regex->new( regex => qr/Deep/, ), ], ), ], ), ], ), Path::Dispatcher::Rule::Eq->new( string => "Man", ), ], block => sub { push @calls, shift->positional_captures }, ), ); $dispatcher->run('Deep Man'); is_deeply([splice @calls], [ ['Deep', 'Man'] ], "alternations can be arbitrarily deep"); $dispatcher->run('Not Appearing in this Dispatcher Man'); is_deeply([splice @calls], [ ], "no match"); my $rule = Path::Dispatcher::Rule::Sequence->new( rules => [ Path::Dispatcher::Rule::Eq->new( string => 'path', case_sensitive => 0, ), Path::Dispatcher::Rule::Eq->new( string => 'dispatcher', case_sensitive => 0, ), ], prefix => 1, delimiter => '::', ); my $match = $rule->match(Path::Dispatcher::Path->new('Path::Dispatcher::Rule::Tokens')); is($match->leftover, 'Rule::Tokens'); done_testing; 011-next-rule.t100640000766000024 223013702474074 16752 0ustar00etherstaff000000000000Path-Dispatcher-1.08/tuse strict; use warnings; use Test::More; use Test::Fatal; use Path::Dispatcher; my @calls; my $dispatcher = Path::Dispatcher->new; $dispatcher->add_rule( Path::Dispatcher::Rule::Regex->new( regex => qr/foo/, block => sub { push @calls, "on"; die "Path::Dispatcher next rule\n"; push @calls, "on post-die?!"; }, ), ); $dispatcher->add_rule( Path::Dispatcher::Rule::Regex->new( regex => qr/foo/, block => sub { push @calls, "last"; }, ), ); my $dispatch = $dispatcher->dispatch('foo'); is_deeply([splice @calls], [], "no blocks called yet of course"); $dispatch->run; is_deeply([splice @calls], ['on', 'last'], "correctly continued to the next rule"); $dispatcher->add_rule( Path::Dispatcher::Rule::Regex->new( regex => qr/bar/, block => sub { push @calls, "bar: before"; my $x = {}->(); push @calls, "bar: last"; }, ), ); like(exception { $dispatcher->run('bar'); }, qr/Not a CODE reference/); is_deeply([splice @calls], ['bar: before'], "regular dies pass through"); done_testing; 005-multi-rule.t100640000766000024 61613702474074 17117 0ustar00etherstaff000000000000Path-Dispatcher-1.08/tuse strict; use warnings; use Test::More; use Path::Dispatcher; my @calls; my $dispatcher = Path::Dispatcher->new; for my $number (qw/first second/) { $dispatcher->add_rule( Path::Dispatcher::Rule::Regex->new( regex => qr/foo/, block => sub { push @calls, $number }, ), ); } $dispatcher->run('foo'); is_deeply(\@calls, ['first']); done_testing; 030-exceptions.t100640000766000024 53413702474074 17176 0ustar00etherstaff000000000000Path-Dispatcher-1.08/tuse strict; use warnings; use Test::More; use Test::Fatal; use Path::Dispatcher; my $dispatcher = Path::Dispatcher->new( rules => [ Path::Dispatcher::Rule::Always->new( block => sub { die "hi gang"; "foobar matched" }, ), ], ); like(exception { $dispatcher->run("foobar"); }, qr/hi gang/); done_testing; 023-alternation.t100640000766000024 337313702474074 17363 0ustar00etherstaff000000000000Path-Dispatcher-1.08/tuse strict; use warnings; use Test::More; use Path::Dispatcher; my @calls; my $dispatcher = Path::Dispatcher->new( rules => [ Path::Dispatcher::Rule::Alternation->new( rules => [ Path::Dispatcher::Rule::Eq->new( string => 'foo', block => sub { push @calls, 'foo' }, ), Path::Dispatcher::Rule::Eq->new( string => 'bar', block => sub { push @calls, 'bar' }, ), ], block => sub { push @calls, 'alternation' }, ), ], ); $dispatcher->run("foo"); is_deeply([splice @calls], ['alternation'], "the alternation matched; doesn't automatically run the subrules"); $dispatcher->run("bar"); is_deeply([splice @calls], ['alternation'], "the alternation matched; doesn't automatically run the subrules"); $dispatcher->run("baz"); is_deeply([splice @calls], [], "each subrule of the intersection must match"); is_deeply([$dispatcher->complete("")], ["foo", "bar"]); is_deeply([$dispatcher->complete("f")], ["foo"]); is_deeply([$dispatcher->complete("b")], ["bar"]); is_deeply([$dispatcher->complete("fo")], ["foo"]); is_deeply([$dispatcher->complete("ba")], ["bar"]); is_deeply([$dispatcher->complete("foo")], []); is_deeply([$dispatcher->complete("bar")], []); is_deeply([$dispatcher->complete("fx")], []); is_deeply([$dispatcher->complete("baz")], []); # test empty alternation $dispatcher = Path::Dispatcher->new( rules => [ Path::Dispatcher::Rule::Alternation->new( rules => [ ], block => sub { push @calls, 'alternation' }, ), ], ); $dispatcher->run("foo"); is_deeply([splice @calls], [], "no subrules means no match"); done_testing; no-tabs.t100644000766000024 445213702474074 17601 0ustar00etherstaff000000000000Path-Dispatcher-1.08/xt/authoruse strict; use warnings; # this test was generated with Dist::Zilla::Plugin::Test::NoTabs 0.15 use Test::More 0.88; use Test::NoTabs; my @files = ( 'lib/Path/Dispatcher.pm', 'lib/Path/Dispatcher/Cookbook.pod', 'lib/Path/Dispatcher/Dispatch.pm', 'lib/Path/Dispatcher/Match.pm', 'lib/Path/Dispatcher/Path.pm', 'lib/Path/Dispatcher/Role/Rules.pm', 'lib/Path/Dispatcher/Rule.pm', 'lib/Path/Dispatcher/Rule/Alternation.pm', 'lib/Path/Dispatcher/Rule/Always.pm', 'lib/Path/Dispatcher/Rule/Chain.pm', 'lib/Path/Dispatcher/Rule/CodeRef.pm', 'lib/Path/Dispatcher/Rule/Dispatch.pm', 'lib/Path/Dispatcher/Rule/Empty.pm', 'lib/Path/Dispatcher/Rule/Enum.pm', 'lib/Path/Dispatcher/Rule/Eq.pm', 'lib/Path/Dispatcher/Rule/Intersection.pm', 'lib/Path/Dispatcher/Rule/Metadata.pm', 'lib/Path/Dispatcher/Rule/Regex.pm', 'lib/Path/Dispatcher/Rule/Sequence.pm', 'lib/Path/Dispatcher/Rule/Tokens.pm', 'lib/Path/Dispatcher/Rule/Under.pm', 't/00-report-prereqs.dd', 't/00-report-prereqs.t', 't/000-compile.t', 't/001-api.t', 't/002-rule.t', 't/003-404.t', 't/004-run.t', 't/005-multi-rule.t', 't/006-abort.t', 't/007-coderef-matcher.t', 't/009-args.t', 't/010-return.t', 't/011-next-rule.t', 't/012-under.t', 't/013-tokens.t', 't/014-tokens-prefix.t', 't/015-regex-prefix.t', 't/017-intersection.t', 't/018-metadata.t', 't/019-intersection-metadata.t', 't/022-numbers-undef.t', 't/023-alternation.t', 't/024-sequence.t', 't/025-sequence-custom-rule.t', 't/026-named-captures.t', 't/027-custom-named-captures.t', 't/030-exceptions.t', 't/031-structured-match.t', 't/032-multiple-delimiter.t', 't/033-chain.t', 't/100-match-object.t', 't/200-payload.t', 't/901-return-values.t', 't/902-coderef.t', 'xt/author/00-compile.t', 'xt/author/changes_has_content.t', 'xt/author/eol.t', 'xt/author/kwalitee.t', 'xt/author/minimum-version.t', 'xt/author/mojibake.t', 'xt/author/no-tabs.t', 'xt/author/pod-no404s.t', 'xt/author/pod-syntax.t', 'xt/author/portability.t', 'xt/release/changes_has_content.t', 'xt/release/cpan-changes.t', 'xt/release/distmeta.t' ); notabs_ok($_) foreach @files; done_testing; 015-regex-prefix.t100640000766000024 144413702474074 17446 0ustar00etherstaff000000000000Path-Dispatcher-1.08/tuse strict; use warnings; use Test::More; use Path::Dispatcher; my @calls; my $rule = Path::Dispatcher::Rule::Regex->new( regex => qr/^(foo)\s*(bar)/, block => sub { push @calls, [$1, $2] }, prefix => 1, ); ok(!$rule->match(Path::Dispatcher::Path->new('foo')), "prefix means the rule matches a prefix of the path, not the other way around"); ok($rule->match(Path::Dispatcher::Path->new('foo bar')), "prefix matches the full path"); ok($rule->match(Path::Dispatcher::Path->new('foo bar baz')), "prefix matches a prefix of the path"); my $match = $rule->match(Path::Dispatcher::Path->new('foobar:baz')); ok($match, "matched foobar:baz"); is_deeply($match->positional_captures, ["foo", "bar"], "match returns just the results"); is($match->leftover, ':baz', "leftovers"); done_testing; 017-intersection.t100640000766000024 246513702474074 17555 0ustar00etherstaff000000000000Path-Dispatcher-1.08/tuse strict; use warnings; use Test::More; use Path::Dispatcher; my @calls; my $dispatcher = Path::Dispatcher->new( rules => [ Path::Dispatcher::Rule::Intersection->new( rules => [ Path::Dispatcher::Rule::Tokens->new( tokens => ['foo'], block => sub { push @calls, 'tokens' }, ), Path::Dispatcher::Rule::Regex->new( regex => qr/^foo$/, block => sub { push @calls, 'regex' }, ), ], block => sub { push @calls, 'intersection' }, ), ], ); $dispatcher->run("foo"); is_deeply([splice @calls], ['intersection'], "the intersection matched; doesn't automatically run the subrules"); $dispatcher->run("food"); is_deeply([splice @calls], [], "each subrule of the intersection must match"); $dispatcher->run(" foo "); is_deeply([splice @calls], [], "each subrule of the intersection must match"); # test empty intersection $dispatcher = Path::Dispatcher->new( rules => [ Path::Dispatcher::Rule::Intersection->new( rules => [ ], block => sub { push @calls, 'intersection' }, ), ], ); $dispatcher->run("foo"); is_deeply([splice @calls], [], "no subrules means no match"); done_testing; 100-match-object.t100640000766000024 125013702474074 17367 0ustar00etherstaff000000000000Path-Dispatcher-1.08/tuse strict; use warnings; use Test::More; use Path::Dispatcher; my $match; my $dispatcher = Path::Dispatcher->new( rules => [ Path::Dispatcher::Rule::Regex->new( regex => qr/^(\w+) (Q)(Q) (\w+)$/, block => sub { $match = shift; }, ), ], ); $dispatcher->run("chewy QQ cute"); is_deeply($match->positional_captures, ["chewy", "Q", "Q", "cute"]); is_deeply($match->pos(1), "chewy"); is_deeply($match->pos(2), "Q"); is_deeply($match->pos(3), "Q"); is_deeply($match->pos(4), "cute"); is_deeply($match->pos(0), undef); is_deeply($match->pos(5), undef); is_deeply($match->pos(-1), "cute"); done_testing; kwalitee.t100644000766000024 27513702474074 20022 0ustar00etherstaff000000000000Path-Dispatcher-1.08/xt/author# this test was generated with Dist::Zilla::Plugin::Test::Kwalitee 2.12 use strict; use warnings; use Test::More 0.88; use Test::Kwalitee 1.21 'kwalitee_ok'; kwalitee_ok(); done_testing; mojibake.t100644000766000024 15113702474074 17767 0ustar00etherstaff000000000000Path-Dispatcher-1.08/xt/author#!perl use strict; use warnings qw(all); use Test::More; use Test::Mojibake; all_files_encoding_ok(); 014-tokens-prefix.t100640000766000024 117313702474074 17635 0ustar00etherstaff000000000000Path-Dispatcher-1.08/tuse strict; use warnings; use Test::More; use Path::Dispatcher; my $rule = Path::Dispatcher::Rule::Tokens->new( tokens => ['foo', 'bar'], block => sub { }, prefix => 1, ); ok(!$rule->match(Path::Dispatcher::Path->new('foo')), "prefix means the rule matches a prefix of the path, not the other way around"); ok($rule->match(Path::Dispatcher::Path->new('foo bar')), "prefix matches the full path"); my $match = $rule->match(Path::Dispatcher::Path->new('foo bar baz')); ok($match, "prefix matches a prefix of the path"); is_deeply($match->positional_captures, ["foo", "bar"]); is($match->leftover, "baz"); done_testing; 022-numbers-undef.t100640000766000024 71413702474074 17570 0ustar00etherstaff000000000000Path-Dispatcher-1.08/tuse strict; use warnings; use Test::More; use Path::Dispatcher; my @recaptures; my $rule = Path::Dispatcher::Rule::Regex->new( regex => qr/^(foo)(bar)?(baz)$/, block => sub { push @recaptures, @{ shift->positional_captures }; }, ); my $match = $rule->match(Path::Dispatcher::Path->new("foobaz")); is_deeply($match->positional_captures, ['foo', undef, 'baz']); $match->run; is_deeply(\@recaptures, ['foo', undef, 'baz']); done_testing; 901-return-values.t100640000766000024 62713702474074 17643 0ustar00etherstaff000000000000Path-Dispatcher-1.08/tuse strict; use warnings; use Test::More; use Test::Fatal; use Path::Dispatcher; my $dispatcher = Path::Dispatcher->new( rules => [ Path::Dispatcher::Rule::CodeRef->new( matcher => sub { [{ cant_handle_complex_list_of_results => 1 }] }, ), ], ); like(exception { $dispatcher->dispatch('foo'); }, qr/Results returned from _match must be a hashref/); done_testing; release000755000766000024 013702474074 16022 5ustar00etherstaff000000000000Path-Dispatcher-1.08/xtdistmeta.t100644000766000024 17213702474074 20141 0ustar00etherstaff000000000000Path-Dispatcher-1.08/xt/release#!perl # This file was automatically generated by Dist::Zilla::Plugin::MetaTests. use Test::CPAN::Meta; meta_yaml_ok(); 00-report-prereqs.t100644000766000024 1357113702474074 17775 0ustar00etherstaff000000000000Path-Dispatcher-1.08/t#!perl use strict; use warnings; # This test was generated by Dist::Zilla::Plugin::Test::ReportPrereqs 0.027 use Test::More tests => 1; use Module::Metadata; use File::Spec; # from $version::LAX my $lax_version_re = qr/(?: undef | (?: (?:[0-9]+) (?: \. | (?:\.[0-9]+) (?:_[0-9]+)? )? | (?:\.[0-9]+) (?:_[0-9]+)? ) | (?: v (?:[0-9]+) (?: (?:\.[0-9]+)+ (?:_[0-9]+)? )? | (?:[0-9]+)? (?:\.[0-9]+){2,} (?:_[0-9]+)? ) )/x; # hide optional CPAN::Meta modules from prereq scanner # and check if they are available my $cpan_meta = "CPAN::Meta"; my $cpan_meta_pre = "CPAN::Meta::Prereqs"; my $HAS_CPAN_META = eval "require $cpan_meta; $cpan_meta->VERSION('2.120900')" && eval "require $cpan_meta_pre"; ## no critic # Verify requirements? my $DO_VERIFY_PREREQS = 1; sub _max { my $max = shift; $max = ( $_ > $max ) ? $_ : $max for @_; return $max; } sub _merge_prereqs { my ($collector, $prereqs) = @_; # CPAN::Meta::Prereqs object if (ref $collector eq $cpan_meta_pre) { return $collector->with_merged_prereqs( CPAN::Meta::Prereqs->new( $prereqs ) ); } # Raw hashrefs for my $phase ( keys %$prereqs ) { for my $type ( keys %{ $prereqs->{$phase} } ) { for my $module ( keys %{ $prereqs->{$phase}{$type} } ) { $collector->{$phase}{$type}{$module} = $prereqs->{$phase}{$type}{$module}; } } } return $collector; } my @include = qw( Encode File::Temp JSON::PP Module::Runtime Sub::Name YAML autodie ); my @exclude = qw( ); # Add static prereqs to the included modules list my $static_prereqs = do './t/00-report-prereqs.dd'; # Merge all prereqs (either with ::Prereqs or a hashref) my $full_prereqs = _merge_prereqs( ( $HAS_CPAN_META ? $cpan_meta_pre->new : {} ), $static_prereqs ); # Add dynamic prereqs to the included modules list (if we can) my ($source) = grep { -f } 'MYMETA.json', 'MYMETA.yml'; my $cpan_meta_error; if ( $source && $HAS_CPAN_META && (my $meta = eval { CPAN::Meta->load_file($source) } ) ) { $full_prereqs = _merge_prereqs($full_prereqs, $meta->prereqs); } else { $cpan_meta_error = $@; # capture error from CPAN::Meta->load_file($source) $source = 'static metadata'; } my @full_reports; my @dep_errors; my $req_hash = $HAS_CPAN_META ? $full_prereqs->as_string_hash : $full_prereqs; # Add static includes into a fake section for my $mod (@include) { $req_hash->{other}{modules}{$mod} = 0; } for my $phase ( qw(configure build test runtime develop other) ) { next unless $req_hash->{$phase}; next if ($phase eq 'develop' and not $ENV{AUTHOR_TESTING}); for my $type ( qw(requires recommends suggests conflicts modules) ) { next unless $req_hash->{$phase}{$type}; my $title = ucfirst($phase).' '.ucfirst($type); my @reports = [qw/Module Want Have/]; for my $mod ( sort keys %{ $req_hash->{$phase}{$type} } ) { next if $mod eq 'perl'; next if grep { $_ eq $mod } @exclude; my $file = $mod; $file =~ s{::}{/}g; $file .= ".pm"; my ($prefix) = grep { -e File::Spec->catfile($_, $file) } @INC; my $want = $req_hash->{$phase}{$type}{$mod}; $want = "undef" unless defined $want; $want = "any" if !$want && $want == 0; my $req_string = $want eq 'any' ? 'any version required' : "version '$want' required"; if ($prefix) { my $have = Module::Metadata->new_from_file( File::Spec->catfile($prefix, $file) )->version; $have = "undef" unless defined $have; push @reports, [$mod, $want, $have]; if ( $DO_VERIFY_PREREQS && $HAS_CPAN_META && $type eq 'requires' ) { if ( $have !~ /\A$lax_version_re\z/ ) { push @dep_errors, "$mod version '$have' cannot be parsed ($req_string)"; } elsif ( ! $full_prereqs->requirements_for( $phase, $type )->accepts_module( $mod => $have ) ) { push @dep_errors, "$mod version '$have' is not in required range '$want'"; } } } else { push @reports, [$mod, $want, "missing"]; if ( $DO_VERIFY_PREREQS && $type eq 'requires' ) { push @dep_errors, "$mod is not installed ($req_string)"; } } } if ( @reports ) { push @full_reports, "=== $title ===\n\n"; my $ml = _max( map { length $_->[0] } @reports ); my $wl = _max( map { length $_->[1] } @reports ); my $hl = _max( map { length $_->[2] } @reports ); if ($type eq 'modules') { splice @reports, 1, 0, ["-" x $ml, "", "-" x $hl]; push @full_reports, map { sprintf(" %*s %*s\n", -$ml, $_->[0], $hl, $_->[2]) } @reports; } else { splice @reports, 1, 0, ["-" x $ml, "-" x $wl, "-" x $hl]; push @full_reports, map { sprintf(" %*s %*s %*s\n", -$ml, $_->[0], $wl, $_->[1], $hl, $_->[2]) } @reports; } push @full_reports, "\n"; } } } if ( @full_reports ) { diag "\nVersions for all modules listed in $source (including optional ones):\n\n", @full_reports; } if ( $cpan_meta_error || @dep_errors ) { diag "\n*** WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING ***\n"; } if ( $cpan_meta_error ) { my ($orig_source) = grep { -f } 'MYMETA.json', 'MYMETA.yml'; diag "\nCPAN::Meta->load_file('$orig_source') failed with: $cpan_meta_error\n"; } if ( @dep_errors ) { diag join("\n", "\nThe following REQUIRED prerequisites were not satisfied:\n", @dep_errors, "\n" ); } pass; # vim: ts=4 sts=4 sw=4 et: Path000755000766000024 013702474074 15411 5ustar00etherstaff000000000000Path-Dispatcher-1.08/libDispatcher.pm100640000766000024 1666213702474074 20224 0ustar00etherstaff000000000000Path-Dispatcher-1.08/lib/Pathpackage Path::Dispatcher; # git description: v1.07-5-ge7be931 # ABSTRACT: Flexible and extensible dispatch our $VERSION = '1.08'; use Moo; use 5.008001; # VERSION use Scalar::Util 'blessed'; use Path::Dispatcher::Rule; use Path::Dispatcher::Dispatch; use Path::Dispatcher::Path; use constant dispatch_class => 'Path::Dispatcher::Dispatch'; use constant path_class => 'Path::Dispatcher::Path'; with 'Path::Dispatcher::Role::Rules'; sub dispatch { my $self = shift; my $path = $self->_autobox_path(shift); my $dispatch = $self->dispatch_class->new; for my $rule ($self->rules) { $self->_dispatch_rule( rule => $rule, dispatch => $dispatch, path => $path, ); } return $dispatch; } sub _dispatch_rule { my $self = shift; my %args = @_; my @matches = $args{rule}->match($args{path}); $args{dispatch}->add_matches(@matches); return @matches; } sub run { my $self = shift; my $path = shift; my $dispatch = $self->dispatch($path); return $dispatch->run(@_); } sub complete { my $self = shift; my $path = $self->_autobox_path(shift); my %seen; return grep { !$seen{$_}++ } map { $_->complete($path) } $self->rules; } sub _autobox_path { my $self = shift; my $path = shift; unless (blessed($path) && $path->isa('Path::Dispatcher::Path')) { $path = $self->path_class->new( path => $path, ); } return $path; } __PACKAGE__->meta->make_immutable; no Moo; # don't require others to load our subclasses explicitly require Path::Dispatcher::Rule::Alternation; require Path::Dispatcher::Rule::Always; require Path::Dispatcher::Rule::Chain; require Path::Dispatcher::Rule::CodeRef; require Path::Dispatcher::Rule::Dispatch; require Path::Dispatcher::Rule::Empty; require Path::Dispatcher::Rule::Enum; require Path::Dispatcher::Rule::Eq; require Path::Dispatcher::Rule::Intersection; require Path::Dispatcher::Rule::Metadata; require Path::Dispatcher::Rule::Regex; require Path::Dispatcher::Rule::Sequence; require Path::Dispatcher::Rule::Tokens; require Path::Dispatcher::Rule::Under; 1; __END__ =pod =encoding UTF-8 =head1 NAME Path::Dispatcher - Flexible and extensible dispatch =head1 VERSION version 1.08 =head1 SYNOPSIS use Path::Dispatcher; my $dispatcher = Path::Dispatcher->new; $dispatcher->add_rule( Path::Dispatcher::Rule::Regex->new( regex => qr{^/(foo)/}, block => sub { warn shift->pos(1); }, ) ); $dispatcher->add_rule( Path::Dispatcher::Rule::Tokens->new( tokens => ['ticket', 'delete', qr/^\d+$/], delimiter => '/', block => sub { delete_ticket(shift->pos(3)) }, ) ); my $dispatch = $dispatcher->dispatch("/foo/bar"); die "404" unless $dispatch->has_matches; $dispatch->run; =head1 DESCRIPTION We really like L and wanted to use it for L's command line. The basic operation is that of dispatch. Dispatch takes a path and a list of rules, and it returns a list of matches. From there you can "run" the rules that matched. These phases are distinct so that, if you need to, you can inspect which rules were matched without ever running their codeblocks. Tab completion support is also available (see in particular L) for the dispatchers you write. Each rule may take a variety of different forms (which I think justifies the "flexible" adjective in the module's description). Some of the rule types are: =over 4 =item L Matches the path against a regular expression. =item L Match one of a set of strings. =item L Execute a coderef to determine whether the path matches the rule. So you can do anything you like. Though writing a domain-specific rule (see below) will enable better introspection and encoding intent. =item L Use another L to match the path. This facilitates both extending dispatchers (a bit like subclassing) and delegating to plugins. =back Since L is designed with good object-oriented programming practices, you can also write your own domain-specific rule classes (which earns it the "extensible" adjective). For example, in L, we have a custom rule for matching, and tab completing, record IDs. You may want to use L which gives you some sugar inspired by L. =head1 ATTRIBUTES =head2 rules A list of L objects. =head1 METHODS =head2 add_rule Adds a L to the end of this dispatcher's rule set. =head2 dispatch path -> dispatch Takes a string (the path) and returns a L object representing a list of matches (L objects). =head2 run path, args Dispatches on the path and then invokes the C method on the L object, for when you don't need to inspect the dispatch. The args are passed down directly into each rule codeblock. No other args are given to the codeblock. =head2 complete path -> strings Given a path, consult each rule for possible completions for the path. This is intended for tab completion. You can use it with L like so: $term->Attribs->{completion_function} = sub { my ($last_word, $line, $start) = @_; my @matches = map { s/^.* //; $_ } $dispatcher->complete($line); return @matches; }; This API is experimental and subject to change. In particular I think I want to return an object that resembles L. =head1 SEE ALSO =over 4 =item L =item L =item L =item L =item L =item L =item L =item L =item L - Not quite ready for release =back =head1 SUPPORT Bugs may be submitted through L (or L). =head1 AUTHOR Shawn M Moore, C<< >> =head1 CONTRIBUTORS =for stopwords sartak Shawn M Moore Karen Etheridge robertkrimen Aaron Trevena David Pottage Florian Ragwitz clkao =over 4 =item * sartak =item * Shawn M Moore =item * Shawn M Moore =item * Karen Etheridge =item * robertkrimen =item * Aaron Trevena =item * David Pottage =item * Shawn M Moore =item * Shawn M Moore =item * Florian Ragwitz =item * Shawn M Moore =item * clkao =back =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2020 by Shawn M Moore. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut 026-named-captures.t100640000766000024 146513702474074 17756 0ustar00etherstaff000000000000Path-Dispatcher-1.08/tuse strict; use warnings; use Test::More; BEGIN { if ($] <= 5.010001) { plan skip_all => 'This test requires Perl 5.10.1'; } } use Path::Dispatcher; my $dispatcher = Path::Dispatcher->new( rules => [ Path::Dispatcher::Rule::Regex->new( regex => qr/^(\w+) (?\w+) (?\w+)?$/, block => sub { shift }, ), ], ); my $match = $dispatcher->run("positional named "); is_deeply($match->positional_captures, ["positional", "named", undef]); is_deeply($match->named_captures, { second => "named" }); $match = $dispatcher->run("positional firstnamed secondnamed"); is_deeply($match->positional_captures, ["positional", "firstnamed", "secondnamed"]); is_deeply($match->named_captures, { second => "firstnamed", third => "secondnamed" }); done_testing; 00-compile.t100644000766000024 405313702474074 20100 0ustar00etherstaff000000000000Path-Dispatcher-1.08/xt/authoruse 5.006; use strict; use warnings; # this test was generated with Dist::Zilla::Plugin::Test::Compile 2.058 use Test::More 0.94; plan tests => 21; my @module_files = ( 'Path/Dispatcher.pm', 'Path/Dispatcher/Dispatch.pm', 'Path/Dispatcher/Match.pm', 'Path/Dispatcher/Path.pm', 'Path/Dispatcher/Role/Rules.pm', 'Path/Dispatcher/Rule.pm', 'Path/Dispatcher/Rule/Alternation.pm', 'Path/Dispatcher/Rule/Always.pm', 'Path/Dispatcher/Rule/Chain.pm', 'Path/Dispatcher/Rule/CodeRef.pm', 'Path/Dispatcher/Rule/Dispatch.pm', 'Path/Dispatcher/Rule/Empty.pm', 'Path/Dispatcher/Rule/Enum.pm', 'Path/Dispatcher/Rule/Eq.pm', 'Path/Dispatcher/Rule/Intersection.pm', 'Path/Dispatcher/Rule/Metadata.pm', 'Path/Dispatcher/Rule/Regex.pm', 'Path/Dispatcher/Rule/Sequence.pm', 'Path/Dispatcher/Rule/Tokens.pm', 'Path/Dispatcher/Rule/Under.pm' ); # no fake home requested my @switches = ( -d 'blib' ? '-Mblib' : '-Ilib', ); use File::Spec; use IPC::Open3; use IO::Handle; open my $stdin, '<', File::Spec->devnull or die "can't open devnull: $!"; my @warnings; for my $lib (@module_files) { # see L my $stderr = IO::Handle->new; diag('Running: ', join(', ', map { my $str = $_; $str =~ s/'/\\'/g; q{'} . $str . q{'} } $^X, @switches, '-e', "require q[$lib]")) if $ENV{PERL_COMPILE_TEST_DEBUG}; my $pid = open3($stdin, '>&STDERR', $stderr, $^X, @switches, '-e', "require q[$lib]"); binmode $stderr, ':crlf' if $^O eq 'MSWin32'; my @_warnings = <$stderr>; waitpid($pid, 0); is($?, 0, "$lib loaded ok"); shift @_warnings if @_warnings and $_warnings[0] =~ /^Using .*\bblib/ and not eval { +require blib; blib->VERSION('1.01') }; if (@_warnings) { warn @_warnings; push @warnings, @_warnings; } } is(scalar(@warnings), 0, 'no warnings found') or diag 'got warnings: ', explain(\@warnings); BAIL_OUT("Compilation problems") if !Test::More->builder->is_passing; pod-syntax.t100644000766000024 25213702474074 20316 0ustar00etherstaff000000000000Path-Dispatcher-1.08/xt/author#!perl # This file was automatically generated by Dist::Zilla::Plugin::PodSyntaxTests. use strict; use warnings; use Test::More; use Test::Pod 1.41; all_pod_files_ok(); pod-no404s.t100644000766000024 52713702474074 20024 0ustar00etherstaff000000000000Path-Dispatcher-1.08/xt/author#!perl use strict; use warnings; use Test::More; foreach my $env_skip ( qw( SKIP_POD_NO404S AUTOMATED_TESTING ) ){ plan skip_all => "\$ENV{$env_skip} is set, skipping" if $ENV{$env_skip}; } eval "use Test::Pod::No404s"; if ( $@ ) { plan skip_all => 'Test::Pod::No404s required for testing POD'; } else { all_pod_files_ok(); } 00-report-prereqs.dd100644000766000024 2347113702474074 20121 0ustar00etherstaff000000000000Path-Dispatcher-1.08/tdo { my $x = { 'configure' => { 'requires' => { 'ExtUtils::MakeMaker' => '0', 'Module::Build::Tiny' => '0.034', 'perl' => '5.008001' } }, 'develop' => { 'recommends' => { 'Dist::Zilla::PluginBundle::Author::ETHER' => '0.158', 'Dist::Zilla::PluginBundle::Git::VersionManager' => '0.007' }, 'requires' => { 'Encode' => '0', 'File::Spec' => '0', 'IO::Handle' => '0', 'IPC::Open3' => '0', 'Test::CPAN::Changes' => '0.19', 'Test::CPAN::Meta' => '0', 'Test::EOL' => '0', 'Test::Kwalitee' => '1.21', 'Test::MinimumVersion' => '0', 'Test::Mojibake' => '0', 'Test::More' => '0.96', 'Test::NoTabs' => '0', 'Test::Pod' => '1.41', 'Test::Pod::No404s' => '0', 'Test::Portability::Files' => '0', 'strict' => '0', 'warnings' => '0' } }, 'runtime' => { 'requires' => { 'Carp' => '0', 'Moo' => '0', 'Moo::Role' => '0', 'MooX::TypeTiny' => '0', 'Scalar::Util' => '0', 'Try::Tiny' => '0', 'Type::Tiny' => '0', 'Type::Utils' => '0', 'Types::Standard' => '0', 'constant' => '0', 'overload' => '0', 'perl' => '5.008001' } }, 'test' => { 'recommends' => { 'CPAN::Meta' => '2.120900' }, 'requires' => { 'File::Spec' => '0', 'Module::Metadata' => '0', 'Test::Fatal' => '0', 'Test::More' => '0', 'perl' => '5.008001', 'strict' => '0', 'warnings' => '0' } }, 'x_Dist_Zilla' => { 'requires' => { 'Dist::Zilla' => '5', 'Dist::Zilla::Plugin::Authority' => '1.009', 'Dist::Zilla::Plugin::AutoMetaResources' => '0', 'Dist::Zilla::Plugin::AutoPrereqs' => '5.038', 'Dist::Zilla::Plugin::BumpVersionAfterRelease::Transitional' => '0.004', 'Dist::Zilla::Plugin::CheckIssues' => '0', 'Dist::Zilla::Plugin::CheckMetaResources' => '0', 'Dist::Zilla::Plugin::CheckPrereqsIndexed' => '0.019', 'Dist::Zilla::Plugin::CheckSelfDependency' => '0', 'Dist::Zilla::Plugin::CheckStrictVersion' => '0', 'Dist::Zilla::Plugin::ConfirmRelease' => '0', 'Dist::Zilla::Plugin::CopyFilesFromRelease' => '0', 'Dist::Zilla::Plugin::EnsureLatestPerl' => '0', 'Dist::Zilla::Plugin::FileFinder::ByName' => '0', 'Dist::Zilla::Plugin::FileFinder::Filter' => '0', 'Dist::Zilla::Plugin::GenerateFile::FromShareDir' => '0', 'Dist::Zilla::Plugin::Git::Check' => '0', 'Dist::Zilla::Plugin::Git::CheckFor::CorrectBranch' => '0.004', 'Dist::Zilla::Plugin::Git::CheckFor::MergeConflicts' => '0', 'Dist::Zilla::Plugin::Git::Commit' => '2.020', 'Dist::Zilla::Plugin::Git::Contributors' => '0.029', 'Dist::Zilla::Plugin::Git::Describe' => '0.004', 'Dist::Zilla::Plugin::Git::GatherDir' => '2.016', 'Dist::Zilla::Plugin::Git::Push' => '0', 'Dist::Zilla::Plugin::Git::Remote::Check' => '0', 'Dist::Zilla::Plugin::Git::Tag' => '0', 'Dist::Zilla::Plugin::GitHub::Update' => '0.40', 'Dist::Zilla::Plugin::GithubMeta' => '0.54', 'Dist::Zilla::Plugin::InstallGuide' => '1.200005', 'Dist::Zilla::Plugin::Keywords' => '0.004', 'Dist::Zilla::Plugin::License' => '5.038', 'Dist::Zilla::Plugin::MakeMaker::Fallback' => '0.029', 'Dist::Zilla::Plugin::Manifest' => '0', 'Dist::Zilla::Plugin::MetaConfig' => '0', 'Dist::Zilla::Plugin::MetaJSON' => '0', 'Dist::Zilla::Plugin::MetaNoIndex' => '0', 'Dist::Zilla::Plugin::MetaProvides::Package' => '1.15000002', 'Dist::Zilla::Plugin::MetaTests' => '0', 'Dist::Zilla::Plugin::MetaYAML' => '0', 'Dist::Zilla::Plugin::MinimumPerl' => '1.006', 'Dist::Zilla::Plugin::ModuleBuildTiny::Fallback' => '0.018', 'Dist::Zilla::Plugin::MojibakeTests' => '0.8', 'Dist::Zilla::Plugin::NextRelease' => '5.033', 'Dist::Zilla::Plugin::PodSyntaxTests' => '5.040', 'Dist::Zilla::Plugin::PodWeaver' => '4.008', 'Dist::Zilla::Plugin::Prereqs' => '0', 'Dist::Zilla::Plugin::Prereqs::AuthorDeps' => '0.006', 'Dist::Zilla::Plugin::PromptIfStale' => '0', 'Dist::Zilla::Plugin::Readme' => '0', 'Dist::Zilla::Plugin::ReadmeAnyFromPod' => '0.142180', 'Dist::Zilla::Plugin::RewriteVersion::Transitional' => '0.006', 'Dist::Zilla::Plugin::Run::AfterBuild' => '0.041', 'Dist::Zilla::Plugin::Run::AfterRelease' => '0.038', 'Dist::Zilla::Plugin::RunExtraTests' => '0.024', 'Dist::Zilla::Plugin::StaticInstall' => '0.005', 'Dist::Zilla::Plugin::Substitute' => '0', 'Dist::Zilla::Plugin::Test::CPAN::Changes' => '0.012', 'Dist::Zilla::Plugin::Test::ChangesHasContent' => '0', 'Dist::Zilla::Plugin::Test::Compile' => '2.039', 'Dist::Zilla::Plugin::Test::EOL' => '0.17', 'Dist::Zilla::Plugin::Test::Kwalitee' => '2.10', 'Dist::Zilla::Plugin::Test::MinimumVersion' => '2.000010', 'Dist::Zilla::Plugin::Test::NoTabs' => '0.08', 'Dist::Zilla::Plugin::Test::Pod::No404s' => '1.003', 'Dist::Zilla::Plugin::Test::Portability' => '2.000007', 'Dist::Zilla::Plugin::Test::ReportPrereqs' => '0.022', 'Dist::Zilla::Plugin::TestRelease' => '0', 'Dist::Zilla::Plugin::UploadToCPAN' => '0', 'Dist::Zilla::Plugin::UseUnsafeInc' => '0', 'Dist::Zilla::PluginBundle::Author::ETHER' => '0.119', 'Dist::Zilla::PluginBundle::Git::VersionManager' => '0.007', 'Software::License::Perl_5' => '0' } } }; $x; }007-coderef-matcher.t100640000766000024 101013702474074 20057 0ustar00etherstaff000000000000Path-Dispatcher-1.08/tuse strict; use warnings; use Test::More; use Path::Dispatcher; my (@matches, @calls); my $dispatcher = Path::Dispatcher->new; $dispatcher->add_rule( Path::Dispatcher::Rule::CodeRef->new( matcher => sub { push @matches, $_; length > 5 ? {} : 0 }, block => sub { my $match = shift; push @calls, [@_] }, ), ); $dispatcher->run('foobar'); is_deeply([splice @matches], ['foobar']); is_deeply([splice @calls], [ [] ]); $dispatcher->run('other'); is($matches[0]->path, 'other'); done_testing; portability.t100644000766000024 26713702474074 20560 0ustar00etherstaff000000000000Path-Dispatcher-1.08/xt/authoruse strict; use warnings; use Test::More; eval 'use Test::Portability::Files'; plan skip_all => 'Test::Portability::Files required for testing portability' if $@; run_tests(); 031-structured-match.t100640000766000024 216113702474074 20332 0ustar00etherstaff000000000000Path-Dispatcher-1.08/tuse strict; use warnings; use Test::More; use Path::Dispatcher; my $outer = Path::Dispatcher::Rule::Regex->new( regex => qr/^(\w+) /, prefix => 1, ); my $inner = Path::Dispatcher::Rule::Regex->new( regex => qr/^(\w+)/, block => sub { return shift } ); my $dispatcher = Path::Dispatcher->new( rules => [ Path::Dispatcher::Rule::Under->new( predicate => $outer, rules => [ $inner ], ), ], ); my $match = $dispatcher->run("hello world"); my $parent = $match->parent; ok($parent, 'we have a parent too'); ok($match, 'matched'); is($parent->pos(1), 'hello', 'outer capture'); is($match->pos(1), 'world', 'inner capture'); is($parent->rule, $outer, 'outer rule'); is($match->rule, $inner, 'inner rule'); is_deeply($parent->positional_captures, ['hello'], 'all pos captures'); is_deeply($match->positional_captures, ['world'], 'all pos captures'); is($parent->path->path, 'hello world', 'outer path'); is($match->path->path, 'world', 'inner path'); is($parent->leftover, 'world', 'outer leftover'); is($match->leftover, undef, 'no inner leftover'); done_testing; cpan-changes.t100644000766000024 34413702474074 20657 0ustar00etherstaff000000000000Path-Dispatcher-1.08/xt/releaseuse strict; use warnings; # this test was generated with Dist::Zilla::Plugin::Test::CPAN::Changes 0.012 use Test::More 0.96 tests => 1; use Test::CPAN::Changes; subtest 'changes_ok' => sub { changes_file_ok('Changes'); }; 032-multiple-delimiter.t100640000766000024 404613702474074 20650 0ustar00etherstaff000000000000Path-Dispatcher-1.08/tuse strict; use warnings; use Test::More; use Path::Dispatcher; my @calls; my $dispatcher = Path::Dispatcher->new; $dispatcher->add_rule( Path::Dispatcher::Rule::Sequence->new( delimiter => ' ', rules => [ Path::Dispatcher::Rule::Eq->new( string => 'foo', ), Path::Dispatcher::Rule::Eq->new( string => 'bar', ), ], block => sub { push @calls, shift->positional_captures }, ), ); $dispatcher->run('foo bar'); is_deeply([splice @calls], [ ['foo', 'bar'] ], "correctly populated number vars from [str, str] token rule"); $dispatcher->run('foo bar'); is_deeply([splice @calls], [ ['foo', 'bar'] ], "correctly populated number vars from [str, str] token rule"); $dispatcher->run(' foo bar '); is_deeply([splice @calls], [ ['foo', 'bar'] ], "correctly populated number vars from [str, str] token rule"); $dispatcher = Path::Dispatcher->new; $dispatcher->add_rule( Path::Dispatcher::Rule::Sequence->new( delimiter => '/', rules => [ Path::Dispatcher::Rule::Eq->new( string => 'foo', ), Path::Dispatcher::Rule::Eq->new( string => 'bar', ), ], block => sub { push @calls, shift->positional_captures }, ), ); $dispatcher->run('/foo/bar'); is_deeply([splice @calls], [ ['foo', 'bar'] ], "correctly populated number vars from [str, str] token rule"); $dispatcher->run('/foo/bar/'); is_deeply([splice @calls], [ ['foo', 'bar'] ], "correctly populated number vars from [str, str] token rule"); $dispatcher->run('/foo//bar/'); is_deeply([splice @calls], [ ['foo', 'bar'] ], "correctly populated number vars from [str, str] token rule"); $dispatcher->run('foo/bar'); is_deeply([splice @calls], [ ['foo', 'bar'] ], "correctly populated number vars from [str, str] token rule"); $dispatcher->run('///foo///bar///'); is_deeply([splice @calls], [ ['foo', 'bar'] ], "correctly populated number vars from [str, str] token rule"); done_testing; Dispatcher000755000766000024 013702474074 17477 5ustar00etherstaff000000000000Path-Dispatcher-1.08/lib/PathPath.pm100640000766000024 405213702474074 21066 0ustar00etherstaff000000000000Path-Dispatcher-1.08/lib/Path/Dispatcherpackage Path::Dispatcher::Path; # ABSTRACT: path and some optional metadata our $VERSION = '1.08'; use Moo; use MooX::TypeTiny; use Types::Standard qw(Str HashRef); use overload q{""} => sub { shift->path }; has path => ( is => 'ro', isa => Str, predicate => 'has_path', ); has metadata => ( is => 'ro', isa => HashRef, predicate => 'has_metadata', ); # allow Path::Dispatcher::Path->new($path) around BUILDARGS => sub { my $orig = shift; my $self = shift; if (@_ == 1 && !ref($_[0])) { unshift @_, 'path'; } $self->$orig(@_); }; sub clone_path { my $self = shift; my $path = shift; return $self->new({ %$self, path => $path, @_ }); } sub get_metadata { my $self = shift; my $name = shift; return $self->metadata->{$name}; } __PACKAGE__->meta->make_immutable; no Moo; 1; __END__ =pod =encoding UTF-8 =head1 NAME Path::Dispatcher::Path - path and some optional metadata =head1 VERSION version 1.08 =head1 SYNOPSIS my $path = Path::Dispatcher::Path->new( path => "/REST/Ticket/1", metadata => { http_method => "DELETE", }, ); $path->path; # /REST/Ticket/1 $path->get_metadata("http_method"); # DELETE =head1 ATTRIBUTES =head2 path A string representing the path. C is basically a boxed string. :) =head2 metadata A hash representing arbitrary metadata. The L rule is designed to match against members of this hash. =head1 SUPPORT Bugs may be submitted through L (or L). =head1 AUTHOR Shawn M Moore, C<< >> =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2020 by Shawn M Moore. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Rule.pm100640000766000024 744713702474074 21114 0ustar00etherstaff000000000000Path-Dispatcher-1.08/lib/Path/Dispatcherpackage Path::Dispatcher::Rule; # ABSTRACT: predicate and codeblock our $VERSION = '1.08'; use Moo; use MooX::TypeTiny; use Types::Standard qw(Bool); use Path::Dispatcher::Match; use constant match_class => "Path::Dispatcher::Match"; has payload => ( is => 'ro', predicate => 'has_payload', ); has prefix => ( is => 'ro', isa => Bool, default => 0, ); # support for deprecated "block" attribute sub block { shift->payload(@_) } sub has_block { shift->has_payload(@_) } around BUILDARGS => sub { my $orig = shift; my $self = shift; my $args = $self->$orig(@_); $args->{payload} ||= delete $args->{block} if exists $args->{block}; return $args; }; sub match { my $self = shift; my $path = shift; my %args = @_; my $result; if ($self->prefix) { $result = $self->_prefix_match($path); } else { $result = $self->_match($path); } return if !$result; if (ref($result) ne 'HASH') { die "Results returned from _match must be a hashref"; } my $match = $self->match_class->new( path => $path, rule => $self, %{ $args{extra_constructor_args} || {} }, %$result, ); return $match; } sub complete { return (); # no completions } sub _prefix_match { my $self = shift; return $self->_match(@_); } sub run { my $self = shift; my $payload = $self->payload; die "No codeblock to run" if !$payload; die "Payload is not a coderef" if ref($payload) ne 'CODE'; $self->payload->(@_); } __PACKAGE__->meta->make_immutable; no Moo; 1; __END__ =pod =encoding UTF-8 =head1 NAME Path::Dispatcher::Rule - predicate and codeblock =head1 VERSION version 1.08 =head1 SYNOPSIS my $rule = Path::Dispatcher::Rule::Regex->new( regex => qr/^quit/, block => sub { die "Program terminated by user.\n" }, ); $rule->match("die"); # undef, because "die" !~ /^quit/ my $match = $rule->match("quit"); # creates a Path::Dispatcher::Match $match->run; # exits the program =head1 DESCRIPTION A rule has a predicate and an optional codeblock. Rules can be matched (which checks the predicate against the path) and they can be ran (which invokes the codeblock). This class is not meant to be instantiated directly, because there is no predicate matching function. Instead use one of the subclasses such as L. =head1 ATTRIBUTES =head2 block An optional block of code to be run. Please use the C method instead of invoking this attribute directly. =head2 prefix A boolean indicating whether this rule can match a prefix of a path. If false, then the predicate must match the entire path. One use-case is that you may want a catch-all rule that matches anything beginning with the token C. The unmatched, latter part of the path will be available in the match object. =head1 METHODS =head2 match path -> match Takes a path and returns a L object if it matched the predicate, otherwise C. The match object contains information about the match, such as the results (e.g. for regex, a list of the captured variables), the C path if C matching was used, etc. =head2 run Runs the rule's codeblock. If none is present, it throws an exception. =head1 SUPPORT Bugs may be submitted through L (or L). =head1 AUTHOR Shawn M Moore, C<< >> =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2020 by Shawn M Moore. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut minimum-version.t100644000766000024 22513702474074 21346 0ustar00etherstaff000000000000Path-Dispatcher-1.08/xt/authoruse strict; use warnings; use Test::More; use Test::MinimumVersion; all_minimum_version_ok( qq{5.008003} , { skip => ['t/026-named-captures.t'] }); Match.pm100640000766000024 716213702474074 21233 0ustar00etherstaff000000000000Path-Dispatcher-1.08/lib/Path/Dispatcherpackage Path::Dispatcher::Match; # ABSTRACT: the result of a successful rule match our $VERSION = '1.08'; use Moo; use MooX::TypeTiny; use Type::Utils qw(class_type); use Types::Standard qw(Str ArrayRef HashRef Undef); use Path::Dispatcher::Path; use Path::Dispatcher::Rule; has path => ( is => 'ro', isa => class_type('Path::Dispatcher::Path'), required => 1, ); has leftover => ( is => 'ro', isa => Str, ); has rule => ( is => 'ro', isa => class_type('Path::Dispatcher::Rule'), required => 1, handles => ['payload'], ); has positional_captures => ( is => 'ro', isa => ArrayRef[Str|Undef], default => sub { [] }, ); has named_captures => ( is => 'ro', isa => HashRef[Str|Undef], default => sub { {} }, ); has parent => ( is => 'ro', isa => class_type('Path::Dispatcher::Match'), predicate => 'has_parent', ); sub run { my $self = shift; local $_ = $self->path; return scalar $self->rule->run($self, @_); } sub pos { my $self = shift; my $index = shift; return undef if $index == 0; $index-- if $index > 0; return $self->positional_captures->[$index]; } sub named { my $self = shift; my $key = shift; return $self->named_captures->{$key}; } __PACKAGE__->meta->make_immutable; no Moo; 1; __END__ =pod =encoding UTF-8 =head1 NAME Path::Dispatcher::Match - the result of a successful rule match =head1 VERSION version 1.08 =head1 SYNOPSIS my $rule = Path::Dispatcher::Rule::Tokens->new( tokens => [ 'attack', qr/^\w+$/ ], block => sub { my $match = shift; attack($match->pos(2)) }, ); my $match = $rule->match("attack dragon"); # introspection $match->path # "attack dragon" $match->leftover # empty string (populated with prefix rules) $match->rule # $rule $match->positional_captures # ["attack", "dragon"] (decided by the rule) $match->pos(1) # "attack" $match->pos(2) # "dragon" $match->run # attack("dragon") =head1 DESCRIPTION If a L successfully matches a path, it creates one or more C objects. =head1 ATTRIBUTES =head2 rule The L that created this match. =head2 path The path that the rule matched. =head2 leftover The rest of the path. This is populated when the rule matches a prefix of the path. =head2 positional_captures Any positional captures generated by the rule. For example, L populates this with the capture variables. =head2 named_captures Any named captures generated by the rule. For example, L populates this with named captures. =head2 parent The parent match object, if applicable (which may be set if this match is the child of, for exampl, a L prefix) =head1 METHODS =head2 run Executes the rule's codeblock with the same arguments. =head2 pos($i) Returns the C<$i>th positional capture, 1-indexed. =head1 SUPPORT Bugs may be submitted through L (or L). =head1 AUTHOR Shawn M Moore, C<< >> =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2020 by Shawn M Moore. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut 025-sequence-custom-rule.t100640000766000024 1035713702474074 21152 0ustar00etherstaff000000000000Path-Dispatcher-1.08/tuse strict; use warnings; use Test::More; use Path::Dispatcher; my @calls; do { package MyApp::Dispatcher::Rule::Language; use Moo; extends 'Path::Dispatcher::Rule::Enum'; has '+enum' => ( default => sub { [qw/ruby perl php python/] }, ); }; my $dispatcher = Path::Dispatcher->new( rules => [ Path::Dispatcher::Rule::Sequence->new( rules => [ Path::Dispatcher::Rule::Eq->new(string => 'use'), MyApp::Dispatcher::Rule::Language->new, ], block => sub { push @calls, shift->positional_captures }, ), ], ); $dispatcher->run("use perl"); is_deeply([splice @calls], [["use", "perl"]]); $dispatcher->run("use python"); is_deeply([splice @calls], [["use", "python"]]); $dispatcher->run("use php"); is_deeply([splice @calls], [["use", "php"]]); $dispatcher->run("use ruby"); is_deeply([splice @calls], [["use", "ruby"]]); $dispatcher->run("use c++"); is_deeply([splice @calls], []); is_deeply([$dispatcher->complete("u")], ["use"]); is_deeply([$dispatcher->complete("use")], ["use ruby", "use perl", "use php", "use python"]); is_deeply([$dispatcher->complete("use ")], ["use ruby", "use perl", "use php", "use python"]); is_deeply([$dispatcher->complete("use r")], ["use ruby"]); is_deeply([$dispatcher->complete("use p")], ["use perl", "use php", "use python"]); is_deeply([$dispatcher->complete("use pe")], ["use perl"]); is_deeply([$dispatcher->complete("use ph")], ["use php"]); is_deeply([$dispatcher->complete("use py")], ["use python"]); is_deeply([$dispatcher->complete("use px")], []); is_deeply([$dispatcher->complete("use x")], []); $dispatcher = Path::Dispatcher->new( rules => [ Path::Dispatcher::Rule::Sequence->new( rules => [ Path::Dispatcher::Rule::Eq->new(string => 'use'), MyApp::Dispatcher::Rule::Language->new, Path::Dispatcher::Rule::Eq->new(string => 'please'), ], block => sub { push @calls, shift->positional_captures }, ), ], ); $dispatcher->run("use perl"); is_deeply([splice @calls], []); $dispatcher->run("use perl please"); is_deeply([splice @calls], [["use", "perl", "please"]]); $dispatcher->run("use python"); is_deeply([splice @calls], []); $dispatcher->run("use python please"); is_deeply([splice @calls], [["use", "python", "please"]]); $dispatcher->run("use php"); is_deeply([splice @calls], []); $dispatcher->run("use php please"); is_deeply([splice @calls], [["use", "php", "please"]]); $dispatcher->run("use ruby"); is_deeply([splice @calls], []); $dispatcher->run("use ruby please"); is_deeply([splice @calls], [["use", "ruby", "please"]]); $dispatcher->run("use c++"); is_deeply([splice @calls], []); $dispatcher->run("use c++ please"); is_deeply([splice @calls], []); is_deeply([$dispatcher->complete("u")], ["use"]); is_deeply([$dispatcher->complete("use")], ["use ruby", "use perl", "use php", "use python"]); is_deeply([$dispatcher->complete("use ")], ["use ruby", "use perl", "use php", "use python"]); is_deeply([$dispatcher->complete("use r")], ["use ruby"]); is_deeply([$dispatcher->complete("use p")], ["use perl", "use php", "use python"]); is_deeply([$dispatcher->complete("use pe")], ["use perl"]); is_deeply([$dispatcher->complete("use ph")], ["use php"]); is_deeply([$dispatcher->complete("use py")], ["use python"]); is_deeply([$dispatcher->complete("use px")], []); is_deeply([$dispatcher->complete("use x")], []); is_deeply([$dispatcher->complete("use ruby")], ["use ruby please"]); is_deeply([$dispatcher->complete("use ruby ")], ["use ruby please"]); is_deeply([$dispatcher->complete("use ruby pl")], ["use ruby please"]); is_deeply([$dispatcher->complete("use ruby pleas")], ["use ruby please"]); is_deeply([$dispatcher->complete("use ruby please")], []); is_deeply([$dispatcher->complete("use ruby plx")], []); is_deeply([$dispatcher->complete("use perl")], ["use perl please"]); is_deeply([$dispatcher->complete("use perl ")], ["use perl please"]); is_deeply([$dispatcher->complete("use perl pl")], ["use perl please"]); is_deeply([$dispatcher->complete("use perl pleas")], ["use perl please"]); is_deeply([$dispatcher->complete("use perl please")], []); is_deeply([$dispatcher->complete("use perl plx")], []); done_testing; 019-intersection-metadata.t100640000766000024 211613702474074 21326 0ustar00etherstaff000000000000Path-Dispatcher-1.08/tuse strict; use warnings; use Test::More; use Path::Dispatcher; my $dispatcher = Path::Dispatcher->new( rules => [ Path::Dispatcher::Rule::Intersection->new( block => sub { "creating a ticket" }, rules => [ Path::Dispatcher::Rule::Tokens->new( delimiter => '/', tokens => ['=', 'model', 'Ticket'], ), Path::Dispatcher::Rule::Metadata->new( field => 'http_method', matcher => Path::Dispatcher::Rule::Eq->new(string => 'POST'), ), ], ), ], ); my @results = $dispatcher->run(Path::Dispatcher::Path->new( path => "/=/model/Ticket", metadata => { http_method => "POST", }, )); is_deeply(\@results, ["creating a ticket"], "matched path and metadata"); @results = $dispatcher->run(Path::Dispatcher::Path->new( path => "/=/model/Ticket.yml", metadata => { http_method => "GET", }, )); is_deeply(\@results, [], "didn't match metadata"); done_testing; 027-custom-named-captures.t100640000766000024 176313702474074 21270 0ustar00etherstaff000000000000Path-Dispatcher-1.08/tuse strict; use warnings; use Test::More; use Path::Dispatcher; { package My::Rule::NamedEnum; use Moo; use Types::Standard qw( Str RegexpRef ); extends 'Path::Dispatcher::Rule'; has name => ( is => 'ro', isa => Str, required => 1, ); has regex => ( is => 'ro', isa => RegexpRef, required => 1, ); sub _match { my $self = shift; my $path = shift; return unless $path =~ $self->regex; return { named_captures => { $self->name => $&, }, }; } } my $dispatcher = Path::Dispatcher->new( rules => [ My::Rule::NamedEnum->new( name => 'hoo-ah', regex => qr/^\w+::/, block => sub { shift }, ) ], ); my $match = $dispatcher->run("Foo::Bar"); is_deeply($match->positional_captures, []); is_deeply($match->named_captures, { "hoo-ah" => "Foo::" }); done_testing; Rule000755000766000024 013702474074 20406 5ustar00etherstaff000000000000Path-Dispatcher-1.08/lib/Path/DispatcherEq.pm100640000766000024 463413702474074 21454 0ustar00etherstaff000000000000Path-Dispatcher-1.08/lib/Path/Dispatcher/Rulepackage Path::Dispatcher::Rule::Eq; # ABSTRACT: predicate is a string equality our $VERSION = '1.08'; use Moo; use MooX::TypeTiny; use Types::Standard qw(Str Bool); extends 'Path::Dispatcher::Rule'; has string => ( is => 'ro', isa => Str, required => 1, ); has case_sensitive => ( is => 'ro', isa => Bool, default => 1, ); sub _match { my $self = shift; my $path = shift; if ($self->case_sensitive) { return unless $path->path eq $self->string; } else { return unless lc($path->path) eq lc($self->string); } return {}; } sub _prefix_match { my $self = shift; my $path = shift; my $truncated = substr($path->path, 0, length($self->string)); if ($self->case_sensitive) { return unless $truncated eq $self->string; } else { return unless lc($truncated) eq lc($self->string); } return { leftover => substr($path->path, length($self->string)), }; } sub complete { my $self = shift; my $path = shift->path; my $completed = $self->string; # by convention, complete does include the path itself if it # is a complete match return if length($path) >= length($completed); my $partial = substr($completed, 0, length($path)); if ($self->case_sensitive) { return unless $partial eq $path; } else { return unless lc($partial) eq lc($path); } return $completed; } __PACKAGE__->meta->make_immutable; no Moo; 1; __END__ =pod =encoding UTF-8 =head1 NAME Path::Dispatcher::Rule::Eq - predicate is a string equality =head1 VERSION version 1.08 =head1 SYNOPSIS my $rule = Path::Dispatcher::Rule::Eq->new( string => 'comment', block => sub { display_comment(shift->pos(1)) }, ); =head1 DESCRIPTION Rules of this class simply check whether the string is equal to the path. =head1 ATTRIBUTES =head2 string =head1 SUPPORT Bugs may be submitted through L (or L). =head1 AUTHOR Shawn M Moore, C<< >> =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2020 by Shawn M Moore. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Dispatch.pm100640000766000024 607213702474074 21735 0ustar00etherstaff000000000000Path-Dispatcher-1.08/lib/Path/Dispatcherpackage Path::Dispatcher::Dispatch; # ABSTRACT: a list of matches our $VERSION = '1.08'; use Moo; use MooX::TypeTiny; use Try::Tiny; use Carp qw(confess); use Types::Standard qw(ArrayRef); use Path::Dispatcher::Match; has _matches => ( is => 'ro', isa => ArrayRef, default => sub { [] }, ); sub add_match { my $self = shift; $_->isa('Path::Dispatcher::Match') or confess "$_ is not a Path::Dispatcher::Match" for @_; push @{ $self->{_matches} }, @_; } sub matches { @{ shift->{_matches} } } sub has_match { scalar @{ shift->{_matches} } } sub first_match { shift->{_matches}[0] } # aliases sub add_matches { goto \&add_match } sub has_matches { goto \&has_match } sub run { my $self = shift; my @args = @_; my @matches = $self->matches; my @results; while (my $match = shift @matches) { my $exception; try { local $SIG{__DIE__} = 'DEFAULT'; push @results, $match->run(@args); # we always stop after the first match UNLESS they explicitly # ask to continue on to the next rule die "Path::Dispatcher abort\n"; } catch { $exception = $_; }; last if $exception =~ /^Path::Dispatcher abort\n/; next if $exception =~ /^Path::Dispatcher next rule\n/; die $exception; } return @results if wantarray; return $results[0]; } __PACKAGE__->meta->make_immutable; no Moo; 1; __END__ =pod =encoding UTF-8 =head1 NAME Path::Dispatcher::Dispatch - a list of matches =head1 VERSION version 1.08 =head1 SYNOPSIS my $dispatcher = Path::Dispatcher->new( rules => [ Path::Dispatcher::Rule::Tokens->new( tokens => [ 'attack', qr/^\w+$/ ], block => sub { attack(shift->pos(2)) }, ), ], ); my $dispatch = $dispatcher->dispatch("attack goblin"); $dispatch->matches; # list of matches (in this case, one) $dispatch->has_matches; # whether there were any matches $dispatch->run; # attacks the goblin =head1 DESCRIPTION Dispatching creates a C which is little more than a (possibly empty!) list of matches. =head1 ATTRIBUTES =head2 matches The list of L that correspond to the rules that were matched. =head1 METHODS =head2 run Executes the first match. Each match's L method is evaluated in scalar context. The return value of this method is a list of these scalars (or the first if called in scalar context). =head1 SUPPORT Bugs may be submitted through L (or L). =head1 AUTHOR Shawn M Moore, C<< >> =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2020 by Shawn M Moore. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut changes_has_content.t100644000766000024 104413702474074 22225 0ustar00etherstaff000000000000Path-Dispatcher-1.08/xt/authoruse strict; use warnings; use Test::More; plan skip_all => 'xt/release/changes_has_content.t is missing' if not -e 'xt/release/changes_has_content.t'; # skip for master branch, only for travis if (($ENV{TRAVIS_PULL_REQUEST} || '') eq 'false') { chomp(my $branch_name = ($ENV{TRAVIS_BRANCH} || `git rev-parse --abbrev-ref HEAD`)); $TODO = 'Changes need not have content for this release yet if this is only the '.$1.' branch' if ($branch_name || '') =~ /^(master|devel)$/; } do './xt/release/changes_has_content.t'; die $@ if $@; Cookbook.pod100640000766000024 567313702474074 22120 0ustar00etherstaff000000000000Path-Dispatcher-1.08/lib/Path/Dispatcher# PODNAME: Path::Dispatcher::Cookbook # ABSTRACT: A cookbook for Path::Dispatcher __END__ =pod =encoding UTF-8 =head1 NAME Path::Dispatcher::Cookbook - A cookbook for Path::Dispatcher =head1 VERSION version 1.08 =head1 NAME Path::Dispatcher::Cookbook - A cookbook for Path::Dispatcher =head1 RECIPES =head2 How can I change the path delimiter from a space ' ' to a slash '/'? When importing the L sugar, specify the C option for the C group. package My::Dispatcher; use Path::Dispatcher::Declarative -base, -default => { token_delimiter => '/', }; Or define a subclass of L with a C method: package Web::Dispatcher::Maker; use base 'Path::Dispatcher::Declarative'; use constant token_delimiter => '/'; package My::Dispatcher; use Web::Dispatcher::Maker -base; =head2 How can I do rule chaining (like in Catalyst)? You can use a C rule approximate chaining behavior: package MyDispatcher; use Path::Dispatcher::Declarative -base; under show => sub { chain { print "Displaying "; }; on inventory => sub { print "inventory:\n"; ... }; on score => sub { print "score:\n"; ... }; }; package main; MyDispatcher->run("show inventory"); # "Displaying inventory:\n ..." MyDispatcher->run("show score"); # "Displaying score:\n ..." =head2 How can I configure tab completion for shells? First add a dispatcher rule for generating completions based on the path. Here we name it _gencomp, so that if the user types "app _gencomp hel" it will print out the various completions of "hel". on qr/^_gencomp\s*(.*)/ => sub { my $prefix = shift->pos(1); $prefix = "" if !defined($prefix); print "$_\n" for dispatcher->complete($prefix); }; Then tell your shell about how to use _gencomp. For zsh it might look like this (replace "APP" with your binary name): /usr/share/zsh/site-functions/_APP: #compdef APP typeset -a APP_completions APP_completions=($($words[1] _gencomp $words[2,-1])) compadd $APP_completions For bash it might look like this: /etc/bash_completion.d/APP.bash: function _APP_() { COMPREPLY=($($1 _gencomp ${COMP_WORDS[COMP_CWORD]})) } complete -F _APP_ APP =head1 SUPPORT Bugs may be submitted through L (or L). =head1 AUTHOR Shawn M Moore, C<< >> =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2020 by Shawn M Moore. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Enum.pm100640000766000024 577013702474074 22015 0ustar00etherstaff000000000000Path-Dispatcher-1.08/lib/Path/Dispatcher/Rulepackage Path::Dispatcher::Rule::Enum; # ABSTRACT: one of a list of strings must match our $VERSION = '1.08'; use Moo; use MooX::TypeTiny; use Types::Standard qw(Str ArrayRef Bool); extends 'Path::Dispatcher::Rule'; has enum => ( is => 'ro', isa => ArrayRef[Str], required => 1, ); has case_sensitive => ( is => 'ro', isa => Bool, default => 1, ); sub _match { my $self = shift; my $path = shift; if ($self->case_sensitive) { for my $value (@{ $self->enum }) { return {} if $path->path eq $value; } } else { for my $value (@{ $self->enum }) { return {} if lc($path->path) eq lc($value); } } return; } sub _prefix_match { my $self = shift; my $path = shift; my $truncated = substr($path->path, 0, length($self->string)); if ($self->case_sensitive) { for my $value (@{ $self->enum }) { next unless $truncated eq $value; return { leftover => substr($path->path, length($self->string)), }; } } else { for my $value (@{ $self->enum }) { next unless lc($truncated) eq lc($value); return { leftover => substr($path->path, length($self->string)), }; } } return; } sub complete { my $self = shift; my $path = shift->path; my @completions; # by convention, complete does include the path itself if it # is a complete match my @enum = grep { length($path) < length($_) } @{ $self->enum }; if ($self->case_sensitive) { for my $value (@enum) { my $partial = substr($value, 0, length($path)); push @completions, $value if $partial eq $path; } } else { for my $value (@enum) { my $partial = substr($value, 0, length($path)); push @completions, $value if lc($partial) eq lc($path); } } return @completions; } __PACKAGE__->meta->make_immutable; no Moo; 1; __END__ =pod =encoding UTF-8 =head1 NAME Path::Dispatcher::Rule::Enum - one of a list of strings must match =head1 VERSION version 1.08 =head1 SYNOPSIS my $rule = Path::Dispatcher::Rule::Enum->new( enum => [qw(perl ruby python php)], block => sub { warn "I love " . shift->pos(1) }, ); =head1 DESCRIPTION Rules of this class check whether the path matches any of its L strings. =head1 ATTRIBUTES =head2 enum =head2 case_sensitive =head1 SUPPORT Bugs may be submitted through L (or L). =head1 AUTHOR Shawn M Moore, C<< >> =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2020 by Shawn M Moore. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut changes_has_content.t100644000766000024 210013702474074 22335 0ustar00etherstaff000000000000Path-Dispatcher-1.08/xt/releaseuse Test::More tests => 2; note 'Checking Changes'; my $changes_file = 'Changes'; my $newver = '1.08'; my $trial_token = '-TRIAL'; my $encoding = 'UTF-8'; SKIP: { ok(-e $changes_file, "$changes_file file exists") or skip 'Changes is missing', 1; ok(_get_changes($newver), "$changes_file has content for $newver"); } done_testing; sub _get_changes { my $newver = shift; # parse changelog to find commit message open(my $fh, '<', $changes_file) or die "cannot open $changes_file: $!"; my $changelog = join('', <$fh>); if ($encoding) { require Encode; $changelog = Encode::decode($encoding, $changelog, Encode::FB_CROAK()); } close $fh; my @content = grep { /^$newver(?:$trial_token)?(?:\s+|$)/ ... /^\S/ } # from newver to un-indented split /\n/, $changelog; shift @content; # drop the version line # drop unindented last line and trailing blank lines pop @content while ( @content && $content[-1] =~ /^(?:\S|\s*$)/ ); # return number of non-blank lines return scalar @content; } Role000755000766000024 013702474074 20400 5ustar00etherstaff000000000000Path-Dispatcher-1.08/lib/Path/DispatcherRules.pm100640000766000024 277513702474074 22177 0ustar00etherstaff000000000000Path-Dispatcher-1.08/lib/Path/Dispatcher/Rolepackage Path::Dispatcher::Role::Rules; # ABSTRACT: "has a list of rules" our $VERSION = '1.08'; use Moo::Role; use Carp qw(confess); use Types::Standard qw(ArrayRef); has _rules => ( is => 'ro', isa => ArrayRef, init_arg => 'rules', default => sub { [] }, ); sub add_rule { my $self = shift; $_->isa('Path::Dispatcher::Rule') or confess "$_ is not a Path::Dispatcher::Rule" for @_; push @{ $self->{_rules} }, @_; } sub unshift_rule { my $self = shift; $_->isa('Path::Dispatcher::Rule') or confess "$_ is not a Path::Dispatcher::Rule" for @_; unshift @{ $self->{_rules} }, @_; } sub rules { @{ shift->{_rules} } } no Moo::Role; 1; __END__ =pod =encoding UTF-8 =head1 NAME Path::Dispatcher::Role::Rules - "has a list of rules" =head1 VERSION version 1.08 =head1 DESCRIPTION Classes that compose this role get the following things: =head1 ATTRIBUTES =head2 _rules =head1 METHODS =head2 rules =head2 add_rule =head1 SUPPORT Bugs may be submitted through L (or L). =head1 AUTHOR Shawn M Moore, C<< >> =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2020 by Shawn M Moore. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Chain.pm100640000766000024 227313702474074 22126 0ustar00etherstaff000000000000Path-Dispatcher-1.08/lib/Path/Dispatcher/Rulepackage Path::Dispatcher::Rule::Chain; # ABSTRACT: Chain rules for Path::Dispatcher our $VERSION = '1.08'; use Moo; extends 'Path::Dispatcher::Rule::Always'; around payload => sub { my $orig = shift; my $self = shift; my $payload = $self->$orig(@_); if (!@_) { return sub { $payload->(@_); die "Path::Dispatcher next rule\n"; # FIXME From Path::Dispatcher::Declarative... maybe this should go in a common place? }; } return $payload; }; __PACKAGE__->meta->make_immutable; no Moo; 1; __END__ =pod =encoding UTF-8 =head1 NAME Path::Dispatcher::Rule::Chain - Chain rules for Path::Dispatcher =head1 VERSION version 1.08 =head1 SUPPORT Bugs may be submitted through L (or L). =head1 AUTHOR Shawn M Moore, C<< >> =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2020 by Shawn M Moore. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Empty.pm100640000766000024 202313702474074 22173 0ustar00etherstaff000000000000Path-Dispatcher-1.08/lib/Path/Dispatcher/Rulepackage Path::Dispatcher::Rule::Empty; # ABSTRACT: matches only the empty path our $VERSION = '1.08'; use Moo; extends 'Path::Dispatcher::Rule'; sub _match { my $self = shift; my $path = shift; return if length $path->path; return { leftover => $path->path }; } __PACKAGE__->meta->make_immutable; no Moo; 1; __END__ =pod =encoding UTF-8 =head1 NAME Path::Dispatcher::Rule::Empty - matches only the empty path =head1 VERSION version 1.08 =head1 DESCRIPTION Rules of this class match only the empty path. =head1 SUPPORT Bugs may be submitted through L (or L). =head1 AUTHOR Shawn M Moore, C<< >> =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2020 by Shawn M Moore. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Regex.pm100640000766000024 427713702474074 22164 0ustar00etherstaff000000000000Path-Dispatcher-1.08/lib/Path/Dispatcher/Rulepackage Path::Dispatcher::Rule::Regex; # ABSTRACT: predicate is a regular expression our $VERSION = '1.08'; use Moo; use MooX::TypeTiny; use Types::Standard qw(RegexpRef); extends 'Path::Dispatcher::Rule'; has regex => ( is => 'ro', isa => RegexpRef, required => 1, ); my $named_captures = $] > 5.010 ? eval 'sub { %+ }' : sub { }; sub _match { my $self = shift; my $path = shift; # davem++ http://www.nntp.perl.org/group/perl.perl5.porters/2013/03/msg200156.html if ($self->prefix) { eval q{$'}; } return unless my @positional = $path->path =~ $self->regex; my %named = $named_captures->(); my %extra; # only provide leftover if we need it. $' is slow, and it may be undef if ($self->prefix) { $extra{leftover} = eval q{$'}; delete $extra{leftover} if !defined($extra{leftover}); } return { positional_captures => \@positional, named_captures => \%named, %extra, } } __PACKAGE__->meta->make_immutable; no Moo; 1; __END__ =pod =encoding UTF-8 =head1 NAME Path::Dispatcher::Rule::Regex - predicate is a regular expression =head1 VERSION version 1.08 =head1 SYNOPSIS my $rule = Path::Dispatcher::Rule::Regex->new( regex => qr{^/comment(s?)/(\d+)$}, block => sub { display_comment(shift->pos(2)) }, ); =head1 DESCRIPTION Rules of this class use a regular expression to match against the path. =head1 ATTRIBUTES =head2 regex The regular expression to match against the path. It works just as you'd expect! The capture variables (C<$1>, C<$2>, etc) will be available in the match object as C<< ->pos(1) >> etc. C<$`>, C<$&>, and C<$'> are not restored. =head1 SUPPORT Bugs may be submitted through L (or L). =head1 AUTHOR Shawn M Moore, C<< >> =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2020 by Shawn M Moore. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Under.pm100640000766000024 1007713702474074 22202 0ustar00etherstaff000000000000Path-Dispatcher-1.08/lib/Path/Dispatcher/Rulepackage Path::Dispatcher::Rule::Under; # ABSTRACT: rules under a predicate our $VERSION = '1.08'; use Moo; use MooX::TypeTiny; use Type::Tiny; use Type::Utils qw(class_type); extends 'Path::Dispatcher::Rule'; with 'Path::Dispatcher::Role::Rules'; my $PREFIX_RULE_TYPE = "Type::Tiny"->new( name => "PrefixRule", parent => class_type("Path::Dispatcher::Rule"), constraint => sub { return ( shift()->prefix ) ? 1 : 0 }, message => sub { "This rule ($_) does not match just prefixes!" }, ); has predicate => ( is => 'ro', isa => $PREFIX_RULE_TYPE ); sub match { my $self = shift; my $path = shift; my $prefix_match = $self->predicate->match($path) or return; my $leftover = $prefix_match->leftover; $leftover = '' if !defined($leftover); my $new_path = $path->clone_path($leftover); # Pop off @matches until we have a last rule that is not ::Chain # # A better technique than isa might be to use the concept of 'endpoint', 'midpoint', or 'anypoint' rules and # add a method to ::Rule that lets evaluate whether any rule is of the right kind (i.e. ->is_endpoint) # # Because the checking for ::Chain endpointedness is here, this means that outside of an ::Under, ::Chain behaves like # an ::Always (one that will always trigger next_rule if it's block is ran) # my @matches = map { $_->match( $new_path, extra_constructor_args => { parent => $prefix_match, }, ) } $self->rules; pop @matches while @matches && $matches[-1]->rule->isa('Path::Dispatcher::Rule::Chain'); return @matches; } sub complete { my $self = shift; my $path = shift; my $predicate = $self->predicate; my $prefix_match = $predicate->match($path) or return $predicate->complete($path); my $new_path = $path->clone_path($prefix_match->leftover); my $prefix = substr($path->path, 0, length($path->path) - length($new_path->path)); my @completions = map { $_->complete($new_path) } $self->rules; if ($predicate->can('untokenize')) { return map { $predicate->untokenize($prefix, $_) } @completions; } else { return map { "$prefix$_" } @completions; } } __PACKAGE__->meta->make_immutable; no Moo; 1; __END__ =pod =encoding UTF-8 =head1 NAME Path::Dispatcher::Rule::Under - rules under a predicate =head1 VERSION version 1.08 =head1 SYNOPSIS my $ticket = Path::Dispatcher::Rule::Tokens->new( tokens => [ 'ticket' ], prefix => 1, ); my $create = Path::Dispatcher::Rule::Tokens->new( tokens => [ 'create' ], block => sub { create_ticket() }, ); my $delete = Path::Dispatcher::Rule::Tokens->new( tokens => [ 'delete', qr/^\d+$/ ], block => sub { delete_ticket(shift->pos(2)) }, ); my $rule = Path::Dispatcher::Rule::Under->new( predicate => $ticket, rules => [ $create, $delete ], ); $rule->match("ticket create"); $rule->match("ticket delete 3"); =head1 DESCRIPTION Rules of this class have two-phase matching: if the predicate is matched, then the contained rules are matched. The benefit of this is less repetition of the predicate, both in terms of code and in matching it. =head1 ATTRIBUTES =head2 predicate A rule (which I match prefixes) whose match determines whether the contained rules are considered. The leftover path of the predicate is used as the path for the contained rules. =head2 rules A list of rules that will be try to be matched only if the predicate is matched. =head1 SUPPORT Bugs may be submitted through L (or L). =head1 AUTHOR Shawn M Moore, C<< >> =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2020 by Shawn M Moore. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Always.pm100640000766000024 204113702474074 22335 0ustar00etherstaff000000000000Path-Dispatcher-1.08/lib/Path/Dispatcher/Rulepackage Path::Dispatcher::Rule::Always; # ABSTRACT: always matches our $VERSION = '1.08'; use Moo; extends 'Path::Dispatcher::Rule'; sub _match { my $self = shift; my $path = shift; return { leftover => $path->path, }; } __PACKAGE__->meta->make_immutable; no Moo; 1; __END__ =pod =encoding UTF-8 =head1 NAME Path::Dispatcher::Rule::Always - always matches =head1 VERSION version 1.08 =head1 DESCRIPTION Rules of this class always match. If a prefix match is requested, the full path is returned as leftover. =head1 SUPPORT Bugs may be submitted through L (or L). =head1 AUTHOR Shawn M Moore, C<< >> =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2020 by Shawn M Moore. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Tokens.pm100640000766000024 1252413702474074 22367 0ustar00etherstaff000000000000Path-Dispatcher-1.08/lib/Path/Dispatcher/Rulepackage Path::Dispatcher::Rule::Tokens; # ABSTRACT: predicate is a list of tokens our $VERSION = '1.08'; use Moo; use MooX::TypeTiny; use Types::Standard qw(Str ArrayRef Bool); extends 'Path::Dispatcher::Rule'; has tokens => ( is => 'ro', isa => ArrayRef, required => 1, ); has delimiter => ( is => 'ro', isa => Str, default => ' ', ); has case_sensitive => ( is => 'ro', isa => Bool, default => 1, ); sub _match_as_far_as_possible { my $self = shift; my $path = shift; my @got = $self->tokenize($path->path); my @expected = @{ $self->tokens }; my @matched; while (@got && @expected) { my $expected = $expected[0]; my $got = $got[0]; last unless $self->_match_token($got, $expected); push @matched, $got; shift @expected; shift @got; } return (\@matched, \@got, \@expected); } sub _match { my $self = shift; my $path = shift; my ($matched, $got, $expected) = $self->_match_as_far_as_possible($path); return if @$expected; # didn't provide everything necessary return if @$got && !$self->prefix; # had tokens left over my $leftover = $self->untokenize(@$got); return if !$matched; return { positional_captures => $matched, leftover => $leftover, }; } sub complete { my $self = shift; my $path = shift; my ($matched, $got, $expected) = $self->_match_as_far_as_possible($path); return if @$got > 1; # had tokens leftover return if !@$expected; # consumed all tokens my $next = shift @$expected; my $part = @$got ? shift @$got : ''; my @completions; for my $completion (ref($next) eq 'ARRAY' ? @$next : $next) { next if ref($completion); next unless substr($completion, 0, length($part)) eq $part; push @completions, $self->untokenize(@$matched, $completion); } return @completions; } sub _each_token { my $self = shift; my $got = shift; my $expected = shift; my $callback = shift; if (ref($expected) eq 'ARRAY') { for my $alternative (@$expected) { $self->_each_token($got, $alternative, $callback); } } elsif (!ref($expected) || ref($expected) eq 'Regexp') { $callback->($got, $expected); } else { die "Unexpected token '$expected'"; # the irony is not lost on me :) } } sub _match_token { my $self = shift; my $got = shift; my $expected = shift; my $matched = 0; $self->_each_token($got, $expected, sub { my ($g, $e) = @_; if (!ref($e)) { ($g, $e) = (lc $g, lc $e) if !$self->case_sensitive; $matched ||= $g eq $e; } elsif (ref($e) eq 'Regexp') { $matched ||= $g =~ $e; } }); return $matched; } sub tokenize { my $self = shift; my $path = shift; return grep { length } split $self->delimiter, $path; } sub untokenize { my $self = shift; my @tokens = @_; return join $self->delimiter, grep { length } map { split $self->delimiter, $_ } @tokens; } __PACKAGE__->meta->make_immutable; no Moo; 1; __END__ =pod =encoding UTF-8 =head1 NAME Path::Dispatcher::Rule::Tokens - predicate is a list of tokens =head1 VERSION version 1.08 =head1 SYNOPSIS my $rule = Path::Dispatcher::Rule::Tokens->new( tokens => [ "comment", "show", qr/^\d+$/ ], delimiter => '/', block => sub { display_comment(shift->pos(3)) }, ); $rule->match("/comment/show/25"); =head1 DESCRIPTION Rules of this class use a list of tokens to match the path. =head1 ATTRIBUTES =head2 tokens Each token can be a literal string, a regular expression, or a list of either (which are taken to mean alternations). For example, the tokens: [ 'ticket', [ 'show', 'display' ], [ qr/^\d+$/, qr/^#\w{3}/ ] ] first matches "ticket". Then, the next token must be "show" or "display". The final token must be a number or a pound sign followed by three word characters. The results are the tokens in the original string, as they were matched. If you have three tokens, then C<< match->pos(1) >> will be the string's first token ("ticket"), C<< match->pos(2) >> its second ("display"), and C<< match->pos(3) >> its third ("#AAA"). Capture groups inside a regex token are completely ignored. =head2 delimiter A string that is used to tokenize the path. The delimiter must be a string because prefix matches use C on unmatched tokens to return the leftover path. In the future this may be extended to support having a regex delimiter. The default is a space, but if you're matching URLs you probably want to change this to a slash. =head2 case_sensitive Decide whether the rule matching is case sensitive. Default is 1, case sensitive matching. =head1 SUPPORT Bugs may be submitted through L (or L). =head1 AUTHOR Shawn M Moore, C<< >> =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2020 by Shawn M Moore. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut CodeRef.pm100640000766000024 364413702474074 22416 0ustar00etherstaff000000000000Path-Dispatcher-1.08/lib/Path/Dispatcher/Rulepackage Path::Dispatcher::Rule::CodeRef; # ABSTRACT: predicate is any subroutine our $VERSION = '1.08'; use Moo; use MooX::TypeTiny; use Types::Standard qw(CodeRef); extends 'Path::Dispatcher::Rule'; has matcher => ( is => 'ro', isa => CodeRef, required => 1, ); sub _match { my $self = shift; my $path = shift; local $_ = $path; return $self->matcher->($path); } __PACKAGE__->meta->make_immutable; no Moo; 1; __END__ =pod =encoding UTF-8 =head1 NAME Path::Dispatcher::Rule::CodeRef - predicate is any subroutine =head1 VERSION version 1.08 =head1 SYNOPSIS my $rule = Path::Dispatcher::Rule::CodeRef->new( matcher => sub { time % 2 }, block => sub { warn "Odd time!" }, ); my $undef = $rule->match("foo"); # even time; no match :) my $match = $rule->match("foo"); # odd time; creates a Path::Dispatcher::Match $rule->run; # warns "Odd time!" =head1 DESCRIPTION Rules of this class can match arbitrarily complex values. This should be used only when there is no other recourse, because there's no way we can inspect how things match. You're much better off creating a custom subclass of L if at all possible. =head1 ATTRIBUTES =head2 matcher A coderef that returns C if there's no match, otherwise a list of strings (the results). The coderef receives the path object as its argument, and the path string as C<$_>. =head1 SUPPORT Bugs may be submitted through L (or L). =head1 AUTHOR Shawn M Moore, C<< >> =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2020 by Shawn M Moore. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Dispatch.pm100640000766000024 352613702474074 22645 0ustar00etherstaff000000000000Path-Dispatcher-1.08/lib/Path/Dispatcher/Rulepackage Path::Dispatcher::Rule::Dispatch; # ABSTRACT: redispatch our $VERSION = '1.08'; use Moo; use MooX::TypeTiny; use Type::Utils qw(class_type); extends 'Path::Dispatcher::Rule'; has dispatcher => ( is => 'ro', isa => class_type("Path::Dispatcher"), required => 1, handles => ['rules', 'complete'], ); sub match { my $self = shift; my $path = shift; my $dispatch = $self->dispatcher->dispatch($path); return $dispatch->matches; } __PACKAGE__->meta->make_immutable; no Moo; 1; __END__ =pod =encoding UTF-8 =head1 NAME Path::Dispatcher::Rule::Dispatch - redispatch =head1 VERSION version 1.08 =head1 SYNOPSIS my $dispatcher = Path::Dispatcher->new( rules => [ Path::Dispatcher::Rule::Tokens->new( tokens => [ 'help' ], block => sub { show_help }, ), Path::Dispatcher::Rule::Tokens->new( tokens => [ 'quit' ], block => sub { exit }, ), ], ); my $rule = Path::Dispatcher::Rule::Dispatch->new( dispatcher => $dispatcher, ); $rule->run("help"); =head1 DESCRIPTION Rules of this class use another dispatcher to match the path. =head1 ATTRIBUTES =head2 dispatcher A L object. Its matches will be returned by matching this rule. =head1 SUPPORT Bugs may be submitted through L (or L). =head1 AUTHOR Shawn M Moore, C<< >> =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2020 by Shawn M Moore. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Metadata.pm100640000766000024 374013702474074 22624 0ustar00etherstaff000000000000Path-Dispatcher-1.08/lib/Path/Dispatcher/Rulepackage Path::Dispatcher::Rule::Metadata; # ABSTRACT: match path's metadata our $VERSION = '1.08'; use Moo; use MooX::TypeTiny; use Type::Utils qw(class_type); use Types::Standard qw(Str); extends 'Path::Dispatcher::Rule'; has field => ( is => 'ro', isa => Str, required => 1, ); has matcher => ( is => 'ro', isa => class_type("Path::Dispatcher::Rule"), required => 1, ); sub _match { my $self = shift; my $path = shift; my $got = $path->get_metadata($self->field); # wow, offensive.. but powerful my $metadata_path = $path->clone_path($got); return unless $self->matcher->match($metadata_path); return { leftover => $path->path, }; } __PACKAGE__->meta->make_immutable; no Moo; 1; __END__ =pod =encoding UTF-8 =head1 NAME Path::Dispatcher::Rule::Metadata - match path's metadata =head1 VERSION version 1.08 =head1 SYNOPSIS my $path = Path::Dispatcher::Path->new( path => '/REST/Ticket' metadata => { http_method => 'POST', }, ); my $rule = Path::Dispatcher::Rule::Metadata->new( field => 'http_method', matcher => Path::Dispatcher::Rule::Eq->new(string => 'POST'), ); $rule->run($path); =head1 DESCRIPTION Rules of this class match the metadata portion of a path. =head1 ATTRIBUTES =head2 field The metadata field/key name. =head2 matcher A L object for matching against the value of the field. =head1 SUPPORT Bugs may be submitted through L (or L). =head1 AUTHOR Shawn M Moore, C<< >> =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2020 by Shawn M Moore. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Sequence.pm100640000766000024 553713702474074 22662 0ustar00etherstaff000000000000Path-Dispatcher-1.08/lib/Path/Dispatcher/Rulepackage Path::Dispatcher::Rule::Sequence; # ABSTRACT: a sequence of rules our $VERSION = '1.08'; use Moo; use MooX::TypeTiny; use Types::Standard qw(Str); extends 'Path::Dispatcher::Rule'; with 'Path::Dispatcher::Role::Rules'; has delimiter => ( is => 'ro', isa => Str, default => ' ', ); sub _match_as_far_as_possible { my $self = shift; my $path = shift; my @tokens = $self->tokenize($path->path); my @rules = $self->rules; my @matched; while (@tokens && @rules) { my $rule = $rules[0]; my $token = $tokens[0]; last unless $rule->match($path->clone_path($token)); push @matched, $token; shift @rules; shift @tokens; } return (\@matched, \@tokens, \@rules); } sub _match { my $self = shift; my $path = shift; my ($matched, $tokens, $rules) = $self->_match_as_far_as_possible($path); return if @$rules; # didn't provide everything necessary return if @$tokens && !$self->prefix; # had tokens left over my $leftover = $self->untokenize(@$tokens); return { leftover => $leftover, positional_captures => $matched, }; } sub complete { my $self = shift; my $path = shift; my ($matched, $tokens, $rules) = $self->_match_as_far_as_possible($path); return if @$tokens > 1; # had tokens leftover return if !@$rules; # consumed all rules my $rule = shift @$rules; my $token = @$tokens ? shift @$tokens : ''; return map { $self->untokenize(@$matched, $_) } $rule->complete($path->clone_path($token)); } sub tokenize { my $self = shift; my $path = shift; return grep { length } split $self->delimiter, $path; } sub untokenize { my $self = shift; my @tokens = @_; return join $self->delimiter, grep { length } map { split $self->delimiter, $_ } @tokens; } __PACKAGE__->meta->make_immutable; no Moo; 1; __END__ =pod =encoding UTF-8 =head1 NAME Path::Dispatcher::Rule::Sequence - a sequence of rules =head1 VERSION version 1.08 =head1 SYNOPSIS =head1 DESCRIPTION This is basically a more robust and flexible version of L. Instead of a mish-mash of strings, regexes, and array references, a Sequence rule has just a list of other rules. =head1 ATTRIBUTES =head2 rules =head2 delimiter =head1 SUPPORT Bugs may be submitted through L (or L). =head1 AUTHOR Shawn M Moore, C<< >> =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2020 by Shawn M Moore. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Alternation.pm100640000766000024 233513702474074 23363 0ustar00etherstaff000000000000Path-Dispatcher-1.08/lib/Path/Dispatcher/Rulepackage Path::Dispatcher::Rule::Alternation; # ABSTRACT: any rule must match our $VERSION = '1.08'; use Moo; extends 'Path::Dispatcher::Rule'; with 'Path::Dispatcher::Role::Rules'; sub _match { my $self = shift; my $path = shift; my @rules = $self->rules; return if @rules == 0; for my $rule (@rules) { return {} if $rule->match($path); } return; } sub complete { my $self = shift; return map { $_->complete(@_) } $self->rules; } __PACKAGE__->meta->make_immutable; no Moo; 1; __END__ =pod =encoding UTF-8 =head1 NAME Path::Dispatcher::Rule::Alternation - any rule must match =head1 VERSION version 1.08 =head1 SYNOPSIS =head1 DESCRIPTION =head1 ATTRIBUTES =head2 rules =head1 SUPPORT Bugs may be submitted through L (or L). =head1 AUTHOR Shawn M Moore, C<< >> =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2020 by Shawn M Moore. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Intersection.pm100640000766000024 221213702474074 23543 0ustar00etherstaff000000000000Path-Dispatcher-1.08/lib/Path/Dispatcher/Rulepackage Path::Dispatcher::Rule::Intersection; # ABSTRACT: all rules must match our $VERSION = '1.08'; use Moo; extends 'Path::Dispatcher::Rule'; with 'Path::Dispatcher::Role::Rules'; sub _match { my $self = shift; my $path = shift; my @rules = $self->rules; return if @rules == 0; for my $rule (@rules) { return unless $rule->match($path); } return {}; } __PACKAGE__->meta->make_immutable; no Moo; 1; __END__ =pod =encoding UTF-8 =head1 NAME Path::Dispatcher::Rule::Intersection - all rules must match =head1 VERSION version 1.08 =head1 SYNOPSIS =head1 DESCRIPTION =head1 ATTRIBUTES =head2 rules =head1 SUPPORT Bugs may be submitted through L (or L). =head1 AUTHOR Shawn M Moore, C<< >> =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2020 by Shawn M Moore. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut