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
use
statement 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 || return
is 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.
for
keyword 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
return
keyword 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
CamelCase
and reside inCATS::
namespace (exception:cats
package 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
). use
statements MUST be sorted alphabetically inside of each category. Categories MUST be listed in the following order, separated by empty line:use strict
anduse warnings
directivesExporter
- standard and external packages
use lib
directives- 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 strict
anduse warnings
statements. no strict
/no warnings
statement 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
html
or$Javascript
filter ordquote
method 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
lang
directory). - Members of the
capt
hash MUST be listed in the order of first occurrence in the corresponding template. PROCESS
directive SHOULD be preferred toINCLUDE
unless variable localization is actually required.PROCESS
andINCLUDE
directive 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
FOREACH
loops.
- 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
style
tags MAY be used for local styles (usingextra_head
block). - 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
JOIN
keyword, not comma. - Subqueries MUST have aliases (
SELECT ... FROM (SELECT ...) ALIAS
). CHECK
,FOREIGN KEY
andUNIQUE
constraints SHOULD be named.- Each foreign key MUST contain
ON DELETE
clause. - Migrations MUST be located in
migrations
subdirectory and MUST be named according to patternYYYYMMDD-migration-name.sql
.
- Code from
cats-main
andcats-problem
repositories MUST be compatible with Perl v5.14. - Code from
cats-judge
repository 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::UI
modules MUST be used only byRouter
. - SQL structure changes MUST include migration in the same commit.
- All
use lib
statements 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 #issue
at 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 #issue
at the end of the subject.