=pod

=encoding utf-8

=head1 NAME

sanity - The ONLY meta pragma you'll ever need!

=head1 SYNOPSIS

  use sanity;
  use sanity 'strictures';
  use sanity 'Modern::Perl';

  use sanity qw(
     strictures -warnings/uninitialized/FATAL
     NO:autovivification NO:autovivification/store
     PRINT_PRAGMA_HASH
  );
  use sanity '!0*b^Npow{8T7_yZt<?cT6/?ZCO=Y0LV_Duoc';  # Safer ASCII version
  use sanity '¡0Dz鵆㤧뱞⡫瘑빸ን둈댬嚝⠨舁聼䮋';  # Shorter UTF8 version

=head1 DESCRIPTION

Modern::Perl?  common::sense?  no nonsense?  use latest?

Everybody has their own opinion on what pragmas and modules are "required"
for every person to use.  These opinions turn into "personal pragmas", so that
people don't have to type several C<use> lines of header in front of every module
they write.

Personal opinions and pragmas don't really belong in the CPAN namespace.  (It's
CPAN, not Personal PAN.  If you want a Personal PAN, go call Pizza Hut.)  But
copying code on potentially hundreds of modules doesn't make sense, either.

That was my mentality when I had a personal opinion of my own.  Why repeat the same
problem like everybody else?

This "sanity" module attempts to level the playing field by making it a
B<customizable> personal pragma, allowing you to both reduce the code needed and
still implement all of the modules/pragmas you need.

As an illustration to what it's capable of, this pragma will emulate all of the
other personal pragmas, most of them 100% working exactly how they do it.

=head1 PARAMETERS

Sanity's parameters fall into three types: flags, aliases, and hashes.  (Oh my!)

=head2 Flags and Aliases

Flags are single pragma/module declarations, strict/warning flags, or other
items that need flags.  Aliases are merely one or more flags, grouped
together to better emulate the pragma/module's functionality.

Let's start off with an example:

  # These three statements do the same thing as...
  use Modern::Perl;
  use sanity 'Modern::Perl';
  use sanity qw(strict warnings mro/dfs feature IO::File IO::Handle);

  # ...these statements
  use strict;
  use warnings;
  use mro 'dfs';
  use feature ':all';
  use IO::File;
  use IO::Handle;

Basically, it does the same thing as the meta pragma L<Modern::Perl>, except
you actually don't need that module for it to work.  While there is some magic
to make sure, say, C<feature> gets loaded with various versions of Perl, it typically
just works using a standard C<import> call.  The C<strict> and C<warnings> flags
are combined aliases that enable all of the warnings that they would do via a standard
call.

=head3 Negating flags/aliases

You can turn off flags in the statement:

  use sanity qw(Modern::Perl -mro/dfs);

This does the same thing as above, except it doesn't import the C<mro> pragma.  You
can negate any flag, including combined aliases, as long as it makes sense.  In other
words, you need a positive included before you can negate something.

=head3 NO:* flags/aliases

Some pragmas work by using the C<B<unimport>> function, so that the English makes sense.
To keep that syntax, these pragmas are included with a C<NO:> prefix:

  use sanity 'NO:multidimensional';
  use sanity 'NO:indirect/FATAL';

This will run the C<unimport> function on these pragmas, even though sanity was called
via the C<import> function (via C<use>).

=head3 Perl versions

Sanity also supports Perl versions as a special kind of alias to specify minimum Perl
versions:

  # These are all the same:
  use v5.10.1;
  use sanity 'v5.10.1';
  use sanity v5.10.1;  # as a VSTRING
  use sanity 5.10.1;   # works too

  # Upgrade the Perl version of your favorite pragma
  use sanity qw(NO:nonsense v5.12);

Note that the version must be at least v5.8.  This should be fine for most people.  (If
I get a ticket requesting support for a Perl version older than one released in 2002, I
will hunt you down and break your keyboard in half.)

=head3 The Default

What does C<sanity> do without any parameters?  Why my personal preference, of course :)
It's listed in the C<meta pragma> section of the L<LIST OF FLAGS> below.  I detail the
reasons behind my choices L<here|sanity::sanity>.

=head2 Hashes

So, there's all of these flags, but unless you're using one of the combined aliases,
typing them all out is usually just as much (or more) code as the several lines of C<use>
statements.  Well, they are all flags so that it fits into a giant bitmap, and that
bitmap can be compressed into a large ASCII (or UTF-8) "number".

