Skip to content

Instantly share code, notes, and snippets.

@hkoba
Created March 18, 2018 14:38
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hkoba/37ec19af3c7a362f1288367c8f2adf91 to your computer and use it in GitHub Desktop.
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
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