temporal has asked for the wisdom of the Perl Monks concerning the following question:
Hello there monks,
I feel like this is something that should be picked to pieces somewhere but my best searching efforts haven't turned up an answer for my case. So I'll provide a unexpectedly long example and hopefully some wise monk can nail this down:
I have (as usual) an admittedly clunky script that use feature 'say' for basic debug outputs. What can I say, I was writing this pretty hastily and didn't think this script would evolve to the point where I would need to consider verbosity. All those annoying say messages are certainly unnecessary to the users but I'd like to keep them in the code just for later debugging.
Yeah, hold on, I know you probably have all kinds of simple fixes - let's nix those right now and move on to the actual problem at hand.
I could write a cute one-liner that goes and comments out all the say statements - then I could toggle as needed from CLI. Nope! Unfortunately some of them were unwisely inserted in compound and|or statements or are just otherwise hard to identify and exclusively comment. It doesn't help that my unhealthily compulsive use of PerlTidy leads to multi-line statements based on a line length limit, so no dice.
I could create a verbosity variable and use that to turn each individual say statement on or off:say 'this is a feature' unless $verbose; No, thank you! I hate having to write that into each statement or even doing regex sub to make it happen. That's just entirely too much repetition.
I'm down to a couple options. First option being that I roll my own say sub:
sub say {print shift, "\n" if $verbose}It's easy, sure. But that's not the point! I want to be able to disable or redefine an imported subroutine. Secondly, I could replace all the says to warn. Not going to happen either, I use warnings already because they are error messages for users of this script not just status updates and boring information dumps. Retrospect tells me that maybe warnings are better suited for debug output and STDOUT print routines for user output since toggling warnings on and off is simple enough but it is what it is.
Okay, so enter no which should presumably be able to unimport a target routine from any module that supports it. Deleting it right out of definition in the current package scope. Think I've got that right.
Unfortunately I can't have say something like no feature 'say' unless $verbose;, can't use or no in conditional or anything like that. Probably something to do with that you can't have code blocks (like BEGIN) get conditionally executed due to Perl's interpreter flow, correct me if I'm wrong. But I guess I can try this:
use feature 'say'; unless ($verbose) { no feature 'say'; #say 'this goes unsayable'; } say 'said';
No dice on that, no only applies to the current code block {}. I was expecting it to operate over the package's scope. So it operates kind of like local does.
Let's try something new; how about manually deleting/redefining the subroutine in the symbol table?
use feature 'say'; undef &say; *say = \¬_say; say 'test'; sub not_say { print 'not saying'; }
Maybe I'm getting my namespaces all mixed up because that doesn't seem to redefine the sub at all.
I'm done fooling around - it's CPAN time. The most likely candidate appears to be Sub::Delete, which promises to delete a subroutine (cleanly, I don't yet understand enough of Perl's mechanics to fully understand what it means by that).
use feature 'say'; use Sub::Delete; delete_sub 'say'; say 'testing';
Doesn't do the trick either. I also went back for the past couple examples and tried specifying the sub as 'main::say' and 'feature::say' but got no love there, either.
So my silly example aside, I'm missing a piece of this puzzle. I thought that subs got imported into the current package's scope, which means that I can remove or redefine them. Where is this sub hiding?
TLDR:
How do I dynamically redefine imported subroutines?
|
---|