The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

Acme::Util - Frequently Hacked Functions

DESCRIPTION

A cookbook of tasty functions for the terminally lazy, impatient and hubristic

TAGS

Rather than listing a group of functions by name, related subs can be imported using the tag syntax:

use Acme::Util qw(:tag);

The following tags have been defined:

:io

    appendfile, atime, ctime, mtime, reader, readfile, writefile

:www

    html, js, text, xml, xmlparse

:text

    capitalize, commify, csv, ltrim, plural, rtrim, trim

:misc

    any, apply, arrayref, coderef, find, hashref, scalarref, clone, id, respond, swap

:math

    div, inf, infinity, isbig, isfloat, isinf, isnan, isneg, isnum, isuv

FUNCTIONS

any

usage

    # return 0 or 1
    my $flip = any();

    # return a random element of the ARRAY or a random HASH key
    my $el = any($hash_or_array_ref);

    # return a randomly selected list of ARRAY elements / HASH keys
    my @els = any($hash_or_array_ref, $number_of_items_to_pick);

    # as above, but return the elements as an ARRAY ref (if
    # $number_of_items_to_pick is greater than 1)
    my $els = any($hash_or_array_ref, $number_of_items_to_pick);

    # allow the same element to be picked multiple times
    my @els = any($hash_or_array_ref, $number_of_items_to_pick,
        $with_replacement);
    my $els = any($hash_or_array_ref, $number_of_items_to_pick,
        $with_replacement);

    # return a random number between 0 and $integer_max inclusive
    my $int = any($integer_max);

    # return a random number between $integer_min and $integer_max
    # inclusive
    my $int = any($integer_min, $integer_max);

description

Returns a randomly chosen member of the referenced ARRAY, or a random key from the referenced HASH.

If the second argument is supplied, that number of items is chosen and returned as a list - defaults to 1.

If the third argument is supplied, items can be repeatedly chosen - defaults to 0 (false).

If the first argument is an integer x, an integer between 0 and x (inclusive) is returned.

If no argument is supplied, 0 or 1 is returned randomly.

If the first and second arguments are integers x and y, then an integer between x and y (inclusive) is returned.

    any($ref, ...) does not modify the original HASH/ARRAY.

    any($ref, $reflength) returns a shuffled list e.g.

    # perform a non-destructive shuffle of the elements of $array
    my @shuffled = any($array, $#$array + 1)

When supplied with a HASH or ARRAY ref, and a second argument (specifying the number of items to pick) greater than 1, the selected values are returned as a list in list context and an ARRAY ref in scalar context.

appendfile

usage

    appendfile($file, $data, %args);

description

This is a simple wrapper for writefile()'s APPEND option.

Appends $data to the file whose path is specified by $file.

See writefile() for %args options.

apply

usage

    my $result = apply $coderef, @optional_args;

        # or 

    my $result = apply sub { do_something() }, @optional_args;

        # or 

    my $result = apply \&Name::Space::sub, @optional_args;

description

Invokes the subroutine supplied as the first argument, passing any arguments in @optional_args as parameters.

Returns the result of the subroutine call.

arrayref

usage

    do_something() if (arrayref $arg);

description

Returns a true value if $arg is a blessed or unblessed ARRAY reference.

Returns a false value otherwise.

atime

usage

    my $atime = atime($file);

description

Returns the time (in seconds since the epoch) the specified file was last accessed.

capitalize

usage

    my $capitalized = capitalize($string);

    # or 

    my $capitalized = capitalize($string, @do_not_capitalize_these_words);

description

Initial-capitalizes $string i.e. any words (defined as consecutive characters between word-boundaries (\b)) in $string that don't already contain capitals are lowercased and their initials are uppercased.

Note: apostrophes are treated as word characters, so:

    "There's more than one way to do it"

becomes:

    "There's More Than One Way To Do It"
        

rather than:

    "There'S More Than One Way To Do It"

Any arguments supplied after $string are treated as exceptions and left as is.

For non-trivial capitalization see the { case => 'highlight' } option of Damian Conway's Text::Autoformat.

In the absence of an explicit exception list, Acme::Util's capitalize() (and Text::Autoformat's { case => 'title' }) mechanically renders the text:

    'what i did on my summer vacation in monterey'