This number can be calculated using the flag C<PRINT_PRAGMA_HASH>:

  # This is merely the definition of uni::perl
  use sanity (qw(
     v5.10 strict feature/5.10
  ), (
     map { "warnings/$_/FATAL" } qw(closed threads internal debugging pack substr malloc
     unopened portable prototype inplace io pipe unpack regexp deprecated exiting glob
     digit printf utf8 layer reserved parenthesis taint closure semicolon)
  ), qw(
     -warnings/exec/FATAL
     -warnings/newline/FATAL
     utf8
     open/utf8
     open/std
     mro/c3
     Carp
  ), 'PRINT_PRAGMA_HASH');

  # Outputs:
  # use sanity '!04[D{9Fhfqc-7m738S4HK6B#D5=v{,T$(0)F5i';  # Safer ASCII version
  # use sanity '¡05༕ቑ釩腜쥸봱楇䐍퇥熠ᾯ緻褻真堩';  # Shorter UTF8 version

You can use that hash as the output illustrates without having to type out the entire big
set of commands or flags.

=head2 Other Meta Pragmas

Have your own set that is too long, and you don't like the ugliness of the hash?  Send me
your suggestion and I'll probably add it in.

=head1 CAVEATS

=head2 'NO:' ne '-'

A C<NO:> flag is NOT the same as negating a flag!  You also cannot remove the C<NO:>
from a flag, as it's part of the name of the flag, not a special modifier.

  # These two are NOT the same!
  use sanity 'NO:indirect';  # runs indirect->unimport()
  use sanity '-indirect';    # Dies, as there is no such flag/alias

  # This runs through the strictures alias and runs autovivification->unimport()
  use sanity qw(strictures NO:autovivification);

  # This runs through the strictures alias WITHOUT running indirect->unimport()
  use sanity qw(strictures -NO:indirect);

  use sanity '-indirect';    # This isn't what you want...
  no  sanity 'NO:indirect';  # ...you really meant to do this...
  use indirect;              # ...but this is better

=head2 Special clearing of strict/warnings

Since most people want exactly the strictness and warnings they specify, sanity will
clear these out first before running through the list.

  # This...
  use sanity qw(strict -strict/vars);

  # ...is the same as this...
  no strict;
  use strict qw(subs refs);

Also, some special magic is in place to ensure that newer warnings/features aren't
fatal to older Perls.  See L<https://rt.perl.org/rt3/Ticket/Display.html?id=112920>.

=head2 "Author" pragmas

Certain pragmas really only exist to make sure the code is designed right.  These
pragmas are deemed "optional" by C<sanity>.  In other words, if the user doesn't
have them, it will just silently ignore them and move on.  If C<sanity> thinks your
an author/coder of the module itself (.git/svn/$ENV checks), it will give you a
warning that they are missing, but move on.

The following modules don't "instadie".  Modules that fall under this list don't
change the nature of how Perl works, or would let you do something that would
normally fatally error.

  overloading
  autovivification
  indirect
  multidimensional
  bareword::filehandles
  criticism

  # (autovivification probably shouldn't be here, since it actually
  # prevents autoviv, but it's generally used as an author tool.)

This feature was borrowed from L<strictures> and tweaked.

=head1 LIST OF FLAGS

