The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
#=package Cheat::Sheet::Util
#=version 0.0.5
#=tagline Cheat sheet for utility modules
#=author  =  Copyright 2011 Xiong Changnian <xiong@cpan.org>   =
#=license = Free Software = Artistic License 2.0 = NO WARRANTY =
#=quote 
    I only had a high school education and believe me,
    I had to cheat to get that. 
    --Sparky Anderson

#-#========================================================================#-#
#-#=====# # UTILITY MODULES
#-#                             # [<-44 cols to end                78 cols ->]
#-#                             # #2345678901234567890123456789012345678901234
#-#
#=head2 Scalar::Util
use Scalar::Util;               # General-utility scalar subroutines
use Scalar::Util qw(
    weaken isweak reftype refaddr blessed isvstring readonly tainted 
    dualvar looks_like_number openhandle set_prototype 
);
    weaken $ref;            # $ref will not keep @$ref, %$ref, etc. from GC
                            # note: copies of weak refs are not weak
    $bool = isweak  $ref;       # true if $ref is a weak reference
    $type = reftype $ref;       # 'SCALAR', 'ARRAY', 'HASH', or undef
    $addr = refaddr $ref;       # machine address of $ref or undef
    $got  = blessed $ref;       # class of blessed ref or undef 
    $bool = isvstring $s;       # true if $s is a v-string
    $bool = readonly  $s;       # true if $s is a readonly scalar
    $bool = tainted   $s;       # true if $s is tainted
    $got  = dualvar $num, $string;      # $got is $num or $string in context 
    $bool = looks_like_number $n;       # true if $n can be a number
    $fh   = openhandle $t_fh;       # $h if $t_fh is a tied or open filehandle
    set_prototype $cref, $proto;        # sets prototype of &$cref to $proto
## Scalar::Util

#=head2 List::Util
use List::Util;                 # General-utility list subroutines
use List::Util qw( max maxstr min minstr first reduce shuffle sum );
    $got  = max    @a;          # returns item >  than all the rest
    $got  = maxstr @a;          # returns item gt than all the rest
    $got  = min    @a;          # returns item <  than all the rest
    $got  = minstr @a;          # returns item lt than all the rest
    $got  = first  {$_} @a;     # ~grep but returns only first true item 
    $got  = reduce { $bool?$a:$b } @a;  # returns one item; last man standing 
    $got  = sum @a;             # sum of all elements
    @gots = shuffle @a;         # pseudo-randomizes order of @a
    # "The following are additions that have been requested..."
    sub any { $_ && return 1 for @_; 0 };       # One argument is true
    sub all { $_ || return 0 for @_; 1 };       # All arguments are true
    sub none { $_ && return 0 for @_; 1 };      # All arguments are false
    sub notall { $_ || return 1 for @_; 0 };    # One argument is false
    sub true { scalar grep { $_ } @_ };         # How many elements are true
    sub false { scalar grep { !$_ } @_ };       # How many elements are false
## List::Util

