# -*- mode: perl; coding: utf-8 -*- package YATT::Util::Symbol; use base qw(Exporter); use strict; use warnings FATAL => qw(all); BEGIN { our @EXPORT_OK = qw(class globref stash fields_hash fields_hash_of_class add_isa lift_isa_to declare_alias rebless_with ); our @EXPORT = @EXPORT_OK; } use Carp; use YATT::Util qw(numeric lsearch); sub class { ref $_[0] || $_[0] } sub globref { my ($thing, $name) = @_; no strict 'refs'; \*{class($thing) . "::$name"}; } sub stash { *{globref($_[0], '')}{HASH} } sub declare_alias ($$) { my ($name, $sub, $pack) = @_; $pack ||= caller; *{globref($pack, $name)} = $sub; } sub fields_hash_of_class { *{globref($_[0], 'FIELDS')}{HASH}; } *fields_hash = do { if ($] >= 5.009) { \&fields_hash_of_class; } else { sub { $_[0]->[0] } } }; sub rebless_array_with { my ($self, $newclass) = @_; $self->[0] = fields_hash_of_class($newclass); bless $self, $newclass; } *rebless_with = do { if ($] >= 5.009) { require YATT::Util::SymbolHash; \&YATT::Util::SymbolHash::rebless_hash_with; } else { \&rebless_array_with; } }; sub add_isa { my ($pack, $targetClass, @baseClass) = @_; my $isa = globref($targetClass, 'ISA'); my @uniqBase; if (my $array = *{$isa}{ARRAY}) { foreach my $baseClass (@baseClass) { next if $targetClass eq $baseClass; next if lsearch {$_ eq $baseClass} $array; push @uniqBase, $baseClass; } } else { *{$isa} = []; @uniqBase = @baseClass; } push @{*{$isa}{ARRAY}}, @uniqBase; } sub lift_isa_to { my ($new_parent, $child) = @_; my $orig = *{globref($child, 'ISA')}; my $isa = *{$orig}{ARRAY}; *{$orig} = $isa = [] unless $isa; my @orig = @$isa; # croak "Multiple inheritance is not supported: $child isa @orig" # if @orig > 1; # !!: *{$orig} = [$new_parent]; is not ok. @$isa = $new_parent; return unless @orig; add_isa(undef, $new_parent, @orig); } 1;