=head2 Emulation of "meta pragmas"

  ex::caution:
     strict
     warnings
  NO:crap:  # Same as above
  shit:     # Same as above
  latest:
     strict
     warnings
     feature
  sane:
     strict
     warnings
     feature
     utf8
  NO:nonsense:
     strict
     warnings
     true
     namespace::autoclean
  Modern::Perl:
     strict
     warnings
     mro 'dfs'
     feature
     IO::File
     IO::Handle
  strictures: (without the 5.8.4 checks; that crap is old)
     v5.8.4 (forced, to make sure things work)
     strict
     warnings FATAL => 'all'
     no indirect 'fatal'
     no multidimensional
     no bareword::filehandles
  common::sense: (without the "memory usage" BS)
     utf8
     strict qw(subs vars)
     feature qw(say state switch)
     no warnings
     warnings FATAL => qw(closed threads internal debugging pack malloc portable prototype
                          inplace io pipe unpack deprecated glob digit printf
                          layer reserved taint closure semicolon)
     no warnings qw(exec newline unopened);
  uni::perl: (ditto)
     v5.10
     strict
     feature qw(say state switch)
     no warnings
     warnings qw(FATAL closed threads internal debugging pack substr malloc
                     unopened portable prototype inplace io pipe unpack regexp
                     deprecated exiting glob digit printf utf8 layer
                     reserved parenthesis taint closure semicolon)
     no warnings qw(exec newline)
     utf8
     open (:utf8 :std)
     mro 'c3'
     Carp
  sanity:
     v5.10.1
     utf8
     open (:utf8 :std)
     mro 'c3'
     strict qw(subs vars)
     no strict 'refs'
     warnings FATAL => 'all'
     no warnings qw(uninitialized)
     feature
     no autovivification qw(fetch exists delete store strict)
     no indirect 'fatal'
     no multidimensional
  perl5i::0 / 1 / 2 / latest:
     [the real module] (the pragma is too insane to try to duplicate here)
  Acme::Very::Modern::Perl:  (a joke, but it's still here all the same)
     strict
     warnings
     mro 'c3'
     feature
     IO::File
     IO::Handle
     utf8
     open (:utf8 :std)
     no warnings
     warnings FATAL => qw(closed threads internal debugging pack malloc portable prototype
                          inplace io pipe unpack deprecated glob digit printf
                          layer reserved taint closure semicolon)
     no warnings qw(exec newline unopened);
     perl5i::latest
     Toolkit
     Carp

=head2 Other flags/aliases

  strict/* => strict '[whatever]'        # supports all flags
  strict   => strict qw(refs subs vars)

  # other "hints"
  integer
  locale
  bytes
  re/taint
  re/eval
  filetest
  utf8
  NO:overloading

  warnings/*       => warnings NONFATAL => '[whatever]'  # supports all flags, multi or not
  warnings/*/FATAL => warnings    FATAL => '[whatever]'  # supports all flags; FATAL trumps NONFATAL
  warnings         => warnings NONFATAL => 'all'
  warnings/FATAL   => warnings    FATAL => 'all'

  feature/*        => feature '[whatever]'  # supports all flags
  feature/5.##     => # similar to feature enabling via 'use v5.##'; major version only
  feature/5.9.5    => # also exists, just like feature/5.10
  feature          => feature ':all'  # not exactly, but in spirit

  # Perl versions, described above
  v5.##.##

  # autodie
  autodie/* => autodie ':[whatever]'  # supports all _category_ flags, like all, io, shm, etc.
                                      # (Will expand if requested, but I don't want to waste
                                      # all of that bit space right now.)
  autodie   => autodie ':default'

  # other CORE pragmas
  bigint
  bignum
  bigrat
  charnames
  charnames/short
  charnames/full
  encoding::warnings
  encoding::warnings/FATAL
  mro/dfs                    # default for 'mro'
  mro/c3
  open/*

  # namespace cleaners
  namespace::clean       # included last; adds -except => 'meta'
  namespace::functions   # included last
  namespace::autoclean
  namespace::sweep

  # others
  NO:autovivification/*
  NO:autovivification => no autovivification qw(fetch exists delete)

  criticism/*
  criticism   => criticism 'gentle'

  perl5i::0
  perl5i::1
  perl5i::2
  perl5i::3
  perl5i::latest

  NO:indirect
  NO:indirect/global
  NO:indirect/fatal
  NO:multidimensional
  NO:bareword::filehandles

  subs::auto
  utf8::all
  IO::File
  IO::Handle
  IO::All
  Carp
  vendorlib
  true
  autolocale
  Toolkit

Am I missing something?  Let me know.

=head1 TODO

Actually need to write sanity::sanity POD.

=head1 AVAILABILITY

The project homepage is L<https://github.com/SineSwiper/sanity/wiki>.

The latest version of this module is available from the Comprehensive Perl
Archive Network (CPAN). Visit L<http://www.perl.com/CPAN/> to find a CPAN
site near you, or see L<https://metacpan.org/module/sanity/>.

=for :stopwords cpan testmatrix url annocpan anno bugtracker rt cpants kwalitee diff irc mailto metadata placeholders metacpan

=head1 SUPPORT

=head2 Internet Relay Chat

You can get live help by using IRC ( Internet Relay Chat ). If you don't know what IRC is,
please read this excellent guide: L<http://en.wikipedia.org/wiki/Internet_Relay_Chat>. Please
be courteous and patient when talking to us, as we might be busy or sleeping! You can join
those networks/channels and get help:

=over 4

=item *

irc.perl.org

You can connect to the server at 'irc.perl.org' and join this channel: #distzilla then talk to this person for help: SineSwiper.

=back

=head2 Bugs / Feature Requests

Please report any bugs or feature requests via L<L<https://github.com/SineSwiper/sanity/issues>|GitHub>.

=head1 AUTHOR

Brendan Byrd <[email protected]>

=head1 COPYRIGHT AND LICENSE

This software is Copyright (c) 2012 by Brendan Byrd.

This is free software, licensed under:

 The Artistic License 2.0 (GPL Compatible)