#=head2 List::MoreUtils
use List::MoreUtils ':all';     # The stuff missing in List::Util
use List::MoreUtils qw(
    any all none notall true false firstidx first_index 
    lastidx last_index insert_after insert_after_string 
    apply after after_incl before before_incl indexes 
    firstval first_value lastval last_value each_array
    each_arrayref pairwise natatime mesh zip uniq minmax
);
    # These operators take a block (~grep), setting $_ to each item in @a
    # Your block should test $_ and return a $bool
    $bool  = any    {$_} @a;    # true if any test  is  true   (  $A ||  $B )
    $bool  = all    {$_} @a;    # true if all tests are true   (  $A &&  $B )
    $bool  = none   {$_} @a;    # true if all tests are false  ( !$A && !$B )
    $bool  = notall {$_} @a;    # true if any test  is  false  ( !$A || !$B )
    #   #   #   #   #   #   De Morgan's Laws:    #   #   #   #   #   #   #   # 
    # ( !$A && !$B ) == !(  $A || $B  ) and ( !$A || !$B ) == !(  $A &&  $B )
    # (  $A &&  $B ) == !( !$A || !$B ) and (  $A ||  $B ) == !( !$A && !$B )
    $count = true   {$_} @a;        # how many true tests
    $count = false  {$_} @a;        # how many false tests
    $got  = firstidx{$_} @a;        # first item with true test
    $got  = first_index             # ditto; alias firstidx
    $got  = lastidx {$_} @a;        # last item with true test
    $got  = last_index              # ditto; alias lastidx
    $got  = insert_after {$_} $v => @a;   # put $v in @a after first true test        
    $got  = insert_after_string $s, $v => @a;  # insert after first item eq $s
    @gots = apply       {$_} @a;    # ~ map but doesn't modify @a
    @gots = after       {$_} @a;    # ( c )    ~~ after       {/b/} (a, b, c)
    @gots = after_incl  {$_} @a;    # ( b, c ) ~~ after_incl  {/b/} (a, b, c)
    @gots = before      {$_} @a;    # ( a )    ~~ before      {/b/} (a, b, c)
    @gots = before_incl {$_} @a;    # ( a, b ) ~~ before_incl {/b/} (a, b, c)
    @gots = indexes     {$_} @a;    # ( 1 )    ~~ indexes     {/b/} (a, b, c)
    $got  = firstval    {$_} @a;    # ~List::Util::first() but -1 on fail
    $got  = first_value             # ditto; alias firstval
    $got  = lastval     {$_} @a;    # last item testing true
    $got  = last_value              # ditto; alias lastval
    $cref = each_array @a, @b, @c;  # creates an n-tuplewise iterator closure
    while ( my ($A, $B, $C) = $cref->() ) {     # returns empty list 
        # Your code here                        #   when all lists exhausted
    };
    $cref = each_arrayref @a, @b, @c;   # iterator returns refs to arg lists
    $cref = natatime $n, @a;    # creates $n-at-a-time iterator from one list
    @gots = pairwise    {$_} @a, @b;    # ~map over two arrays
    @gots = mesh @a, @b, @c;    # ( $a[0], $b[0], $c[0], $a[1], $b[1], $c[1] )
    @gots = zip  @a, @b, @c;    # ditto; alias mesh
    @gots = uniq @a;            # returns *only* unique elements
    ( $min, $max )  = minmax @a;    # ~( List::Util::min(@a), ::max(@a) )
    @refs = part { $p = f($_) } @a; # partitions @a into multiple lists
    # you return integer $p as index of @refs; @refs is a list of arrayrefs
## List::MoreUtils

#=head2 List::AllUtils
use List::AllUtils qw( :all );  # Everything from List::Util, List::MoreUtils
    
