Function-Runner
view release on metacpan or search on metacpan
lib/Function/Runner.pm view on Meta::CPAN
package Function::Runner;
use strict; use warnings; use utf8; use 5.10.0;
use Data::Dumper;
our $VERSION = '0.003';
my $PEEK_LEVEL = 5; # Disallow peeks below this level
sub peek { # ( $level, $res ) --> $res
my ($level, $res) = @_;
# Comment out logging in PROD
_log_save($res);
# Guard: Do nothing if $level is lower than PEEK_LEVEL
return $res if $level < $PEEK_LEVEL;
# Print content of $res
my $file = (caller(0))[1];
my $line = (caller(0))[2];
say "$file line $line: ". Dumper $res;
return $res;
}
my $LOG = []; # Container for logs from peek()
sub _log_save { # ($res)
my $res = shift;
# Add to log regardless of PEEK_LEVEL
my $pkg = (caller(1))[0];
my $file = (caller(1))[1];
my $line = (caller(1))[2];
push @$LOG, ["file:$file - pkg:$pkg - line:$line: ",$res];
#push @$LOG, "file:$file - pkg:$pkg - line:$line: ".$res;
return $res;
}
sub _log_fetch { return $LOG }
sub _log_clear { $LOG = [] }
## CONSTRUCTORS
sub new {
# Clear the LOG
$LOG = [];
my $fn_map = {}; # initial function map
my $defn = $_[1]; # user-provided function definition
my $pkg = (caller)[0]; # calling package
_die("missing defn or pkg") unless defined $defn && defined $pkg;
# See: https://perldoc.perl.org/perlmod#Symbol-Tables
my $tab = eval '\%'.$pkg.'::'; # symbol table of calling package
peek 3, ['Symbol Table: ','\%'.$pkg.'::',"has ref: \"".ref($tab).'"'];
_mk_fn_map($fn_map,$defn,$tab,$pkg);# build fn_map from $defn and $tab
peek 3, ['Completed fn_map: ',$fn_map];
bless { defn=>$defn,
fn=>$fn_map,
log=>{ step => [], # Store steps and results
func => [] } # Store funcs and results
},
$_[0];
}
## METHODS
my $LEVEL = 0; # Tracks recursion levels
sub _mk_fn_map {
my ($fn_map, $defn, $tab, $pkg) = @_;
# Walk the defn, get all coderefs
foreach my $step (keys %$defn) {
my $res = $defn->{$step};
my $ref = ref $res;
peek 3, ["Processing StepDef: $step",$res, " has res: \"$ref\""];
if ($ref eq '') { # Coderef. e.g. '&bye' or '/greet'
# Guard: Skip if Step not Func
# Step Example: '/greet'
# Func Example: '&bye'
if ($res =~ /^\/(.*)/) {
peek 3, "Ignored StepDef when building fn_map: $res";
next;
}
my ($sym) = ($res =~ /^&(.*)/);
peek 3, "Processing Func: $res";
_die("Bad res: $res") unless defined $sym;
# Guard: Skip if already in $fn_map
if (exists $fn_map->{$sym}) {
peek 3, "Func already mapped: $res";
next;
}
# Guard: The given symbol e.g. 'hello' must be defined as a
# function in the calling package
my $is_code = eval 'defined &'.$pkg.'::'.$sym ? 1 : 0;
peek 3, "Func: $res is code: \"$is_code\"";
_die("\n\n"."\"$sym\" not a coderef in \"$pkg\"")
unless $is_code;
# Add mapping of symbol to coderef
$fn_map->{$sym} = $tab->{$sym};
peek 3, "Add to fn_map: $res";
} elsif ($ref eq 'HASH') { # Defn e.g. { ':ok' => ... }
( run in 1.290 second using v1.01-cache-2.11-cpan-e93a5daba3e )