Rose-HTML-Objects
view release on metacpan or search on metacpan
lib/Rose/HTML/Object.pm view on Meta::CPAN
# We "can" do what will eventually be AUTOLOADed HTML attribute methods
sub can
{
my($self, $name) = @_;
my $class = ref($self) || $self;
my $code = $self->SUPER::can($name);
return $code if($code);
return unless($self->html_attr_is_valid($name) && $class->autoload_html_attr_methods);
# can() expects a code ref that will actually work...
return sub
{
my $self = $_[0];
my $code = $self->SUPER::can($name); # exists already?
goto &$code if($code);
$AUTOLOAD = $class;
goto &AUTOLOAD
};
}
sub __method_was_autoloaded
{
my($class) = ref($_[0]) || $_[0];
no strict 'refs';
exists ${$class . '::__AUTOLOADED'}{$_[1]};
}
sub create_html_attr_methods
{
my($class) = shift;
my $count = 0;
foreach my $attr (@_ ? @_ : $class->valid_html_attrs)
{
no strict 'refs';
my $method = $class . '::' . $attr;
next if(defined &$method);
*$method = sub { shift->html_attr($attr, @_) };
$count++;
}
return $count;
}
sub import
{
my($class) = shift;
foreach my $arg (@_)
{
if($arg eq ':customize')
{
$class->import_methods(
{ target_class => (caller)[0] },
qw(object_type_class_exists object_type_class_keys
delete_object_type_class object_type_classes
clear_object_type_classes object_type_class
inherit_object_type_classes object_type_classes_cache
inherit_object_type_class add_object_type_classes
delete_object_type_classes add_object_type_class
localizer locale default_localizer default_locale));
}
else
{
carp "$class: Unknown import argument '$arg'";
}
}
}
# XXX: This is undocumented for now...
#
# =item B<import_methods NAME1 [, NAME2, ...]>
#
# Import methods from the named class (the invocant) into the current class.
# This works by searching the class hierarchy, starting from the invocant class,
# and using a breadth-first search. When an existing method with the requested
# NAME is found, it is aliased into the current (calling) package. If a method
# of the desired name is not found, a fatal error is thrown.
#
# This is a somewhat evil hack that i used internally to get around some
# inconvenient consequences of multiple inheritence and its interaction with
# Perl's default left-most depth-first method dispatch.
#
# This method is an implementation detail and is not part of the public "user"
# API. It is described here for the benefit of those who are subclassing
# L<Rose::HTML::Object> and who also may find themselves in a bit of a multiple
# inheritence bind.
#
# Example:
#
# package MyTag;
#
# use base 'SomeTag';
#
# use MyOtherTag;
#
# # Do a bredth-first search, starting in the class MyOtherTag,
# # for methods named 'foo' and 'bar', and alias them into
# # this package (MyTag)
# MyOtherTag->import_methods('foo', 'bar');
# If method dispatch was breadth-first, I probably wouldn't need this...
sub import_methods
{
my($this_class) = shift;
my $options = ref $_[0] && ref $_[0] eq 'HASH' ? shift : {};
my $target_class = $options->{'target_class'} || (caller)[0];
my(@search_classes, @parents);
@parents = ($this_class);
while(my $class = shift(@parents))
{
push(@search_classes, $class);
no strict 'refs';
foreach my $subclass (@{$class . '::ISA'})
{
push(@parents, $subclass);
}
}
my %methods;
foreach my $arg (@_)
{
if(ref $arg eq 'HASH')
{
$methods{$_} = $arg->{$_} for(keys %$arg);
}
else
{
$methods{$arg} = $arg;
}
}
METHOD: while(my($method, $import_as) = each(%methods))
{
no strict 'refs';
foreach my $class (@search_classes)
{
if(defined &{$class . '::' . $method})
{
#print STDERR "${target_class}::$import_as = ${class}::$method\n";
*{$target_class . '::' . $import_as} = \&{$class . '::' . $method};
next METHOD;
}
}
Carp::croak "Could not find method '$method' in any subclass of $this_class";
}
}
sub DESTROY { }
sub AUTOLOAD
{
my($self) = $_[0];
if(my $class = ref($self))
{
my $name = $AUTOLOAD;
$name =~ s/.*://;
if($class->html_attr_is_valid($name) && $class->autoload_html_attr_methods)
{
( run in 0.927 second using v1.01-cache-2.11-cpan-5735350b133 )