PrePAN

Sign in to PrePAN

Print::OrDie "or die $!" Wrappers for print-like core method with configurable die action

Author
juliodcs@github
Date
URL
Status
In Review
Good

Synopsis

package Print::OrDie;
use strict;

require Exporter;

our @EXPORT_OK = qw(
  printo   printe   printat
  sayo     saye     sayat
  printfo  printfe  printfat
);

use constant {
    E_BAD_DIE => __PACKAGE__
      . " ArgumentError: Bad die method option.\n"
      . " --> Ussage: 'use_' + (die|carp|cluck|croak|confess)\n",
    E_BAD_USE => __PACKAGE__ . " ArgumentError: Use only one die option\n",
};

my $die_opt = 'croak';    # Default action

sub import {
    use warnings;
    my ( $package, @list ) = @_;
    my ( $die, @import_list );
    foreach my $op (@list) {
        if ( $op =~ m{ ^ use_(\S+) $ }x ) {
            die E_BAD_USE if defined $die;
            $die = $1;
            die E_BAD_DIE
              if $die !~ m{^(?: die|warn|carp|cluck|croak|confess )$}x;
        }
        else {
            push @import_list, $op;
        }
    }
    $die_opt = $die // $die_opt;
    @_ = ( $package, @import_list );
    goto \&Exporter::import;
}

use warnings;    # Before redefining 'import'

sub die_method {
    my $package = $die_opt eq 'warn' || $die_opt eq 'die' ? q() : 'Carp::';
    &{ \&{$package . $die_opt} }("$!");
    return;
}

sub printo {
    print {*STDOUT} @_ or die_method;
}

sub printe {
    print {*STDERR} @_ or die_method;
}

sub printat(&@) {
    print { shift->() } @_ or die_method;
}

sub sayo {
    print {*STDOUT} @_, "\n" or die_method;
}

sub saye {
    print {*STDERR} @_, "\n" or die_method;
}

sub sayat(&@) {
    print { shift->() } @_, "\n" or die_method;
}

sub printfo {
    printf {*STDOUT} @_ or die_method;
}

sub printfe {
    printf {*STDERR} @_ or die_method;
}

sub printfat(&@) {
    printf { shift->() } @_ or die_method;
}

1;

Description

Simple wrappers for core print-like methods (print, say, printf). The goal is to avoid using "print or die" since autodie does not work with print.

The "die" action can be configured by importing use_"action". Where "action" can be croak (default), die, carp, cluck, and confess.

Every method has three wrappers (with o/e/at at the end of the names)

The "o" method writes on STDOUT, the "e" method writes to STDERR and the "at" writes to file handle. The "at" methods will require a block, which is anyways the recommended way (according to Perl Best Practices) of passing filehandles when using print-like methods.

Example:

use Print::OrDie qw(use_confess sayo saye sayat);

# It will 'confess' if there's some error.  
sayo 'FOOBAR'; # writes "FOOBAR\n" at STDOUT
saye 'FOOBAR'; # writes "FOOBAR\n" at STDERR
sayat {*STDERR} 'FOOBAR'; # same as before
sayat {$my_file_handle} 'FOOBAR'; # writes "FOOBAR\n" at given file handle

Example:

use Print::OrDie qw(use_confess sayat printfat);
use autodie;

# It will 'confess' if there's some error.  
open my $fh, '>', 'foobar.txt';
sayat {$fh} 'FOO';
close $fh;
$fh = undef;
printfat {$fh // *STDOUT} 'FOO %s', 'BAR';

Will write "FOO\n" on the 'foobar.txt' file and 'FOO BAR' on the console (STDOUT)

Example

use autodie;
use File::Temp qw( tempfile );
use Print::OrDie qw( use_confess sayat sayo );

my ( $fh, $filename ) = tempfile();
close $fh;

print {$fh} q(); # It will not fail

sayat {$fh} q(); # It will fail

sayo 'finished'; # Will never execute

Comments

If the use case is to complement autodie, then the 2nd example shouldn't use "or die ..." for the other builtin calls, but rely on "use autodie" (and put this line into the example, too).
Thanks @eserte. Yes, the main reason of this module is that autodie does not check calls to print. However, this module is not meant to automatically protect those print methods, but instead to create some 'safe' ones. Also, since the die action can be configured, you could just warn instead of dying.

Please sign up to post a review.