summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@lorry>2014-10-04 17:35:57 +0000
committerLorry Tar Creator <lorry-tar-importer@lorry>2014-10-04 17:35:57 +0000
commita3341f774a4aa00765970301e259be818929a7cf (patch)
treef59eaff8b72b2ad1090f8ff3b8be4c89536db204
downloadExporter-Tiny-tarball-a3341f774a4aa00765970301e259be818929a7cf.tar.gz
-rw-r--r--CONTRIBUTING83
-rw-r--r--COPYRIGHT65
-rw-r--r--CREDITS6
-rw-r--r--Changes108
-rw-r--r--INSTALL38
-rw-r--r--LICENSE379
-rw-r--r--MANIFEST27
-rw-r--r--META.json76
-rw-r--r--META.yml41
-rw-r--r--Makefile.PL144
-rw-r--r--README421
-rw-r--r--SIGNATURE49
-rw-r--r--dist.ini3
-rw-r--r--doap.ttl348
-rw-r--r--examples/Example/Exporter.pm56
-rw-r--r--lib/Exporter/Shiny.pm111
-rw-r--r--lib/Exporter/Tiny.pm833
-rw-r--r--t/01basic.t38
-rw-r--r--t/02renaming.t50
-rw-r--r--t/03generators.t38
-rw-r--r--t/04into.t36
-rw-r--r--t/05shiny.t40
-rw-r--r--t/06notwant.t41
-rw-r--r--t/07regexp.t48
-rw-r--r--t/08tags.t66
-rw-r--r--t/09warnings.t83
-rw-r--r--t/10no.t54
27 files changed, 3282 insertions, 0 deletions
diff --git a/CONTRIBUTING b/CONTRIBUTING
new file mode 100644
index 0000000..ba115b4
--- /dev/null
+++ b/CONTRIBUTING
@@ -0,0 +1,83 @@
+NAME
+ CONTRIBUTING
+
+DESCRIPTION
+ If you're reading this document, that means you might be thinking about
+ helping me out with this project. Thanks!
+
+ Here's some ways you could help out:
+
+ * Bug reports
+
+ Found a bug? Great! (Well, not so great I suppose.)
+
+ The place to report them is <https://rt.cpan.org/>. Don't e-mail me
+ about it, as your e-mail is more than likely to get lost amongst the
+ spam.
+
+ An example script clearly demonstrating the bug (preferably written
+ using Test::More) would be greatly appreciated.
+
+ * Patches
+
+ If you've found a bug and written a fix for it, even better!
+
+ Generally speaking you should check out the latest copy of the code
+ from the source repository rather than using the CPAN distribution.
+ The file META.yml should contain a link to the source repository. If
+ not, then try <https://github.com/tobyink> or submit a bug report.
+ (As far as I'm concerned the lack of a link is a bug.) Many of my
+ distributions are also mirrored at <https://bitbucket.org/tobyink>.
+
+ To submit the patch, do a pull request on GitHub or Bitbucket, or
+ attach a diff file to a bug report. Unless otherwise stated, I'll
+ assume that your contributions are licensed under the same terms as
+ the rest of the project.
+
+ (If using git, feel free to work in a branch. For Mercurial, I'd
+ prefer bookmarks within the default branch.)
+
+ * Documentation
+
+ If there's anything unclear in the documentation, please submit this
+ as a bug report or patch as above.
+
+ Non-toy example scripts that I can bundle would also be appreciated.
+
+ * Translation
+
+ Translations of documentation would be welcome.
+
+ For translations of error messages and other strings embedded in the
+ code, check with me first. Sometimes the English strings may not in
+ a stable state, so it would be a waste of time translating them.
+
+ Coding Style
+ I tend to write using something approximating the Allman style, using
+ tabs for indentation and Unix-style line breaks.
+
+ * <http://en.wikipedia.org/wiki/Indent_style#Allman_style>
+
+ * <http://www.derkarl.org/why_to_tabs.html>
+
+ I nominally encode all source files as UTF-8, though in practice most of
+ them use a 7-bit-safe ASCII-compatible subset of UTF-8.
+
+AUTHOR
+ Toby Inkster <tobyink@cpan.org>.
+
+COPYRIGHT AND LICENCE
+ Copyright (c) 2012-2014 by Toby Inkster.
+
+ CONTRIBUTING is available under three different licences permitting its
+ redistribution: the CC-BY-SA_UK-2.0 licence, plus the same licences as
+ Perl itself, which is distributed under the GNU General Public Licence
+ version 1, and the Artistic Licence.
+
+ This file is licensed under the Creative Commons Attribution-ShareAlike
+ 2.0 UK: England & Wales License. To view a copy of this license, visit
+ <http://creativecommons.org/licenses/by-sa/2.0/uk/>.
+
+ This file is free software; you can redistribute it and/or modify it
+ under the same terms as the Perl 5 programming language system itself.
+
diff --git a/COPYRIGHT b/COPYRIGHT
new file mode 100644
index 0000000..a25d300
--- /dev/null
+++ b/COPYRIGHT
@@ -0,0 +1,65 @@
+Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
+Upstream-Name: Exporter-Tiny
+Upstream-Contact: Toby Inkster (TOBYINK) <tobyink@cpan.org>
+Source: https://metacpan.org/release/Exporter-Tiny
+
+Files: lib/Exporter/Shiny.pm
+ t/05shiny.t
+ t/06notwant.t
+ t/07regexp.t
+ t/08tags.t
+ t/09warnings.t
+ t/10no.t
+Copyright: This software is copyright (c) 2014 by Toby Inkster.
+License: GPL-1.0+ or Artistic-1.0
+
+Files: Changes
+ META.json
+ META.yml
+ doap.ttl
+Copyright: Copyright 2014 Toby Inkster.
+License: GPL-1.0+ or Artistic-1.0
+
+Files: CONTRIBUTING
+ INSTALL
+ LICENSE
+ examples/Example/Exporter.pm
+Copyright: Unknown
+License: Unknown
+
+Files: t/01basic.t
+ t/02renaming.t
+ t/03generators.t
+ t/04into.t
+Copyright: This software is copyright (c) 2013 by Toby Inkster.
+License: GPL-1.0+ or Artistic-1.0
+
+Files: COPYRIGHT
+ CREDITS
+ SIGNATURE
+Copyright: None
+License: public-domain
+
+Files: README
+ lib/Exporter/Tiny.pm
+Copyright: This software is copyright (c) 2013-2014 by Toby Inkster.
+License: GPL-1.0+ or Artistic-1.0
+
+Files: Makefile.PL
+ dist.ini
+Copyright: Copyright 2013 Toby Inkster.
+License: GPL-1.0+ or Artistic-1.0
+
+License: Artistic-1.0
+ This software is Copyright (c) 2014 by the copyright holder(s).
+
+ This is free software, licensed under:
+
+ The Artistic License 1.0
+
+License: GPL-1.0
+ This software is Copyright (c) 2014 by the copyright holder(s).
+
+ This is free software, licensed under:
+
+ The GNU General Public License, Version 1, February 1989
diff --git a/CREDITS b/CREDITS
new file mode 100644
index 0000000..db9fbfa
--- /dev/null
+++ b/CREDITS
@@ -0,0 +1,6 @@
+Maintainer:
+- Toby Inkster (TOBYINK) <tobyink@cpan.org>
+
+Thanks:
+- CHOCOLATEBOY <chocolateboy@cpan.org>
+
diff --git a/Changes b/Changes
new file mode 100644
index 0000000..2598ecb
--- /dev/null
+++ b/Changes
@@ -0,0 +1,108 @@
+Exporter-Tiny
+=============
+
+Created: 2013-09-05
+Home page: <https://metacpan.org/release/Exporter-Tiny>
+Bug tracker: <http://rt.cpan.org/Dist/Display.html?Queue=Exporter-Tiny>
+Maintainer: Toby Inkster (TOBYINK) <tobyink@cpan.org>
+
+0.042 2014-10-04
+
+ [ Documentation ]
+ - Document the warning emitted when you provide options to a function you
+ are unimporting.
+
+ [ Other ]
+ - Housekeeping on %TRACKED.
+
+0.041_02 2014-09-19
+
+ [ Bug Fixes ]
+ - Option validation needs to happen after expanding tags.
+
+0.041_01 2014-09-18
+
+ - Add an `unimport` feature.
+
+0.040 2014-09-17
+
+ [ Packaging ]
+ - Repackage as a stable release.
+
+0.039_01 2014-07-20
+
+ [ Documentation ]
+ - Document warning and error messages produced by Exporter::Tiny.
+
+ [ Other ]
+ - Exporter::Tiny would previously cause B.pm to be loaded into memory any
+ time it exported anything. It no longer does.
+ - No longer die when redefining locally defined subs.
+ - Warn when redefining any subs.
+
+0.038 2014-04-04
+
+0.037_03 2014-04-02
+
+ [ Bug Fixes ]
+ - Only attempt to merge hashes if we're sure they're both really hashes!
+
+0.037_02 2014-04-02
+
+ - Improved handling of hashrefs of options passed to tags, and hashrefs of
+ options found within %EXPORT_TAGS arrayrefs.
+
+0.037_01 2014-03-26
+
+ [ Documentation ]
+ - Fix minor error in documentation of generators.
+
+ [ Other ]
+ - Added: Support Exporter.pm's import negation syntax qw( !foo ).
+ - Added: Support Exporter.pm's regexp import syntax qw( /foo/ ).
+
+0.036 2014-03-11
+
+0.035_02 2014-03-01
+
+ [ Documentation ]
+ - Document exactly what Exporter::Shiny is supposed to do.
+
+ [ Test Suite ]
+ - Make t/02renaming.t less noisy.
+
+0.035_01 2014-03-01
+
+ [ Packaging ]
+ - Explicitly list minimum Perl version: 5.6.1.
+
+0.034 2014-01-19
+
+0.033_01 2014-01-19
+
+ - Added: Add a new wrapper module called Exporter::Shiny.
+
+0.032 2013-12-30
+
+0.031_01 2013-12-30
+
+ [ Test Suite ]
+ - No longer require a recent version of Test::More; the Test::More bundled
+ with Perl 5.6.2 should suffice.
+
+0.030 2013-09-26
+
+ [ Test Suite ]
+ - Test for the 'into' option.
+
+0.029_01 2013-09-26
+
+ [ Documentation ]
+ - Exporter::TypeTiny is being retired, so modify documentation and
+ distribution metadata for Exporter::Tiny to no longer point there.
+
+0.026 2013-09-05 Initial release
+
+ [ Packaging ]
+ - Split Exporter::Tiny out from Exporter::TypeTiny.
+ CHOCOLATEBOY++
diff --git a/INSTALL b/INSTALL
new file mode 100644
index 0000000..f15a3b0
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,38 @@
+ Installing Exporter-Tiny should be straightforward.
+
+INSTALLATION WITH CPANMINUS
+ If you have cpanm, you only need one line:
+
+ % cpanm Exporter::Tiny
+
+ 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 Exporter::Tiny
+
+INSTALLATION WITH THE CPAN SHELL
+ Alternatively, if your CPAN shell is set up, you should just be able to
+ do:
+
+ % cpan Exporter::Tiny
+
+MANUAL INSTALLATION
+ As a last resort, you can manually install it. Download the tarball and
+ unpack it.
+
+ Consult the file META.json for a list of pre-requisites. Install these
+ first.
+
+ To build Exporter-Tiny:
+
+ % 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
+
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..351778e
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,379 @@
+This software is copyright (c) 2014 by Toby Inkster.
+
+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) 2014 by Toby Inkster.
+
+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.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <name of author>
+
+ 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.
+
+ <signature of Ty Coon>, 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) 2014 by Toby Inkster.
+
+This is free software, licensed under:
+
+ The Artistic License 1.0
+
+The Artistic License
+
+Preamble
+
+The intent of this document is to state the conditions under which a Package
+may be copied, such that the Copyright Holder maintains some semblance of
+artistic control over the development of the package, while giving the users of
+the package the right to use and distribute the Package in a more-or-less
+customary fashion, plus the right to make reasonable modifications.
+
+Definitions:
+
+ - "Package" refers to the collection of files distributed by the Copyright
+ Holder, and derivatives of that collection of files created through
+ textual modification.
+ - "Standard Version" refers to such a Package if it has not been modified,
+ or has been modified in accordance with the wishes of the Copyright
+ Holder.
+ - "Copyright Holder" is whoever is named in the copyright or copyrights for
+ the package.
+ - "You" is you, if you're thinking about copying or distributing this Package.
+ - "Reasonable copying fee" is whatever you can justify on the basis of media
+ cost, duplication charges, time of people involved, and so on. (You will
+ not be required to justify it to the Copyright Holder, but only to the
+ computing community at large as a market that must bear the fee.)
+ - "Freely Available" means that no fee is charged for the item itself, though
+ there may be fees involved in handling the item. It also means that
+ recipients of the item may redistribute it under the same conditions they
+ received it.
+
+1. You may make and give away verbatim copies of the source form of the
+Standard Version of this Package without restriction, provided that you
+duplicate all of the original copyright notices and associated disclaimers.
+
+2. You may apply bug fixes, portability fixes and other modifications derived
+from the Public Domain or from the Copyright Holder. A Package modified in such
+a way shall still be considered the Standard Version.
+
+3. You may otherwise modify your copy of this Package in any way, provided that
+you insert a prominent notice in each changed file stating how and when you
+changed that file, and provided that you do at least ONE of the following:
+
+ a) place your modifications in the Public Domain or otherwise make them
+ Freely Available, such as by posting said modifications to Usenet or an
+ equivalent medium, or placing the modifications on a major archive site
+ such as ftp.uu.net, or by allowing the Copyright Holder to include your
+ modifications in the Standard Version of the Package.
+
+ b) use the modified Package only within your corporation or organization.
+
+ c) rename any non-standard executables so the names do not conflict with
+ standard executables, which must also be provided, and provide a separate
+ manual page for each non-standard executable that clearly documents how it
+ differs from the Standard Version.
+
+ d) make other distribution arrangements with the Copyright Holder.
+
+4. You may distribute the programs of this Package in object code or executable
+form, provided that you do at least ONE of the following:
+
+ a) distribute a Standard Version of the executables and library files,
+ together with instructions (in the manual page or equivalent) on where to
+ get the Standard Version.
+
+ b) accompany the distribution with the machine-readable source of the Package
+ with your modifications.
+
+ c) accompany any non-standard executables with their corresponding Standard
+ Version executables, giving the non-standard executables non-standard
+ names, and clearly documenting the differences in manual pages (or
+ equivalent), together with instructions on where to get the Standard
+ Version.
+
+ d) make other distribution arrangements with the Copyright Holder.
+
+5. You may charge a reasonable copying fee for any distribution of this
+Package. You may charge any fee you choose for support of this Package. You
+may not charge a fee for this Package itself. However, you may distribute this
+Package in aggregate with other (possibly commercial) programs as part of a
+larger (possibly commercial) software distribution provided that you do not
+advertise this Package as a product of your own.
+
+6. The scripts and library files supplied as input to or produced as output
+from the programs of this Package do not automatically fall under the copyright
+of this Package, but belong to whomever generated them, and may be sold
+commercially, and may be aggregated with this Package.
+
+7. C or perl subroutines supplied by you and linked into this Package shall not
+be considered part of this Package.
+
+8. The name of the Copyright Holder may not be used to endorse or promote
+products derived from this software without specific prior written permission.
+
+9. THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+
+The End
+
diff --git a/MANIFEST b/MANIFEST
new file mode 100644
index 0000000..26d4441
--- /dev/null
+++ b/MANIFEST
@@ -0,0 +1,27 @@
+CONTRIBUTING
+COPYRIGHT
+CREDITS
+Changes
+INSTALL
+LICENSE
+MANIFEST
+META.json
+META.yml
+Makefile.PL
+README
+SIGNATURE
+dist.ini
+doap.ttl
+examples/Example/Exporter.pm
+lib/Exporter/Shiny.pm
+lib/Exporter/Tiny.pm
+t/01basic.t
+t/02renaming.t
+t/03generators.t
+t/04into.t
+t/05shiny.t
+t/06notwant.t
+t/07regexp.t
+t/08tags.t
+t/09warnings.t
+t/10no.t
diff --git a/META.json b/META.json
new file mode 100644
index 0000000..79ece81
--- /dev/null
+++ b/META.json
@@ -0,0 +1,76 @@
+{
+ "abstract" : "an exporter with the features of Sub::Exporter but only core dependencies",
+ "author" : [
+ "Toby Inkster (TOBYINK) <tobyink@cpan.org>"
+ ],
+ "dynamic_config" : 0,
+ "generated_by" : "Dist::Inkt::Profile::TOBYINK version 0.023, CPAN::Meta::Converter version 2.140640",
+ "keywords" : [],
+ "license" : [
+ "perl_5"
+ ],
+ "meta-spec" : {
+ "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec",
+ "version" : "2"
+ },
+ "name" : "Exporter-Tiny",
+ "no_index" : {
+ "directory" : [
+ "eg",
+ "examples",
+ "inc",
+ "t",
+ "xt"
+ ]
+ },
+ "optional_features" : {},
+ "prereqs" : {
+ "configure" : {
+ "requires" : {
+ "ExtUtils::MakeMaker" : "6.17"
+ }
+ },
+ "runtime" : {
+ "requires" : {
+ "perl" : "5.006001"
+ }
+ },
+ "test" : {
+ "recommends" : {
+ "Test::Fatal" : "0",
+ "Test::Warnings" : "0"
+ },
+ "requires" : {
+ "Test::More" : "0.47"
+ }
+ }
+ },
+ "provides" : {
+ "Exporter::Shiny" : {
+ "file" : "lib/Exporter/Shiny.pm",
+ "version" : "0.042"
+ },
+ "Exporter::Tiny" : {
+ "file" : "lib/Exporter/Tiny.pm",
+ "version" : "0.042"
+ }
+ },
+ "release_status" : "stable",
+ "resources" : {
+ "bugtracker" : {
+ "web" : "http://rt.cpan.org/Dist/Display.html?Queue=Exporter-Tiny"
+ },
+ "homepage" : "https://metacpan.org/release/Exporter-Tiny",
+ "license" : [
+ "http://dev.perl.org/licenses/"
+ ],
+ "repository" : {
+ "type" : "git",
+ "url" : "git://github.com/tobyink/p5-exporter-tiny.git",
+ "web" : "https://github.com/tobyink/p5-exporter-tiny"
+ },
+ "x_IRC" : "irc://irc.perl.org/#moops",
+ "x_identifier" : "http://purl.org/NET/cpan-uri/dist/Exporter-Tiny/project"
+ },
+ "version" : "0.042"
+}
diff --git a/META.yml b/META.yml
new file mode 100644
index 0000000..d83f602
--- /dev/null
+++ b/META.yml
@@ -0,0 +1,41 @@
+---
+abstract: 'an exporter with the features of Sub::Exporter but only core dependencies'
+author:
+ - 'Toby Inkster (TOBYINK) <tobyink@cpan.org>'
+build_requires:
+ Test::More: '0.47'
+configure_requires:
+ ExtUtils::MakeMaker: '6.17'
+dynamic_config: 0
+generated_by: 'Dist::Inkt::Profile::TOBYINK version 0.023, CPAN::Meta::Converter version 2.140640'
+keywords: []
+license: perl
+meta-spec:
+ url: http://module-build.sourceforge.net/META-spec-v1.4.html
+ version: '1.4'
+name: Exporter-Tiny
+no_index:
+ directory:
+ - eg
+ - examples
+ - inc
+ - t
+ - xt
+optional_features: {}
+provides:
+ Exporter::Shiny:
+ file: lib/Exporter/Shiny.pm
+ version: '0.042'
+ Exporter::Tiny:
+ file: lib/Exporter/Tiny.pm
+ version: '0.042'
+requires:
+ perl: '5.006001'
+resources:
+ IRC: irc://irc.perl.org/#moops
+ Identifier: http://purl.org/NET/cpan-uri/dist/Exporter-Tiny/project
+ bugtracker: http://rt.cpan.org/Dist/Display.html?Queue=Exporter-Tiny
+ homepage: https://metacpan.org/release/Exporter-Tiny
+ license: http://dev.perl.org/licenses/
+ repository: git://github.com/tobyink/p5-exporter-tiny.git
+version: '0.042'
diff --git a/Makefile.PL b/Makefile.PL
new file mode 100644
index 0000000..4578ac2
--- /dev/null
+++ b/Makefile.PL
@@ -0,0 +1,144 @@
+use strict;
+use ExtUtils::MakeMaker 6.17;
+
+my $EUMM = eval( $ExtUtils::MakeMaker::VERSION );
+
+my $meta = {
+ "abstract" => "an exporter with the features of Sub::Exporter but only core dependencies",
+ "author" => ["Toby Inkster (TOBYINK) <tobyink\@cpan.org>"],
+ "dynamic_config" => 0,
+ "generated_by" => "Dist::Inkt::Profile::TOBYINK version 0.023, CPAN::Meta::Converter version 2.140640",
+ "keywords" => [],
+ "license" => ["perl_5"],
+ "meta-spec" => {
+ url => "http://search.cpan.org/perldoc?CPAN::Meta::Spec",
+ version => 2,
+ },
+ "name" => "Exporter-Tiny",
+ "no_index" => { directory => ["eg", "examples", "inc", "t", "xt"] },
+ "prereqs" => {
+ configure => { requires => { "ExtUtils::MakeMaker" => 6.17 } },
+ runtime => { requires => { perl => 5.006001 } },
+ test => {
+ recommends => { "Test::Fatal" => 0, "Test::Warnings" => 0 },
+ requires => { "Test::More" => 0.47 },
+ },
+ },
+ "provides" => {
+ "Exporter::Shiny" => { file => "lib/Exporter/Shiny.pm", version => 0.042 },
+ "Exporter::Tiny" => { file => "lib/Exporter/Tiny.pm", version => 0.042 },
+ },
+ "release_status" => "stable",
+ "resources" => {
+ bugtracker => {
+ web => "http://rt.cpan.org/Dist/Display.html?Queue=Exporter-Tiny",
+ },
+ homepage => "https://metacpan.org/release/Exporter-Tiny",
+ license => ["http://dev.perl.org/licenses/"],
+ repository => {
+ type => "git",
+ url => "git://github.com/tobyink/p5-exporter-tiny.git",
+ web => "https://github.com/tobyink/p5-exporter-tiny",
+ },
+ x_identifier => "http://purl.org/NET/cpan-uri/dist/Exporter-Tiny/project",
+ x_IRC => "irc://irc.perl.org/#moops",
+ },
+ "version" => 0.042,
+};
+
+my %dynamic_config;
+
+my %WriteMakefileArgs = (
+ ABSTRACT => $meta->{abstract},
+ AUTHOR => ($EUMM >= 6.5702 ? $meta->{author} : $meta->{author}[0]),
+ DISTNAME => $meta->{name},
+ VERSION => $meta->{version},
+ EXE_FILES => [ map $_->{file}, values %{ $meta->{x_provides_scripts} || {} } ],
+ NAME => do { my $n = $meta->{name}; $n =~ s/-/::/g; $n },
+ test => { TESTS => "t/*.t" },
+ %dynamic_config,
+);
+
+$WriteMakefileArgs{LICENSE} = $meta->{license}[0] if $EUMM >= 6.3001;
+
+sub deps
+{
+ my %r;
+ for my $stage (@_)
+ {
+ for my $dep (keys %{$meta->{prereqs}{$stage}{requires}})
+ {
+ next if $dep eq 'perl';
+ my $ver = $meta->{prereqs}{$stage}{requires}{$dep};
+ $r{$dep} = $ver if !exists($r{$dep}) || $ver >= $r{$dep};
+ }
+ }
+ \%r;
+}
+
+my ($build_requires, $configure_requires, $runtime_requires, $test_requires);
+if ($EUMM >= 6.6303)
+{
+ $WriteMakefileArgs{BUILD_REQUIRES} ||= deps('build');
+ $WriteMakefileArgs{CONFIGURE_REQUIRES} ||= deps('configure');
+ $WriteMakefileArgs{TEST_REQUIRES} ||= deps('test');
+ $WriteMakefileArgs{PREREQ_PM} ||= deps('runtime');
+}
+elsif ($EUMM >= 6.5503)
+{
+ $WriteMakefileArgs{BUILD_REQUIRES} ||= deps('build', 'test');
+ $WriteMakefileArgs{CONFIGURE_REQUIRES} ||= deps('configure');
+ $WriteMakefileArgs{PREREQ_PM} ||= deps('runtime');
+}
+elsif ($EUMM >= 6.52)
+{
+ $WriteMakefileArgs{CONFIGURE_REQUIRES} ||= deps('configure');
+ $WriteMakefileArgs{PREREQ_PM} ||= deps('runtime', 'build', 'test');
+}
+else
+{
+ $WriteMakefileArgs{PREREQ_PM} ||= deps('configure', 'build', 'test', 'runtime');
+}
+
+{
+ my ($minperl) = reverse sort(
+ grep defined && /^[0-9]+(\.[0-9]+)?$/,
+ map $meta->{prereqs}{$_}{requires}{perl},
+ qw( configure build runtime )
+ );
+
+ if (defined($minperl))
+ {
+ die "Installing $meta->{name} requires Perl >= $minperl"
+ unless $] >= $minperl;
+
+ $WriteMakefileArgs{MIN_PERL_VERSION} ||= $minperl
+ if $EUMM >= 6.48;
+ }
+}
+
+sub FixMakefile
+{
+ return unless -d 'inc';
+ my $file = shift;
+
+ local *MAKEFILE;
+ open MAKEFILE, "< $file" or die "FixMakefile: Couldn't open $file: $!; bailing out";
+ my $makefile = do { local $/; <MAKEFILE> };
+ close MAKEFILE or die $!;
+
+ $makefile =~ s/\b(test_harness\(\$\(TEST_VERBOSE\), )/$1'inc', /;
+ $makefile =~ s/( -I\$\(INST_ARCHLIB\))/ -Iinc$1/g;
+ $makefile =~ s/( "-I\$\(INST_LIB\)")/ "-Iinc"$1/g;
+ $makefile =~ s/^(FULLPERL = .*)/$1 "-Iinc"/m;
+ $makefile =~ s/^(PERL = .*)/$1 "-Iinc"/m;
+
+ open MAKEFILE, "> $file" or die "FixMakefile: Couldn't open $file: $!; bailing out";
+ print MAKEFILE $makefile or die $!;
+ close MAKEFILE or die $!;
+}
+
+my $mm = WriteMakefile(%WriteMakefileArgs);
+FixMakefile($mm->{FIRST_MAKEFILE} || 'Makefile');
+exit(0);
+
diff --git a/README b/README
new file mode 100644
index 0000000..6c702ef
--- /dev/null
+++ b/README
@@ -0,0 +1,421 @@
+NAME
+ Exporter::Tiny - an exporter with the features of Sub::Exporter but only
+ core dependencies
+
+SYNOPSIS
+ package MyUtils;
+ use base "Exporter::Tiny";
+ our @EXPORT = qw(frobnicate);
+ sub frobnicate { my $n = shift; ... }
+ 1;
+
+ package MyScript;
+ use MyUtils "frobnicate" => { -as => "frob" };
+ print frob(42);
+ exit;
+
+DESCRIPTION
+ Exporter::Tiny supports many of Sub::Exporter's external-facing features
+ including renaming imported functions with the `-as`, `-prefix` and
+ `-suffix` options; explicit destinations with the `into` option; and
+ alternative installers with the `installler` option. But it's written in
+ only about 40% as many lines of code and with zero non-core dependencies.
+
+ Its internal-facing interface is closer to Exporter.pm, with configuration
+ done through the @EXPORT, @EXPORT_OK and %EXPORT_TAGS package variables.
+
+ Exporter::Tiny performs most of its internal duties (including resolution
+ of tag names to sub names, resolution of sub names to coderefs, and
+ installation of coderefs into the target package) as method calls, which
+ means they can be overridden to provide interesting behaviour.
+
+ Utility Functions
+ These are really for internal use, but can be exported if you need them.
+
+ `mkopt(\@array)`
+ Similar to `mkopt` from Data::OptList. It doesn't support all the
+ fancy options that Data::OptList does (`moniker`, `require_unique`,
+ `must_be` and `name_test`) but runs about 50% faster.
+
+ `mkopt_hash(\@array)`
+ Similar to `mkopt_hash` from Data::OptList. See also `mkopt`.
+
+TIPS AND TRICKS IMPORTING FROM EXPORTER::TINY
+ For the purposes of this discussion we'll assume we have a module called
+ `MyUtils` which exports one function, `frobnicate`. `MyUtils` inherits
+ from Exporter::Tiny.
+
+ Many of these tricks may seem familiar from Sub::Exporter. That is
+ intentional. Exporter::Tiny doesn't attempt to provide every feature of
+ Sub::Exporter, but where it does it usually uses a fairly similar API.
+
+ Basic importing
+ # import "frobnicate" function
+ use MyUtils "frobnicate";
+
+ # import all functions that MyUtils offers
+ use MyUtils -all;
+
+ Renaming imported functions
+ # call it "frob"
+ use MyUtils "frobnicate" => { -as => "frob" };
+
+ # call it "my_frobnicate"
+ use MyUtils "frobnicate" => { -prefix => "my_" };
+
+ # can set a prefix for *all* functions imported from MyUtils
+ # by placing the options hashref *first*.
+ use MyUtils { prefix => "my_" }, "frobnicate";
+ # (note the lack of hyphen before `prefix`.)
+
+ # call it "frobnicate_util"
+ use MyUtils "frobnicate" => { -suffix => "_util" };
+ use MyUtils { suffix => "_util" }, "frobnicate";
+
+ # import it twice with two different names
+ use MyUtils
+ "frobnicate" => { -as => "frob" },
+ "frobnicate" => { -as => "frbnct" };
+
+ Lexical subs
+ {
+ use Sub::Exporter::Lexical lexical_installer => { -as => "lex" };
+ use MyUtils { installer => lex }, "frobnicate";
+
+ frobnicate(...); # ok
+ }
+
+ frobnicate(...); # not ok
+
+ Import functions into another package
+ use MyUtils { into => "OtherPkg" }, "frobnicate";
+
+ OtherPkg::frobincate(...);
+
+ Import functions into a scalar
+ my $func;
+ use MyUtils "frobnicate" => { -as => \$func };
+
+ $func->(...);
+
+ Import functions into a hash
+ OK, Sub::Exporter doesn't do this...
+
+ my %funcs;
+ use MyUtils { into => \%funcs }, "frobnicate";
+
+ $funcs{frobnicate}->(...);
+
+ DO NOT WANT!
+ This imports everything except "frobnicate":
+
+ use MyUtils qw( -all !frobnicate );
+
+ Negated imports always "win", so the following will not import
+ "frobnicate", no matter how many times you repeat it...
+
+ use MyUtils qw( !frobnicate frobnicate frobnicate frobnicate );
+
+ Importing by regexp
+ Here's how you could import all functions beginning with an "f":
+
+ use MyUtils qw( /^F/i );
+
+ Or import everything except functions beginning with a "z":
+
+ use MyUtils qw( -all !/^Z/i );
+
+ Note that regexps are always supplied as *strings* starting with "/", and
+ not as quoted regexp references (`qr/.../`).
+
+ Unimporting
+ You can unimport the functions that MyUtils added to your namespace:
+
+ no MyUtils;
+
+ Or just specific ones:
+
+ no MyUtils qw(frobnicate);
+
+ If you renamed a function when you imported it, you should unimport by the
+ new name:
+
+ use MyUtils frobnicate => { -as => "frob" };
+ ...;
+ no MyUtils "frob";
+
+ Unimporting using tags and regexps should mostly do what you want.
+
+TIPS AND TRICKS EXPORTING USING EXPORTER::TINY
+ Simple configuration works the same as Exporter; inherit from this module,
+ and use the @EXPORT, @EXPORT_OK and %EXPORT_TAGS package variables to list
+ subs to export.
+
+ Generators
+ Exporter::Tiny has always allowed exported subs to be generated (like
+ Sub::Exporter), but until version 0.025 did not have an especially nice
+ API for it.
+
+ Now, it's easy. If you want to generate a sub `foo` to export, list it in
+ @EXPORT or @EXPORT_OK as usual, and then simply give your exporter module
+ a class method called `_generate_foo`.
+
+ push @EXPORT_OK, 'foo';
+
+ sub _generate_foo {
+ my $class = shift;
+ my ($name, $args, $globals) = @_;
+
+ return sub {
+ ...;
+ }
+ }
+
+ You can also generate tags:
+
+ my %constants;
+ BEGIN {
+ %constants = (FOO => 1, BAR => 2);
+ }
+ use constant \%constants;
+
+ $EXPORT_TAGS{constants} = sub {
+ my $class = shift;
+ my ($name, $args, $globals) = @_;
+
+ return keys(%constants);
+ };
+
+ Overriding Internals
+ An important difference between Exporter and Exporter::Tiny is that the
+ latter calls all its internal functions as *class methods*. This means
+ that your subclass can *override them* to alter their behaviour.
+
+ The following methods are available to be overridden. Despite being named
+ with a leading underscore, they are considered public methods. (The
+ underscore is there to avoid accidentally colliding with any of your own
+ function names.)
+
+ `_exporter_validate_opts($globals)`
+ This method is called once each time `import` is called. It is passed
+ a reference to the global options hash. (That is, the optional leading
+ hashref in the `use` statement, where the `into` and `installer`
+ options can be provided.)
+
+ You may use this method to munge the global options, or validate them,
+ throwing an exception or printing a warning.
+
+ The default implementation does nothing interesting.
+
+ `_exporter_validate_unimport_opts($globals)`
+ Like `_exporter_validate_opts`, but called for `unimport`.
+
+ `_exporter_merge_opts($tag_opts, $globals, @exports)`
+ Called to merge options which have been provided for a tag into the
+ options provided for the exports that the tag expanded to.
+
+ `_exporter_expand_tag($name, $args, $globals)`
+ This method is called to expand an import tag (e.g. ":constants"). It
+ is passed the tag name (minus the leading ":"), an optional hashref of
+ options (like `{ -prefix => "foo_" }`), and the global options
+ hashref.
+
+ It is expected to return a list of ($name, $args) arrayref pairs.
+ These names can be sub names to export, or further tag names (which
+ must have their ":"). If returning tag names, be careful to avoid
+ creating a tag expansion loop!
+
+ The default implementation uses %EXPORT_TAGS to expand tags, and
+ provides fallbacks for the `:default` and `:all` tags.
+
+ `_exporter_expand_regexp($regexp, $args, $globals)`
+ Like `_exporter_expand_regexp`, but given a regexp-like string instead
+ of a tag name.
+
+ The default implementation greps through @EXPORT_OK for imports, and
+ the list of already-imported functions for exports.
+
+ `_exporter_expand_sub($name, $args, $globals)`
+ This method is called to translate a sub name to a hash of name =>
+ coderef pairs for exporting to the caller. In general, this would just
+ be a hash with one key and one value, but, for example, Type::Library
+ overrides this method so that "+Foo" gets expanded to:
+
+ (
+ Foo => sub { $type },
+ is_Foo => sub { $type->check(@_) },
+ to_Foo => sub { $type->assert_coerce(@_) },
+ assert_Foo => sub { $type->assert_return(@_) },
+ )
+
+ The default implementation checks that the name is allowed to be
+ exported (using the `_exporter_permitted_regexp` method), gets the
+ coderef using the generator if there is one (or by calling `can` on
+ your exporter otherwise) and calls `_exporter_fail` if it's unable to
+ generate or retrieve a coderef.
+
+ `_exporter_permitted_regexp($globals)`
+ This method is called to retrieve a regexp for validating the names of
+ exportable subs. If a sub doesn't match the regexp, then the default
+ implementation of `_exporter_expand_sub` will refuse to export it. (Of
+ course, you may override the default `_exporter_expand_sub`.)
+
+ The default implementation of this method assembles the regexp from
+ @EXPORT and @EXPORT_OK.
+
+ `_exporter_fail($name, $args, $globals)`
+ Called by `_exporter_expand_sub` if it can't find a coderef to export.
+
+ The default implementation just throws an exception. But you could
+ emit a warning instead, or just ignore the failed export.
+
+ If you don't throw an exception then you should be aware that this
+ method is called in list context, and any list it returns will be
+ treated as an `_exporter_expand_sub`-style hash of names and coderefs
+ for export.
+
+ `_exporter_install_sub($name, $args, $globals, $coderef)`
+ This method actually installs the exported sub into its new
+ destination. Its return value is ignored.
+
+ The default implementation handles sub renaming (i.e. the `-as`,
+ `-prefix` and `-suffix` functions. This method does a lot of stuff; if
+ you need to override it, it's probably a good idea to just pre-process
+ the arguments and then call the super method rather than trying to
+ handle all of it yourself.
+
+ `_exporter_uninstall_sub($name, $args, $globals)`
+ The opposite of `_exporter_install_sub`.
+
+DIAGNOSTICS
+ Overwriting existing sub '%s::%s' with sub '%s' exported by %s
+ A warning issued if Exporter::Tiny is asked to export a symbol which
+ will result in an existing sub being overwritten. This warning can be
+ suppressed using either of the following:
+
+ use MyUtils { replace => 1 }, "frobnicate";
+ use MyUtils "frobnicate" => { -replace => 1 };
+
+ Or can be upgraded to a fatal error:
+
+ use MyUtils { replace => "die" }, "frobnicate";
+ use MyUtils "frobnicate" => { -replace => "die" };
+
+ Refusing to overwrite existing sub '%s::%s' with sub '%s' exported by %s
+ The fatal version of the above warning.
+
+ Could not find sub '%s' exported by %s
+ You requested to import a sub which the package does not provide.
+
+ Cannot provide an -as option for tags
+ Because a tag may provide more than one function, it does not make
+ sense to request a single name for it. Instead use `-prefix` or
+ `-suffix`.
+
+ Passing options to unimport '%s' makes no sense
+ When you import a sub, it occasionally makes sense to pass some
+ options for it. However, when unimporting, options do nothing, so this
+ warning is issued.
+
+HISTORY
+ Type::Library had a bunch of custom exporting code which poked coderefs
+ into its caller's stash. It needed this to be something more powerful than
+ most exporters so that it could switch between exporting Moose, Mouse and
+ Moo-compatible objects on request. Sub::Exporter would have been capable,
+ but had too many dependencies for the Type::Tiny project.
+
+ Meanwhile Type::Utils, Types::TypeTiny and Test::TypeTiny each used the
+ venerable Exporter.pm. However, this meant they were unable to use the
+ features like Sub::Exporter-style function renaming which I'd built into
+ Type::Library:
+
+ ## import "Str" but rename it to "String".
+ use Types::Standard "Str" => { -as => "String" };
+
+ And so I decided to factor out code that could be shared by all
+ Type-Tiny's exporters into a single place: Exporter::TypeTiny.
+
+ As of version 0.026, Exporter::TypeTiny was also made available as
+ Exporter::Tiny, distributed independently on CPAN. CHOCOLATEBOY had
+ convinced me that it was mature enough to live a life of its own.
+
+ As of version 0.030, Type-Tiny depends on Exporter::Tiny and
+ Exporter::TypeTiny is being phased out.
+
+OBLIGATORY EXPORTER COMPARISON
+ Exporting is unlikely to be your application's performance bottleneck, but
+ nonetheless here are some comparisons.
+
+ Comparative sizes according to Devel::SizeMe:
+
+ Exporter 217.1Kb
+ Sub::Exporter::Progressive 263.2Kb
+ Exporter::Tiny 267.7Kb
+ Exporter + Exporter::Heavy 281.5Kb
+ Exporter::Renaming 406.2Kb
+ Sub::Exporter 701.0Kb
+
+ Performance exporting a single sub:
+
+ Rate SubExp ExpTiny SubExpProg ExpPM
+ SubExp 2489/s -- -56% -85% -88%
+ ExpTiny 5635/s 126% -- -67% -72%
+ SubExpProg 16905/s 579% 200% -- -16%
+ ExpPM 20097/s 707% 257% 19% --
+
+ (Exporter::Renaming globally changes the behaviour of Exporter.pm, so
+ could not be included in the same benchmarks.)
+
+ (Non-Core) Dependencies:
+
+ Exporter -1
+ Exporter::Renaming 0
+ Exporter::Tiny 0
+ Sub::Exporter::Progressive 0
+ Sub::Exporter 3
+
+ Features:
+
+ ExpPM ExpTiny SubExp SubExpProg
+ Can export code symbols............. Yes Yes Yes Yes
+ Can export non-code symbols......... Yes
+ Groups/tags......................... Yes Yes Yes Yes
+ Export by regexp.................... Yes Yes
+ Bang prefix......................... Yes Yes
+ Allows renaming of subs............. Yes Yes Maybe
+ Install code into scalar refs....... Yes Yes Maybe
+ Can be passed an "into" parameter... Yes Yes Maybe
+ Can be passed an "installer" sub.... Yes Yes Maybe
+ Config avoids package variables..... Yes
+ Supports generators................. Yes Yes
+ Sane API for generators............. Yes Yes
+ Unimport............................ Yes
+
+ (Certain Sub::Exporter::Progressive features are only available if
+ Sub::Exporter is installed.)
+
+BUGS
+ Please report any bugs to
+ <http://rt.cpan.org/Dist/Display.html?Queue=Exporter-Tiny>.
+
+SUPPORT
+ IRC: support is available through in the *#moops* channel on irc.perl.org
+ <http://www.irc.perl.org/channels.html>.
+
+SEE ALSO
+ Exporter::Shiny, Sub::Exporter, Exporter.
+
+AUTHOR
+ Toby Inkster <tobyink@cpan.org>.
+
+COPYRIGHT AND LICENCE
+ This software is copyright (c) 2013-2014 by Toby Inkster.
+
+ This is free software; you can redistribute it and/or modify it under the
+ same terms as the Perl 5 programming language system itself.
+
+DISCLAIMER OF WARRANTIES
+ 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.
+
diff --git a/SIGNATURE b/SIGNATURE
new file mode 100644
index 0000000..4d30a89
--- /dev/null
+++ b/SIGNATURE
@@ -0,0 +1,49 @@
+This file contains message digests of all files listed in MANIFEST,
+signed via the Module::Signature module, version 0.73.
+
+To verify the content in this distribution, first make sure you have
+Module::Signature installed, then type:
+
+ % cpansign -v
+
+It will check each file's integrity, as well as the signature's
+validity. If "==> Signature verified OK! <==" is not displayed,
+the distribution may already have been compromised, and you should
+not run its Makefile.PL or Build.PL.
+
+-----BEGIN PGP SIGNED MESSAGE-----
+Hash: SHA1
+
+SHA1 33317486c4fa2cf7fec85bf92ed38ac0f64233a0 CONTRIBUTING
+SHA1 5980cc638348a4f7438480d881a82ae5e17a1630 COPYRIGHT
+SHA1 e3b0c464bb56d4285fa64e31a70b301692dd825c CREDITS
+SHA1 5c7b2ac127f2c84b4bac86a882a671fe17a933e3 Changes
+SHA1 3b20e9835f489bbf71b1deb6aa7c10729482aa77 INSTALL
+SHA1 34f5e12514b91055de4b164a1f2327ef5c30ba53 LICENSE
+SHA1 7d98e1b385b7b5d70cb9a1497eea3b233f4baa8a MANIFEST
+SHA1 525d4669e3507fc769ab765d6438218af3e9adbb META.json
+SHA1 e50e4613cc1d1abd87c290d1f2953eedad430de2 META.yml
+SHA1 1c9cf0c5db5b9abf7a137c2db5eebd93baafce48 Makefile.PL
+SHA1 29f2538f2e202b70d54cf08d0d7499fa7ddf4c5d README
+SHA1 a43593d3e3a79c5f455977ba75083d9f191f6af6 dist.ini
+SHA1 066ce57aee9422a1789f0b42a968b3bb16a4c117 doap.ttl
+SHA1 3f65666b300ab7e7a1e5e25fb69e4ce6675e0f63 examples/Example/Exporter.pm
+SHA1 90df17b2a1b5cf0ddf5e81d7f8c6fcdf6152f800 lib/Exporter/Shiny.pm
+SHA1 57ff9abef5131446f439a23224522805307fc743 lib/Exporter/Tiny.pm
+SHA1 6ba2757140a1c118ae5bac4c10ea8a6275ee15f2 t/01basic.t
+SHA1 8b9c883098fbdaf8999c6f8f909a79297870af86 t/02renaming.t
+SHA1 103845d83b41f8d3c503d50e9d6012790b25f77f t/03generators.t
+SHA1 6a20cb44b8b22885209f6c3f30cbcf5adb80c52c t/04into.t
+SHA1 e50bb7649f42c23b8873dd2e72ef63d85e443b28 t/05shiny.t
+SHA1 8c545aab416cd36ee4fde0cc50cf6b59200a9aac t/06notwant.t
+SHA1 803a876d8e5e5b5af567f7a3a6e7a1071a4a48ed t/07regexp.t
+SHA1 dbce3f55c87fefdfe5abba21afa5a9c9a9a08cf0 t/08tags.t
+SHA1 9cc0bdbc9fd24f98161b4d314bc7c841f2fa8efc t/09warnings.t
+SHA1 2b5c5da82a5c8f2d69d46915b9921d2ceb6ca214 t/10no.t
+-----BEGIN PGP SIGNATURE-----
+Version: GnuPG v1
+
+iEYEARECAAYFAlQwL/wACgkQzr+BKGoqfTkonACeP1ZH9sdg3mJTHQpxoxdgTNQP
+I8YAnjYQAQLXP2fg8wYUZKcbDS5aFJml
+=JZvp
+-----END PGP SIGNATURE-----
diff --git a/dist.ini b/dist.ini
new file mode 100644
index 0000000..d207ae1
--- /dev/null
+++ b/dist.ini
@@ -0,0 +1,3 @@
+;;class='Dist::Inkt::Profile::TOBYINK'
+;;name='Exporter-Tiny'
+
diff --git a/doap.ttl b/doap.ttl
new file mode 100644
index 0000000..29c03f0
--- /dev/null
+++ b/doap.ttl
@@ -0,0 +1,348 @@
+@prefix cpan-uri: <http://purl.org/NET/cpan-uri/terms#> .
+@prefix dc: <http://purl.org/dc/terms/> .
+@prefix doap: <http://usefulinc.com/ns/doap#> .
+@prefix doap-changeset: <http://ontologi.es/doap-changeset#> .
+@prefix doap-deps: <http://ontologi.es/doap-deps#> .
+@prefix foaf: <http://xmlns.com/foaf/0.1/> .
+@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
+@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
+
+<http://dev.perl.org/licenses/>
+ dc:title "the same terms as the perl 5 programming language system itself".
+
+<http://purl.org/NET/cpan-uri/dist/Exporter-Tiny/project>
+ a doap:Project;
+ cpan-uri:x_IRC <irc://irc.perl.org/#moops>;
+ dc:contributor <http://purl.org/NET/cpan-uri/person/tobyink>;
+ doap-deps:runtime-requirement [ doap-deps:on "perl 5.006001"^^doap-deps:CpanId ];
+ doap-deps:test-recommendation [ doap-deps:on "Test::Fatal"^^doap-deps:CpanId ], [ doap-deps:on "Test::Warnings"^^doap-deps:CpanId ];
+ doap-deps:test-requirement [ doap-deps:on "Test::More 0.47"^^doap-deps:CpanId ];
+ doap:bug-database <http://rt.cpan.org/Dist/Display.html?Queue=Exporter-Tiny>;
+ doap:created "2013-09-05"^^xsd:date;
+ doap:developer <http://purl.org/NET/cpan-uri/person/tobyink>;
+ doap:download-page <https://metacpan.org/release/Exporter-Tiny>;
+ doap:homepage <https://metacpan.org/release/Exporter-Tiny>;
+ doap:license <http://dev.perl.org/licenses/>;
+ doap:maintainer <http://purl.org/NET/cpan-uri/person/tobyink>;
+ doap:name "Exporter-Tiny";
+ doap:programming-language "Perl";
+ doap:release <http://purl.org/NET/cpan-uri/dist/Exporter-Tiny/v_0-026>, <http://purl.org/NET/cpan-uri/dist/Exporter-Tiny/v_0-029_01>, <http://purl.org/NET/cpan-uri/dist/Exporter-Tiny/v_0-030>, <http://purl.org/NET/cpan-uri/dist/Exporter-Tiny/v_0-031_01>, <http://purl.org/NET/cpan-uri/dist/Exporter-Tiny/v_0-032>, <http://purl.org/NET/cpan-uri/dist/Exporter-Tiny/v_0-033_01>, <http://purl.org/NET/cpan-uri/dist/Exporter-Tiny/v_0-034>, <http://purl.org/NET/cpan-uri/dist/Exporter-Tiny/v_0-035_01>, <http://purl.org/NET/cpan-uri/dist/Exporter-Tiny/v_0-035_02>, <http://purl.org/NET/cpan-uri/dist/Exporter-Tiny/v_0-036>, <http://purl.org/NET/cpan-uri/dist/Exporter-Tiny/v_0-037_01>, <http://purl.org/NET/cpan-uri/dist/Exporter-Tiny/v_0-037_02>, <http://purl.org/NET/cpan-uri/dist/Exporter-Tiny/v_0-037_03>, <http://purl.org/NET/cpan-uri/dist/Exporter-Tiny/v_0-038>, <http://purl.org/NET/cpan-uri/dist/Exporter-Tiny/v_0-039_01>, <http://purl.org/NET/cpan-uri/dist/Exporter-Tiny/v_0-040>, <http://purl.org/NET/cpan-uri/dist/Exporter-Tiny/v_0-041_01>, <http://purl.org/NET/cpan-uri/dist/Exporter-Tiny/v_0-041_02>, <http://purl.org/NET/cpan-uri/dist/Exporter-Tiny/v_0-042>;
+ doap:repository [
+ a doap:GitRepository;
+ doap:browse <https://github.com/tobyink/p5-exporter-tiny>;
+ ];
+ doap:shortdesc "an exporter with the features of Sub::Exporter but only core dependencies";
+ rdfs:seeAlso <http://purl.org/NET/cpan-uri/dist/Type-Tiny/project>.
+
+<http://purl.org/NET/cpan-uri/dist/Exporter-Tiny/v_0-026>
+ a doap:Version;
+ rdfs:label "Initial release";
+ dc:identifier "Exporter-Tiny-0.026"^^xsd:string;
+ dc:issued "2013-09-05"^^xsd:date;
+ doap-changeset:changeset [
+ doap-changeset:item [
+ a doap-changeset:Packaging;
+ rdfs:label "Split Exporter::Tiny out from Exporter::TypeTiny.";
+ doap-changeset:thanks <http://purl.org/NET/cpan-uri/person/chocolateboy>;
+ ];
+ doap-changeset:versus <http://purl.org/NET/cpan-uri/dist/Type-Tiny/v_0-026>;
+ ];
+ doap-changeset:released-by <http://purl.org/NET/cpan-uri/person/tobyink>;
+ doap:file-release <http://backpan.cpan.org/authors/id/T/TO/TOBYINK/Exporter-Tiny-0.026.tar.gz>;
+ doap:revision "0.026"^^xsd:string.
+
+<http://purl.org/NET/cpan-uri/dist/Exporter-Tiny/v_0-029_01>
+ a cpan-uri:DeveloperRelease, doap:Version;
+ dc:identifier "Exporter-Tiny-0.029_01"^^xsd:string;
+ dc:issued "2013-09-26"^^xsd:date;
+ doap-changeset:changeset [
+ doap-changeset:item [
+ a doap-changeset:Documentation, doap-changeset:Packaging;
+ rdfs:label "Exporter::TypeTiny is being retired, so modify documentation and distribution metadata for Exporter::Tiny to no longer point there.";
+ ];
+ doap-changeset:versus <http://purl.org/NET/cpan-uri/dist/Exporter-Tiny/v_0-026>;
+ ];
+ doap-changeset:released-by <http://purl.org/NET/cpan-uri/person/tobyink>;
+ doap:file-release <http://backpan.cpan.org/authors/id/T/TO/TOBYINK/Exporter-Tiny-0.029_01.tar.gz>;
+ doap:revision "0.029_01"^^xsd:string.
+
+<http://purl.org/NET/cpan-uri/dist/Exporter-Tiny/v_0-030>
+ a doap:Version;
+ dc:identifier "Exporter-Tiny-0.030"^^xsd:string;
+ dc:issued "2013-09-26"^^xsd:date;
+ doap-changeset:changeset [
+ doap-changeset:item [
+ a doap-changeset:Tests;
+ rdfs:label "Test for the 'into' option.";
+ ];
+ doap-changeset:versus <http://purl.org/NET/cpan-uri/dist/Exporter-Tiny/v_0-029_01>;
+ ];
+ doap-changeset:released-by <http://purl.org/NET/cpan-uri/person/tobyink>;
+ doap:file-release <http://backpan.cpan.org/authors/id/T/TO/TOBYINK/Exporter-Tiny-0.030.tar.gz>;
+ doap:revision "0.030"^^xsd:string.
+
+<http://purl.org/NET/cpan-uri/dist/Exporter-Tiny/v_0-031_01>
+ a cpan-uri:DeveloperRelease, doap:Version;
+ dc:identifier "Exporter-Tiny-0.031_01"^^xsd:string;
+ dc:issued "2013-12-30"^^xsd:date;
+ doap-changeset:changeset [
+ doap-changeset:item [
+ a doap-changeset:Packaging, doap-changeset:Tests;
+ rdfs:label "No longer require a recent version of Test::More; the Test::More bundled with Perl 5.6.2 should suffice.";
+ ];
+ doap-changeset:versus <http://purl.org/NET/cpan-uri/dist/Exporter-Tiny/v_0-030>;
+ ];
+ doap-changeset:released-by <http://purl.org/NET/cpan-uri/person/tobyink>;
+ doap:file-release <http://backpan.cpan.org/authors/id/T/TO/TOBYINK/Exporter-Tiny-0.031_01.tar.gz>;
+ doap:revision "0.031_01"^^xsd:string.
+
+<http://purl.org/NET/cpan-uri/dist/Exporter-Tiny/v_0-032>
+ a doap:Version;
+ dc:identifier "Exporter-Tiny-0.032"^^xsd:string;
+ dc:issued "2013-12-30"^^xsd:date;
+ doap-changeset:released-by <http://purl.org/NET/cpan-uri/person/tobyink>;
+ doap:file-release <http://backpan.cpan.org/authors/id/T/TO/TOBYINK/Exporter-Tiny-0.032.tar.gz>;
+ doap:revision "0.032"^^xsd:string;
+ rdfs:comment "No functional changes since 0.031_01.".
+
+<http://purl.org/NET/cpan-uri/dist/Exporter-Tiny/v_0-033_01>
+ a cpan-uri:DeveloperRelease, doap:Version;
+ dc:identifier "Exporter-Tiny-0.033_01"^^xsd:string;
+ dc:issued "2014-01-19"^^xsd:date;
+ doap-changeset:changeset [
+ doap-changeset:item [
+ a doap-changeset:Addition;
+ rdfs:label "Add a new wrapper module called Exporter::Shiny.";
+ ];
+ doap-changeset:versus <http://purl.org/NET/cpan-uri/dist/Exporter-Tiny/v_0-032>;
+ ];
+ doap-changeset:released-by <http://purl.org/NET/cpan-uri/person/tobyink>;
+ doap:file-release <http://backpan.cpan.org/authors/id/T/TO/TOBYINK/Exporter-Tiny-0.033_01.tar.gz>;
+ doap:revision "0.033_01"^^xsd:string.
+
+<http://purl.org/NET/cpan-uri/dist/Exporter-Tiny/v_0-034>
+ a doap:Version;
+ dc:identifier "Exporter-Tiny-0.034"^^xsd:string;
+ dc:issued "2014-01-19"^^xsd:date;
+ doap-changeset:released-by <http://purl.org/NET/cpan-uri/person/tobyink>;
+ doap:file-release <http://backpan.cpan.org/authors/id/T/TO/TOBYINK/Exporter-Tiny-0.034.tar.gz>;
+ doap:revision "0.034"^^xsd:string;
+ rdfs:comment "No functional changes since 0.033_01.".
+
+<http://purl.org/NET/cpan-uri/dist/Exporter-Tiny/v_0-035_01>
+ a cpan-uri:DeveloperRelease, doap:Version;
+ dc:identifier "Exporter-Tiny-0.035_01"^^xsd:string;
+ dc:issued "2014-03-01"^^xsd:date;
+ doap-changeset:changeset [
+ doap-changeset:item [
+ a doap-changeset:Packaging;
+ rdfs:label "Explicitly list minimum Perl version: 5.6.1.";
+ ];
+ doap-changeset:versus <http://purl.org/NET/cpan-uri/dist/Exporter-Tiny/v_0-034>;
+ ];
+ doap-changeset:released-by <http://purl.org/NET/cpan-uri/person/tobyink>;
+ doap:file-release <http://backpan.cpan.org/authors/id/T/TO/TOBYINK/Exporter-Tiny-0.035_01.tar.gz>;
+ doap:revision "0.035_01"^^xsd:string.
+
+<http://purl.org/NET/cpan-uri/dist/Exporter-Tiny/v_0-035_02>
+ a cpan-uri:DeveloperRelease, doap:Version;
+ dc:identifier "Exporter-Tiny-0.035_02"^^xsd:string;
+ dc:issued "2014-03-01"^^xsd:date;
+ doap-changeset:changeset [
+ doap-changeset:item [
+ a doap-changeset:Documentation;
+ rdfs:label "Document exactly what Exporter::Shiny is supposed to do.";
+ ], [
+ a doap-changeset:Tests;
+ rdfs:label "Make t/02renaming.t less noisy.";
+ ];
+ doap-changeset:versus <http://purl.org/NET/cpan-uri/dist/Exporter-Tiny/v_0-035_01>;
+ ];
+ doap-changeset:released-by <http://purl.org/NET/cpan-uri/person/tobyink>;
+ doap:file-release <http://backpan.cpan.org/authors/id/T/TO/TOBYINK/Exporter-Tiny-0.035_02.tar.gz>;
+ doap:revision "0.035_02"^^xsd:string.
+
+<http://purl.org/NET/cpan-uri/dist/Exporter-Tiny/v_0-036>
+ a doap:Version;
+ dc:identifier "Exporter-Tiny-0.036"^^xsd:string;
+ dc:issued "2014-03-11"^^xsd:date;
+ doap-changeset:released-by <http://purl.org/NET/cpan-uri/person/tobyink>;
+ doap:file-release <http://backpan.cpan.org/authors/id/T/TO/TOBYINK/Exporter-Tiny-0.036.tar.gz>;
+ doap:revision "0.036"^^xsd:string;
+ rdfs:comment "No functional changes since 0.035_02.".
+
+<http://purl.org/NET/cpan-uri/dist/Exporter-Tiny/v_0-037_01>
+ a cpan-uri:DeveloperRelease, doap:Version;
+ dc:identifier "Exporter-Tiny-0.037_01"^^xsd:string;
+ dc:issued "2014-03-26"^^xsd:date;
+ doap-changeset:changeset [
+ doap-changeset:item [
+ a doap-changeset:Documentation;
+ rdfs:label "Fix minor error in documentation of generators.";
+ ], [
+ a doap-changeset:Addition;
+ rdfs:label "Support Exporter.pm's import negation syntax qw( !foo ).";
+ ], [
+ a doap-changeset:Addition;
+ rdfs:label "Support Exporter.pm's regexp import syntax qw( /foo/ ).";
+ ];
+ doap-changeset:versus <http://purl.org/NET/cpan-uri/dist/Exporter-Tiny/v_0-036>;
+ ];
+ doap-changeset:released-by <http://purl.org/NET/cpan-uri/person/tobyink>;
+ doap:file-release <http://backpan.cpan.org/authors/id/T/TO/TOBYINK/Exporter-Tiny-0.037_01.tar.gz>;
+ doap:revision "0.037_01"^^xsd:string.
+
+<http://purl.org/NET/cpan-uri/dist/Exporter-Tiny/v_0-037_02>
+ a cpan-uri:DeveloperRelease, doap:Version;
+ dc:identifier "Exporter-Tiny-0.037_02"^^xsd:string;
+ dc:issued "2014-04-02"^^xsd:date;
+ doap-changeset:changeset [
+ doap-changeset:item [
+ a doap-changeset:Change;
+ rdfs:label "Improved handling of hashrefs of options passed to tags, and hashrefs of options found within %EXPORT_TAGS arrayrefs.";
+ ];
+ doap-changeset:versus <http://purl.org/NET/cpan-uri/dist/Exporter-Tiny/v_0-037_01>;
+ ];
+ doap-changeset:released-by <http://purl.org/NET/cpan-uri/person/tobyink>;
+ doap:file-release <http://backpan.cpan.org/authors/id/T/TO/TOBYINK/Exporter-Tiny-0.037_02.tar.gz>;
+ doap:revision "0.037_02"^^xsd:string.
+
+<http://purl.org/NET/cpan-uri/dist/Exporter-Tiny/v_0-037_03>
+ a cpan-uri:DeveloperRelease, doap:Version;
+ dc:identifier "Exporter-Tiny-0.037_03"^^xsd:string;
+ dc:issued "2014-04-02"^^xsd:date;
+ doap-changeset:changeset [
+ doap-changeset:item [
+ a doap-changeset:Bugfix;
+ rdfs:label "Only attempt to merge hashes if we're sure they're both really hashes!";
+ ];
+ doap-changeset:versus <http://purl.org/NET/cpan-uri/dist/Exporter-Tiny/v_0-037_02>;
+ ];
+ doap-changeset:released-by <http://purl.org/NET/cpan-uri/person/tobyink>;
+ doap:file-release <http://backpan.cpan.org/authors/id/T/TO/TOBYINK/Exporter-Tiny-0.037_03.tar.gz>;
+ doap:revision "0.037_03"^^xsd:string.
+
+<http://purl.org/NET/cpan-uri/dist/Exporter-Tiny/v_0-038>
+ a doap:Version;
+ dc:identifier "Exporter-Tiny-0.038"^^xsd:string;
+ dc:issued "2014-04-04"^^xsd:date;
+ doap-changeset:released-by <http://purl.org/NET/cpan-uri/person/tobyink>;
+ doap:file-release <http://backpan.cpan.org/authors/id/T/TO/TOBYINK/Exporter-Tiny-0.038.tar.gz>;
+ doap:revision "0.038"^^xsd:string;
+ rdfs:comment "No functional changes since 0.037_03.".
+
+<http://purl.org/NET/cpan-uri/dist/Exporter-Tiny/v_0-039_01>
+ a cpan-uri:DeveloperRelease, doap:Version;
+ dc:identifier "Exporter-Tiny-0.039_01"^^xsd:string;
+ dc:issued "2014-07-20"^^xsd:date;
+ doap-changeset:changeset [
+ doap-changeset:item [
+ a doap-changeset:Documentation;
+ rdfs:label "Document warning and error messages produced by Exporter::Tiny.";
+ ], [
+ a doap-changeset:Change;
+ rdfs:label "No longer die when redefining locally defined subs.";
+ ], [
+ a doap-changeset:Change;
+ rdfs:label "Warn when redefining any subs.";
+ ], [
+ a doap-changeset:Change;
+ rdfs:label "Exporter::Tiny would previously cause B.pm to be loaded into memory any time it exported anything. It no longer does.";
+ ];
+ doap-changeset:versus <http://purl.org/NET/cpan-uri/dist/Exporter-Tiny/v_0-038>;
+ ];
+ doap-changeset:released-by <http://purl.org/NET/cpan-uri/person/tobyink>;
+ doap:file-release <http://backpan.cpan.org/authors/id/T/TO/TOBYINK/Exporter-Tiny-0.039_01.tar.gz>;
+ doap:revision "0.039_01"^^xsd:string.
+
+<http://purl.org/NET/cpan-uri/dist/Exporter-Tiny/v_0-040>
+ a doap:Version;
+ dc:identifier "Exporter-Tiny-0.040"^^xsd:string;
+ dc:issued "2014-09-17"^^xsd:date;
+ doap-changeset:changeset [
+ doap-changeset:item [
+ a doap-changeset:Packaging;
+ rdfs:label "Repackage as a stable release.";
+ ];
+ doap-changeset:versus <http://purl.org/NET/cpan-uri/dist/Exporter-Tiny/v_0-039_01>;
+ ];
+ doap-changeset:released-by <http://purl.org/NET/cpan-uri/person/tobyink>;
+ doap:file-release <http://backpan.cpan.org/authors/id/T/TO/TOBYINK/Exporter-Tiny-0.040.tar.gz>;
+ doap:revision "0.040"^^xsd:string.
+
+<http://purl.org/NET/cpan-uri/dist/Exporter-Tiny/v_0-041_01>
+ a cpan-uri:DeveloperRelease, doap:Version;
+ dc:identifier "Exporter-Tiny-0.041_01"^^xsd:string;
+ dc:issued "2014-09-18"^^xsd:date;
+ doap-changeset:changeset [
+ doap-changeset:item [
+ a doap-changeset:Change;
+ rdfs:label "Add an `unimport` feature.";
+ ];
+ doap-changeset:versus <http://purl.org/NET/cpan-uri/dist/Exporter-Tiny/v_0-040>;
+ ];
+ doap-changeset:released-by <http://purl.org/NET/cpan-uri/person/tobyink>;
+ doap:file-release <http://backpan.cpan.org/authors/id/T/TO/TOBYINK/Exporter-Tiny-0.041_01.tar.gz>;
+ doap:revision "0.041_01"^^xsd:string.
+
+<http://purl.org/NET/cpan-uri/dist/Exporter-Tiny/v_0-041_02>
+ a cpan-uri:DeveloperRelease, doap:Version;
+ dc:identifier "Exporter-Tiny-0.041_02"^^xsd:string;
+ dc:issued "2014-09-19"^^xsd:date;
+ doap-changeset:changeset [
+ doap-changeset:item [
+ a doap-changeset:Bugfix;
+ rdfs:label "Option validation needs to happen after expanding tags.";
+ ];
+ doap-changeset:versus <http://purl.org/NET/cpan-uri/dist/Exporter-Tiny/v_0-041_01>;
+ ];
+ doap-changeset:released-by <http://purl.org/NET/cpan-uri/person/tobyink>;
+ doap:file-release <http://backpan.cpan.org/authors/id/T/TO/TOBYINK/Exporter-Tiny-0.041_02.tar.gz>;
+ doap:revision "0.041_02"^^xsd:string.
+
+<http://purl.org/NET/cpan-uri/dist/Exporter-Tiny/v_0-042>
+ a doap:Version;
+ dc:identifier "Exporter-Tiny-0.042"^^xsd:string;
+ dc:issued "2014-10-04"^^xsd:date;
+ doap-changeset:changeset [
+ doap-changeset:item [
+ a doap-changeset:Documentation;
+ rdfs:label "Document the warning emitted when you provide options to a function you are unimporting.";
+ ], [
+ a doap-changeset:Change;
+ rdfs:label "Housekeeping on %TRACKED.";
+ ];
+ doap-changeset:versus <http://purl.org/NET/cpan-uri/dist/Exporter-Tiny/v_0-041_02>;
+ ];
+ doap-changeset:released-by <http://purl.org/NET/cpan-uri/person/tobyink>;
+ doap:file-release <http://backpan.cpan.org/authors/id/T/TO/TOBYINK/Exporter-Tiny-0.042.tar.gz>;
+ doap:revision "0.042"^^xsd:string.
+
+<http://purl.org/NET/cpan-uri/dist/Type-Tiny/project>
+ a doap:Project;
+ dc:contributor <http://purl.org/NET/cpan-uri/person/tobyink>;
+ doap:download-page <https://metacpan.org/release/Type-Tiny>;
+ doap:homepage <https://metacpan.org/release/Type-Tiny>;
+ doap:name "Type-Tiny";
+ doap:programming-language "Perl";
+ doap:release <http://purl.org/NET/cpan-uri/dist/Type-Tiny/v_0-026>.
+
+<http://purl.org/NET/cpan-uri/dist/Type-Tiny/v_0-026>
+ a doap:Version;
+ dc:identifier "Type-Tiny-0.026"^^xsd:string;
+ doap-changeset:released-by <http://purl.org/NET/cpan-uri/person/tobyink>;
+ doap:file-release <http://backpan.cpan.org/authors/id/T/TO/TOBYINK/Type-Tiny-0.026.tar.gz>;
+ doap:revision "0.026"^^xsd:string.
+
+<http://purl.org/NET/cpan-uri/person/chocolateboy>
+ a foaf:Person;
+ foaf:nick "CHOCOLATEBOY";
+ foaf:page <https://metacpan.org/author/CHOCOLATEBOY>.
+
+<http://purl.org/NET/cpan-uri/person/tobyink>
+ a foaf:Person;
+ foaf:mbox <mailto:tobyink@cpan.org>;
+ foaf:name "Toby Inkster";
+ foaf:nick "TOBYINK";
+ foaf:page <https://metacpan.org/author/TOBYINK>.
+
diff --git a/examples/Example/Exporter.pm b/examples/Example/Exporter.pm
new file mode 100644
index 0000000..dedc876
--- /dev/null
+++ b/examples/Example/Exporter.pm
@@ -0,0 +1,56 @@
+use 5.006001;
+use strict;
+use warnings;
+
+package Example::Exporter;
+
+# Inherit from Exporter::Tiny.
+#
+use base 'Exporter::Tiny';
+
+# The list of functions to export by default.
+# Be conservative.
+#
+our @EXPORT = qw( fib );
+
+# The list of functions which are allowed to
+# be exported. Be liberal.
+#
+our @EXPORT_OK = qw( embiggen );
+
+# Note that there was no need to list "fib"
+# in @EXPORT_OK. It was in @EXPORT, so it's
+# implicitly ok.
+
+# This is the definition of the "fib" function
+# that we want to export.
+#
+sub fib {
+ my $n = $_[0];
+
+ (int($n) eq $n) && ($n >= 0)
+ or die "Expected natural number as argument; got '$n'";
+
+ return $n if $n < 2;
+
+ fib($n - 1) + fib($n - 2);
+}
+
+# We won't define a standard embiggen function.
+# Instead we will generate one when requested.
+#
+sub _generate_embiggen {
+ my ($class, $name, $arg, $globals) = @_;
+
+ my $embiggen_amount = exists($arg->{amount}) ? $arg->{amount} : 1;
+
+ # This is the sub that will be installed into
+ # the caller's namespace.
+ #
+ return sub ($) {
+ my $n = $_[0];
+ return $n + $embiggen_amount;
+ }
+}
+
+1; # Make Perl Happyâ„¢
diff --git a/lib/Exporter/Shiny.pm b/lib/Exporter/Shiny.pm
new file mode 100644
index 0000000..063cb47
--- /dev/null
+++ b/lib/Exporter/Shiny.pm
@@ -0,0 +1,111 @@
+package Exporter::Shiny;
+
+use 5.006001;
+use strict;
+use warnings;
+
+use Exporter::Tiny ();
+
+our $AUTHORITY = 'cpan:TOBYINK';
+our $VERSION = '0.042';
+
+sub import {
+ my $me = shift;
+ my $caller = caller;
+
+ (my $nominal_file = $caller) =~ s(::)(/)g;
+ $INC{"$nominal_file\.pm"} ||= __FILE__;
+
+ if (@_ == 2 and $_[0] eq -setup)
+ {
+ my (undef, $opts) = @_;
+ @_ = @{ delete($opts->{exports}) || [] };
+
+ if (%$opts) {
+ Exporter::Tiny::_croak(
+ 'Unsupported Sub::Exporter-style options: %s',
+ join(q[, ], sort keys %$opts),
+ );
+ }
+ }
+
+ ref($_) && Exporter::Tiny::_croak('Expected sub name, got ref %s', $_) for @_;
+
+ no strict qw(refs);
+ push @{"$caller\::ISA"}, 'Exporter::Tiny';
+ push @{"$caller\::EXPORT_OK"}, @_;
+}
+
+1;
+
+__END__
+
+=pod
+
+=encoding utf-8
+
+=head1 NAME
+
+Exporter::Shiny - shortcut for Exporter::Tiny
+
+=head1 SYNOPSIS
+
+ use Exporter::Shiny qw( foo bar );
+
+Is a shortcut for:
+
+ use base "Exporter::Tiny";
+ push our(@EXPORT_OK), qw( foo bar );
+
+For compatibility with L<Sub::Exporter>, the following longer syntax is
+also supported:
+
+ use Exporter::Shiny -setup => {
+ exports => [qw( foo bar )],
+ };
+
+=head1 DESCRIPTION
+
+This is a very small wrapper to simplify using L<Exporter::Tiny>.
+
+It does the following:
+
+=over
+
+=item * Marks your package as loaded in C<< %INC >>;
+
+=item * Pushes any function names in the import list onto your C<< @EXPORT_OK >>; and
+
+=item * Pushes C<< "Exporter::Tiny" >> onto your C<< @ISA >>.
+
+=back
+
+It doesn't set up C<< %EXPORT_TAGS >> or C<< @EXPORT >>, but there's
+nothing stopping you doing that yourself.
+
+=head1 BUGS
+
+Please report any bugs to
+L<http://rt.cpan.org/Dist/Display.html?Queue=Exporter-Tiny>.
+
+=head1 SEE ALSO
+
+L<Exporter::Tiny>.
+
+=head1 AUTHOR
+
+Toby Inkster E<lt>tobyink@cpan.orgE<gt>.
+
+=head1 COPYRIGHT AND LICENCE
+
+This software is copyright (c) 2014 by Toby Inkster.
+
+This is free software; you can redistribute it and/or modify it under
+the same terms as the Perl 5 programming language system itself.
+
+=head1 DISCLAIMER OF WARRANTIES
+
+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.
+
diff --git a/lib/Exporter/Tiny.pm b/lib/Exporter/Tiny.pm
new file mode 100644
index 0000000..6e77338
--- /dev/null
+++ b/lib/Exporter/Tiny.pm
@@ -0,0 +1,833 @@
+package Exporter::Tiny;
+
+use 5.006001;
+use strict;
+use warnings; no warnings qw(void once uninitialized numeric redefine);
+
+our $AUTHORITY = 'cpan:TOBYINK';
+our $VERSION = '0.042';
+our @EXPORT_OK = qw< mkopt mkopt_hash _croak _carp >;
+
+sub _croak ($;@) { require Carp; my $fmt = shift; @_ = sprintf($fmt, @_); goto \&Carp::croak }
+sub _carp ($;@) { require Carp; my $fmt = shift; @_ = sprintf($fmt, @_); goto \&Carp::carp }
+
+my $_process_optlist = sub
+{
+ my $class = shift;
+ my ($global_opts, $opts, $want, $not_want) = @_;
+
+ while (@$opts)
+ {
+ my $opt = shift @{$opts};
+ my ($name, $value) = @$opt;
+
+ ($name =~ m{\A\!(/.+/[msixpodual]+)\z}) ?
+ do {
+ my @not = $class->_exporter_expand_regexp($1, $value, $global_opts);
+ ++$not_want->{$_->[0]} for @not;
+ } :
+ ($name =~ m{\A\!(.+)\z}) ?
+ (++$not_want->{$1}) :
+ ($name =~ m{\A[:-](.+)\z}) ?
+ push(@$opts, $class->_exporter_expand_tag($1, $value, $global_opts)) :
+ ($name =~ m{\A/.+/[msixpodual]+\z}) ?
+ push(@$opts, $class->_exporter_expand_regexp($name, $value, $global_opts)) :
+ # else ?
+ push(@$want, $opt);
+ }
+};
+
+sub import
+{
+ my $class = shift;
+ my $global_opts = +{ @_ && ref($_[0]) eq q(HASH) ? %{+shift} : () };
+ $global_opts->{into} = caller unless exists $global_opts->{into};
+
+ my @want;
+ my %not_want; $global_opts->{not} = \%not_want;
+ my @args = do { no strict qw(refs); @_ ? @_ : @{"$class\::EXPORT"} };
+ my $opts = mkopt(\@args);
+ $class->$_process_optlist($global_opts, $opts, \@want, \%not_want);
+
+ my $permitted = $class->_exporter_permitted_regexp($global_opts);
+ $class->_exporter_validate_opts($global_opts);
+
+ for my $wanted (@want)
+ {
+ next if $not_want{$wanted->[0]};
+
+ my %symbols = $class->_exporter_expand_sub(@$wanted, $global_opts, $permitted);
+ $class->_exporter_install_sub($_, $wanted->[1], $global_opts, $symbols{$_})
+ for keys %symbols;
+ }
+}
+
+sub unimport
+{
+ my $class = shift;
+ my $global_opts = +{ @_ && ref($_[0]) eq q(HASH) ? %{+shift} : () };
+ $global_opts->{into} = caller unless exists $global_opts->{into};
+ $global_opts->{is_unimport} = 1;
+
+ my @want;
+ my %not_want; $global_opts->{not} = \%not_want;
+ my @args = do { our %TRACKED; @_ ? @_ : keys(%{$TRACKED{$class}{$global_opts->{into}}}) };
+ my $opts = mkopt(\@args);
+ $class->$_process_optlist($global_opts, $opts, \@want, \%not_want);
+
+ my $permitted = $class->_exporter_permitted_regexp($global_opts);
+ $class->_exporter_validate_unimport_opts($global_opts);
+
+ my $expando = $class->can('_exporter_expand_sub');
+ $expando = undef if $expando == \&_exporter_expand_sub;
+
+ for my $wanted (@want)
+ {
+ next if $not_want{$wanted->[0]};
+
+ if ($wanted->[1])
+ {
+ _carp("Passing options to unimport '%s' makes no sense", $wanted->[0])
+ unless (ref($wanted->[1]) eq 'HASH' and not keys %{$wanted->[1]});
+ }
+
+ my %symbols = defined($expando)
+ ? $class->$expando(@$wanted, $global_opts, $permitted)
+ : ($wanted->[0] => sub { "dummy" });
+ $class->_exporter_uninstall_sub($_, $wanted->[1], $global_opts)
+ for keys %symbols;
+ }
+}
+
+# Called once per import/unimport, passed the "global" import options.
+# Expected to validate the options and carp or croak if there are problems.
+# Can also take the opportunity to do other stuff if needed.
+#
+sub _exporter_validate_opts { 1 }
+sub _exporter_validate_unimport_opts { 1 }
+
+# Called after expanding a tag or regexp to merge the tag's options with
+# any sub-specific options.
+#
+sub _exporter_merge_opts
+{
+ my $class = shift;
+ my ($tag_opts, $global_opts, @stuff) = @_;
+
+ $tag_opts = {} unless ref($tag_opts) eq q(HASH);
+ _croak('Cannot provide an -as option for tags')
+ if exists $tag_opts->{-as};
+
+ my $optlist = mkopt(\@stuff);
+ for my $export (@$optlist)
+ {
+ next if defined($export->[1]) && ref($export->[1]) ne q(HASH);
+
+ my %sub_opts = ( %{ $export->[1] or {} }, %$tag_opts );
+ $sub_opts{-prefix} = sprintf('%s%s', $tag_opts->{-prefix}, $export->[1]{-prefix})
+ if exists($export->[1]{-prefix}) && exists($tag_opts->{-prefix});
+ $sub_opts{-suffix} = sprintf('%s%s', $export->[1]{-suffix}, $tag_opts->{-suffix})
+ if exists($export->[1]{-suffix}) && exists($tag_opts->{-suffix});
+ $export->[1] = \%sub_opts;
+ }
+ return @$optlist;
+}
+
+# Given a tag name, looks it up in %EXPORT_TAGS and returns the list of
+# associated functions. The default implementation magically handles tags
+# "all" and "default". The default implementation interprets any undefined
+# tags as being global options.
+#
+sub _exporter_expand_tag
+{
+ no strict qw(refs);
+
+ my $class = shift;
+ my ($name, $value, $globals) = @_;
+ my $tags = \%{"$class\::EXPORT_TAGS"};
+
+ return $class->_exporter_merge_opts($value, $globals, $tags->{$name}->($class, @_))
+ if ref($tags->{$name}) eq q(CODE);
+
+ return $class->_exporter_merge_opts($value, $globals, @{$tags->{$name}})
+ if exists $tags->{$name};
+
+ return $class->_exporter_merge_opts($value, $globals, @{"$class\::EXPORT"}, @{"$class\::EXPORT_OK"})
+ if $name eq 'all';
+
+ return $class->_exporter_merge_opts($value, $globals, @{"$class\::EXPORT"})
+ if $name eq 'default';
+
+ $globals->{$name} = $value || 1;
+ return;
+}
+
+# Given a regexp-like string, looks it up in @EXPORT_OK and returns the
+# list of matching functions.
+#
+sub _exporter_expand_regexp
+{
+ no strict qw(refs);
+ our %TRACKED;
+
+ my $class = shift;
+ my ($name, $value, $globals) = @_;
+ my $compiled = eval("qr$name");
+
+ my @possible = $globals->{is_unimport}
+ ? keys( %{$TRACKED{$class}{$globals->{into}}} )
+ : @{"$class\::EXPORT_OK"};
+
+ $class->_exporter_merge_opts($value, $globals, grep /$compiled/, @possible);
+}
+
+# Helper for _exporter_expand_sub. Returns a regexp matching all subs in
+# the exporter package which are available for export.
+#
+sub _exporter_permitted_regexp
+{
+ no strict qw(refs);
+ my $class = shift;
+ my $re = join "|", map quotemeta, sort {
+ length($b) <=> length($a) or $a cmp $b
+ } @{"$class\::EXPORT"}, @{"$class\::EXPORT_OK"};
+ qr{^(?:$re)$}ms;
+}
+
+# Given a sub name, returns a hash of subs to install (usually just one sub).
+# Keys are sub names, values are coderefs.
+#
+sub _exporter_expand_sub
+{
+ my $class = shift;
+ my ($name, $value, $globals, $permitted) = @_;
+ $permitted ||= $class->_exporter_permitted_regexp($globals);
+
+ no strict qw(refs);
+
+ if ($name =~ $permitted)
+ {
+ my $generator = $class->can("_generate_$name");
+ return $name => $class->$generator($name, $value, $globals) if $generator;
+
+ my $sub = $class->can($name);
+ return $name => $sub if $sub;
+ }
+
+ $class->_exporter_fail(@_);
+}
+
+# Called by _exporter_expand_sub if it is unable to generate a key-value
+# pair for a sub.
+#
+sub _exporter_fail
+{
+ my $class = shift;
+ my ($name, $value, $globals) = @_;
+ return if $globals->{is_unimport};
+ _croak("Could not find sub '%s' exported by %s", $name, $class);
+}
+
+# Actually performs the installation of the sub into the target package. This
+# also handles renaming the sub.
+#
+sub _exporter_install_sub
+{
+ my $class = shift;
+ my ($name, $value, $globals, $sym) = @_;
+
+ my $into = $globals->{into};
+ my $installer = $globals->{installer} || $globals->{exporter};
+
+ $name = $value->{-as} || $name;
+ unless (ref($name) eq q(SCALAR))
+ {
+ my ($prefix) = grep defined, $value->{-prefix}, $globals->{prefix}, q();
+ my ($suffix) = grep defined, $value->{-suffix}, $globals->{suffix}, q();
+ $name = "$prefix$name$suffix";
+ }
+
+ return ($$name = $sym) if ref($name) eq q(SCALAR);
+ return ($into->{$name} = $sym) if ref($into) eq q(HASH);
+
+ no strict qw(refs);
+
+ if (exists &{"$into\::$name"} and \&{"$into\::$name"} != $sym)
+ {
+ my ($level) = grep defined, $value->{-replace}, $globals->{replace}, q(0);
+ my $action = {
+ carp => \&_carp,
+ 0 => \&_carp,
+ '' => \&_carp,
+ warn => \&_carp,
+ nonfatal => \&_carp,
+ croak => \&_croak,
+ fatal => \&_croak,
+ die => \&_croak,
+ }->{$level} || sub {};
+
+ $action->(
+ $action == \&_croak
+ ? "Refusing to overwrite existing sub '%s::%s' with sub '%s' exported by %s"
+ : "Overwriting existing sub '%s::%s' with sub '%s' exported by %s",
+ $into,
+ $name,
+ $_[0],
+ $class,
+ );
+ }
+
+ our %TRACKED;
+ $TRACKED{$class}{$into}{$name} = $sym;
+
+ no warnings qw(prototype);
+ $installer
+ ? $installer->($globals, [$name, $sym])
+ : (*{"$into\::$name"} = $sym);
+}
+
+sub _exporter_uninstall_sub
+{
+ our %TRACKED;
+ my $class = shift;
+ my ($name, $value, $globals, $sym) = @_;
+ my $into = $globals->{into};
+ ref $into and return;
+
+ no strict qw(refs);
+
+ # Cowardly refuse to uninstall a sub that differs from the one
+ # we installed!
+ my $our_coderef = $TRACKED{$class}{$into}{$name};
+ my $cur_coderef = exists(&{"$into\::$name"}) ? \&{"$into\::$name"} : -1;
+ return unless $our_coderef == $cur_coderef;
+
+ my $stash = \%{"$into\::"};
+ my $old = delete $stash->{$name};
+ my $full_name = join('::', $into, $name);
+ foreach my $type (qw(SCALAR HASH ARRAY IO)) # everything but the CODE
+ {
+ next unless defined(*{$old}{$type});
+ *$full_name = *{$old}{$type};
+ }
+
+ delete $TRACKED{$class}{$into}{$name};
+}
+
+sub mkopt
+{
+ my $in = shift or return [];
+ my @out;
+
+ $in = [map(($_ => ref($in->{$_}) ? $in->{$_} : ()), sort keys %$in)]
+ if ref($in) eq q(HASH);
+
+ for (my $i = 0; $i < @$in; $i++)
+ {
+ my $k = $in->[$i];
+ my $v;
+
+ ($i == $#$in) ? ($v = undef) :
+ !defined($in->[$i+1]) ? (++$i, ($v = undef)) :
+ !ref($in->[$i+1]) ? ($v = undef) :
+ ($v = $in->[++$i]);
+
+ push @out, [ $k => $v ];
+ }
+
+ \@out;
+}
+
+sub mkopt_hash
+{
+ my $in = shift or return;
+ my %out = map +($_->[0] => $_->[1]), @{ mkopt($in) };
+ \%out;
+}
+
+1;
+
+__END__
+
+=pod
+
+=encoding utf-8
+
+=for stopwords frobnicate greps regexps
+
+=head1 NAME
+
+Exporter::Tiny - an exporter with the features of Sub::Exporter but only core dependencies
+
+=head1 SYNOPSIS
+
+ package MyUtils;
+ use base "Exporter::Tiny";
+ our @EXPORT = qw(frobnicate);
+ sub frobnicate { my $n = shift; ... }
+ 1;
+
+ package MyScript;
+ use MyUtils "frobnicate" => { -as => "frob" };
+ print frob(42);
+ exit;
+
+=head1 DESCRIPTION
+
+Exporter::Tiny supports many of Sub::Exporter's external-facing features
+including renaming imported functions with the C<< -as >>, C<< -prefix >> and
+C<< -suffix >> options; explicit destinations with the C<< into >> option;
+and alternative installers with the C<< installler >> option. But it's written
+in only about 40% as many lines of code and with zero non-core dependencies.
+
+Its internal-facing interface is closer to Exporter.pm, with configuration
+done through the C<< @EXPORT >>, C<< @EXPORT_OK >> and C<< %EXPORT_TAGS >>
+package variables.
+
+Exporter::Tiny performs most of its internal duties (including resolution
+of tag names to sub names, resolution of sub names to coderefs, and
+installation of coderefs into the target package) as method calls, which
+means they can be overridden to provide interesting behaviour.
+
+=head2 Utility Functions
+
+These are really for internal use, but can be exported if you need them.
+
+=over
+
+=item C<< mkopt(\@array) >>
+
+Similar to C<mkopt> from L<Data::OptList>. It doesn't support all the
+fancy options that Data::OptList does (C<moniker>, C<require_unique>,
+C<must_be> and C<name_test>) but runs about 50% faster.
+
+=item C<< mkopt_hash(\@array) >>
+
+Similar to C<mkopt_hash> from L<Data::OptList>. See also C<mkopt>.
+
+=back
+
+=head1 TIPS AND TRICKS IMPORTING FROM EXPORTER::TINY
+
+For the purposes of this discussion we'll assume we have a module called
+C<< MyUtils >> which exports one function, C<< frobnicate >>. C<< MyUtils >>
+inherits from Exporter::Tiny.
+
+Many of these tricks may seem familiar from L<Sub::Exporter>. That is
+intentional. Exporter::Tiny doesn't attempt to provide every feature of
+Sub::Exporter, but where it does it usually uses a fairly similar API.
+
+=head2 Basic importing
+
+ # import "frobnicate" function
+ use MyUtils "frobnicate";
+
+ # import all functions that MyUtils offers
+ use MyUtils -all;
+
+=head2 Renaming imported functions
+
+ # call it "frob"
+ use MyUtils "frobnicate" => { -as => "frob" };
+
+ # call it "my_frobnicate"
+ use MyUtils "frobnicate" => { -prefix => "my_" };
+
+ # can set a prefix for *all* functions imported from MyUtils
+ # by placing the options hashref *first*.
+ use MyUtils { prefix => "my_" }, "frobnicate";
+ # (note the lack of hyphen before `prefix`.)
+
+ # call it "frobnicate_util"
+ use MyUtils "frobnicate" => { -suffix => "_util" };
+ use MyUtils { suffix => "_util" }, "frobnicate";
+
+ # import it twice with two different names
+ use MyUtils
+ "frobnicate" => { -as => "frob" },
+ "frobnicate" => { -as => "frbnct" };
+
+=head2 Lexical subs
+
+ {
+ use Sub::Exporter::Lexical lexical_installer => { -as => "lex" };
+ use MyUtils { installer => lex }, "frobnicate";
+
+ frobnicate(...); # ok
+ }
+
+ frobnicate(...); # not ok
+
+=head2 Import functions into another package
+
+ use MyUtils { into => "OtherPkg" }, "frobnicate";
+
+ OtherPkg::frobincate(...);
+
+=head2 Import functions into a scalar
+
+ my $func;
+ use MyUtils "frobnicate" => { -as => \$func };
+
+ $func->(...);
+
+=head2 Import functions into a hash
+
+OK, Sub::Exporter doesn't do this...
+
+ my %funcs;
+ use MyUtils { into => \%funcs }, "frobnicate";
+
+ $funcs{frobnicate}->(...);
+
+=head2 DO NOT WANT!
+
+This imports everything except "frobnicate":
+
+ use MyUtils qw( -all !frobnicate );
+
+Negated imports always "win", so the following will not import
+"frobnicate", no matter how many times you repeat it...
+
+ use MyUtils qw( !frobnicate frobnicate frobnicate frobnicate );
+
+=head2 Importing by regexp
+
+Here's how you could import all functions beginning with an "f":
+
+ use MyUtils qw( /^F/i );
+
+Or import everything except functions beginning with a "z":
+
+ use MyUtils qw( -all !/^Z/i );
+
+Note that regexps are always supplied as I<strings> starting with
+C<< "/" >>, and not as quoted regexp references (C<< qr/.../ >>).
+
+=head2 Unimporting
+
+You can unimport the functions that MyUtils added to your namespace:
+
+ no MyUtils;
+
+Or just specific ones:
+
+ no MyUtils qw(frobnicate);
+
+If you renamed a function when you imported it, you should unimport by
+the new name:
+
+ use MyUtils frobnicate => { -as => "frob" };
+ ...;
+ no MyUtils "frob";
+
+Unimporting using tags and regexps should mostly do what you want.
+
+=head1 TIPS AND TRICKS EXPORTING USING EXPORTER::TINY
+
+Simple configuration works the same as L<Exporter>; inherit from this module,
+and use the C<< @EXPORT >>, C<< @EXPORT_OK >> and C<< %EXPORT_TAGS >>
+package variables to list subs to export.
+
+=head2 Generators
+
+Exporter::Tiny has always allowed exported subs to be generated (like
+L<Sub::Exporter>), but until version 0.025 did not have an especially nice
+API for it.
+
+Now, it's easy. If you want to generate a sub C<foo> to export, list it in
+C<< @EXPORT >> or C<< @EXPORT_OK >> as usual, and then simply give your
+exporter module a class method called C<< _generate_foo >>.
+
+ push @EXPORT_OK, 'foo';
+
+ sub _generate_foo {
+ my $class = shift;
+ my ($name, $args, $globals) = @_;
+
+ return sub {
+ ...;
+ }
+ }
+
+You can also generate tags:
+
+ my %constants;
+ BEGIN {
+ %constants = (FOO => 1, BAR => 2);
+ }
+ use constant \%constants;
+
+ $EXPORT_TAGS{constants} = sub {
+ my $class = shift;
+ my ($name, $args, $globals) = @_;
+
+ return keys(%constants);
+ };
+
+=head2 Overriding Internals
+
+An important difference between L<Exporter> and Exporter::Tiny is that
+the latter calls all its internal functions as I<< class methods >>. This
+means that your subclass can I<< override them >> to alter their behaviour.
+
+The following methods are available to be overridden. Despite being named
+with a leading underscore, they are considered public methods. (The underscore
+is there to avoid accidentally colliding with any of your own function names.)
+
+=over
+
+=item C<< _exporter_validate_opts($globals) >>
+
+This method is called once each time C<import> is called. It is passed a
+reference to the global options hash. (That is, the optional leading hashref
+in the C<use> statement, where the C<into> and C<installer> options can be
+provided.)
+
+You may use this method to munge the global options, or validate them,
+throwing an exception or printing a warning.
+
+The default implementation does nothing interesting.
+
+=item C<< _exporter_validate_unimport_opts($globals) >>
+
+Like C<_exporter_validate_opts>, but called for C<unimport>.
+
+=item C<< _exporter_merge_opts($tag_opts, $globals, @exports) >>
+
+Called to merge options which have been provided for a tag into the
+options provided for the exports that the tag expanded to.
+
+=item C<< _exporter_expand_tag($name, $args, $globals) >>
+
+This method is called to expand an import tag (e.g. C<< ":constants" >>).
+It is passed the tag name (minus the leading ":"), an optional hashref
+of options (like C<< { -prefix => "foo_" } >>), and the global options
+hashref.
+
+It is expected to return a list of ($name, $args) arrayref pairs. These
+names can be sub names to export, or further tag names (which must have
+their ":"). If returning tag names, be careful to avoid creating a tag
+expansion loop!
+
+The default implementation uses C<< %EXPORT_TAGS >> to expand tags, and
+provides fallbacks for the C<< :default >> and C<< :all >> tags.
+
+=item C<< _exporter_expand_regexp($regexp, $args, $globals) >>
+
+Like C<_exporter_expand_regexp>, but given a regexp-like string instead
+of a tag name.
+
+The default implementation greps through C<< @EXPORT_OK >> for imports,
+and the list of already-imported functions for exports.
+
+=item C<< _exporter_expand_sub($name, $args, $globals) >>
+
+This method is called to translate a sub name to a hash of name => coderef
+pairs for exporting to the caller. In general, this would just be a hash with
+one key and one value, but, for example, L<Type::Library> overrides this
+method so that C<< "+Foo" >> gets expanded to:
+
+ (
+ Foo => sub { $type },
+ is_Foo => sub { $type->check(@_) },
+ to_Foo => sub { $type->assert_coerce(@_) },
+ assert_Foo => sub { $type->assert_return(@_) },
+ )
+
+The default implementation checks that the name is allowed to be exported
+(using the C<_exporter_permitted_regexp> method), gets the coderef using
+the generator if there is one (or by calling C<< can >> on your exporter
+otherwise) and calls C<_exporter_fail> if it's unable to generate or
+retrieve a coderef.
+
+=item C<< _exporter_permitted_regexp($globals) >>
+
+This method is called to retrieve a regexp for validating the names of
+exportable subs. If a sub doesn't match the regexp, then the default
+implementation of C<_exporter_expand_sub> will refuse to export it. (Of
+course, you may override the default C<_exporter_expand_sub>.)
+
+The default implementation of this method assembles the regexp from
+C<< @EXPORT >> and C<< @EXPORT_OK >>.
+
+=item C<< _exporter_fail($name, $args, $globals) >>
+
+Called by C<_exporter_expand_sub> if it can't find a coderef to export.
+
+The default implementation just throws an exception. But you could emit
+a warning instead, or just ignore the failed export.
+
+If you don't throw an exception then you should be aware that this
+method is called in list context, and any list it returns will be treated
+as an C<_exporter_expand_sub>-style hash of names and coderefs for
+export.
+
+=item C<< _exporter_install_sub($name, $args, $globals, $coderef) >>
+
+This method actually installs the exported sub into its new destination.
+Its return value is ignored.
+
+The default implementation handles sub renaming (i.e. the C<< -as >>,
+C<< -prefix >> and C<< -suffix >> functions. This method does a lot of
+stuff; if you need to override it, it's probably a good idea to just
+pre-process the arguments and then call the super method rather than
+trying to handle all of it yourself.
+
+=item C<< _exporter_uninstall_sub($name, $args, $globals) >>
+
+The opposite of C<_exporter_install_sub>.
+
+=back
+
+=head1 DIAGNOSTICS
+
+=over
+
+=item B<< Overwriting existing sub '%s::%s' with sub '%s' exported by %s >>
+
+A warning issued if Exporter::Tiny is asked to export a symbol which
+will result in an existing sub being overwritten. This warning can be
+suppressed using either of the following:
+
+ use MyUtils { replace => 1 }, "frobnicate";
+ use MyUtils "frobnicate" => { -replace => 1 };
+
+Or can be upgraded to a fatal error:
+
+ use MyUtils { replace => "die" }, "frobnicate";
+ use MyUtils "frobnicate" => { -replace => "die" };
+
+=item B<< Refusing to overwrite existing sub '%s::%s' with sub '%s' exported by %s >>
+
+The fatal version of the above warning.
+
+=item B<< Could not find sub '%s' exported by %s >>
+
+You requested to import a sub which the package does not provide.
+
+=item B<< Cannot provide an -as option for tags >>
+
+Because a tag may provide more than one function, it does not make sense
+to request a single name for it. Instead use C<< -prefix >> or C<< -suffix >>.
+
+=item B<< Passing options to unimport '%s' makes no sense >>
+
+When you import a sub, it occasionally makes sense to pass some options
+for it. However, when unimporting, options do nothing, so this warning
+is issued.
+
+=back
+
+=head1 HISTORY
+
+L<Type::Library> had a bunch of custom exporting code which poked coderefs
+into its caller's stash. It needed this to be something more powerful than
+most exporters so that it could switch between exporting Moose, Mouse and
+Moo-compatible objects on request. L<Sub::Exporter> would have been capable,
+but had too many dependencies for the Type::Tiny project.
+
+Meanwhile L<Type::Utils>, L<Types::TypeTiny> and L<Test::TypeTiny> each
+used the venerable L<Exporter.pm|Exporter>. However, this meant they were
+unable to use the features like L<Sub::Exporter>-style function renaming
+which I'd built into Type::Library:
+
+ ## import "Str" but rename it to "String".
+ use Types::Standard "Str" => { -as => "String" };
+
+And so I decided to factor out code that could be shared by all Type-Tiny's
+exporters into a single place: Exporter::TypeTiny.
+
+As of version 0.026, Exporter::TypeTiny was also made available as
+L<Exporter::Tiny>, distributed independently on CPAN. CHOCOLATEBOY had
+convinced me that it was mature enough to live a life of its own.
+
+As of version 0.030, Type-Tiny depends on Exporter::Tiny and
+Exporter::TypeTiny is being phased out.
+
+=head1 OBLIGATORY EXPORTER COMPARISON
+
+Exporting is unlikely to be your application's performance bottleneck, but
+nonetheless here are some comparisons.
+
+B<< Comparative sizes according to L<Devel::SizeMe>: >>
+
+ Exporter 217.1Kb
+ Sub::Exporter::Progressive 263.2Kb
+ Exporter::Tiny 267.7Kb
+ Exporter + Exporter::Heavy 281.5Kb
+ Exporter::Renaming 406.2Kb
+ Sub::Exporter 701.0Kb
+
+B<< Performance exporting a single sub: >>
+
+ Rate SubExp ExpTiny SubExpProg ExpPM
+SubExp 2489/s -- -56% -85% -88%
+ExpTiny 5635/s 126% -- -67% -72%
+SubExpProg 16905/s 579% 200% -- -16%
+ExpPM 20097/s 707% 257% 19% --
+
+(Exporter::Renaming globally changes the behaviour of Exporter.pm, so could
+not be included in the same benchmarks.)
+
+B<< (Non-Core) Dependencies: >>
+
+ Exporter -1
+ Exporter::Renaming 0
+ Exporter::Tiny 0
+ Sub::Exporter::Progressive 0
+ Sub::Exporter 3
+
+B<< Features: >>
+
+ ExpPM ExpTiny SubExp SubExpProg
+ Can export code symbols............. Yes Yes Yes Yes
+ Can export non-code symbols......... Yes
+ Groups/tags......................... Yes Yes Yes Yes
+ Export by regexp.................... Yes Yes
+ Bang prefix......................... Yes Yes
+ Allows renaming of subs............. Yes Yes Maybe
+ Install code into scalar refs....... Yes Yes Maybe
+ Can be passed an "into" parameter... Yes Yes Maybe
+ Can be passed an "installer" sub.... Yes Yes Maybe
+ Config avoids package variables..... Yes
+ Supports generators................. Yes Yes
+ Sane API for generators............. Yes Yes
+ Unimport............................ Yes
+
+(Certain Sub::Exporter::Progressive features are only available if
+Sub::Exporter is installed.)
+
+=head1 BUGS
+
+Please report any bugs to
+L<http://rt.cpan.org/Dist/Display.html?Queue=Exporter-Tiny>.
+
+=head1 SUPPORT
+
+B<< IRC: >> support is available through in the I<< #moops >> channel
+on L<irc.perl.org|http://www.irc.perl.org/channels.html>.
+
+=head1 SEE ALSO
+
+L<Exporter::Shiny>,
+L<Sub::Exporter>,
+L<Exporter>.
+
+=head1 AUTHOR
+
+Toby Inkster E<lt>tobyink@cpan.orgE<gt>.
+
+=head1 COPYRIGHT AND LICENCE
+
+This software is copyright (c) 2013-2014 by Toby Inkster.
+
+This is free software; you can redistribute it and/or modify it under
+the same terms as the Perl 5 programming language system itself.
+
+=head1 DISCLAIMER OF WARRANTIES
+
+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.
+
diff --git a/t/01basic.t b/t/01basic.t
new file mode 100644
index 0000000..72dd3d7
--- /dev/null
+++ b/t/01basic.t
@@ -0,0 +1,38 @@
+=pod
+
+=encoding utf-8
+
+=head1 PURPOSE
+
+Very basic Exporter::Tiny test.
+
+Check that it allows us to import the functions named in C<< @EXPORT >>.
+
+=head1 AUTHOR
+
+Toby Inkster E<lt>tobyink@cpan.orgE<gt>.
+
+=head1 COPYRIGHT AND LICENCE
+
+This software is copyright (c) 2013 by Toby Inkster.
+
+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
+
+use strict;
+use warnings;
+use Test::More tests => 2;
+
+use lib qw( examples ../examples );
+
+use Example::Exporter;
+
+diag("Perl $]");
+
+is fib(6), 8, 'Correctly imported "fib" from Example::Exporter';
+
+ok !__PACKAGE__->can('embiggen'), 'Did not inadvertantly import "embiggen"';
+
diff --git a/t/02renaming.t b/t/02renaming.t
new file mode 100644
index 0000000..857b81c
--- /dev/null
+++ b/t/02renaming.t
@@ -0,0 +1,50 @@
+=pod
+
+=encoding utf-8
+
+=head1 PURPOSE
+
+Check renaming imported functions.
+
+=head1 AUTHOR
+
+Toby Inkster E<lt>tobyink@cpan.orgE<gt>.
+
+=head1 COPYRIGHT AND LICENCE
+
+This software is copyright (c) 2013 by Toby Inkster.
+
+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
+
+use strict;
+use warnings;
+use Test::More tests => 6;
+
+BEGIN { *note = *diag unless __PACKAGE__->can("note") };
+
+use lib qw( examples ../examples );
+
+note "Rename functions using -as"; do {
+ package Local::AAA;
+ use Example::Exporter fib => { -as => 'fibonacci' };
+ ::is fibonacci(6), 8, 'Correctly imported "fibonacci" from Example::Exporter';
+ ::ok !__PACKAGE__->can('fib'), 'Did not inadvertantly import "fib"';
+};
+
+note "Rename functions using -prefix"; do {
+ package Local::BBB;
+ use Example::Exporter fib => { -prefix => 'my' };
+ ::is myfib(6), 8, 'Correctly imported "myfib" from Example::Exporter';
+ ::ok !__PACKAGE__->can('fib'), 'Did not inadvertantly import "fib"';
+};
+
+note "Rename functions using -suffix"; do {
+ package Local::CCC;
+ use Example::Exporter fib => { -suffix => 'onacci' };
+ ::is fibonacci(6), 8, 'Correctly imported "fibonacci" from Example::Exporter';
+ ::ok !__PACKAGE__->can('fib'), 'Did not inadvertantly import "fib"';
+};
+
diff --git a/t/03generators.t b/t/03generators.t
new file mode 100644
index 0000000..1f69d10
--- /dev/null
+++ b/t/03generators.t
@@ -0,0 +1,38 @@
+=pod
+
+=encoding utf-8
+
+=head1 PURPOSE
+
+Check renaming imported functions.
+
+=head1 AUTHOR
+
+Toby Inkster E<lt>tobyink@cpan.orgE<gt>.
+
+=head1 COPYRIGHT AND LICENCE
+
+This software is copyright (c) 2013 by Toby Inkster.
+
+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
+
+use strict;
+use warnings;
+use Test::More tests => 4;
+
+use lib qw( examples ../examples );
+
+use Example::Exporter
+ embiggen => {},
+ embiggen => { -suffix => '_by_2', amount => 2 },
+ embiggen => { -suffix => '_by_42', amount => 42 };
+
+is embiggen(10), 11, 'embiggen';
+is embiggen_by_2(10), 12, 'embiggen_by_2';
+is embiggen_by_42(10), 52, 'embiggen_by_42';
+
+is prototype(\&embiggen), '$', 'correct prototype';
+
diff --git a/t/04into.t b/t/04into.t
new file mode 100644
index 0000000..d621fef
--- /dev/null
+++ b/t/04into.t
@@ -0,0 +1,36 @@
+=pod
+
+=encoding utf-8
+
+=head1 PURPOSE
+
+Check the C<< -into >> option works.
+
+=head1 AUTHOR
+
+Toby Inkster E<lt>tobyink@cpan.orgE<gt>.
+
+=head1 COPYRIGHT AND LICENCE
+
+This software is copyright (c) 2013 by Toby Inkster.
+
+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
+
+use strict;
+use warnings;
+use Test::More tests => 2;
+
+use lib qw( examples ../examples );
+
+{
+ package Foo;
+ use Example::Exporter { into => "Bar" }, qw( fib );
+}
+
+{ package Bar; }
+
+ok( not "Foo"->can("fib") );
+ok( "Bar"->can("fib") );
diff --git a/t/05shiny.t b/t/05shiny.t
new file mode 100644
index 0000000..9b5875d
--- /dev/null
+++ b/t/05shiny.t
@@ -0,0 +1,40 @@
+=pod
+
+=encoding utf-8
+
+=head1 PURPOSE
+
+Very basic Exporter::Shiny test.
+
+=head1 AUTHOR
+
+Toby Inkster E<lt>tobyink@cpan.orgE<gt>.
+
+=head1 COPYRIGHT AND LICENCE
+
+This software is copyright (c) 2014 by Toby Inkster.
+
+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
+
+use strict;
+use warnings;
+use Test::More tests => 1;
+
+{
+ package Local::Foo;
+ use Exporter::Shiny qw(foo bar);
+ sub foo {
+ return 42;
+ }
+ sub bar {
+ return 666;
+ }
+}
+
+use Local::Foo qw(foo);
+
+is(foo(), 42);
diff --git a/t/06notwant.t b/t/06notwant.t
new file mode 100644
index 0000000..992bbd7
--- /dev/null
+++ b/t/06notwant.t
@@ -0,0 +1,41 @@
+=pod
+
+=encoding utf-8
+
+=head1 PURPOSE
+
+Test the C<< !notwant >> notation.
+
+=head1 AUTHOR
+
+Toby Inkster E<lt>tobyink@cpan.orgE<gt>.
+
+=head1 COPYRIGHT AND LICENCE
+
+This software is copyright (c) 2014 by Toby Inkster.
+
+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
+
+use strict;
+use warnings;
+use Test::More tests => 1;
+
+{
+ package Local::Foo;
+ use Exporter::Shiny qw(foo bar);
+ sub foo {
+ return 42;
+ }
+ sub bar {
+ return 666;
+ }
+}
+
+my %imported;
+'Local::Foo'->import({ into => \%imported }, qw( -all !foo ));
+
+is_deeply([sort keys %imported], ['bar']);
diff --git a/t/07regexp.t b/t/07regexp.t
new file mode 100644
index 0000000..998dc4e
--- /dev/null
+++ b/t/07regexp.t
@@ -0,0 +1,48 @@
+=pod
+
+=encoding utf-8
+
+=head1 PURPOSE
+
+Test the C<< /regexp/ >> notation.
+
+=head1 AUTHOR
+
+Toby Inkster E<lt>tobyink@cpan.orgE<gt>.
+
+=head1 COPYRIGHT AND LICENCE
+
+This software is copyright (c) 2014 by Toby Inkster.
+
+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
+
+use strict;
+use warnings;
+use Test::More tests => 2;
+
+{
+ package Local::Foo;
+ use Exporter::Shiny qw(foo bar);
+ sub foo {
+ return 42;
+ }
+ sub bar {
+ return 666;
+ }
+}
+
+{
+ my %imported;
+ 'Local::Foo'->import({ into => \%imported }, qw( /^F/i ));
+ is_deeply([sort keys %imported], ['foo']);
+}
+
+{
+ my %imported;
+ 'Local::Foo'->import({ into => \%imported }, qw( -all !/^F/i ));
+ is_deeply([sort keys %imported], ['bar']);
+}
diff --git a/t/08tags.t b/t/08tags.t
new file mode 100644
index 0000000..036dc3b
--- /dev/null
+++ b/t/08tags.t
@@ -0,0 +1,66 @@
+=pod
+
+=encoding utf-8
+
+=head1 PURPOSE
+
+Test that tag expansion works sanely.
+
+=head1 AUTHOR
+
+Toby Inkster E<lt>tobyink@cpan.orgE<gt>.
+
+=head1 COPYRIGHT AND LICENCE
+
+This software is copyright (c) 2014 by Toby Inkster.
+
+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
+
+use strict;
+use warnings;
+use Test::More tests => 7;
+
+BEGIN {
+ package Local::Foo;
+ use Exporter::Shiny qw(foo bar);
+ our %EXPORT_TAGS = (
+ first => [ 'foo' => { xxx => 41 }, 'bar' ],
+ second => [ 'foo', 'bar' ],
+ upper => [
+ 'foo' => { -as => 'O', -prefix => 'F', -suffix => 'O' },
+ 'bar' => { -as => 'A', -prefix => 'B', -suffix => 'R' },
+ ],
+ );
+ sub _generate_foo {
+ my $me = shift;
+ my ($name, $args) = @_;
+ return sub () { $args->{xxx} };
+ }
+ sub _generate_bar {
+ my $me = shift;
+ my ($name, $args) = @_;
+ return sub () { $args->{xxx} };
+ }
+};
+
+use Local::Foo
+ -first => { -prefix => 'first_' },
+ -second => { -prefix => 'second_', xxx => 666 },
+ -first => { -prefix => 'third_', xxx => 42 };
+
+is(first_foo, 41);
+is(first_bar, undef);
+
+is(second_foo, 666);
+is(second_bar, 666);
+
+is(third_foo, 42);
+is(third_bar, 42);
+
+use Local::Foo -upper => { -prefix => 'MY', xxx => 999 };
+
+is(MYFOO, 999);
diff --git a/t/09warnings.t b/t/09warnings.t
new file mode 100644
index 0000000..72d40f3
--- /dev/null
+++ b/t/09warnings.t
@@ -0,0 +1,83 @@
+=pod
+
+=encoding utf-8
+
+=head1 PURPOSE
+
+Test sub redefinition warnings/errors.
+
+=head1 AUTHOR
+
+Toby Inkster E<lt>tobyink@cpan.orgE<gt>.
+
+=head1 COPYRIGHT AND LICENCE
+
+This software is copyright (c) 2014 by Toby Inkster.
+
+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
+
+use strict;
+use warnings;
+use Test::More;
+
+BEGIN {
+ eval "use Test::Fatal; use Test::Warnings qw(warning :no_end_test); 1"
+ or plan skip_all => "test requires Test::Warnings and Test::Fatal";
+
+ plan tests => 4;
+};
+
+BEGIN {
+ package Local::Exporter;
+ use Exporter::Shiny qw(foo bar);
+ sub foo { 666 }
+ sub bar { 999 }
+};
+
+like(
+ warning { eval q{
+ package Local::Test1;
+ sub foo { 42 }
+ use Local::Exporter -all;
+ 1;
+ } },
+ qr/^Overwriting existing sub 'Local::Test1::foo' with sub 'foo' exported by Local::Exporter/,
+ 'warning about overwriting sub',
+);
+
+like(
+ exception { eval q{
+ package Local::Test2;
+ sub foo { 42 }
+ use Local::Exporter { replace => 'die' }, -all;
+ 1;
+ } or die $@ },
+ qr/^Refusing to overwrite existing sub 'Local::Test2::foo' with sub 'foo' exported by Local::Exporter/,
+ '... which can be fatalized',
+);
+
+is_deeply(
+ warning { eval q{
+ package Local::Test3;
+ sub foo { 42 }
+ use Local::Exporter { replace => 'die' }, -all;
+ 1;
+ } },
+ [],
+ '... or suppressed',
+);
+
+is_deeply(
+ warning { eval q{
+ package Local::Test4;
+ use Local::Exporter -all;
+ use Local::Exporter qw(foo);
+ 1;
+ } },
+ [],
+ 'but importing the exact same sub twice is OK',
+);
diff --git a/t/10no.t b/t/10no.t
new file mode 100644
index 0000000..66b0f82
--- /dev/null
+++ b/t/10no.t
@@ -0,0 +1,54 @@
+=pod
+
+=encoding utf-8
+
+=head1 PURPOSE
+
+Check C<< unimport >> works.
+
+=head1 AUTHOR
+
+Toby Inkster E<lt>tobyink@cpan.orgE<gt>.
+
+=head1 COPYRIGHT AND LICENCE
+
+This software is copyright (c) 2014 by Toby Inkster.
+
+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
+
+use strict;
+use warnings;
+use Test::More tests => 7;
+
+use lib qw( examples ../examples );
+
+{
+ package Local::Pkg1;
+ use Example::Exporter;
+ ::is( fib(6), 8, 'fib exported' );
+ no Example::Exporter;
+}
+
+ok( !Local::Pkg1->can('fib'), 'tidied fib' );
+
+{
+ package Local::Pkg2;
+ use Example::Exporter fib => { -as => 'fibo' };
+ ::is( fibo(6), 8, 'fibo exported' );
+ no Example::Exporter;
+}
+
+ok( !Local::Pkg2->can('fibo'), 'tidied fibo' );
+
+{
+ package Local::Pkg3;
+ use Example::Exporter -all;
+ ::is( fib(6), 8, 'fib exported' );
+ ::is( embiggen(6), 7, 'embiggen exported' );
+ no Example::Exporter qw( /^F/i );
+}
+
+ok( Local::Pkg3->can('embiggen') && !Local::Pkg3->can('fib'), 'tidied by regexp' );