as:

    'What I Did On My Summer Vacation In Monterey'

Whereas Text::Autoformat's { case => 'highlight' } option offers the much more titular:

    'What I Did on my Summer Vacation in Monterey'

clone

usage

    use Acme::Util qw(clone);

    $a = Foo->new();
    $b = { alpha => 'beta', gamma => 'vlissides' };

    tie %c, 'Foo::Bar';

    $d = clone($a);
    $e = clone($b);
    $f = clone(\%c);

    # or

    my $node2 = {
        name        => 'node2',
        children    => [ $node3, $node4 ],
        parent      => weaken ($node1)      # weaken() to avoid memory leak
    };

    # clone $node2 but preserve the original $node1 (rather than cloning
    # through it all the way to the root)

    my $clone = clone($node2, [ $node1 ]);

        # or, equivalently

    my $clone = clone($node2, [ $node2->{parent} ]);

description

clone() returns a recursive copy of its argument, which can be an arbitrary (scalar) type including nested HASH, ARRAY and reference types (including weak references), tied variables and objects.

To duplicate non-scalar types (e.g. lists, ARRAYs and HASHes), pass them to clone() by reference. e.g.

    my $copy = clone (\@array);

    # or

    my %copy = %{ clone (\%hash) };

clone() takes an optional second argument: a reference to an ARRAY containing a list of exceptions i.e. values that should be 'passed-thru' verbatim. This is useful for, amongst other things, cloning nodes in a hierarchy without duplicating the structure all the way to the root.

For a slower, but more flexible solution see Storable's dclone().

coderef

usage

    do_something() if (coderef $arg);

description

Returns a true value if $arg is a blessed or unblessed CODE reference.

Returns a false value otherwise.

commify

usage

    my $pretty = commify($int);

description

Returns a reader-friendly representation of the supplied integer punctuated with commas at the customary thousands/millions (&c.) points.

Thus:

    printf "%-9u\t%11s%s", $_, commify($_), $/
        for (map { $_ x $_ } 1 .. 9);

prints:

    1                     1
    22                   22
    333                 333
    4444              4,444
    55555            55,555
    666666          666,666
    7777777       7,777,777
    88888888     88,888,888
    999999999   999,999,999

csv

usage

    my $csv = csv($fields, $arrayref);

        # or

    my $csv = csv [ 'alpha', 'beta', 'gamma', 'vlissides' ],
        [
            { alpha => 'fee',   beta => 'fie',    gamma => 'foe',   vlissides => 'fum'    }, 
            { alpha => 'foo',   beta => 'bar',    gamma => 'baz',   vlissides => 'foobar'  }, 
            { alpha => 'one',   beta => 'two',    gamma => 'three', vlissides => 'four' }
        ];

        # or

     my $csv = csv [ 'alpha', 'beta', 'gamma', 'vlissides' ],
        [
            [ qw(fee fie foe fum) ],
            [ qw(foo bar baz foobar) ],
            [ qw(one two three four) ],
        ];

    # yields

    "alpha","beta","gamma","delta"
    "fee","fie","foe","fum"
    "foo","bar","baz","foobar"
    "one","two","three","four"

description

    $fields:    an ARRAY ref representing a list of field names
    $arrayref:  a reference to an ARRAY of HASH or ARRAY references

Returns either a string or (in list context) a list representing the rows of a CSV (Comma Separated Values) document generated from the supplied HASH or ARRAY refs and using the fields listed in $fields as the field names.

Field names and values are double quoted.

ctime

usage

    my $ctime = ctime($file);

description

Returns the time (in seconds since the epoch) the specified file was created.

div

usage

    my ($quotient, $remainder) = div ($numerator, $denominator);

    # e.g.
    
    my ($q, $r) = div (13, 3);

    # $q = 4, $r = 1:
    # 13 ($numerator) = 4 ($quotient) x 3 ($denominator) + 1 ($remainder) 

description

Integer division operator: in list context, returns the quotient and remainder when the first operand ($numerator) is divided by the second ($denominator).

