Actually, the eval is trapping the error. When I put a die $@ if $@; after the eval, it propagates the same error. I haven't tried using the string form of eval but I don't expect that to work any better than the block eval (though it might if it forces perl to bind SUPER at run time, and thus bind it to the base class instead of CustomMethodMaker, which is why I thought to try eval in the first place).
The reason it works without Class::MethodMaker is (near as I can tell, anyway) that you're creating the sub in the same class for which you want to find the super class. In other words, it might be that if you wrote a third class that installs the method (in which SUPER is called) into the base class, it wouldn't work.
It's also possible that the error is actually being generated somewhere else in the call chain when the required method is called. I didn't have time to do a full trace of the code earlier. Creating a simple test module that installs the SUPER-calling method into the example which doesn't use Class::MethodMaker would tell you if the issue is actually with using SUPER outside the base class, though, so that's maybe a good avenue to explore.
Sorry I can't look into it any more right now. I'm at school and don't have access to Perl. :(
HTH, anyway.
bbfu
Black flowers blossom
Fearless on my breath
| [reply] [d/l] [select] |
Actually, the eval is trapping the error. When I put a die $@ if $@; after the eval, it propagates the same error.
Duh, you're right. :-) I was testing for @$ instead of $@. /me slaps forehead.
The reason it works without Class::MethodMaker is (near as I can tell, anyway) that you're creating the sub in the same class for which you want to find the super class. In other words, it might be that if you wrote a third class that installs the method (in which SUPER is called) into the base class, it wouldn't work.
I think you're right. Could it possibly be that I've discovered a feature that is impossible for Perl? Nahh... probably I just haven't found the answer yet. :-)
Creating a simple test module that installs the SUPER-calling method into the example which doesn't use Class::MethodMaker would tell you if the issue is actually with using SUPER outside the base class, though, so that's maybe a good avenue to explore.
I'll give that a shot (not sure if I can do it, but I'll try).
-Dan
| [reply] |
Ok, I think I found the cause of the problem, and a way to work around it, though it's a little ugly.
If you look in perlboot under SUPER, you find the following:
So, "SUPER::speak" means look in the current package's @ISA for "speak", invoking the first one found.
In other words, SUPER ignores the class of the object it's called upon, and always looks in the current package's @ISA to find the super class. So, when you create the anonymous sub to be the method, it's actually created in your CustomMethodMaker class, and so that's whose @ISA it uses, even though it's later installed into the FixedBug class. (Technically, it's not actually put into the FixedBug class. Rather, a reference to it is put into FixedBug's symbol table. The sub still resides in CustomMethodMaker.) Personally, I don't think is the correct thing to do (I think SUPER should look in the @ISA of the package that the object is blessed into) but it's documented, so it can't be a bug. ;)
So, to do what you want to do, you need to force the call to SUPER to be in the correct package. The way to do this is to note what package your installer function is called from, and manually set yourself back to that package just prior to calling the super-method. Of course, since you only know what package your installer function is called from at run-time, you have to set the package dynamically at run-time, via (string) eval.
I created a simple set of test classes. You should just need to use the eval and caller() lines in MyTest::MethodInstaller::install(). With your original example code, you'll have to get the caller two levels higher (ie, caller(2)). Once for the import, and once for something else internal to Class::MethodMaker. Or, you could use Class::MethodMaker's internal (undocumented) find_target_class() method, which searches up the call stack for the first namespace which is not a descendant of Class::MethodMaker. That would probably be better (more robust, somewhat less likely to change).
The code:
Well, that should get you working, though I think the eval trick is ugly and shouldn't be necessary in the first place. Oh well. C'est la vie.
bbfu
Black flowers blossom
Fearless on my breath
| [reply] [d/l] |
| [reply] |