package Object::InsideOut; {
use strict;
use warnings;
no warnings 'redefine';
sub create_field
{
my ($GBL, $call, @args) = @_;
push(@{$$GBL{'export'}}, 'create_field');
if ($call eq 'create_field') {
$$GBL{'init'} = 1;
}
# Dynamically create a new object field
*Object::InsideOut::create_field = sub
{
# Handle being called as a method or subroutine
if ($_[0] eq __PACKAGE__) {
shift;
}
my ($class, $field, @attrs) = @_;
# Verify valid class
if (! $$GBL{'isa'}->($class, __PACKAGE__)) {
OIO::Args->die(
'message' => 'Not an Object::InsideOut class',
'Arg' => $class);
}
# Check for valid field
if ($field !~ /^\s*[@%]\s*[a-zA-Z_]\w*\s*$/) {
OIO::Args->die(
'message' => 'Not an array or hash declaration',
'Arg' => $field);
}
# Convert attributes to single string
my $attr;
if (@attrs) {
s/^\s*(.*?)\s*$/$1/ foreach @attrs;
$attr = join(',', @attrs);
$attr =~ s/[\r\n]/ /sg;
$attr =~ s/,\s*,/,/g;
$attr =~ s/\s*,\s*:/ :/g;
if ($attr !~ /^\s*:/) {
$attr = ":Field($attr)";
}
} else {
$attr = ':Field';
}
# Create the declaration
my @errs;
local $SIG{'__WARN__'} = sub { push(@errs, @_); };
my $code = "package $class; my $field $attr;";
eval $code;
if (my $e = Exception::Class::Base->caught()) {
die($e);
}
if ($@ || @errs) {
my ($err) = split(/ at /, $@ || join(" | ", @errs));
OIO::Code->die(
'message' => 'Failure creating field',
'Error' => $err,
'Code' => $code);
}
# Process the declaration
process_fields();
};
# Runtime hierarchy building
*Object::InsideOut::add_class = sub
{
my $class = shift;
if (ref($class)) {
OIO::Method->die('message' => q/'add_class' called as an object method/);
}
if ($class eq __PACKAGE__) {
OIO::Method->die('message' => q/'add_class' called on non-class 'Object::InsideOut'/);
}
if (! $class->isa(__PACKAGE__)) {
OIO::Method->die('message' => "'add_class' called on non-Object::InsideOut class '$class'");
}
my $pkg = shift;
if (! $pkg) {
OIO::Args->die(
'message' => 'Missing argument',
'Usage' => "$class\->add_class(\$class)");
}
# Already in the hierarchy - ignore
return if ($class->isa($pkg));
no strict 'refs';
# If no package symbols, then load it
if (! grep { $_ !~ /::$/ } keys(%{$pkg.'::'})) {
eval "require $pkg";
if ($@) {
OIO::Code->die(
'message' => "Failure loading package '$pkg'",
'Error' => $@);
}
# Empty packages make no sense
if (! grep { $_ !~ /::$/ } keys(%{$pkg.'::'})) {
OIO::Code->die('message' => "Package '$pkg' is empty");
}
}
# Import the package, if needed
if (@_) {
eval { $pkg->import(@_); };
if ($@) {
OIO::Code->die(
'message' => "Failure running 'import' on package '$pkg'",
'Error' => $@);
}
}
my $tree_bu = $$GBL{'tree'}{'bu'};
my $tree_td = $$GBL{'tree'}{'td'};
# Foreign class added
if (! exists($$tree_bu{$pkg})) {
# Get inheritance 'classes' hash
if (! exists($$GBL{'heritage'}{$class})) {
create_heritage($class);
}
# Add package to inherited classes
$$GBL{'heritage'}{$class}{'cl'}{$pkg} = undef;
return;
}
# Add to class trees
foreach my $cl (keys(%{$tree_bu})) {
next if (! grep { $_ eq $class } @{$$tree_bu{$cl}});
# Splice in the added class's tree
my @tree;
foreach (@{$$tree_bu{$cl}}) {
push(@tree, $_);
if ($_ eq $class) {
my %seen;
@seen{@{$$tree_bu{$cl}}} = undef;
foreach (@{$$tree_bu{$pkg}}) {
push(@tree, $_) if (! exists($seen{$_}));
}
}
}
# Add to @ISA array
push(@{$cl.'::ISA'}, $pkg);
# Save revised trees
$$tree_bu{$cl} = \@tree;
@{$$tree_td{$cl}} = reverse(@tree);
}
};
# Do the original call
@_ = @args;
goto &$call;
}
} # End of package's lexical scope
# Ensure correct versioning
($Object::InsideOut::VERSION == 3.21)
or die("Version mismatch\n");
# EOF
syntax highlighted by Code2HTML, v. 0.9.1