i.e.

    $numerator = $quotient * $denominator + $remainder

In scalar context, returns just the quotient. To return the remainder, use %.

find

usage

    my $index = find ($arrayref, $scalar)

        # or

    my $index = find ($arrayref, $scalar, $from)

description

Returns the offset of $scalar within $arrayref, with the first position denoted by 0.

$scalar can be a number, string or reference.

-1 is returned if the item is not found.

If the third argument is supplied, the search begins at that index (the offset is still calculated from the beginning of the ARRAY ref).

hashref

usage

    do_something() if (hashref $arg);

description

Returns a true value if $arg is a blessed or unblessed HASH reference.

Returns a false value otherwise.

html

usage

    html ($text);

        # or

    html ();

description

Returns $text with the 'text/html' Content-type header prefixed; or just the header if no $text is provided.

Prints the prefixed page out directly if called in void context.

id

usage

    id()

description

Returns a quick 'n' dirty Unique Identifier. Uses $$ (amongst other things), so not necessarily reliable under SpeedyCGI, mod_perl &c.

infinity inf

usage

    my $inf = infinity()

        # or

    my $inf = inf()

description

Perl 5.8 claims to support infinity natively, but falls short on many platforms. This utility function is a trivial wrapper for the Swiss-Army $Inf provided by Math::Complex, which jumps through every possible hoop to deliver a high-quality infinity product for your reckoning pleasure.

isnum

usage

    isnum ($val)

description

Returns a nonzero value (indicating the numeric type) if $val is a number.

The numeric types are a conjunction of the following flags:

    0x01  IS_NUMBER_IN_UV               (number within UV range - maybe not int)
    0x02  IS_NUMBER_GREATER_THAN_UV_MAX (the pointed-to UV is undefined)
    0x04  IS_NUMBER_NOT_INT             (saw . or E notation)
    0x08  IS_NUMBER_NEG                 (leading minus sign)
    0x10  IS_NUMBER_INFINITY            (this is big)
    0x20  IS_NUMBER_NAN                 (this is not)

Rather than obliging the user to twiddle with bits, the following flavours of isnum (corresponding to the flags above) are also available:

    isint
    isuv
    isbig
    isfloat
    isneg
    isinf
    isnan

isint returns -1 if its operand is a negative integer, 1 if it's 0 or a positive integer, and 0 otherwise.

The others always return 1 or 0.

js

usage

    js ($text);

        # or

    js ();

description

Returns the JavaScript in $text with the 'application/x-javascript' Content-type header prefixed; or just the header if no $text is provided.

Prints the prefixed page out directly if called in void context

ltrim

usage

    my $trimmed = ltrim ($string);

description

Returns a copy of $string with whitespace removed from the beginning.

mtime

usage

    my $mtime = mtime($file);

description

Returns the time (in seconds since the epoch) the specified file was last modified.

plural

usage

    my $plural = plural($stem, $count);

        # or

    my $plural = plural($stem, $count, $plural);

description

Plural() takes a singular word or word-stem as an argument; it evaluates $count to see if it is equal to 1; if it is, $stem is returned unchanged; otherwise $stem is pluralised by adding $plural, or 's' if $plural hasn't been supplied.

Thus:

        my $plural = plural('error', $error);

        will return:
        
            'errors' if $error == 0
            'error'  if $error == 1
            'errors' if $error >  1

This simple implementation does not support irregular plurals that modify the stem. For solutions to that, and indeed, most other non-trivial pluralization problems, the reader is referred to Damian Conway's Lingua::EN::Inflect.

reader

usage

    my $source = '';
    my $read = reader($path, IRS => '...', CHOMP => 1);

    while ($read->(\$source)) {
        do_something_with($source);
    }

        # or

    while ($read->()) { # implied target: $_
        do_something_with($_);
    }

description

This method implements a generator/continuation interface to the fine art of file slurpage. It provides a private (lexically scoped) filehandle and an associated file reader (in the form of a closure).

This closure should be called with a reference to the variable one wishes to be assigned the next line from the file.

If no argument is supplied then $_ is assumed to be the target.

The generator yields true while the file is slurping, and undef thereafter.