#=head2 List::Compare
use List::Compare;              # Compare elements of two or more lists
# This object-oriented module is highly orthogonal, 
#   so that nearly any selection or choice may be combined with any other. 
# Most methods are equally okay for ( just two ) or ( three or more ) lists; 
#   some will Carp if called inappropriately.
#                            === Options/Modes === 
#           Regular: (default) Two lists, sorted results, many method calls ok
#          Unsorted: Don't sort method results              ( faster ) 
#       Accelerated: Only one method call possible per $lc  ( faster )
#          Multiple: Three or more lists in constructor 
# ! (specify $ix to refer to a given list; default 0; omit for only two lists)
#         Seen-hash: Use hashrefs instead of arrayrefs: 
#   [ 11, 12, 14, 14, 14, 15 ] ~~ { 11 => 1, 12 => 1, 14 => 3, 15 => 1 }
#
    # Construct a work-object 
    my $lc = List::Compare->new(             \@a, \@b, @c );  # default
    my $lc = List::Compare->new( '-u',       \@a, \@b, @c );  # unsorted
    my $lc = List::Compare->new(       '-a', \@a, \@b, @c );  # accelerated
    my $lc = List::Compare->new( '-u', '-a', \@a, \@b, @c );  #! -u before -a
    # Wrap constructor arguments in a hashref
    my $lc = List::Compare->new({
        unsorted    => 1,
        accelerated => 1,
        lists       => [ \@a, \@b, @c ],
    });
    # Methods return lists of results
    @gots = $lc->get_intersection;          # found in each/both list(s)
    @gots = $lc->get_union;                 # found in any/either list
    @gots = $lc->get_bag;                   # ~get_union but also duplicates
    @gots = $lc->get_unique($ix);           # found only in list $ix
    @gots = $lc->get_complement($ix);       # not found in $ix, but elsewhere
    @gots = $lc->get_symmetric_difference;  # found in only one list
    $gots = $lc->get_intersection_ref;          # ~methods above but
    $gots = $lc->get_union_ref;                 #           returns \@gots
    $gots = $lc->get_bag_ref;                   #       "
    $gots = $lc->get_unique_ref($ix);           #       "
    $gots = $lc->get_complement_ref($ix);       #       "
    $gots = $lc->get_symmetric_difference_ref;  #       "
    # Methods return boolean truth      # ( $ixL, $ixR ) default to ( 0, 1 )
    $bool = $lc->is_LsubsetR( $ixL, $ixR );     # true if all L in R
    $bool = $lc->is_RsubsetL( $ixL, $ixR );     # true if all R in L
    $bool = $lc->is_LequivalentR( $ixL, $ixR ); # true if same items in L, R
    $bool = $lc->is_LdisjointR( $ixL, $ixR );   # true if no items in common
    # Methods return list of which lists ($ix) satisfying conditions
    @ixs  = $lc->is_member_which($string);      # some item in $ix eq $string
    @ixs  = $lc->are_members_which(\@strings);  # ~prev but eq any in @strings
    # Dump
    $lc->print_subset_chart;        # pretty-print tables showing some
    $lc->print_equivalence_chart;   #   relationships; row/col as $ix
# List::Compare

#=head2 Hash::Util
use Hash::Util;                 # Hash locking, key locking, value locking
use Hash::Util qw(
    lock_keys lock_keys_plus unlock_keys 
    lock_value unlock_value 
    lock_hash unlock_hash lock_hash_recurse unlock_hash_recurse
    hash_locked hidden_keys legal_keys all_keys 
);
    # Restrict %hash to a set of keys; can delete but can't add other keys
    \%hash = lock_keys     ( %hash );           # current keys %hash
    \%hash = lock_keys     ( %hash, @keys );    # @keys; subset of keys @hash
    \%hash = lock_keys_plus( %hash, @keys );    #        superset
    \%hash = unlock_keys   ( %hash );           # remove restrictions
    # Cannot alter value of $key but can delete the k/v pair
    \%hash = lock_value    ( %hash, $key );
    \%hash = unlock_value  ( %hash, $key );
    # Lock the whole %hash; can't add, delete, or change value at all
    \%hash = lock_hash              ( %hash );
    \%hash = unlock_hash            ( %hash );
    \%hash = lock_hash_recurse      ( %hash );  # HoHoH... only
    \%hash = unlock_hash_recurse    ( %hash );  #   ditto
    # Other functions...
    $bool  = hash_unlocked ( %hash );       # true if %hash is unlocked
    @keys  = legal_keys    ( %hash );       # list of keys allowed
    @keys  = hidden_keys   ( %hash );       # see docs; experimental feature
    \%hash = all_keys( %hash, @keys, @hidden );       # experimental feature
    # Just like Daddy but take hashref arguments
    \%hash = lock_ref_keys          ( \%hash );
    \%hash = lock_ref_keys          ( \%hash, @keys );
    \%hash = lock_ref_keys_plus     ( \%hash, @keys );
    \%hash = unlock_ref_keys        ( \%hash );
    \%hash = lock_ref_value         ( \%hash, $key );
    \%hash = unlock_ref_value       ( \%hash, $key );
    \%hash = lock_hashref           ( \%hash );
    \%hash = unlock_hashref         ( \%hash );
    \%hash = lock_hashref_recurse   ( \%hash );
    \%hash = unlock_hashref_recurse ( \%hash );
    $bool  = hash_ref_unlocked      ( \%hash );
    @keys  = legal_ref_keys         ( \%hash );
    @keys  = hidden_ref_keys        ( \%hash );
## Hash::Util

__END__

#-#========================================================================#-#