Re: locating specific function calls
by Corion (Patriarch) on Apr 11, 2007 at 12:41 UTC
|
I'm not sure I understand what you want correctly. Let me restate your problem and propose a solution - I think this solution is not a good solution but I think it would solve the problem as I perceive it:
I think your problem is that you have a printf-like function __x() and want to make sure that wherever you have a call to it all template names in the string are present in the additional parameter list. This is complicated by the fact that people could use @additional_args, or by helper subroutines like __x_err, which is
sub __x_err {
my $msg = shift;
__x("$msg: {err}", err => $!, @_);
};
, so a simple regular expression won't help too much.
I think one tedious solution would be to use Devel::Cover to map out all branches in your code that lead to a call of __x() and then to (manually) generate those parameter conditions that are missing from your test suite to make sure all those branches are actually reached.
I thought of writing a program that generates such conditions automatically, but so far I haven't felt the need - but maybe there is existing prior art. Hence my solution requires lots of manual work just to make sure your calling conventions are always followed. Using a regular expression to fish out all calls to __x() and then verifying that they all match a certain pattern might be saner, but there are always edge cases that might make this infeasible as well, unless you find that all your uses of __x() and __x_err() are simple uses (as they should maybe be, for a simple logging routine).
Now, did I understand your problem well enough to propose a (bad, tedious) solution or did I run off in the wrong direction alltogether? :) | [reply] [d/l] [select] |
|
|
My implementation will be a module, which does help people with internationalization. I can offer the automatic checks on call correctness, when the users refrain from the use of @additional_args and $msg, as in your example. So that's not really a no-go.
What certainly is not possible, it to generate all conditions (automatically) to reach all corners of the
code.
I know that the first parameter of the function is a string, and that the other parameters are named. I only have to check wether the names are within the string. As second activity, for each of the strings I like to see that
they are used: they must be translatable using gettext().
Thanks for your ideas so far.
| [reply] |
Re: locating specific function calls
by shmem (Chancellor) on Apr 11, 2007 at 12:44 UTC
|
I am looking for a way to run all occurrences of a certain function in a file.
I don't get what you are up to. Run the file, and all ocurrences of the function will eventually been run... what is your __x() function about?
Maybe you are looking for a way to wrap functions?
if ($debug) {
my $sub = \&some_function;
my $wrapsub = sub { __x(@_); $sub->(@_) };
*some_function = $wrapsub;
}
Then, whenever some_function() is invoked, your __x() is called first.
--shmem
_($_=" "x(1<<5)."?\n".q·/)Oo. G°\ /
/\_¯/(q /
---------------------------- \__(m.====·.(_("always off the crowd"))."·
");sub _{s./.($e="'Itrs `mnsgdq Gdbj O`qkdq")=~y/"-y/#-z/;$e.e && print}
| [reply] [d/l] [select] |
|
|
No, that's not the direction I want to go. I would like to find the calls to a function without running the module; the calls can be anywhere, even within an if() which is always false. I still need to find that application of the function.
| [reply] [d/l] |
Re: locating specific function calls
by Fletch (Bishop) on Apr 11, 2007 at 13:10 UTC
|
B::Xref may be of use? I'm likewise fuzzy on what's being requested. Perhaps Params::Validate would be another way of attacking this from the callee's end instead of verifying the callers.
| [reply] |
|
|
Ok, let tell me a little more about the plan.
When your program needs to support multiple languages, then you can use gettext. Its use has various syntaxes, of which Locale::TextDomain seems to be the nicest: __x("found {count} files", count => 6). To use gettext(), the string needs to be translated into all supported languages.
After translation, these messages have to go somewhere. Of course, you can simply die/warn/croak, but a generally applicable module is not sure about the destination of the output. More complex applications have to apply nasty tricks to catch and handle "die()" in third-party code. With Log::Dispatch and Log::Log4perl you can help the message find its way cleaner, but do not translate
So, what I want to do, is link the translation framework with the distribution network. Any piece of distributed text must be translated, and therefore I would like to avoid the explicit call to __x(). I try to write this:
use Log::Report textdomain => 'my-domain';
report trace => "{count} files", count => 10;
with "compile-time" parameter checking. In stead of the
unchecked
use Log::Report textdomain => 'my-domain';
report trace => __x("{count} files", count => 10);
In the major module of a set of related modules, you will be able to say:
use Log::Report textdomain => 'my-domain'
, directory => '/usr/share/locale';
etc: I do not want to repeat configuration information in each pm file. And I do not want to limit the whole application (containing multiple distributions) to one domain. The default use of the current modules have these limitations: I wish to change the default.
In the "main" script, you must be able to say something like:
use Log::Report
destinations =>
[ CRITICAL => 'syslog'
, 'ERRORS-' => 'die'
, 'TRACE,INFO' => 'ignore'
];
Be aware: all syntax still under development, and will certainly be clearer.
To come back to my original question: I want to simplify the use and automatically check the "report()" calls without running the program. | [reply] [d/l] [select] |
Re: locating specific function calls
by Moron (Curate) on Apr 11, 2007 at 13:46 UTC
|
^C It sounds like you are talking about subroutine call profiling, ^I for which Devel::AutoProfiler might be useful.
__________________________________________________________________________________
^M Free your mind!
Key to hats: ^I=white ^B=black ^P=yellow ^E=red ^C=green ^M=blue - see Moron's scratchpad for fuller explanation.
| [reply] |
|
|
| [reply] |
Re: locating specific function calls
by Moron (Curate) on Apr 11, 2007 at 14:45 UTC
|
^C Is this then a 'cheapo' parse?
^I on *NIX you can grep for the subroutine identifier, or on Windows command line prompt, something like: type *.pl | perl -e 'print grep /\b__x\b/, <>;'
__________________________________________________________________________________
^M Free your mind!
Key to hats: ^I=white ^B=black ^P=yellow ^E=red ^C=green ^M=blue - see Moron's scratchpad for fuller explanation.
| [reply] [d/l] |
|
|
Yes, that is about what xgettext is doing to create a lexicon which needs to be translated into all languages. I would really love to build this lexicon without that trick.
| [reply] |
|
|
You need double quote in Windows. But doesn't this work?
perl -e "print grep /\b__x\b/, <>;" *.pl
| [reply] [d/l] |
Re: locating specific function calls
by Moron (Curate) on Apr 11, 2007 at 14:22 UTC
|
^C Next interpretation of OP then: to find all calls to a subroutine without executing it.^I The PPI set of modules provide the means to parse Perl code without executing it and includes facilities for documenting and structurising the parse tree.
__________________________________________________________________________________
^M Free your mind!
Key to hats: ^I=white ^B=black ^P=yellow ^E=red ^C=green ^M=blue - see Moron's scratchpad for fuller explanation.
| [reply] |
|
|
My question explicitly states that I do not want to parse thousands of lines with PPI. I am looking for a different solution.
In my terminolgy, the application is the end-user/final product, where modules are (reusable) components.
| [reply] |
|
|
Oops forgot that, sorry!
__________________________________________________________________________________
^M Free your mind!
Key to hats: ^I=white ^B=black ^P=yellow ^E=red ^C=green ^M=blue - see Moron's scratchpad for fuller explanation.
| [reply] |