The file is automatically closed either when the file has been read, or the closure goes out of scope - whichever comes first.

readfile

description

    Swiss-Army Slurp

usage

    # vanilla
    readfile $path; # print the file
        # or
    my $file = readfile $path;
        
    # handle warnings/fatal errors
    my $file = readfile $path, WARN => \&my_warn, DIE => sub { die @_ };
        
    # lines
    my @file = readfile $path;
        
    # set Input Record Separator
    my @file = readfile $path, IRS => '...';
        
    # strip Input Record Separator from result
    my @file = readfile $path, IRS => '...', CHOMP => 1;

    # open a binary file (e.g. on Windows/Cygwin)
    my $file = readfile $path, BINARY => 1;
        
    # all together now...
    my $file = readfile (
        $path,
        WARN    => $warn,
        DIE     => $die,
        IRS     => '...',
        BINARY  => 1,
        CHOMP   => 1);

    # synonyms for IRS      => DELIM, SPLIT, DELIMITER
    # synonym  for BINARY   => BINMODE

respond

usage

    respond ($scalar)
    respond (@list)

description

respond() performs a context-sensitive return:

    In void context the supplied arguments are printed.

    In scalar context it returns:
    
        the supplied argument if there's only one
        the concatenation of its arguments if there's more than one

    In list context it returns the arguments unchanged.

rtrim

usage

    my $trimmed = rtrim ($string);

description

Returns a copy of $string with whitespace removed from the end.

scalarref

usage

    do_something() if (scalarref $arg);

description

Returns a true value if $arg is a blessed or unblessed SCALAR reference.

Returns a false value otherwise.

squash

usage

    my $text = squash ($string);

description

Returns a 'flat' copy of $string i.e. with initial and terminal whitespace removed and one or more internal whitespace characters (including carriage-returns and newlines) squashed into a single space.

swap

usage

    swap($x, $y);

description

Sets the value of $x to $y and vice-versa.

swap() is prototyped to receive its arguments by reference, and modifies its arguments in place like chop, chomp &c.

No value is returned

text

usage

    text ($text);

        # or

    text ();

description

Returns $text with the 'text/plain' Content-type header prefixed; or just the header if no $text is provided.

Prints the prefixed page out directly if called in void context.

trim

usage

    my $trimmed = trim ($string);

description

Returns a copy of $string with whitespace removed from the beginning and end; in addition, consecutive internal spaces are squashed to a single space.

urlize

usage:

    my $url = urlize('Foo: BAR baz'); # returns 'foo_bar_baz'

    # or

    my $url = urlize('Foo - BAR - baz', 'html'); # returns 'foo_bar_baz.html'

description:

Makes its text argument URL-friendly.

Returns the first argument lowercased with any consecutive non-alphanumeric characters replaced by an underscore.

If the optional second argument is provided, this is appended as an extension prefixed by '.'

writefile

usage

    writefile($file, $data, %args);

description

Write $data to filename $file. Additional herbs and spices are specified as a list of pairs, in the same manner as readfile (and reader).

Currently, the following options are supported:

APPEND => 1 for append (as opposed to truncate) MODE => $mode (to roll your own file access mode) BINARY/BINMODE => 1 to write a binary file (e.g. on Windows/Cygwin)

xml

usage

    xml ($text);

        # or

    xml ();

description

Returns (optional) $text with the 'text/xml' Content-type header prefixed; or just the header if no $text is provided.

Prints the prefixed page out directly if called in void context.

xmlparse

usage

    xmlparse ($parser, $xml_path_or_data);

description

Convenience wrapper for XML::Parser (or XML::Parser::Expat - or indeed any parser that supports parse() and parsefile()) that is agnostic with regard to whether $xml is a file/filehandle or raw XML text.

The $parser should be prefabricated according to taste.

BUGS

clone() currently segfaults if it encounters a Regex object

SEE ALSO

Scalar::Util, List::Util, Clone, Storable, File::Butler, Toolbox

AUTHOR

chocolateboy: <chocolate.boy@email.com>

COPYRIGHT

Copyright (c) 2001-2004, chocolateboy.

This module is free software. It may be used, redistributed and/or modified under the same terms as Perl itself.