Attribute-GlobalEnable

 view release on metacpan or  search on metacpan

lib/Attribute/GlobalEnable.pm  view on Meta::CPAN

package Attribute::GlobalEnable;

our $VERSION = '0.1';

use strict;
use warnings;
use Attribute::Handlers;
use Carp qw( croak );
use base qw( Exporter );
use Time::HiRes qw( time );


## hold the switch settings for each module, method etc. (see above)
my $ENABLE_CHK      = {};

## set the hash for the Debug attribute and the key for the hash ##
my $ENABLE_ATTR     = {};

## hold flag definitions.
my $ENABLE_FLAG     = {};

## hold our current package (our sub-package name really)
my $PACKAGE         = '';

## mark this as true once we've automatically loaded all the stuff.  It's
## once true, other packages that load this module will ONLY get the 
## symbols exported.
my $DONE_INIT       = 0;



##
## import is an auto sub... happens when you... well... import.  In our case
## it automatically exports our attribute functionality to the properr places.
## The first time it runs should be when it is initialized.  After this
## initialization process, it will only export the proper symbols (checks
## $DONE_INIT).
##
## this should return true if it is successfull... it should bail otherwise.
sub import {
  return _export_my_attribute_symbols() if $DONE_INIT;
  my $class = shift();
  croak "Must specify some arguments." if not @_;
  my $args  = {@_};

  ## set the package to the caller
  $PACKAGE = caller();
  croak "Must sub-package ".$PACKAGE if not $PACKAGE or $PACKAGE eq __PACKAGE__;

  ## make sure our sub-packaged module is using the exporter
  _export_the_exporter_to( $PACKAGE ) or die "Bad exporting exporter";

  ## check to make sure ENABLE_CHK exists, and is a hashref ##
  if ( not $args->{ENABLE_CHK} or ref $args->{ENABLE_CHK} ne 'HASH' ) {
    croak "ENABLE_CHK needs to be set with a hash ref for this module "
      ."to be used.";
  }

  ## build the enabled attributes and store internally
  _check_and_build_enable_attr($args) or die "bad ENABLE_ATTR";

  ## handle the flags array and store internally.
  _check_and_build_enable_flags($args) or die "Bad ENABLE_FLAGS";

  ## convert the checks from the passed in hash to our internal hash ##
  _build_enable_chks($args) or die "Bad ENABLE_CHK";

  ## build and export the attribute functions
  _build_attr_exports() or die "Bad build ATTR exports";

  ## export the proper subs to the package that init'd this ##
  _export_my_attribute_symbols();

  return $DONE_INIT++;
}





sub _export_the_exporter_to {
  my $package = shift();

  my $eval_str = "{ package $package; use Exporter; use base qw( Exporter ); }";
  eval $eval_str;
  _eval_die($eval_str, $@) if $@;

  return 1;
}




sub _build_attr_exports {
  ## set the proper attribute functions to point to our internal handler ##
  foreach my $attribute ( keys %$ENABLE_ATTR ) {

    ## set the attribute function to our internal one ##
    my $eval_str = "sub UNIVERSAL::$attribute : ATTR(CODE) { return "
      . __PACKAGE__ ."::My_attr_handler(\@_) }";

    eval $eval_str;
    _eval_die( $eval_str, $@) if $@;

    ## set exporting for each attribute as well so that we can get imported
    ## $attributes as function calls.
    $eval_str = "push \@${PACKAGE}::EXPORT_OK, \$attribute; "

lib/Attribute/GlobalEnable.pm  view on Meta::CPAN

}


sub _is_attribute_on {
  my $attribute = shift();
  my $package   = shift();
  my $chk       = shift();
  my $debug_str = $ENABLE_ATTR->{$attribute};

  ## if ALL debugging is on or if package specific debugging is on
  ## or if function specific debugging is on.
  my $debug_level = 0;
  if ( $ENABLE_CHK->{$attribute}->{"ALL_$debug_str"} ) {
    $debug_level = $ENABLE_CHK->{$attribute}->{"ALL_$debug_str"};
  } elsif ( $ENABLE_CHK->{$attribute}->{"${debug_str}_$chk"} ) {
    $debug_level = $ENABLE_CHK->{$attribute}->{"${debug_str}_$chk"};
  } elsif ( $ENABLE_CHK->{$attribute}->{"${debug_str}_$package"} ) {
    $debug_level = $ENABLE_CHK->{$attribute}->{"${debug_str}_$package"};
  }

  return $debug_level;
}


##
## this is a basic method for generating the wrapped debug sub.
## it's looking for the debug_$debug_level subroutine.  It'll crap out
## if it can't find it.  It starts looking for whatever level it's set at,
## and walks down one by one till it finds an applicable debug sub. 
sub _generate_attr_sub {
  my $debug_level = pop @_;
  my $attribute   = $_[3];

  while ( $debug_level ) {
    my $debug_sub = join( "_", "attr${attribute}", $debug_level--);
    return $PACKAGE->$debug_sub( @_ ) if $PACKAGE->can( $debug_sub );
  }

  ## crap out if we reach here cause there's no debug level for this ##
  die "I couldn't find a debug level at or below the one set.";
}


##
## this handles the static function calls that are exported to each package
## that wishes to use them.  It checks to see if the proper flags are set
## for it do run the user built function.  if not, it does nothing.
sub my_static_handler {
  my $attribute   = shift();
  my $flag        = shift();

  ## checks to see if this debug level is set by a flag being passed in.  If
  ## the flag doesn't exist in our flags hash, then we can assume that
  ## the flag variable isn't actually a flag, and is probably part of the
  ## debug arguments... so put it back onto our args list.
  my $debug_level = _is_flag_on($attribute, $flag);
  if( not defined $debug_level ) {
    unshift( @_, $flag ) if not defined $debug_level;
  }

  my $full_package = (caller(2))[3];

  my $caller_sub_name     = '';
  GET_PROPER_PACKAGE_NAME: {
    my @packages     = split /::/, $full_package;
    pop @packages;
    $caller_sub_name = join '::', @packages;
  }

  $debug_level = _is_attribute_on(
    $attribute,
    $full_package,
    $caller_sub_name
  ) if not $debug_level;

  return if not $debug_level;


  ## we've got our debug level at this point, but we need to make sure that
  ## there is an associated debug sub that matches the level.  If not, then
  ## we'll skip down till we find one.
  my $executable;
  while ( $debug_level ) {
    $executable = $PACKAGE->can( "our${attribute}_". $debug_level--);
    last if defined $executable;
  }

  return if not defined $executable;
      
  return &$executable(@_);
}


sub _is_flag_on {
  my $attribute = shift();
  my $flag      = shift() or return undef;

  return undef if not defined $ENABLE_FLAG->{$attribute}->{$flag};

  return $ENABLE_CHK->{$attribute}->{$ENABLE_ATTR->{$attribute} . "_$flag"} || 0;
}



##
##
## EEE  OOOO FFFF
##
##

=pod

=head1 NAME

Attribute::GlobalEnable - Enable Attrubutes and flags globally across all code.

=head1 SYNOPSIS

  package Attribute::GlobalEnable::MyPackage;
  
  use Attibute::GlobalEnable(



( run in 3.083 seconds using v1.01-cache-2.11-cpan-13bb782fe5a )