StyleGuide
EPrints has been under development for many years and has some fluff about the place. For new programmers this document is intended as a 'style guide' to at least keep the code and documentation consistent across new modules.
Contents
Programming Style
Naming
It helps if all things are written in a consistent style: when one looks at code, we recognise things by the format of the name:
Global Variables
Global variables are variables that are in scope for the entire system, not restricted to specific user sessions. Examples of Global Variables are the AUTH_OK code returned by the Apache web server subsystem.
EPrints follows the general Perl convention, and such variables (and CONSTANTS) should be in CAPITAL LETTERS
As a general rule code outside the core should not really be creating global variables, however there are situations
AUTH_OK = "1";
Local Variables
Variables in code must always be pre-declared, and should be given the most appropriate level of restriction
my, our and local variables are all available to you, however we really really suggest you use my variables wherever possible.
Local variables should be given names that reflect their content ($authenticated) rather than a short nmenonic ($au). Local variables should be underscore seperated ($current_password), not camelCased ($currentPassword)
'The appropriate length of a name is inversely proportional to the size of its scope.' --Mark-Jason Dominus 'Choose mnemonic identifiers. If you can't remember what mnemonic means, you've got a problem.' -- Larry Wall
Preferred technique:
my $proxy_depositor; $proxy_depositor = get_proxy_depositor($session, $eprint);
Acceptable technicque:
my $proxy_depositor = get_proxy_depositor($session, $eprint);
Subroutines
Subroutines (aka functions, aka methods) should also be underscore seperated
Public methods
These are the API calls that are used to interact with your code.
Public methods must start with a lowe-case letter [a-z], and are required to have POD above them explaining the function and use of the method.
Private methods
Private functions are the subroutines in your modules that people should not be using. Private functions should start with an underscore, and have simple perl comments above them, explaining the function of the subroutine.
Modules
Modules (aka packages) are the file that contains the collection of methods & private funtions that makes your code do whatever it does.
Modules are named in the perl style: Perl informally reserves lowercase module names for pragma modules like integer and strict. Other modules should begin with a capital letter and use mixed case
package EPrints::Plugin::Sword::Import::FiddleDeeDee
Subroutines
sub get_value { my( $self, $arg1, $arg2 ) = @_; return $r; }
Where possible, use "return" rather than an "if" block.
AVOID:
sub get_value { my( $self, $arg1 ) = @_; my $r; if( $arg1 ) { $r = $arg1 * 2; } else { log( "some error" ); } return $r; }
Prefer this style instead, treating the problem like a basic exception to the normal running of the function:
sub get_value { my( $self, $arg1 ) = @_; if( !defined $arg1 ) { log( "some error" ); return; } return $arg1 * 2; }
Conditionals
if( ref($a) eq "ARRAY" ) { print "Dang"; return 0; }
If the code inside the condition this is acceptable:
return 0 if( ref($a) eq "ARRAY" );
$a = 23 if( !defined $a );
However this is NEVER OK:
if( !defined $a ) $a = 23;
Loops
foreach my $field ( @fields ) { push @foo, $field->get_name(); }
OR, when nested:
FIELD: foreach my $field ( @fields ) { VALUE: foreach my $value ( @{$field->{ "lsd" }} ) { next VALUE if !defined $value; $values{ $value } = 1; } }
Avoid $_ where possible, it is just confusing to everyone else (and has a tendency to be written over by Lazy Programmers)
Try and use "next" rather than if when inside loops.
Description
Below the license block the name, description and synopsis (a synopsis is an example of usage). Lastly the METHODS title begins the section for inline subroutine documentation.
=head1 NAME EPrints::MyModule - A one line description of MyModule =head1 DESCRIPTION One or two paragraphs explaining the function of EPrints::MyModule. =head1 SYNOPSIS use EPrints::MyModule; my $obj = EPrints::MyModule->new( $opts ); $obj->do_thing( $thingy ); =head1 METHODS =over 4 =cut
Methods
Public Methods
Each public subroutine should have POD documentation above it, with hashes to separate it from the method above. A large module should probably be split into different sections, e.g. "CONSTRUCTOR METHODS", "ACCESSOR METHODS", etc. Private methods can be documented using Perl comments.
###################################################################### =item $objname = EPrints::StyleGuide->my_sub( $arg1, [$opt_arg2], \%opts ) A description of what my_sub does and arguments it takes ($opt_arg2 is shown as optional by using brackets). A description of $arg1 if needed, along with an example: EPrints::StyleGuide->my_sub( "eprintid" ); EPrints::StyleGuide->my_sub( $arg1, undef, { opt1 => $var1, # What is var1 opt2 => $var2, # What is var2 } ); Further elaboration on the effect of $var2. =cut ###################################################################### sub my_sub { ... }
Private Methods
Automatically reformatting code
There is a wonderful utility called perltidy (find link)
This reformats perl for you (and does a syntax check at the same time... lovely.
Use:
perltidy -gnu -csc -b JSON.pm
-gnu reformats into the general 'gnu' style (as opposed to the "Larry Wall/Perl" style) -csc adds comments to the end of longish loops -b edits the file in place (so you may want to leave that off initially)