This document describes coding style conventions used by CATS project.
Code for this project is located in cats-main, cats-judge and cats-problem repositories.
Required conventions are designated by words MUST and MUST NOT. Existing code (mostly) conforms with required conventions. Non-conforming contributions will probably be rejected. Patches fixing violations in existing code will probably be accepted.
Recommended conventions are designated by words SHOULD and SHOULD NOT. Existing code partially conforms with recommended conventions. However, there are significant exceptions due to either historical or practical reasons. Non-conforming contributions may be accepted if there is a good reason for violation. Patches fixing violations of recommended conventions in existing code without any other changes will probably be rejected.
Absent conventions are designated by word MAY. Those choices are explicitly not standardized and allowed be different in each instance.
Some historical code, mostly located in unused directory, does not conform to any conventions and is not expected to ever change.
- Perl code MUST be indented by 4 (four) spaces.
- Template and Javascript code MUST be indented by 2 (two) spaces.
- Code MUST NOT contain trailing spaces. In particular, spaces to the right of operators demanded by conventions below MUST NOT be present if the line is split after the operator.
- Code MUST NOT contain tab characters.
- Operators, including fat comma (
=>) and conditional (?:) MUST be surrounded by a single space from each side. - Comma MUST be have a single space on the right and MUST NOT have a space on the left.
- Multiple assignments or array/hash constructors MAY be presented in tabular form by aligning items vertically with spaces. Otherwise, whenever space is used between tokens, it MUST be a single space.
- Functions and
usestatement categories MUST be separated by a single empty line. - Single empty lines MAY be used to separate logical blocks of code.
- Code MUST NOT have two or more consecutive empty lines.
- Parentheses MUST NOT have spaces inside.
- Parentheses MUST have spaces outside except between subroutine name and parameter list, where space MUST NOT be present.
- Square brackets MUST NOT have spaces inside when they designate array access and MUST have spaces inside otherwise (
$v[1]but[ 1, 2, 3 ]). - Curly brackets MUST NOT have spaces inside when they designate defererence or hash access and MUST have spaces inside otherwise (
$h{$k}and@{f()}but{ x => 1 }). - Code lines MUST be shorter than 120 characters.
- Code lines SHOULD be shorter than 100 characters.
- When a statement is split into several lines, split position SHOULD be after the operator of the lowest possible priority. Exception: if a line is split at the position of low-priority logical operator (
and,or), such operator MUST go on the new line. - Semicolon MUST NOT have space on the left and SHOULD be followed by either a comment or end of line.
- There SHOULD be no more than one statement per line.
- For compound statements and subroutines, opening braces of body code blocks MUST be at the end of the line, not on a separate line.
- When splitting long condition of the prefix compound statement into several lines, closing parentheses together with opening brace SHOULD be split into a separate line with the same identation as the compound statement.
- Prefix and suffix compound statements as well as low-priority logical operators MAY be used interchangeably.
- Suffix compound statements MUST NOT have parentheses around the condition.
- Low-priority logical operators MUST NOT be used inside of statements (
if ($x and $y)is wrong). - High-priority logical operators MUST NOT be used between statements (
$x || returnis wrong). - Embedded SQL MUST start from a new line, after opening quote. Exception: very short SQL parts during request construction.
- Parameters passed to SQL statement MUST start from the new line.
- Lists spanning more than one line SHOULD have a trailing comma.
- Redundant parentheses SHOULD be omitted.
forkeyword MUST be used instead offoreach.- Parameter assignment MUST be the first line of subroutine and SHOULD be of the form
my ($p1, $p2, ...) = @_;. - Subroutines MUST NOT use prototypes (exception:
()for constants). - Single-statement subroutines SHOULD omit trailing semicolon.
- Subroutines SHOULD omit the
returnkeyword in the final statement. - Multi-level array and hash dereferencing MUST NOT omit
->operator ($x->{y}->[z], not$x->{y}[z]).
- Comments MUST be worded as full English sentences, with capitalization and periods.
- Comment MUST have a single space between
#character and text. - Comments MUST be either on a separate line immediately preceding commented code or at the end of the commented line. First option SHOULD be preferred.
- Commented-out code SHOULD NOT be committed.
- Subroutines accepting named parameters SHOULD be preceded by a comment with a list of parameter names.
- Strings without interpolation MUST use single quotes.
- Regexps SHOULD use slash.
- With alternative quoting, tilde character MUST be used for both strings and regexps (
q~,qq~,m~,s~). - Alternative quoting with tilde MUST be used for all embedded SQL.
- Identifiers used as hash keys MUST NOT be quoted (except where required by language).
- Package/class identifiers MUST use
CamelCaseand reside inCATS::namespace (exception:catspackage for global constants defined inCATS::Constants). - All other identifiers MUST use
snake_case. - Object instance variable MUST be named
$self. - Packages MUST NOT export anything by default (exception:
CATS::DB). usestatements MUST be sorted alphabetically inside of each category. Categories MUST be listed in the following order, separated by empty line:use strictanduse warningsdirectivesExporter- standard and external packages
use libdirectives- CATS packages.
- Import lists MUST use
qw()and MUST be sorted alphabetically. - New code SHOULD NOT introduce new global variables.
- Leading underscore MAY be used to indicate package-local subroutines.
- Packages MUST be less than 1000 lines long.
- File MAY contain several packages.
- Package names SHOULD correspond to file names according to standard Perl convention.
- Inner scope identifiers MUST NOT shadow outer scope ones.
- All modules MUST start from
use strictanduse warningsstatements. no strict/no warningsstatement MUST be enclosed in the smallest possible block.- Code MUST NOT generate any warnings.
- User-supplied values MUST be passed to SQL via parameters only.
- User-supplied strings MUST be quoted with either
htmlor$Javascriptfilter ordquotemethod in templates. - HTTP parameters SHOULD be verified using
CATS::Router.
- CATS-specific URLs MUST be generated by Perl code (using
url_f/url_f_cid/url_function) and MUST have names prefixed withhref_. - User-visible text in templates MUST be internationalized (see
langdirectory). - Members of the
capthash MUST be listed in the order of first occurrence in the corresponding template. PROCESSdirective SHOULD be preferred toINCLUDEunless variable localization is actually required.PROCESSandINCLUDEdirective MUST NOT use quotes around argument except when interpolation is required.- Templates SHOULD try to avoid extra whitespace in HTML by using
[%- -%]and[%~ ~%]constructs. - Templates MUST use loop variable in
FOREACHloops.
- Html MUST be valid HTML5 (except for user-supplied problem texts).
- Attributes MUST be quoted, even if HTML allows otherwise.
- Void elements MUST be closed XML-style (
<br/>). - Non-void elements MUST have explicit closing tag, even if empty (
<td></td>). - Forms MUST be submitted with
button, NOTinput. - Elements SHOULD be styled with CSS, embedded
styletags MAY be used for local styles (usingextra_headblock). - Checkboxes and submit buttons MUST have
value="1".
- SQL keywords and table aliases MUST use
UPPER CASE. - Table and field names MUST use
snake_case. - Comments SHOULD use
/* ... */style. - Joins MUST use
JOINkeyword, not comma. - Subqueries MUST have aliases (
SELECT ... FROM (SELECT ...) ALIAS). CHECK,FOREIGN KEYandUNIQUEconstraints SHOULD be named.- Each foreign key MUST contain
ON DELETEclause. - Migrations MUST be located in
migrationssubdirectory and MUST be named according to patternYYYYMMDD-migration-name.sql.
- Code from
cats-mainandcats-problemrepositories MUST be compatible with Perl v5.14. - Code from
cats-judgerepository MUST be compatible with Perl v5.20. - Contributions SHOULD NOT add dependency on new non-standard modules without prior discussion.
- Templates MUST NOT change any state of the model.
- Controllers (
xxx_frame) MUST be called only byRouter. - Controllers MUST be defined only in
CATS::UI::namespace.CATS::UImodules MUST be used only byRouter. - SQL structure changes MUST include migration in the same commit.
- All
use libstatements in utilities and tests MUST useFindBin.
- Each commit MUST result in working code (and pass tests, where applicable). Temporary breakage in PRs is not allowed, use feature checks when needed.
- Commit message SHOULD start from affected subsystem name, followed by a colon, a space and a subject text.
- Subsystem name MAY be a module name, page name, directory name or several names separated by comma plus space.
- Commit message subject SHOULD be a single English statement.
- Commit message SHOULD use the imperative mood ("Add some feature", "Fix some bug").
- Single-statement commit message MUST NOT end with period.
- Commit message MUST NOT contain double quotes. Single quotes MAY be used around indentifiers in the message.
- Commit message MUST NOT be longer than 80 characters.
- Commit message referencing a GitHub issue SHOULD do it by adding
See #issueat the end of the subject. Multiple issues MAY be referenced from message body. - Commit message auto-closing a GitHub issue MUST do it by adding
Fixes #issueat the end of the subject.