Created
March 18, 2018 14:38
-
-
Save hkoba/37ec19af3c7a362f1288367c8f2adf91 to your computer and use it in GitHub Desktop.
Old post on comp.lang.perl.misc which mentions about `unless caller` usage in perl
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Path: uecisb.is.uec.ac.jp!tweedledum!wnoc-tyo-news!news.nc.u-tokyo.ac.jp!newssinet!daffy!uwvax!uwm.edu!cs.utexas.edu!swrinde!cssun.mathcs.emory.edu!gatech2!usenet.eel.ufl.edu!newsfeed.internetmci.com!btnet!dispatch.news.demon.net!demon!mail2news.demon.co.uk!ignite.demon.co.uk | |
From: Tim Bunce <Tim.Bunce@ig.co.uk> | |
Newsgroups: comp.lang.perl.misc | |
Subject: Re: Request for (constructive!) feedback on module design | |
Date: Sat, 11 Nov 1995 08:43:03 GMT | |
Organization: Paul Ingram Group, Software Systems, +44 1 483 424424 | |
Lines: 248 | |
Sender: news@ig.co.uk | |
Message-ID: <DHvEvJ.GEu@ig.co.uk> | |
References: <1995Nov7.234508.8964@aw101.iasl.ca.boeing.com> | |
X-NNTP-Posting-Host: ignite.demon.co.uk | |
In article <1995Nov7.234508.8964@aw101.iasl.ca.boeing.com>, | |
Vincent D. Skahan <vds7789@aw101.iasl.ca.boeing.com> wrote: | |
> | |
> I'm trying to understand the real-world implications of perl5 modules and am | |
> looking for some feedback on what is "proper and complete". I must admit | |
> that the Perl 5 Module List section on Guidelines for Module Creation | |
> toasted my brain a little. | |
It is rather terse. I think Tom's planning to translate it to English. | |
> I'd appreciate any constructive input regarding | |
> whether or not the attached meets the Module List requirements and/or | |
> recommendations plus anything else anybody comes up with... | |
> | |
> | |
> Xpackage Prompt; | |
Let's start at the beginning. Naming packages is hard. | |
Here's what the Module List says: | |
This name should be as descriptive, accurate and complete as | |
possible. Avoid any risk of ambiguity. Always try to use two or | |
more whole words. Generally the name should reflect what is special | |
about what the module does rather than how it does it. Please use | |
nested module names to informally group or categorise a module. | |
A module should have a very good reason not to have a nested name. | |
Module names should begin with a capital letter. | |
Well you got the last bit spot on! Seriously though, if everyone | |
uses single words and non-nested names there would be many more | |
name clashes... | |
Having 57 modules all called Sort will not make life easy for anyone | |
(though having 23 called Sort::Quick is only marginally better :-). | |
Imagine someone trying to install your module alongside many others. | |
If in any doubt ask for suggestions in comp.lang.perl.misc. | |
Consider, for example, someone writing a WWW prompt module, an X Windows | |
prompt module, a calender reminder prompt module etc etc. What names | |
should those modules have? Prompt? It doesn't allow room for others. | |
The bit that's relevant here is: | |
Generally the name should reflect what is special about what the | |
module does rather than how it does it. Please use nested module | |
names to informally group or categorise a module. A module should | |
have a very good reason not to have a nested name. | |
In your case what's relevant is that it's a textual character terminal | |
user interface prompting module. Umm, rummaging through the Module List | |
I see Text:: and Term:: as possibilities based on those keywords. | |
Looking more closely I see that the Text:: modules are more abstract | |
and not really related to user interfaces. The Term:: modules on the | |
other hand seem very close: Term::Read, Term::ReadLine, Term::Query. | |
Hang on a sec, Term::Query is described as | |
::Query Rdpf Intelligent user prompt/response driver AKSTE | |
at this point you should say to yourself something like "why should | |
I write some code when I might be able to reuse someone elses?". | |
So you go and grab the module from your nearest CPAN and take a look. | |
If it's close but not ideal then you could work with the author to | |
improve it. | |
Let's say, for sake of argument, that it's not appropriate for your | |
needs and so you've got to write your own. That brings us back to | |
picking a name. Since Term:: seems like a suitable category lets | |
call the module Term::Prompt. | |
> X=head1 NAME | |
> X | |
> XPrompt - Perl module to ask questions (with optional default answers) | |
> X | |
> X=head1 DESCRIPTION | |
> X | |
> X Prompt contains various routines to standardize the asking (and answering) | |
> X of interactive prompts to the user of a perl routine. Each permits an | |
> X optional default answer to be specified, which the user can accept by | |
> X merely hitting return. There are a number of routines that can be used: | |
> X | |
> X Prompt::Prompt - ask a question and return the exact answer | |
> X (or an 'accepted' default answer if any) | |
> X | |
> X Prompt::lcPrompt - ask a question but return the answer in all lower case | |
> X | |
> X Prompt::ucPrompt - ask a question but return the answer in all upper case | |
> X | |
> X Prompt::ynPrompt - ask a question and force a yes or no answer. | |
> X Users are forced to return an answer that starts with | |
> X 'y' or 'n' (in either upper of lower case). | |
> X This routine returns lower case to the calling routine. | |
> X | |
> X Usage: | |
> X | |
> X $answer = Prompt::Prompt ("what is your favorite color","blue"); | |
> X $answer = Prompt::lcPrompt("what is your favorite color","blue"); | |
> X $answer = Prompt::ucPrompt("what is your favorite color","Blue"); | |
> X $answer = Prompt::ynPrompt("isn't orange a better color","no way"); | |
The uc* and lc* variants offer almost no value since they can trivially | |
be implemented as | |
$answer = uc Prompt::Prompt(...); | |
$answer = lc Prompt::Prompt(...); | |
It's just not worth writing and documenting the code. | |
How you capitalize your function names is a fairly open issue. Most | |
of the standard modules and perl5-porters use lowercase_with_underscores. | |
I recommend it. | |
Tom has a good style guide for symbol naming, maybe he'll post it. | |
> Xrequire 5.001; # minimum version | |
Good (but is it *really* the minimum required perl version or just the | |
version that you had at the time you wrote it?). | |
> Xrequire Exporter; # we'll be exporting routines | |
Okay. | |
> X# question - should this include Prompt (itself) too ? | |
> X@ISA = qw(Exporter); | |
No. @ISA specified which classes Prompt will inherit methods from. | |
In this case your inheriting the import method from Exporter. | |
> X# question - shouldn't this be EXPORT_OK or not export at all ? | |
> X@EXPORT = qw(Prompt ucPrompt lcPrompt ynPrompt); | |
The Module List says | |
Exports pollute the namespace of the module user. If you must | |
export try to use @EXPORT_OK in preference to @EXPORT and avoid | |
short or common names to reduce the risk of name clashes. | |
Generally anything not exported is still accessible from outside the | |
module using the ModuleName::item_name (or $blessed_ref->method) | |
syntax. By convention you can use a leading underscore on names to | |
informally indicate that they are 'internal' and not for public use. | |
As a general rule, if the module is trying to be object oriented | |
then export nothing. If it's just a collection of functions then | |
@EXPORT_OK anything but use @EXPORT with caution. | |
For a module like this with only few (unambiguously named) functions, | |
it would be quite reasonable to use @EXPORT. | |
If you do export then your documentation doesn't need to use | |
the fully qualified name. Your examples can just say | |
$answer = prompt_yn($question, $default) | |
- ask a question and force a yes or no answer | |
> X# should we 'use strict' for below here ? | |
Yes. | |
> X#------------- just accept whatever they answer in any mixed case ---------- | |
> X# | |
> Xsub Prompt | |
> X{ | |
> X my ($ANSWER); # returned answer | |
> X my ($QUESTION,$DEFAULT) = @_; # passed in parameters | |
> X print "$QUESTION [$DEFAULT] : "; # ask the question | |
> X chomp($ANSWER=<STDIN>); # remove the trailing \n | |
> X | |
> X # permit the user to hit return to take the default | |
> X if ($ANSWER ne "") { | |
> X return $ANSWER; | |
> X } else { | |
> X return $DEFAULT; | |
> X } | |
> X} | |
Most perl programmers reserve $CAPITALS for constants (or file handles). | |
It's generally good practice to put your parameters into variables as | |
the first action in the function. | |
You haven't flushed STDOUT before reading the input. On some systems | |
you wouldn't see the prompt. You could use 'local($|)=1;' to fix that. | |
> X#------------- force a y/n answer and return it in lower case -------------- | |
> X# | |
> Xsub ynPrompt | |
> X{ | |
> X my ($ANSWER); # returned answer | |
> X my ($QUESTION,$DEFAULT) = @_; # passed in parameters | |
> X | |
> X $ANSWER = Prompt::lcPrompt($QUESTION,$DEFAULT); | |
> X | |
> X # --- sneaky alert, make'em answer 'y' or 'no' ---- | |
> X # (future alert, put the choices in a passed-in variable?) | |
> X | |
> X if ($ANSWER =~ /^(y|n)/){ | |
> X return substr($ANSWER,$[,1); | |
> X } | |
> X | |
> X #---- invalid answer given, let's try again ------- | |
> X | |
> X $ANSWER = Prompt::ynPrompt($QUESTION,$DEFAULT); | |
> X | |
> X} | |
What happens if they give an invalid answer again? You need a loop. | |
Also, $[ should not be used in new code. | |
> X#!/usr/local/bin/perl5 | |
> X# | |
> X# prompt.pl - test out perl module to ask questions | |
> X# see Prompt.pm for what the routines do.... | |
> X# | |
> X | |
> Xrequire "Prompt.pm"; | |
> X | |
> X$ans = Prompt::Prompt("whatcha want","One Bourbon, One Scotch, and One Beer"); | |
Writing test code is always a good idea. A neat trick is to put it | |
at the end of the module itself (that way it won't get lost and you | |
may remember to actually update and use it :-). | |
At the end of your Prompt.pm file you can say something like: | |
{ package main; eval join('',<DATA>) || die $@ unless caller(); } | |
1; | |
__END__ | |
package main; | |
import Term::Prompt; | |
... your test code here ... | |
(Alternatively just manually comment out the __END__ when you want to test.) | |
You can then test your code by simply running: perl Prompt.pm | |
I hope all my ranting has been of some use to you (and anyone else | |
who's read this far :) | |
For further reading I'd recommend the man pages: perlmod and perlstyle. | |
Tim. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment