diff options
author | Lorry Tar Creator <lorry-tar-importer@lorry> | 2014-08-24 16:36:19 +0000 |
---|---|---|
committer | Lorry Tar Creator <lorry-tar-importer@lorry> | 2014-08-24 16:36:19 +0000 |
commit | b808141b894ad538db75a7067e0199cbfe6337a9 (patch) | |
tree | b3560724f86d6383c5ded5a79749c3f69592eb51 | |
download | Module-Implementation-tarball-b808141b894ad538db75a7067e0199cbfe6337a9.tar.gz |
Module-Implementation-0.09HEADModule-Implementation-0.09master
35 files changed, 2832 insertions, 0 deletions
@@ -0,0 +1,54 @@ +0.09 2014-08-24 + +- Backed out the Sub::Name change in 0.08. It was pointed out to me by Graham + Knop that adding an XS dependency for a module that's often used to pick + between XS and non-XS implementations doesn't work so well. + + +0.08 2014-08-24 + +- Subroutines copied from an implementation package into the loading package + are now renamed using Sub::Name. This causes them to be considered part of + the loading package, which is important for things like + namespace::autoclean. Reported by Karen Etheridge. RT #98097. + + +0.07 2013-07-14 + +- Require Test::Fatal 0.006+ to avoid test failures. Reported by Salve + Nilsen. RT #76809. + + +0.06 2012-02-12 + +- Require Module::Runtime 0.012, which has a number of useful bug fixes. + + +0.05 2012-02-09 + +- Make Test::Taint an optional dependency. This module requires XS, and + requiring a compiler for Module::Implementation defeats its + purpose. Reported by Peter Rabbitson. RT #74817. + + +0.04 2012-02-08 + +- This module no longer installs an _implementation() subroutine in + callers. Instead, you can call + Module::Implementation::implementation_for($package) to get the + implementation used for a given package. + + +0.03 2012-02-06 + +- The generated loader sub now returns the name of the package it loaded. + + +0.02 2012-02-06 + +- Removed Test::Spelling from this module's prereqs. + + +0.01 2012-02-06 + +- First release upon an unsuspecting world. @@ -0,0 +1,44 @@ + +This is the Perl distribution Module-Implementation. + +Installing Module-Implementation is straightforward. + +## Installation with cpanm + +If you have cpanm, you only need one line: + + % cpanm Module::Implementation + +If you are installing into a system-wide directory, you may need to pass the +"-S" flag to cpanm, which uses sudo to install the module: + + % cpanm -S Module::Implementation + +## Installing with the CPAN shell + +Alternatively, if your CPAN shell is set up, you should just be able to do: + + % cpan Module::Implementation + +## Manual installation + +As a last resort, you can manually install it. Download the tarball, untar it, +then build it: + + % perl Makefile.PL + % make && make test + +Then install it: + + % make install + +If you are installing into a system-wide directory, you may need to run: + + % sudo make install + +## Documentation + +Module-Implementation documentation is available as POD. +You can run perldoc from a shell to read the documentation: + + % perldoc Module::Implementation @@ -0,0 +1,207 @@ +This software is Copyright (c) 2014 by Dave Rolsky. + +This is free software, licensed under: + + The Artistic License 2.0 (GPL Compatible) + + The Artistic License 2.0 + + Copyright (c) 2000-2006, The Perl Foundation. + + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +Preamble + +This license establishes the terms under which a given free software +Package may be copied, modified, distributed, and/or redistributed. +The intent is that the Copyright Holder maintains some artistic +control over the development of that Package while still keeping the +Package available as open source and free software. + +You are always permitted to make arrangements wholly outside of this +license directly with the Copyright Holder of a given Package. If the +terms of this license do not permit the full use that you propose to +make of the Package, you should contact the Copyright Holder and seek +a different licensing arrangement. + +Definitions + + "Copyright Holder" means the individual(s) or organization(s) + named in the copyright notice for the entire Package. + + "Contributor" means any party that has contributed code or other + material to the Package, in accordance with the Copyright Holder's + procedures. + + "You" and "your" means any person who would like to copy, + distribute, or modify the Package. + + "Package" means the collection of files distributed by the + Copyright Holder, and derivatives of that collection and/or of + those files. A given Package may consist of either the Standard + Version, or a Modified Version. + + "Distribute" means providing a copy of the Package or making it + accessible to anyone else, or in the case of a company or + organization, to others outside of your company or organization. + + "Distributor Fee" means any fee that you charge for Distributing + this Package or providing support for this Package to another + party. It does not mean licensing fees. + + "Standard Version" refers to the Package if it has not been + modified, or has been modified only in ways explicitly requested + by the Copyright Holder. + + "Modified Version" means the Package, if it has been changed, and + such changes were not explicitly requested by the Copyright + Holder. + + "Original License" means this Artistic License as Distributed with + the Standard Version of the Package, in its current version or as + it may be modified by The Perl Foundation in the future. + + "Source" form means the source code, documentation source, and + configuration files for the Package. + + "Compiled" form means the compiled bytecode, object code, binary, + or any other form resulting from mechanical transformation or + translation of the Source form. + + +Permission for Use and Modification Without Distribution + +(1) You are permitted to use the Standard Version and create and use +Modified Versions for any purpose without restriction, provided that +you do not Distribute the Modified Version. + + +Permissions for Redistribution of the Standard Version + +(2) You may Distribute verbatim copies of the Source form of the +Standard Version of this Package in any medium without restriction, +either gratis or for a Distributor Fee, provided that you duplicate +all of the original copyright notices and associated disclaimers. At +your discretion, such verbatim copies may or may not include a +Compiled form of the Package. + +(3) You may apply any bug fixes, portability changes, and other +modifications made available from the Copyright Holder. The resulting +Package will still be considered the Standard Version, and as such +will be subject to the Original License. + + +Distribution of Modified Versions of the Package as Source + +(4) You may Distribute your Modified Version as Source (either gratis +or for a Distributor Fee, and with or without a Compiled form of the +Modified Version) provided that you clearly document how it differs +from the Standard Version, including, but not limited to, documenting +any non-standard features, executables, or modules, and provided that +you do at least ONE of the following: + + (a) make the Modified Version available to the Copyright Holder + of the Standard Version, under the Original License, so that the + Copyright Holder may include your modifications in the Standard + Version. + + (b) ensure that installation of your Modified Version does not + prevent the user installing or running the Standard Version. In + addition, the Modified Version must bear a name that is different + from the name of the Standard Version. + + (c) allow anyone who receives a copy of the Modified Version to + make the Source form of the Modified Version available to others + under + + (i) the Original License or + + (ii) a license that permits the licensee to freely copy, + modify and redistribute the Modified Version using the same + licensing terms that apply to the copy that the licensee + received, and requires that the Source form of the Modified + Version, and of any works derived from it, be made freely + available in that license fees are prohibited but Distributor + Fees are allowed. + + +Distribution of Compiled Forms of the Standard Version +or Modified Versions without the Source + +(5) You may Distribute Compiled forms of the Standard Version without +the Source, provided that you include complete instructions on how to +get the Source of the Standard Version. Such instructions must be +valid at the time of your distribution. If these instructions, at any +time while you are carrying out such distribution, become invalid, you +must provide new instructions on demand or cease further distribution. +If you provide valid instructions or cease distribution within thirty +days after you become aware that the instructions are invalid, then +you do not forfeit any of your rights under this license. + +(6) You may Distribute a Modified Version in Compiled form without +the Source, provided that you comply with Section 4 with respect to +the Source of the Modified Version. + + +Aggregating or Linking the Package + +(7) You may aggregate the Package (either the Standard Version or +Modified Version) with other packages and Distribute the resulting +aggregation provided that you do not charge a licensing fee for the +Package. Distributor Fees are permitted, and licensing fees for other +components in the aggregation are permitted. The terms of this license +apply to the use and Distribution of the Standard or Modified Versions +as included in the aggregation. + +(8) You are permitted to link Modified and Standard Versions with +other works, to embed the Package in a larger work of your own, or to +build stand-alone binary or bytecode versions of applications that +include the Package, and Distribute the result without restriction, +provided the result does not expose a direct interface to the Package. + + +Items That are Not Considered Part of a Modified Version + +(9) Works (including, but not limited to, modules and scripts) that +merely extend or make use of the Package, do not, by themselves, cause +the Package to be a Modified Version. In addition, such works are not +considered parts of the Package itself, and are not subject to the +terms of this license. + + +General Provisions + +(10) Any use, modification, and distribution of the Standard or +Modified Versions is governed by this Artistic License. By using, +modifying or distributing the Package, you accept this license. Do not +use, modify, or distribute the Package, if you do not accept this +license. + +(11) If your Modified Version has been derived from a Modified +Version made by someone other than you, you are nevertheless required +to ensure that your Modified Version complies with the requirements of +this license. + +(12) This license does not grant you the right to use any trademark, +service mark, tradename, or logo of the Copyright Holder. + +(13) This license includes the non-exclusive, worldwide, +free-of-charge patent license to make, have made, use, offer to sell, +sell, import and otherwise transfer the Package with respect to any +patent claims licensable by the Copyright Holder that are necessarily +infringed by the Package. If you institute patent litigation +(including a cross-claim or counterclaim) against any party alleging +that the Package constitutes direct or contributory patent +infringement, then this Artistic License to you shall terminate on the +date that such litigation is filed. + +(14) Disclaimer of Warranty: +THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "AS +IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES. THE IMPLIED +WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR +NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY YOUR LOCAL +LAW. UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR CONTRIBUTOR WILL +BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THE PACKAGE, EVEN IF +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/MANIFEST b/MANIFEST new file mode 100644 index 0000000..0a99b1a --- /dev/null +++ b/MANIFEST @@ -0,0 +1,36 @@ +# This file was automatically generated by Dist::Zilla::Plugin::Manifest v5.020. +Changes +INSTALL +LICENSE +MANIFEST +META.json +META.yml +Makefile.PL +README.md +dist.ini +lib/Module/Implementation.pm +t/00-compile.t +t/00-report-prereqs.dd +t/00-report-prereqs.t +t/author-no-tabs.t +t/author-pod-spell.t +t/basic.t +t/both-fail.t +t/env-value.t +t/lib/T/Impl1.pm +t/lib/T/Impl2.pm +t/lib/T/ImplFails1.pm +t/lib/T/ImplFails2.pm +t/more-symbols.t +t/namespace-cleanliness.t +t/one-impl-fails1.t +t/one-impl-fails2.t +t/release-cpan-changes.t +t/release-eol.t +t/release-pod-coverage.t +t/release-pod-linkcheck.t +t/release-pod-no404s.t +t/release-pod-syntax.t +t/release-portability.t +t/requested-fails.t +t/taint.t diff --git a/META.json b/META.json new file mode 100644 index 0000000..f87c0f9 --- /dev/null +++ b/META.json @@ -0,0 +1,621 @@ +{ + "abstract" : "Loads one of several alternate underlying implementations for a module", + "author" : [ + "Dave Rolsky <autarch@urth.org>" + ], + "dynamic_config" : 0, + "generated_by" : "Dist::Zilla version 5.020, CPAN::Meta::Converter version 2.142060", + "license" : [ + "artistic_2" + ], + "meta-spec" : { + "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec", + "version" : "2" + }, + "name" : "Module-Implementation", + "prereqs" : { + "configure" : { + "requires" : { + "ExtUtils::MakeMaker" : "0" + } + }, + "develop" : { + "requires" : { + "Pod::Coverage::TrustPod" : "0", + "Test::CPAN::Changes" : "0.19", + "Test::More" : "0.88", + "Test::NoTabs" : "0", + "Test::Pod" : "1.41", + "Test::Pod::Coverage" : "1.08", + "Test::Spelling" : "0.12" + } + }, + "runtime" : { + "requires" : { + "Carp" : "0", + "Module::Runtime" : "0.012", + "Try::Tiny" : "0", + "strict" : "0", + "warnings" : "0" + } + }, + "test" : { + "recommends" : { + "CPAN::Meta" : "2.120900" + }, + "requires" : { + "ExtUtils::MakeMaker" : "0", + "File::Spec" : "0", + "IO::Handle" : "0", + "IPC::Open3" : "0", + "Test::Fatal" : "0.006", + "Test::More" : "0.88", + "Test::Requires" : "0", + "lib" : "0", + "perl" : "5.006" + } + } + }, + "provides" : { + "Module::Implementation" : { + "file" : "lib/Module/Implementation.pm", + "version" : "0.09" + } + }, + "release_status" : "stable", + "resources" : { + "bugtracker" : { + "mailto" : "bug-module-implementation@rt.cpan.org", + "web" : "http://rt.cpan.org/Public/Dist/Display.html?Name=Module-Implementation" + }, + "homepage" : "http://metacpan.org/release/Module-Implementation", + "repository" : { + "type" : "git", + "url" : "git://github.com/autarch/Module-Implementation.git", + "web" : "https://github.com/autarch/Module-Implementation" + } + }, + "version" : "0.09", + "x_Dist_Zilla" : { + "perl" : { + "version" : "5.016003" + }, + "plugins" : [ + { + "class" : "Dist::Zilla::Plugin::MakeMaker", + "config" : { + "Dist::Zilla::Role::TestRunner" : { + "default_jobs" : 1 + } + }, + "name" : "@DROLSKY/MakeMaker", + "version" : "5.020" + }, + { + "class" : "Dist::Zilla::Plugin::Authority", + "name" : "@DROLSKY/Authority", + "version" : "1.006" + }, + { + "class" : "Dist::Zilla::Plugin::AutoPrereqs", + "name" : "@DROLSKY/AutoPrereqs", + "version" : "5.020" + }, + { + "class" : "Dist::Zilla::Plugin::GatherDir", + "name" : "@DROLSKY/GatherDir", + "version" : "5.020" + }, + { + "class" : "Dist::Zilla::Plugin::GitHub::Meta", + "name" : "@DROLSKY/GitHub::Meta", + "version" : "0.38" + }, + { + "class" : "Dist::Zilla::Plugin::GitHub::Update", + "name" : "@DROLSKY/GitHub::Update", + "version" : "0.38" + }, + { + "class" : "Dist::Zilla::Plugin::MetaResources", + "name" : "@DROLSKY/MetaResources", + "version" : "5.020" + }, + { + "class" : "Dist::Zilla::Plugin::MetaProvides::Package", + "config" : { + "Dist::Zilla::Plugin::MetaProvides::Package" : { + "finder_objects" : [ + { + "class" : "Dist::Zilla::Plugin::FinderCode", + "name" : "@DROLSKY/MetaProvides::Package/AUTOVIV/:InstallModulesPM", + "version" : "5.020" + } + ] + }, + "Dist::Zilla::Role::MetaProvider::Provider" : { + "inherit_missing" : "1", + "inherit_version" : "1", + "meta_noindex" : "1" + } + }, + "name" : "@DROLSKY/MetaProvides::Package", + "version" : "2.000004" + }, + { + "class" : "Dist::Zilla::Plugin::NextRelease", + "name" : "@DROLSKY/NextRelease", + "version" : "5.020" + }, + { + "class" : "Dist::Zilla::Plugin::Test::Pod::Coverage::Configurable", + "name" : "@DROLSKY/Test::Pod::Coverage::Configurable", + "version" : "0.01" + }, + { + "class" : "Dist::Zilla::Plugin::Test::PodSpelling", + "name" : "@DROLSKY/Test::PodSpelling", + "version" : "2.006008" + }, + { + "class" : "Dist::Zilla::Plugin::Test::ReportPrereqs", + "name" : "@DROLSKY/Test::ReportPrereqs", + "version" : "0.019" + }, + { + "class" : "Dist::Zilla::Plugin::Prereqs", + "config" : { + "Dist::Zilla::Plugin::Prereqs" : { + "phase" : "test", + "type" : "requires" + } + }, + "name" : "@DROLSKY/TestMoreDoneTesting", + "version" : "5.020" + }, + { + "class" : "Dist::Zilla::Plugin::PromptIfStale", + "config" : { + "Dist::Zilla::Plugin::PromptIfStale" : { + "check_all_plugins" : "1", + "check_all_prereqs" : "1", + "modules" : [], + "phase" : "release", + "skip" : [] + } + }, + "name" : "@DROLSKY/stale modules, release", + "version" : "0.024" + }, + { + "class" : "Dist::Zilla::Plugin::ReadmeAnyFromPod", + "name" : "@DROLSKY/ReadmeMarkdownInBuild", + "version" : "0.142250" + }, + { + "class" : "Dist::Zilla::Plugin::ReadmeAnyFromPod", + "name" : "@DROLSKY/ReadmeMarkdownInRoot", + "version" : "0.142250" + }, + { + "class" : "Dist::Zilla::Plugin::PruneCruft", + "name" : "@DROLSKY/PruneCruft", + "version" : "5.020" + }, + { + "class" : "Dist::Zilla::Plugin::ManifestSkip", + "name" : "@DROLSKY/ManifestSkip", + "version" : "5.020" + }, + { + "class" : "Dist::Zilla::Plugin::MetaYAML", + "name" : "@DROLSKY/MetaYAML", + "version" : "5.020" + }, + { + "class" : "Dist::Zilla::Plugin::License", + "name" : "@DROLSKY/License", + "version" : "5.020" + }, + { + "class" : "Dist::Zilla::Plugin::ExtraTests", + "name" : "@DROLSKY/ExtraTests", + "version" : "5.020" + }, + { + "class" : "Dist::Zilla::Plugin::ExecDir", + "name" : "@DROLSKY/ExecDir", + "version" : "5.020" + }, + { + "class" : "Dist::Zilla::Plugin::ShareDir", + "name" : "@DROLSKY/ShareDir", + "version" : "5.020" + }, + { + "class" : "Dist::Zilla::Plugin::Manifest", + "name" : "@DROLSKY/Manifest", + "version" : "5.020" + }, + { + "class" : "Dist::Zilla::Plugin::TestRelease", + "name" : "@DROLSKY/TestRelease", + "version" : "5.020" + }, + { + "class" : "Dist::Zilla::Plugin::ConfirmRelease", + "name" : "@DROLSKY/ConfirmRelease", + "version" : "5.020" + }, + { + "class" : "Dist::Zilla::Plugin::UploadToCPAN", + "name" : "@DROLSKY/UploadToCPAN", + "version" : "5.020" + }, + { + "class" : "Dist::Zilla::Plugin::CheckPrereqsIndexed", + "name" : "@DROLSKY/CheckPrereqsIndexed", + "version" : "0.012" + }, + { + "class" : "Dist::Zilla::Plugin::ContributorsFromGit", + "name" : "@DROLSKY/ContributorsFromGit", + "version" : "0.014" + }, + { + "class" : "Dist::Zilla::Plugin::CopyReadmeFromBuild", + "name" : "@DROLSKY/CopyReadmeFromBuild", + "version" : "0.0019" + }, + { + "class" : "Dist::Zilla::Plugin::Git::CheckFor::CorrectBranch", + "config" : { + "Dist::Zilla::Role::Git::Repo" : { + "repo_root" : "." + } + }, + "name" : "@DROLSKY/Git::CheckFor::CorrectBranch", + "version" : "0.011" + }, + { + "class" : "Dist::Zilla::Plugin::Git::CheckFor::MergeConflicts", + "config" : { + "Dist::Zilla::Role::Git::Repo" : { + "repo_root" : "." + } + }, + "name" : "@DROLSKY/Git::CheckFor::MergeConflicts", + "version" : "0.011" + }, + { + "class" : "Dist::Zilla::Plugin::Git::Describe", + "name" : "@DROLSKY/Git::Describe", + "version" : "0.003" + }, + { + "class" : "Dist::Zilla::Plugin::InstallGuide", + "name" : "@DROLSKY/InstallGuide", + "version" : "1.200003" + }, + { + "class" : "Dist::Zilla::Plugin::Meta::Contributors", + "name" : "@DROLSKY/Meta::Contributors", + "version" : "0.001" + }, + { + "class" : "Dist::Zilla::Plugin::MetaConfig", + "name" : "@DROLSKY/MetaConfig", + "version" : "5.020" + }, + { + "class" : "Dist::Zilla::Plugin::MetaJSON", + "name" : "@DROLSKY/MetaJSON", + "version" : "5.020" + }, + { + "class" : "Dist::Zilla::Plugin::PkgVersion", + "name" : "@DROLSKY/PkgVersion", + "version" : "5.020" + }, + { + "class" : "Dist::Zilla::Plugin::SurgicalPodWeaver", + "config" : { + "Dist::Zilla::Plugin::PodWeaver" : { + "finder" : [ + ":InstallModules", + ":ExecFiles" + ], + "plugins" : [ + { + "class" : "Pod::Weaver::Plugin::EnsurePod5", + "name" : "@CorePrep/EnsurePod5", + "version" : "4.006" + }, + { + "class" : "Pod::Weaver::Plugin::H1Nester", + "name" : "@CorePrep/H1Nester", + "version" : "4.006" + }, + { + "class" : "Pod::Weaver::Plugin::SingleEncoding", + "name" : "@Default/SingleEncoding", + "version" : "4.006" + }, + { + "class" : "Pod::Weaver::Section::Name", + "name" : "@Default/Name", + "version" : "4.006" + }, + { + "class" : "Pod::Weaver::Section::Version", + "name" : "@Default/Version", + "version" : "4.006" + }, + { + "class" : "Pod::Weaver::Section::Region", + "name" : "@Default/prelude", + "version" : "4.006" + }, + { + "class" : "Pod::Weaver::Section::Generic", + "name" : "SYNOPSIS", + "version" : "4.006" + }, + { + "class" : "Pod::Weaver::Section::Generic", + "name" : "DESCRIPTION", + "version" : "4.006" + }, + { + "class" : "Pod::Weaver::Section::Generic", + "name" : "OVERVIEW", + "version" : "4.006" + }, + { + "class" : "Pod::Weaver::Section::Collect", + "name" : "ATTRIBUTES", + "version" : "4.006" + }, + { + "class" : "Pod::Weaver::Section::Collect", + "name" : "METHODS", + "version" : "4.006" + }, + { + "class" : "Pod::Weaver::Section::Collect", + "name" : "FUNCTIONS", + "version" : "4.006" + }, + { + "class" : "Pod::Weaver::Section::Leftovers", + "name" : "@Default/Leftovers", + "version" : "4.006" + }, + { + "class" : "Pod::Weaver::Section::Region", + "name" : "@Default/postlude", + "version" : "4.006" + }, + { + "class" : "Pod::Weaver::Section::Authors", + "name" : "@Default/Authors", + "version" : "4.006" + }, + { + "class" : "Pod::Weaver::Section::Legal", + "name" : "@Default/Legal", + "version" : "4.006" + } + ] + } + }, + "name" : "@DROLSKY/SurgicalPodWeaver", + "version" : "0.0021" + }, + { + "class" : "Dist::Zilla::Plugin::EOLTests", + "name" : "@DROLSKY/EOLTests", + "version" : "0.02" + }, + { + "class" : "Dist::Zilla::Plugin::PodSyntaxTests", + "name" : "@DROLSKY/PodSyntaxTests", + "version" : "5.020" + }, + { + "class" : "Dist::Zilla::Plugin::Test::CPAN::Changes", + "name" : "@DROLSKY/Test::CPAN::Changes", + "version" : "0.008" + }, + { + "class" : "Dist::Zilla::Plugin::Test::Compile", + "config" : { + "Dist::Zilla::Plugin::Test::Compile" : { + "bail_out_on_fail" : "0", + "fail_on_warning" : "author", + "fake_home" : "0", + "filename" : "t/00-compile.t", + "module_finder" : [ + ":InstallModules" + ], + "needs_display" : "0", + "phase" : "test", + "script_finder" : [ + ":ExecFiles" + ], + "skips" : [] + } + }, + "name" : "@DROLSKY/Test::Compile", + "version" : "2.046" + }, + { + "class" : "Dist::Zilla::Plugin::Test::NoTabs", + "config" : { + "Dist::Zilla::Plugin::Test::NoTabs" : { + "filename" : "xt/author/no-tabs.t", + "finder" : [ + ":InstallModules", + ":ExecFiles", + ":TestFiles" + ] + } + }, + "name" : "@DROLSKY/Test::NoTabs", + "version" : "0.09" + }, + { + "class" : "Dist::Zilla::Plugin::Test::Pod::LinkCheck", + "name" : "@DROLSKY/Test::Pod::LinkCheck", + "version" : "1.001" + }, + { + "class" : "Dist::Zilla::Plugin::Test::Pod::No404s", + "name" : "@DROLSKY/Test::Pod::No404s", + "version" : "1.001" + }, + { + "class" : "Dist::Zilla::Plugin::Test::Portability", + "name" : "@DROLSKY/Test::Portability", + "version" : "2.000005" + }, + { + "class" : "Dist::Zilla::Plugin::Git::Check", + "config" : { + "Dist::Zilla::Plugin::Git::Check" : { + "untracked_files" : "die" + }, + "Dist::Zilla::Role::Git::DirtyFiles" : { + "allow_dirty" : [ + "Changes", + "CONTRIBUTING.md", + "README.md" + ], + "allow_dirty_match" : [], + "changelog" : "Changes" + }, + "Dist::Zilla::Role::Git::Repo" : { + "repo_root" : "." + } + }, + "name" : "@DROLSKY/Git::Check", + "version" : "2.023" + }, + { + "class" : "Dist::Zilla::Plugin::Git::Commit", + "config" : { + "Dist::Zilla::Plugin::Git::Commit" : { + "add_files_in" : [], + "commit_msg" : "v%v%n%n%c", + "time_zone" : "local" + }, + "Dist::Zilla::Role::Git::DirtyFiles" : { + "allow_dirty" : [ + "Changes", + "CONTRIBUTING.md", + "README.md" + ], + "allow_dirty_match" : [], + "changelog" : "Changes" + }, + "Dist::Zilla::Role::Git::Repo" : { + "repo_root" : "." + } + }, + "name" : "@DROLSKY/Git::Commit", + "version" : "2.023" + }, + { + "class" : "Dist::Zilla::Plugin::Git::Tag", + "config" : { + "Dist::Zilla::Plugin::Git::Tag" : { + "branch" : null, + "signed" : 0, + "tag" : "v0.09", + "tag_format" : "v%v", + "tag_message" : "v%v", + "time_zone" : "local" + }, + "Dist::Zilla::Role::Git::Repo" : { + "repo_root" : "." + } + }, + "name" : "@DROLSKY/Git::Tag", + "version" : "2.023" + }, + { + "class" : "Dist::Zilla::Plugin::Git::Push", + "config" : { + "Dist::Zilla::Plugin::Git::Push" : { + "push_to" : [ + "origin" + ], + "remotes_must_exist" : 1 + }, + "Dist::Zilla::Role::Git::Repo" : { + "repo_root" : "." + } + }, + "name" : "@DROLSKY/Git::Push", + "version" : "2.023" + }, + { + "class" : "Dist::Zilla::Plugin::FinderCode", + "name" : ":InstallModules", + "version" : "5.020" + }, + { + "class" : "Dist::Zilla::Plugin::FinderCode", + "name" : ":IncModules", + "version" : "5.020" + }, + { + "class" : "Dist::Zilla::Plugin::FinderCode", + "name" : ":TestFiles", + "version" : "5.020" + }, + { + "class" : "Dist::Zilla::Plugin::FinderCode", + "name" : ":ExecFiles", + "version" : "5.020" + }, + { + "class" : "Dist::Zilla::Plugin::FinderCode", + "name" : ":ShareFiles", + "version" : "5.020" + }, + { + "class" : "Dist::Zilla::Plugin::FinderCode", + "name" : ":MainModule", + "version" : "5.020" + }, + { + "class" : "Dist::Zilla::Plugin::FinderCode", + "name" : ":AllFiles", + "version" : "5.020" + }, + { + "class" : "Dist::Zilla::Plugin::FinderCode", + "name" : ":NoFiles", + "version" : "5.020" + }, + { + "class" : "Dist::Zilla::Plugin::FinderCode", + "name" : "@DROLSKY/MetaProvides::Package/AUTOVIV/:InstallModulesPM", + "version" : "5.020" + } + ], + "zilla" : { + "class" : "Dist::Zilla::Dist::Builder", + "config" : { + "is_trial" : "0" + }, + "version" : "5.020" + } + }, + "x_authority" : "cpan:DROLSKY", + "x_contributors" : [ + "Peter Rabbitson <ribasushi@cpan.org>" + ] +} + diff --git a/META.yml b/META.yml new file mode 100644 index 0000000..93ce293 --- /dev/null +++ b/META.yml @@ -0,0 +1,454 @@ +--- +abstract: 'Loads one of several alternate underlying implementations for a module' +author: + - 'Dave Rolsky <autarch@urth.org>' +build_requires: + ExtUtils::MakeMaker: '0' + File::Spec: '0' + IO::Handle: '0' + IPC::Open3: '0' + Test::Fatal: '0.006' + Test::More: '0.88' + Test::Requires: '0' + lib: '0' + perl: '5.006' +configure_requires: + ExtUtils::MakeMaker: '0' +dynamic_config: 0 +generated_by: 'Dist::Zilla version 5.020, CPAN::Meta::Converter version 2.142060' +license: artistic_2 +meta-spec: + url: http://module-build.sourceforge.net/META-spec-v1.4.html + version: '1.4' +name: Module-Implementation +provides: + Module::Implementation: + file: lib/Module/Implementation.pm + version: '0.09' +requires: + Carp: '0' + Module::Runtime: '0.012' + Try::Tiny: '0' + strict: '0' + warnings: '0' +resources: + bugtracker: http://rt.cpan.org/Public/Dist/Display.html?Name=Module-Implementation + homepage: http://metacpan.org/release/Module-Implementation + repository: git://github.com/autarch/Module-Implementation.git +version: '0.09' +x_Dist_Zilla: + perl: + version: '5.016003' + plugins: + - + class: Dist::Zilla::Plugin::MakeMaker + config: + Dist::Zilla::Role::TestRunner: + default_jobs: 1 + name: '@DROLSKY/MakeMaker' + version: '5.020' + - + class: Dist::Zilla::Plugin::Authority + name: '@DROLSKY/Authority' + version: '1.006' + - + class: Dist::Zilla::Plugin::AutoPrereqs + name: '@DROLSKY/AutoPrereqs' + version: '5.020' + - + class: Dist::Zilla::Plugin::GatherDir + name: '@DROLSKY/GatherDir' + version: '5.020' + - + class: Dist::Zilla::Plugin::GitHub::Meta + name: '@DROLSKY/GitHub::Meta' + version: '0.38' + - + class: Dist::Zilla::Plugin::GitHub::Update + name: '@DROLSKY/GitHub::Update' + version: '0.38' + - + class: Dist::Zilla::Plugin::MetaResources + name: '@DROLSKY/MetaResources' + version: '5.020' + - + class: Dist::Zilla::Plugin::MetaProvides::Package + config: + Dist::Zilla::Plugin::MetaProvides::Package: + finder_objects: + - + class: Dist::Zilla::Plugin::FinderCode + name: '@DROLSKY/MetaProvides::Package/AUTOVIV/:InstallModulesPM' + version: '5.020' + Dist::Zilla::Role::MetaProvider::Provider: + inherit_missing: '1' + inherit_version: '1' + meta_noindex: '1' + name: '@DROLSKY/MetaProvides::Package' + version: '2.000004' + - + class: Dist::Zilla::Plugin::NextRelease + name: '@DROLSKY/NextRelease' + version: '5.020' + - + class: Dist::Zilla::Plugin::Test::Pod::Coverage::Configurable + name: '@DROLSKY/Test::Pod::Coverage::Configurable' + version: '0.01' + - + class: Dist::Zilla::Plugin::Test::PodSpelling + name: '@DROLSKY/Test::PodSpelling' + version: '2.006008' + - + class: Dist::Zilla::Plugin::Test::ReportPrereqs + name: '@DROLSKY/Test::ReportPrereqs' + version: '0.019' + - + class: Dist::Zilla::Plugin::Prereqs + config: + Dist::Zilla::Plugin::Prereqs: + phase: test + type: requires + name: '@DROLSKY/TestMoreDoneTesting' + version: '5.020' + - + class: Dist::Zilla::Plugin::PromptIfStale + config: + Dist::Zilla::Plugin::PromptIfStale: + check_all_plugins: '1' + check_all_prereqs: '1' + modules: [] + phase: release + skip: [] + name: '@DROLSKY/stale modules, release' + version: '0.024' + - + class: Dist::Zilla::Plugin::ReadmeAnyFromPod + name: '@DROLSKY/ReadmeMarkdownInBuild' + version: '0.142250' + - + class: Dist::Zilla::Plugin::ReadmeAnyFromPod + name: '@DROLSKY/ReadmeMarkdownInRoot' + version: '0.142250' + - + class: Dist::Zilla::Plugin::PruneCruft + name: '@DROLSKY/PruneCruft' + version: '5.020' + - + class: Dist::Zilla::Plugin::ManifestSkip + name: '@DROLSKY/ManifestSkip' + version: '5.020' + - + class: Dist::Zilla::Plugin::MetaYAML + name: '@DROLSKY/MetaYAML' + version: '5.020' + - + class: Dist::Zilla::Plugin::License + name: '@DROLSKY/License' + version: '5.020' + - + class: Dist::Zilla::Plugin::ExtraTests + name: '@DROLSKY/ExtraTests' + version: '5.020' + - + class: Dist::Zilla::Plugin::ExecDir + name: '@DROLSKY/ExecDir' + version: '5.020' + - + class: Dist::Zilla::Plugin::ShareDir + name: '@DROLSKY/ShareDir' + version: '5.020' + - + class: Dist::Zilla::Plugin::Manifest + name: '@DROLSKY/Manifest' + version: '5.020' + - + class: Dist::Zilla::Plugin::TestRelease + name: '@DROLSKY/TestRelease' + version: '5.020' + - + class: Dist::Zilla::Plugin::ConfirmRelease + name: '@DROLSKY/ConfirmRelease' + version: '5.020' + - + class: Dist::Zilla::Plugin::UploadToCPAN + name: '@DROLSKY/UploadToCPAN' + version: '5.020' + - + class: Dist::Zilla::Plugin::CheckPrereqsIndexed + name: '@DROLSKY/CheckPrereqsIndexed' + version: '0.012' + - + class: Dist::Zilla::Plugin::ContributorsFromGit + name: '@DROLSKY/ContributorsFromGit' + version: '0.014' + - + class: Dist::Zilla::Plugin::CopyReadmeFromBuild + name: '@DROLSKY/CopyReadmeFromBuild' + version: '0.0019' + - + class: Dist::Zilla::Plugin::Git::CheckFor::CorrectBranch + config: + Dist::Zilla::Role::Git::Repo: + repo_root: . + name: '@DROLSKY/Git::CheckFor::CorrectBranch' + version: '0.011' + - + class: Dist::Zilla::Plugin::Git::CheckFor::MergeConflicts + config: + Dist::Zilla::Role::Git::Repo: + repo_root: . + name: '@DROLSKY/Git::CheckFor::MergeConflicts' + version: '0.011' + - + class: Dist::Zilla::Plugin::Git::Describe + name: '@DROLSKY/Git::Describe' + version: '0.003' + - + class: Dist::Zilla::Plugin::InstallGuide + name: '@DROLSKY/InstallGuide' + version: '1.200003' + - + class: Dist::Zilla::Plugin::Meta::Contributors + name: '@DROLSKY/Meta::Contributors' + version: '0.001' + - + class: Dist::Zilla::Plugin::MetaConfig + name: '@DROLSKY/MetaConfig' + version: '5.020' + - + class: Dist::Zilla::Plugin::MetaJSON + name: '@DROLSKY/MetaJSON' + version: '5.020' + - + class: Dist::Zilla::Plugin::PkgVersion + name: '@DROLSKY/PkgVersion' + version: '5.020' + - + class: Dist::Zilla::Plugin::SurgicalPodWeaver + config: + Dist::Zilla::Plugin::PodWeaver: + finder: + - ':InstallModules' + - ':ExecFiles' + plugins: + - + class: Pod::Weaver::Plugin::EnsurePod5 + name: '@CorePrep/EnsurePod5' + version: '4.006' + - + class: Pod::Weaver::Plugin::H1Nester + name: '@CorePrep/H1Nester' + version: '4.006' + - + class: Pod::Weaver::Plugin::SingleEncoding + name: '@Default/SingleEncoding' + version: '4.006' + - + class: Pod::Weaver::Section::Name + name: '@Default/Name' + version: '4.006' + - + class: Pod::Weaver::Section::Version + name: '@Default/Version' + version: '4.006' + - + class: Pod::Weaver::Section::Region + name: '@Default/prelude' + version: '4.006' + - + class: Pod::Weaver::Section::Generic + name: SYNOPSIS + version: '4.006' + - + class: Pod::Weaver::Section::Generic + name: DESCRIPTION + version: '4.006' + - + class: Pod::Weaver::Section::Generic + name: OVERVIEW + version: '4.006' + - + class: Pod::Weaver::Section::Collect + name: ATTRIBUTES + version: '4.006' + - + class: Pod::Weaver::Section::Collect + name: METHODS + version: '4.006' + - + class: Pod::Weaver::Section::Collect + name: FUNCTIONS + version: '4.006' + - + class: Pod::Weaver::Section::Leftovers + name: '@Default/Leftovers' + version: '4.006' + - + class: Pod::Weaver::Section::Region + name: '@Default/postlude' + version: '4.006' + - + class: Pod::Weaver::Section::Authors + name: '@Default/Authors' + version: '4.006' + - + class: Pod::Weaver::Section::Legal + name: '@Default/Legal' + version: '4.006' + name: '@DROLSKY/SurgicalPodWeaver' + version: '0.0021' + - + class: Dist::Zilla::Plugin::EOLTests + name: '@DROLSKY/EOLTests' + version: '0.02' + - + class: Dist::Zilla::Plugin::PodSyntaxTests + name: '@DROLSKY/PodSyntaxTests' + version: '5.020' + - + class: Dist::Zilla::Plugin::Test::CPAN::Changes + name: '@DROLSKY/Test::CPAN::Changes' + version: '0.008' + - + class: Dist::Zilla::Plugin::Test::Compile + config: + Dist::Zilla::Plugin::Test::Compile: + bail_out_on_fail: '0' + fail_on_warning: author + fake_home: '0' + filename: t/00-compile.t + module_finder: + - ':InstallModules' + needs_display: '0' + phase: test + script_finder: + - ':ExecFiles' + skips: [] + name: '@DROLSKY/Test::Compile' + version: '2.046' + - + class: Dist::Zilla::Plugin::Test::NoTabs + config: + Dist::Zilla::Plugin::Test::NoTabs: + filename: xt/author/no-tabs.t + finder: + - ':InstallModules' + - ':ExecFiles' + - ':TestFiles' + name: '@DROLSKY/Test::NoTabs' + version: '0.09' + - + class: Dist::Zilla::Plugin::Test::Pod::LinkCheck + name: '@DROLSKY/Test::Pod::LinkCheck' + version: '1.001' + - + class: Dist::Zilla::Plugin::Test::Pod::No404s + name: '@DROLSKY/Test::Pod::No404s' + version: '1.001' + - + class: Dist::Zilla::Plugin::Test::Portability + name: '@DROLSKY/Test::Portability' + version: '2.000005' + - + class: Dist::Zilla::Plugin::Git::Check + config: + Dist::Zilla::Plugin::Git::Check: + untracked_files: die + Dist::Zilla::Role::Git::DirtyFiles: + allow_dirty: + - Changes + - CONTRIBUTING.md + - README.md + allow_dirty_match: [] + changelog: Changes + Dist::Zilla::Role::Git::Repo: + repo_root: . + name: '@DROLSKY/Git::Check' + version: '2.023' + - + class: Dist::Zilla::Plugin::Git::Commit + config: + Dist::Zilla::Plugin::Git::Commit: + add_files_in: [] + commit_msg: v%v%n%n%c + time_zone: local + Dist::Zilla::Role::Git::DirtyFiles: + allow_dirty: + - Changes + - CONTRIBUTING.md + - README.md + allow_dirty_match: [] + changelog: Changes + Dist::Zilla::Role::Git::Repo: + repo_root: . + name: '@DROLSKY/Git::Commit' + version: '2.023' + - + class: Dist::Zilla::Plugin::Git::Tag + config: + Dist::Zilla::Plugin::Git::Tag: + branch: ~ + signed: 0 + tag: v0.09 + tag_format: v%v + tag_message: v%v + time_zone: local + Dist::Zilla::Role::Git::Repo: + repo_root: . + name: '@DROLSKY/Git::Tag' + version: '2.023' + - + class: Dist::Zilla::Plugin::Git::Push + config: + Dist::Zilla::Plugin::Git::Push: + push_to: + - origin + remotes_must_exist: 1 + Dist::Zilla::Role::Git::Repo: + repo_root: . + name: '@DROLSKY/Git::Push' + version: '2.023' + - + class: Dist::Zilla::Plugin::FinderCode + name: ':InstallModules' + version: '5.020' + - + class: Dist::Zilla::Plugin::FinderCode + name: ':IncModules' + version: '5.020' + - + class: Dist::Zilla::Plugin::FinderCode + name: ':TestFiles' + version: '5.020' + - + class: Dist::Zilla::Plugin::FinderCode + name: ':ExecFiles' + version: '5.020' + - + class: Dist::Zilla::Plugin::FinderCode + name: ':ShareFiles' + version: '5.020' + - + class: Dist::Zilla::Plugin::FinderCode + name: ':MainModule' + version: '5.020' + - + class: Dist::Zilla::Plugin::FinderCode + name: ':AllFiles' + version: '5.020' + - + class: Dist::Zilla::Plugin::FinderCode + name: ':NoFiles' + version: '5.020' + - + class: Dist::Zilla::Plugin::FinderCode + name: '@DROLSKY/MetaProvides::Package/AUTOVIV/:InstallModulesPM' + version: '5.020' + zilla: + class: Dist::Zilla::Dist::Builder + config: + is_trial: '0' + version: '5.020' +x_authority: cpan:DROLSKY +x_contributors: + - 'Peter Rabbitson <ribasushi@cpan.org>' diff --git a/Makefile.PL b/Makefile.PL new file mode 100644 index 0000000..5857c49 --- /dev/null +++ b/Makefile.PL @@ -0,0 +1,75 @@ + +# This file was automatically generated by Dist::Zilla::Plugin::MakeMaker v5.020. +use strict; +use warnings; + + + +use ExtUtils::MakeMaker ; + + + +my %WriteMakefileArgs = ( + "ABSTRACT" => "Loads one of several alternate underlying implementations for a module", + "AUTHOR" => "Dave Rolsky <autarch\@urth.org>", + "CONFIGURE_REQUIRES" => { + "ExtUtils::MakeMaker" => 0 + }, + "DISTNAME" => "Module-Implementation", + "EXE_FILES" => [], + "LICENSE" => "artistic_2", + "NAME" => "Module::Implementation", + "PREREQ_PM" => { + "Carp" => 0, + "Module::Runtime" => "0.012", + "Try::Tiny" => 0, + "strict" => 0, + "warnings" => 0 + }, + "TEST_REQUIRES" => { + "ExtUtils::MakeMaker" => 0, + "File::Spec" => 0, + "IO::Handle" => 0, + "IPC::Open3" => 0, + "Test::Fatal" => "0.006", + "Test::More" => "0.88", + "Test::Requires" => 0, + "lib" => 0 + }, + "VERSION" => "0.09", + "test" => { + "TESTS" => "t/*.t" + } +); + + +my %FallbackPrereqs = ( + "Carp" => 0, + "ExtUtils::MakeMaker" => 0, + "File::Spec" => 0, + "IO::Handle" => 0, + "IPC::Open3" => 0, + "Module::Runtime" => "0.012", + "Test::Fatal" => "0.006", + "Test::More" => "0.88", + "Test::Requires" => 0, + "Try::Tiny" => 0, + "lib" => 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); + + + diff --git a/README.md b/README.md new file mode 100644 index 0000000..e1e1edd --- /dev/null +++ b/README.md @@ -0,0 +1,131 @@ +# NAME + +Module::Implementation - Loads one of several alternate underlying implementations for a module + +# VERSION + +version 0.09 + +# SYNOPSIS + + package Foo::Bar; + + use Module::Implementation; + + BEGIN { + my $loader = Module::Implementation::build_loader_sub( + implementations => [ 'XS', 'PurePerl' ], + symbols => [ 'run', 'check' ], + ); + + $loader->(); + } + + package Consumer; + + # loads the first viable implementation + use Foo::Bar; + +# DESCRIPTION + +This module abstracts out the process of choosing one of several underlying +implementations for a module. This can be used to provide XS and pure Perl +implementations of a module, or it could be used to load an implementation for +a given OS or any other case of needing to provide multiple implementations. + +This module is only useful when you know all the implementations ahead of +time. If you want to load arbitrary implementations then you probably want +something like a plugin system, not this module. + +# API + +This module provides two subroutines, neither of which are exported. + +## Module::Implementation::build\_loader\_sub(...) + +This subroutine takes the following arguments. + +- implementations + + This should be an array reference of implementation names. Each name should + correspond to a module in the caller's namespace. + + In other words, using the example in the ["SYNOPSIS"](#synopsis), this module will look + for the `Foo::Bar::XS` and `Foo::Bar::PurePerl` modules. + + This argument is required. + +- symbols + + A list of symbols to copy from the implementation package to the calling + package. + + These can be prefixed with a variable type: `$`, `@`, `%`, `&`, or + `*)`. If no prefix is given, the symbol is assumed to be a subroutine. + + This argument is optional. + +This subroutine _returns_ the implementation loader as a sub reference. + +It is up to you to call this loader sub in your code. + +I recommend that you _do not_ call this loader in an `import()` sub. If a +caller explicitly requests no imports, your `import()` sub will not be run at +all, which can cause weird breakage. + +## Module::Implementation::implementation\_for($package) + +Given a package name, this subroutine returns the implementation that was +loaded for the package. This is not a full package name, just the suffix that +identifies the implementation. For the ["SYNOPSIS"](#synopsis) example, this subroutine +would be called as `Module::Implementation::implementation_for('Foo::Bar')`, +and it would return "XS" or "PurePerl". + +# HOW THE IMPLEMENTATION LOADER WORKS + +The implementation loader works like this ... + +First, it checks for an `%ENV` var specifying the implementation to load. The +env var is based on the package name which loads the implementations. The +`::` package separator is replaced with `_`, and made entirely +upper-case. Finally, we append "\_IMPLEMENTATION" to this name. + +So in our ["SYNOPSIS"](#synopsis) example, the corresponding `%ENV` key would be +`FOO_BAR_IMPLEMENTATION`. + +If this is set, then the loader will **only** try to load this one +implementation. + +If the env var requests an implementation which doesn't match one of the +implementations specified when the loader was created, an error is thrown. + +If this one implementation fails to load then loader throws an error. This is +useful for testing. You can request a specific implementation in a test file +by writing something like this: + + BEGIN { $ENV{FOO_BAR_IMPLEMENTATION} = 'XS' } + use Foo::Bar; + +If the environment variable is _not_ set, then the loader simply tries the +implementations originally passed to `Module::Implementation`. The +implementations are tried in the order in which they were originally passed. + +The loader will use the first implementation that loads without an error. It +will copy any requested symbols from this implementation. + +If none of the implementations can be loaded, then the loader throws an +exception. + +The loader returns the name of the package it loaded. + +# AUTHOR + +Dave Rolsky <autarch@urth.org> + +# COPYRIGHT AND LICENSE + +This software is Copyright (c) 2014 by Dave Rolsky. + +This is free software, licensed under: + + The Artistic License 2.0 (GPL Compatible) diff --git a/dist.ini b/dist.ini new file mode 100644 index 0000000..051790d --- /dev/null +++ b/dist.ini @@ -0,0 +1,14 @@ +name = Module-Implementation +author = Dave Rolsky <autarch@urth.org> +license = Artistic_2_0 +copyright_holder = Dave Rolsky + +version = 0.09 + +[@DROLSKY] +dist = Module-Implementation +stopwords = API +stopwords = PurePerl +stopwords = env +stopwords = namespace +-remove = Test::Synopsis diff --git a/lib/Module/Implementation.pm b/lib/Module/Implementation.pm new file mode 100644 index 0000000..0cdc3b5 --- /dev/null +++ b/lib/Module/Implementation.pm @@ -0,0 +1,290 @@ +package Module::Implementation; +# git description: v0.08-2-gd599347 +$Module::Implementation::VERSION = '0.09'; + +use strict; +use warnings; + +use Module::Runtime 0.012 qw( require_module ); +use Try::Tiny; + +# This is needed for the benefit of Test::CleanNamespaces, which in turn loads +# Package::Stash, which in turn loads this module and expects a minimum +# version. +unless ( exists $Module::Implementation::{VERSION} + && ${ $Module::Implementation::{VERSION} } ) { + + $Module::Implementation::{VERSION} = \42; +} + +my %Implementation; + +sub build_loader_sub { + my $caller = caller(); + + return _build_loader( $caller, @_ ); +} + +sub _build_loader { + my $package = shift; + my %args = @_; + + my @implementations = @{ $args{implementations} }; + my @symbols = @{ $args{symbols} || [] }; + + my $implementation; + my $env_var = uc $package; + $env_var =~ s/::/_/g; + $env_var .= '_IMPLEMENTATION'; + + return sub { + my ( $implementation, $loaded ) = _load_implementation( + $package, + $ENV{$env_var}, + \@implementations, + ); + + $Implementation{$package} = $implementation; + + _copy_symbols( $loaded, $package, \@symbols ); + + return $loaded; + }; +} + +sub implementation_for { + my $package = shift; + + return $Implementation{$package}; +} + +sub _load_implementation { + my $package = shift; + my $env_value = shift; + my $implementations = shift; + + if ($env_value) { + die "$env_value is not a valid implementation for $package" + unless grep { $_ eq $env_value } @{$implementations}; + + my $requested = "${package}::$env_value"; + + # Values from the %ENV hash are tainted. We know it's safe to untaint + # this value because the value was one of our known implementations. + ($requested) = $requested =~ /^(.+)$/; + + try { + require_module($requested); + } + catch { + require Carp; + Carp::croak("Could not load $requested: $_"); + }; + + return ( $env_value, $requested ); + } + else { + my $err; + for my $possible ( @{$implementations} ) { + my $try = "${package}::$possible"; + + my $ok; + try { + require_module($try); + $ok = 1; + } + catch { + $err .= $_ if defined $_; + }; + + return ( $possible, $try ) if $ok; + } + + require Carp; + if ( defined $err && length $err ) { + Carp::croak( + "Could not find a suitable $package implementation: $err"); + } + else { + Carp::croak( + 'Module::Runtime failed to load a module but did not throw a real error. This should never happen. Something is very broken' + ); + } + } +} + +sub _copy_symbols { + my $from_package = shift; + my $to_package = shift; + my $symbols = shift; + + for my $sym ( @{$symbols} ) { + my $type = $sym =~ s/^([\$\@\%\&\*])// ? $1 : '&'; + + my $from = "${from_package}::$sym"; + my $to = "${to_package}::$sym"; + + { + no strict 'refs'; + no warnings 'once'; + + # Copied from Exporter + *{$to} + = $type eq '&' ? \&{$from} + : $type eq '$' ? \${$from} + : $type eq '@' ? \@{$from} + : $type eq '%' ? \%{$from} + : $type eq '*' ? *{$from} + : die + "Can't copy symbol from $from_package to $to_package: $type$sym"; + } + } +} + +1; + +# ABSTRACT: Loads one of several alternate underlying implementations for a module + +__END__ + +=pod + +=encoding UTF-8 + +=head1 NAME + +Module::Implementation - Loads one of several alternate underlying implementations for a module + +=head1 VERSION + +version 0.09 + +=head1 SYNOPSIS + + package Foo::Bar; + + use Module::Implementation; + + BEGIN { + my $loader = Module::Implementation::build_loader_sub( + implementations => [ 'XS', 'PurePerl' ], + symbols => [ 'run', 'check' ], + ); + + $loader->(); + } + + package Consumer; + + # loads the first viable implementation + use Foo::Bar; + +=head1 DESCRIPTION + +This module abstracts out the process of choosing one of several underlying +implementations for a module. This can be used to provide XS and pure Perl +implementations of a module, or it could be used to load an implementation for +a given OS or any other case of needing to provide multiple implementations. + +This module is only useful when you know all the implementations ahead of +time. If you want to load arbitrary implementations then you probably want +something like a plugin system, not this module. + +=head1 API + +This module provides two subroutines, neither of which are exported. + +=head2 Module::Implementation::build_loader_sub(...) + +This subroutine takes the following arguments. + +=over 4 + +=item * implementations + +This should be an array reference of implementation names. Each name should +correspond to a module in the caller's namespace. + +In other words, using the example in the L</SYNOPSIS>, this module will look +for the C<Foo::Bar::XS> and C<Foo::Bar::PurePerl> modules. + +This argument is required. + +=item * symbols + +A list of symbols to copy from the implementation package to the calling +package. + +These can be prefixed with a variable type: C<$>, C<@>, C<%>, C<&>, or +C<*)>. If no prefix is given, the symbol is assumed to be a subroutine. + +This argument is optional. + +=back + +This subroutine I<returns> the implementation loader as a sub reference. + +It is up to you to call this loader sub in your code. + +I recommend that you I<do not> call this loader in an C<import()> sub. If a +caller explicitly requests no imports, your C<import()> sub will not be run at +all, which can cause weird breakage. + +=head2 Module::Implementation::implementation_for($package) + +Given a package name, this subroutine returns the implementation that was +loaded for the package. This is not a full package name, just the suffix that +identifies the implementation. For the L</SYNOPSIS> example, this subroutine +would be called as C<Module::Implementation::implementation_for('Foo::Bar')>, +and it would return "XS" or "PurePerl". + +=head1 HOW THE IMPLEMENTATION LOADER WORKS + +The implementation loader works like this ... + +First, it checks for an C<%ENV> var specifying the implementation to load. The +env var is based on the package name which loads the implementations. The +C<::> package separator is replaced with C<_>, and made entirely +upper-case. Finally, we append "_IMPLEMENTATION" to this name. + +So in our L</SYNOPSIS> example, the corresponding C<%ENV> key would be +C<FOO_BAR_IMPLEMENTATION>. + +If this is set, then the loader will B<only> try to load this one +implementation. + +If the env var requests an implementation which doesn't match one of the +implementations specified when the loader was created, an error is thrown. + +If this one implementation fails to load then loader throws an error. This is +useful for testing. You can request a specific implementation in a test file +by writing something like this: + + BEGIN { $ENV{FOO_BAR_IMPLEMENTATION} = 'XS' } + use Foo::Bar; + +If the environment variable is I<not> set, then the loader simply tries the +implementations originally passed to C<Module::Implementation>. The +implementations are tried in the order in which they were originally passed. + +The loader will use the first implementation that loads without an error. It +will copy any requested symbols from this implementation. + +If none of the implementations can be loaded, then the loader throws an +exception. + +The loader returns the name of the package it loaded. + +=head1 AUTHOR + +Dave Rolsky <autarch@urth.org> + +=head1 COPYRIGHT AND LICENSE + +This software is Copyright (c) 2014 by Dave Rolsky. + +This is free software, licensed under: + + The Artistic License 2.0 (GPL Compatible) + +=cut diff --git a/t/00-compile.t b/t/00-compile.t new file mode 100644 index 0000000..8d3b17e --- /dev/null +++ b/t/00-compile.t @@ -0,0 +1,50 @@ +use 5.006; +use strict; +use warnings; + +# this test was generated with Dist::Zilla::Plugin::Test::Compile 2.046 + +use Test::More tests => 1 + ($ENV{AUTHOR_TESTING} ? 1 : 0); + + + +my @module_files = ( + 'Module/Implementation.pm' +); + + + +# no fake home requested + +my $inc_switch = -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<perlfaq8/How can I capture STDERR from an external command?> + my $stderr = IO::Handle->new; + + my $pid = open3($stdin, '>&STDERR', $stderr, $^X, $inc_switch, '-e', "require q[$lib]"); + binmode $stderr, ':crlf' if $^O eq 'MSWin32'; + my @_warnings = <$stderr>; + waitpid($pid, 0); + is($?, 0, "$lib loaded ok"); + + if (@_warnings) + { + warn @_warnings; + push @warnings, @_warnings; + } +} + + + +is(scalar(@warnings), 0, 'no warnings found') or diag 'got warnings: ', explain \@warnings if $ENV{AUTHOR_TESTING}; + + diff --git a/t/00-report-prereqs.dd b/t/00-report-prereqs.dd new file mode 100644 index 0000000..a3f6c98 --- /dev/null +++ b/t/00-report-prereqs.dd @@ -0,0 +1,45 @@ +do { my $x = { + 'configure' => { + 'requires' => { + 'ExtUtils::MakeMaker' => '0' + } + }, + 'develop' => { + 'requires' => { + 'Pod::Coverage::TrustPod' => '0', + 'Test::CPAN::Changes' => '0.19', + 'Test::More' => '0.88', + 'Test::NoTabs' => '0', + 'Test::Pod' => '1.41', + 'Test::Pod::Coverage' => '1.08', + 'Test::Spelling' => '0.12' + } + }, + 'runtime' => { + 'requires' => { + 'Carp' => '0', + 'Module::Runtime' => '0.012', + 'Try::Tiny' => '0', + 'strict' => '0', + 'warnings' => '0' + } + }, + 'test' => { + 'recommends' => { + 'CPAN::Meta' => '2.120900' + }, + 'requires' => { + 'ExtUtils::MakeMaker' => '0', + 'File::Spec' => '0', + 'IO::Handle' => '0', + 'IPC::Open3' => '0', + 'Test::Fatal' => '0.006', + 'Test::More' => '0.88', + 'Test::Requires' => '0', + 'lib' => '0', + 'perl' => '5.006' + } + } + }; + $x; + }
\ No newline at end of file diff --git a/t/00-report-prereqs.t b/t/00-report-prereqs.t new file mode 100644 index 0000000..402b3d9 --- /dev/null +++ b/t/00-report-prereqs.t @@ -0,0 +1,176 @@ +#!perl + +use strict; +use warnings; + +# This test was generated by Dist::Zilla::Plugin::Test::ReportPrereqs 0.019 + +use Test::More tests => 1; + +use ExtUtils::MakeMaker; +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( + +); + +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'; +if ( $source && $HAS_CPAN_META ) { + if ( my $meta = eval { CPAN::Meta->load_file($source) } ) { + $full_prereqs = _merge_prereqs($full_prereqs, $meta->prereqs); + } +} +else { + $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 = MM->parse_version( File::Spec->catfile($prefix, $file) ); + $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 ); + 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 ( @dep_errors ) { + diag join("\n", + "\n*** WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING ***\n", + "The following REQUIRED prerequisites were not satisfied:\n", + @dep_errors, + "\n" + ); +} + +pass; + +# vim: ts=4 sts=4 sw=4 et: diff --git a/t/author-no-tabs.t b/t/author-no-tabs.t new file mode 100644 index 0000000..678f479 --- /dev/null +++ b/t/author-no-tabs.t @@ -0,0 +1,47 @@ + +BEGIN { + unless ($ENV{AUTHOR_TESTING}) { + require Test::More; + Test::More::plan(skip_all => 'these tests are for testing by the author'); + } +} + +use strict; +use warnings; + +# this test was generated with Dist::Zilla::Plugin::Test::NoTabs 0.09 + +use Test::More 0.88; +use Test::NoTabs; + +my @files = ( + 'lib/Module/Implementation.pm', + 't/00-compile.t', + 't/00-report-prereqs.dd', + 't/00-report-prereqs.t', + 't/author-no-tabs.t', + 't/author-pod-spell.t', + 't/basic.t', + 't/both-fail.t', + 't/env-value.t', + 't/lib/T/Impl1.pm', + 't/lib/T/Impl2.pm', + 't/lib/T/ImplFails1.pm', + 't/lib/T/ImplFails2.pm', + 't/more-symbols.t', + 't/namespace-cleanliness.t', + 't/one-impl-fails1.t', + 't/one-impl-fails2.t', + 't/release-cpan-changes.t', + 't/release-eol.t', + 't/release-pod-coverage.t', + 't/release-pod-linkcheck.t', + 't/release-pod-no404s.t', + 't/release-pod-syntax.t', + 't/release-portability.t', + 't/requested-fails.t', + 't/taint.t' +); + +notabs_ok($_) foreach @files; +done_testing; diff --git a/t/author-pod-spell.t b/t/author-pod-spell.t new file mode 100644 index 0000000..f5f0487 --- /dev/null +++ b/t/author-pod-spell.t @@ -0,0 +1,36 @@ + +BEGIN { + unless ($ENV{AUTHOR_TESTING}) { + require Test::More; + Test::More::plan(skip_all => 'these tests are for testing by the author'); + } +} + +use strict; +use warnings; +use Test::More; + +# generated by Dist::Zilla::Plugin::Test::PodSpelling 2.006008 +use Test::Spelling 0.12; +use Pod::Wordlist; + + +add_stopwords(<DATA>); +all_pod_files_spelling_ok( qw( bin lib ) ); +__DATA__ +DROLSKY +DROLSKY's +Rolsky +Rolsky's +API +PurePerl +env +namespace +Dave +autarch +Peter +Rabbitson +ribasushi +lib +Module +Implementation diff --git a/t/basic.t b/t/basic.t new file mode 100644 index 0000000..da33b4e --- /dev/null +++ b/t/basic.t @@ -0,0 +1,37 @@ +use strict; +use warnings; + +use Test::More 0.88; + +{ + package T; + + use strict; + use warnings; + + use lib 't/lib'; + + use Module::Implementation; + my $loader = Module::Implementation::build_loader_sub( + implementations => [ 'Impl1', 'Impl2' ], + symbols => ['return_42'], + ); + + ::is( $loader->(), 'T::Impl1', 'loader return loaded package name' ); +} + +{ + ok( T->can('return_42'), 'T package has a return_42 sub' ); + ok( + !T->can('return_package'), + 'T package does not have return_package sub - only copied requested symbols' + ); + is( T::return_42(), 42, 'T::return_42 work as expected' ); + is( + Module::Implementation::implementation_for('T'), + 'Impl1', + 'T::_implementation returns default implementation' + ); +} + +done_testing(); diff --git a/t/both-fail.t b/t/both-fail.t new file mode 100644 index 0000000..e21cb78 --- /dev/null +++ b/t/both-fail.t @@ -0,0 +1,28 @@ +use strict; +use warnings; + +use Test::More 0.88; +use Test::Fatal 0.006; + +{ + package T; + + use strict; + use warnings; + + use lib 't/lib'; + + use Module::Implementation; + my $loader = Module::Implementation::build_loader_sub( + implementations => [ 'ImplFails1', 'ImplFails2' ], + symbols => [qw( return_42 )], + ); + + ::like( + ::exception{ $loader->() }, + qr/Could not find a suitable T implementation/, + 'Got an exception when all implementations fail to load' + ); +} + +done_testing(); diff --git a/t/env-value.t b/t/env-value.t new file mode 100644 index 0000000..c1d439e --- /dev/null +++ b/t/env-value.t @@ -0,0 +1,39 @@ +use strict; +use warnings; + +use Test::More 0.88; + +{ + package T; + + use strict; + use warnings; + + use lib 't/lib'; + + use Module::Implementation; + my $loader = Module::Implementation::build_loader_sub( + implementations => [ 'Impl1', 'Impl2' ], + symbols => ['return_42'], + ); + + $ENV{T_IMPLEMENTATION} = 'Impl2'; + + $loader->(); +} + +{ + ok( T->can('return_42'), 'T package has a return_42 sub' ); + ok( + !T->can('return_package'), + 'T package does not have return_package sub - only copied requested symbols' + ); + is( T::return_42(), 42, 'T::return_42 work as expected' ); + is( + Module::Implementation::implementation_for('T'), + 'Impl2', + 'T::_implementation returns implementation set in ENV' + ); +} + +done_testing(); diff --git a/t/lib/T/Impl1.pm b/t/lib/T/Impl1.pm new file mode 100644 index 0000000..6ac7073 --- /dev/null +++ b/t/lib/T/Impl1.pm @@ -0,0 +1,16 @@ +package T::Impl1; + +use strict; +use warnings; + +sub return_42 { + return 42; +} + +sub return_package { + return __PACKAGE__; +} + +our $SCALAR = 42; +our @ARRAY = ( 1, 2, 3 ); +our %HASH = ( key => 'val' ); diff --git a/t/lib/T/Impl2.pm b/t/lib/T/Impl2.pm new file mode 100644 index 0000000..7de6c47 --- /dev/null +++ b/t/lib/T/Impl2.pm @@ -0,0 +1,18 @@ +package T::Impl2; + +use strict; +use warnings; + +sub return_42 { + return 42; +} + +sub return_package { + return __PACKAGE__; +} + +our $SCALAR = 42; +our @ARRAY = ( 1, 2, 3 ); +our %HASH = ( key => 'val' ); + +1; diff --git a/t/lib/T/ImplFails1.pm b/t/lib/T/ImplFails1.pm new file mode 100644 index 0000000..0f88cff --- /dev/null +++ b/t/lib/T/ImplFails1.pm @@ -0,0 +1,16 @@ +package T::ImplFails1; + +use strict; +use warnings; + +sub return_42 { + return 42; +} + +sub return_package { + return __PACKAGE__; +} + +die 'Error loading something or other'; + +1; diff --git a/t/lib/T/ImplFails2.pm b/t/lib/T/ImplFails2.pm new file mode 100644 index 0000000..c66b649 --- /dev/null +++ b/t/lib/T/ImplFails2.pm @@ -0,0 +1,16 @@ +package T::ImplFails2; + +use strict; +use warnings; + +sub return_42 { + return 42; +} + +sub return_package { + return __PACKAGE__; +} + +die 'Error loading something or other'; + +1; diff --git a/t/more-symbols.t b/t/more-symbols.t new file mode 100644 index 0000000..8bd8329 --- /dev/null +++ b/t/more-symbols.t @@ -0,0 +1,47 @@ +use strict; +use warnings; + +use Test::More 0.88; + +{ + package T; + + use strict; + use warnings; + + use lib 't/lib'; + + use Module::Implementation; + my $loader = Module::Implementation::build_loader_sub( + implementations => [ 'Impl1', 'Impl2' ], + symbols => [qw( return_42 &return_package $SCALAR @ARRAY %HASH )], + ); + + $loader->(); +} + +{ + ok( T->can('return_42'), 'T package has a return_42 sub' ); + ok( T->can('return_package'), 'T package has a return_package sub' ); + is( T::return_42(), 42, 'T::return_42 work as expected' ); + is( + T::return_package(), + 'T::Impl1', + 'T::return_package returns implementation package' + ); + + no warnings 'once'; + is( $T::SCALAR, 42, '$T::SCALAR was copied from implementation' ); + is_deeply( + \@T::ARRAY, + [ 1, 2, 3 ], + '@T::ARRAY was copied from implementation' + ); + is_deeply( + \%T::HASH, + { key => 'val' }, + '%T::HASH was copied from implementation' + ); +} + +done_testing(); diff --git a/t/namespace-cleanliness.t b/t/namespace-cleanliness.t new file mode 100644 index 0000000..a9917bf --- /dev/null +++ b/t/namespace-cleanliness.t @@ -0,0 +1,33 @@ +use strict; +use warnings; + +use Test::More 0.88; + +use Test::Requires { + 'Test::CleanNamespaces' => 0, +}; + +{ + package T; + + use strict; + use warnings; + + use lib 't/lib'; + + use Module::Implementation; + my $loader = Module::Implementation::build_loader_sub( + implementations => [ 'Impl1', 'Impl2' ], + symbols => ['return_42'], + ); + $loader->(); +} + +$INC{'T.pm'} = 1; + +{ + local $TODO = q{Without Sub::Name there's no good way to avoid dirtiness}; + namespaces_clean('T'); +} + +done_testing(); diff --git a/t/one-impl-fails1.t b/t/one-impl-fails1.t new file mode 100644 index 0000000..1df94a0 --- /dev/null +++ b/t/one-impl-fails1.t @@ -0,0 +1,28 @@ +use strict; +use warnings; + +use Test::More 0.88; + +{ + package T; + + use strict; + use warnings; + + use lib 't/lib'; + + use Module::Implementation; + my $loader = Module::Implementation::build_loader_sub( + implementations => [ 'ImplFails1', 'Impl1' ], + symbols => [qw( return_42 )], + ); + + $loader->(); +} + +{ + ok( T->can('return_42'), 'T package has a return_42 sub' ); + ok( !T->can('return_package'), 'T package has a return_package sub' ); +} + +done_testing(); diff --git a/t/one-impl-fails2.t b/t/one-impl-fails2.t new file mode 100644 index 0000000..444d1e8 --- /dev/null +++ b/t/one-impl-fails2.t @@ -0,0 +1,28 @@ +use strict; +use warnings; + +use Test::More 0.88; + +{ + package T; + + use strict; + use warnings; + + use lib 't/lib'; + + use Module::Implementation; + my $loader = Module::Implementation::build_loader_sub( + implementations => [ 'Impl1', 'ImplFails1' ], + symbols => [qw( return_42 )], + ); + + $loader->(); +} + +{ + ok( T->can('return_42'), 'T package has a return_42 sub' ); + ok( !T->can('return_package'), 'T package has a return_package sub' ); +} + +done_testing(); diff --git a/t/release-cpan-changes.t b/t/release-cpan-changes.t new file mode 100644 index 0000000..214650f --- /dev/null +++ b/t/release-cpan-changes.t @@ -0,0 +1,19 @@ +#!perl + +BEGIN { + unless ($ENV{RELEASE_TESTING}) { + require Test::More; + Test::More::plan(skip_all => 'these tests are for release candidate testing'); + } +} + + +use strict; +use warnings; + +use Test::More 0.96 tests => 2; +use_ok('Test::CPAN::Changes'); +subtest 'changes_ok' => sub { + changes_file_ok('Changes'); +}; +done_testing(); diff --git a/t/release-eol.t b/t/release-eol.t new file mode 100644 index 0000000..4ce4ad8 --- /dev/null +++ b/t/release-eol.t @@ -0,0 +1,16 @@ + +BEGIN { + unless ($ENV{RELEASE_TESTING}) { + require Test::More; + Test::More::plan(skip_all => 'these tests are for release candidate testing'); + } +} + +use strict; +use warnings; +use Test::More; + +eval 'use Test::EOL'; +plan skip_all => 'Test::EOL required' if $@; + +all_perl_files_ok({ trailing_whitespace => 1 }); diff --git a/t/release-pod-coverage.t b/t/release-pod-coverage.t new file mode 100644 index 0000000..1f3b7b6 --- /dev/null +++ b/t/release-pod-coverage.t @@ -0,0 +1,43 @@ +#!perl + +BEGIN { + unless ($ENV{RELEASE_TESTING}) { + require Test::More; + Test::More::plan(skip_all => 'these tests are for release candidate testing'); + } +} + +# This file was automatically generated by Dist::Zilla::Plugin::Test::Pod::Coverage::Configurable. + +use Test::Pod::Coverage 1.08; +use Test::More 0.88; +use Pod::Coverage::TrustPod; + +my %skip = map { $_ => 1 } qw( ); + +my @modules; +for my $module ( all_modules() ) { + next if $skip{$module}; + + push @modules, $module; +} + +plan skip_all => 'All the modules we found were excluded from POD coverage test.' + unless @modules; + +plan tests => scalar @modules; + +my %trustme = (); + +for my $module ( sort @modules ) { + pod_coverage_ok( + $module, + { + coverage_class => 'Pod::Coverage::TrustPod', + trustme => $trustme{$module} || [], + }, + "pod coverage for $module" + ); +} + +done_testing(); diff --git a/t/release-pod-linkcheck.t b/t/release-pod-linkcheck.t new file mode 100644 index 0000000..654cf06 --- /dev/null +++ b/t/release-pod-linkcheck.t @@ -0,0 +1,28 @@ +#!perl + +BEGIN { + unless ($ENV{RELEASE_TESTING}) { + require Test::More; + Test::More::plan(skip_all => 'these tests are for release candidate testing'); + } +} + + +use strict; +use warnings; +use Test::More; + +foreach my $env_skip ( qw( + SKIP_POD_LINKCHECK +) ){ + plan skip_all => "\$ENV{$env_skip} is set, skipping" + if $ENV{$env_skip}; +} + +eval "use Test::Pod::LinkCheck"; +if ( $@ ) { + plan skip_all => 'Test::Pod::LinkCheck required for testing POD'; +} +else { + Test::Pod::LinkCheck->new->all_pod_ok; +} diff --git a/t/release-pod-no404s.t b/t/release-pod-no404s.t new file mode 100644 index 0000000..da185ec --- /dev/null +++ b/t/release-pod-no404s.t @@ -0,0 +1,29 @@ +#!perl + +BEGIN { + unless ($ENV{RELEASE_TESTING}) { + require Test::More; + Test::More::plan(skip_all => 'these tests are for release candidate testing'); + } +} + + +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(); +} diff --git a/t/release-pod-syntax.t b/t/release-pod-syntax.t new file mode 100644 index 0000000..cdd6a6c --- /dev/null +++ b/t/release-pod-syntax.t @@ -0,0 +1,14 @@ +#!perl + +BEGIN { + unless ($ENV{RELEASE_TESTING}) { + require Test::More; + Test::More::plan(skip_all => 'these tests are for release candidate testing'); + } +} + +# This file was automatically generated by Dist::Zilla::Plugin::PodSyntaxTests. +use Test::More; +use Test::Pod 1.41; + +all_pod_files_ok(); diff --git a/t/release-portability.t b/t/release-portability.t new file mode 100644 index 0000000..f0fd79f --- /dev/null +++ b/t/release-portability.t @@ -0,0 +1,19 @@ +#!perl + +BEGIN { + unless ($ENV{RELEASE_TESTING}) { + require Test::More; + Test::More::plan(skip_all => 'these tests are for release candidate testing'); + } +} + + +use strict; +use warnings; + +use Test::More; + +eval 'use Test::Portability::Files'; +plan skip_all => 'Test::Portability::Files required for testing portability' + if $@; +run_tests(); diff --git a/t/requested-fails.t b/t/requested-fails.t new file mode 100644 index 0000000..da34424 --- /dev/null +++ b/t/requested-fails.t @@ -0,0 +1,30 @@ +use strict; +use warnings; + +use Test::More 0.88; +use Test::Fatal 0.006; + +{ + package T; + + use strict; + use warnings; + + use lib 't/lib'; + + use Module::Implementation; + my $loader = Module::Implementation::build_loader_sub( + implementations => [ 'ImplFails1', 'Impl1' ], + symbols => [qw( return_42 )], + ); + + $ENV{T_IMPLEMENTATION} = 'ImplFails1'; + + ::like( + ::exception{ $loader->() }, + qr/Could not load T::ImplFails1/, + 'Got an exception when implementation requested in env value fails to load' + ); +} + +done_testing(); diff --git a/t/taint.t b/t/taint.t new file mode 100644 index 0000000..13f197a --- /dev/null +++ b/t/taint.t @@ -0,0 +1,48 @@ +#!perl -T + +use strict; +use warnings; + +use Test::Requires { + 'Test::Taint' => '0', +}; + +use Test::More 0.88; +use Test::Fatal 0.006; + +taint_checking_ok(); + +{ + package T; + + use strict; + use warnings; + + use lib 't/lib'; + + use Module::Implementation; + my $loader = Module::Implementation::build_loader_sub( + implementations => [ 'Impl1', 'Impl2' ], + symbols => ['return_42'], + ); + + ::taint( $ENV{T_IMPLEMENTATION} = 'Impl2' ); + + ::tainted_ok( $ENV{T_IMPLEMENTATION}, '$ENV{T_IMPLEMENTATION} is tainted' ); + + ::is( + ::exception{ $loader->() }, + undef, + 'no exception when implementation is specified in env var under taint mode' + ); +} + +{ + is( + Module::Implementation::implementation_for('T'), + 'Impl2', + 'T::_implementation returns implementation set in ENV' + ); +} + +done_testing(); |