Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use of UNIVERSAL::can #8

Closed
CliffS opened this issue Feb 6, 2012 · 6 comments
Closed

Use of UNIVERSAL::can #8

CliffS opened this issue Feb 6, 2012 · 6 comments

Comments

@CliffS
Copy link

CliffS commented Feb 6, 2012

In sub lookup, you use UNIVERSAL::can($ctx, $field). This defeats the use of AUTOLOAD to provide parameters.

If it could be changed to $ctx->can($field) it would mean that it would be possible to overload can in the subclass to make AUTOLOAD work.

@reconbot
Copy link

reconbot commented Feb 9, 2012

Can you explain this a bit more, I'm not very familiar with AUTOLOAD. How does the $ctx object have the can method?

@CliffS
Copy link
Author

CliffS commented Feb 10, 2012

This package uses UNIVERSAL::can(). All blessed objects inherit from the
UNIVERSAL class therefore all blessed objects inherit isa and can.

From http://perldoc.perl.org/UNIVERSAL.html you can see:

$sub = $obj->can("print");
$sub = eval { $ref->can("fandango") };

# but never do this!
$sub = UNIVERSAL::can($obj, "print");

If $obj is a blessed object into say package My::Package, perl tries to
find $obj->method in the package My::Package and then all of its
super-classes as defined by @my::Package::ISA then back until it reaches
UNIVERSAL. If it can't find the method, it tries again, looking for a
method called sub AUTOLOAD. If it finds this, it runs it.

However, as this effectively means you are creating methods at runtime,
UNIVERSAL::can will not know about them. Of course, you can overload
can, the same as any other method.

I have the data stored in the blessed hash of a sub-class of
Template::Mustache. What I want to do is (untested):

sub AUTOLOAD
{
   my $self = shift;
   return $self->{$AUTOLOAD};
}

sub can
{
   my $self = shift;
   my $do = shift;
   return exists $self->{$do};
}

When this failed, I tried

 sub render
{
    my $self = shift;
    $self->SUPER::render($self);
}

This fails however because of the test if (ref $ctx eq 'HASH'); and, of
course, ref $self is my package. I ended up with:

sub render
{
     my $self = shift;
     my %hash = %$self;
     $self->SUPER::render(\%hash);
}

which is a little clumsy.

Hope this helps.

@reconbot
Copy link

That makes a ton of sense, should be an easy patch - I just added dotted paths. I'll update my pull request to include this.

@reconbot
Copy link

I'm submitting a patch to use $context->can() but I have a question on the spec. The implementation as I have it will always call method on objects and ignore properties even if they exist. I can't find test cases in the spec that cover this so I'm not sure what the behavior should be, but this seems less then ideal.

reconbot added a commit to reconbot/Template-Mustache that referenced this issue Feb 10, 2012
…e able to work well with classes that make use of AUTOLOAD
@CliffS
Copy link
Author

CliffS commented Feb 10, 2012

The implementation as I have it will always call method on objects and ignore properties even if they exist.

This is correct behaviour, in my opinion. It's then up to the consumer to ensure that the can gives the correct results.

@reconbot
Copy link

It's also according to the spec =)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant