How to contribute¶
Thanks for taking the time to contribute to the open source Tracx toolbox!
Please follow the Documentation, Style and Changelog Guide to make sure that all your great work will work flawlessly and also be properly documented.
Documentation guide¶
This guideline is modified for Tracx taken from here.
In order to enable the automatic documentation generation, the header of
a MATLAB
function has to be formatted properly. The automatic
documentation extracts the commented header of the function (commented
lines between the function’s signature and the first line of code) based
on keywords and blocks.
Rule 1: There should be 1 free space between the percentage sign %
and the text. For instance, a correctly formatted line in the header
reads:
% this is correct
A line in the header that is formatted as follows is ignored:
%this is not correct (note the space)
Rule 2: After the last line of the header, leave one empty line before the body of the function.
% This is the end of the header of the function
x = 5; % the body of the function begins after one empty line
Importantly, do not put a comment above the first line of code, but include the comment inline:
% This is the end of the header of the function
% the body of the function begins after one empty line
x = 5;
Rule 3: A line in the header that includes ..
after the
percentage sign will be ignored in the documentation:
% .. this line will be ignored
Function signature¶
The function signature must be correctly formatted. Leave a space after
every comma and before and after the equal sign =
. A correctly
formatted function signature reads:
function [output1, output2, output3] = someFunction(input1, input2, input3) % good practice
A function signature that is not formatted properly throws an error during the automatic documentation generation:
function [ output1,output2,output3 ]=someFunction( input1,input2,input3 ) % bad practice
Function description¶
The description of the function is a brief explanation of the purpose of the function. Start with a capital letter function name. The description of the function may extend over several lines. However, try to keep the explanations as brief as possible.
function [output1, output2, output3] = someFunction(input1, input2, input3)
% SOMEFUNCTION. This is a description of the function that helps to understand how the function works
% Here the description continues, then we leave an empty comment line
%
Keywords¶
The automatic documentation software relies on keywords to properly format the documented function. A keyword also defines the start of a block with the header of a function. Main keywords include:
Args:
: block with input argument(s)Returns:
block with output argument(s).Example:
: block with example code (formattedMATLAB
syntax).. note::
: highlighted box with text:Authors:
: list with author(s)
Each of them must be followed by non-empty lines and should be separated from the next block by an empty line.
All keywords are optional. For instance, if a function does not have any
input arguments, the keyword Args:
can be omitted.
Any line of the block must be indented by 4 spaces after the comment
sign %
:
% Args:
% input1 (:obj:`object`): Description of input1
% input2 (:obj:`int`): Description of input2
% input3: Description <-- this is bad practice
%
% Returns
% -------
% output1: :obj:`bool` <-- no brackets needed
% Description of output1 <-- start on next line
If the indentation differs, there will be an error.
Keyword Example:
In the block starting with the keyword Example:
, the function’s
signature must be given in order to show how the function should be
used. It is important to leave one empty line before the keyword
Example:
, after the keyword, and after the function’s signature.
% the end of the description
%
% Example:
%
% [output1, output2, output3] = someFunction(input1, input2, input3)
%
% here the other section can begin
Keyword Args:
and Returns
The arguments declared in the blocks: Args:
, Example:
Authors:
must be followed by a colon :
before
the argument description is provided. Except Returns
this needs to be followed by a line with dashes.
The indentation between the argument (with colon) and the description should be at least 4 spaces, so that all argument descriptions are aligned.
% Args:
% input1 (:obj:`int`): Description of input1 <-- good practice
% input2 (:obj:`int`) No colon <-- bad practice
% input3 (:obj:`int`): Not enough distance (4+ spaces) <-- bad practice
% input4: No info on datatype <-- bad practice
%
% Returns
% -------
% longerNameOutput:
% Description of longerNameOutput after 4 spaces
% output1:
% Description begins at the same place as the longest argument <-- good practice
% output2:
% Description begins too soon <-- bad practice
For a structure
argument, it is possible to list its fields. An
empty line is added after the structure
argument. Then, in the next
line, the field is written aligned with the description of the
structure
plus 2 extra spaces.
The field is listed beginning as * .field - description
(note the
space between *
and .
). It is not necessary to leave an empty
line after listing fields and writing the next argument. The following
illustrates how to list a structure with its fields:
% Returns
% -------
% output: output argument with fields:
%
% * .field1 - first field of the structure.
% * .field2 - no indent <-- bad practice
% * .field3 - multi-line comment must begin always
% where the text of the first line begins <-- good practice
% * .field4 - multi-line comment where
% the text in line 2 begins too soon <-- bad practice
% next: next argument can be added without empty line
It is also possible to replace *
with a numbered list. You can use
numbers followed by a dot (e.g., 1.
) instead of * .
.
% Args:
% varargin (:obj:`str varchar`):
%
% * **opt input 1** (:obj:`float`): Description of optional argument1.
% * **opt input 2** (:obj:`float`): Description of optional argument 2. Note do not linebreak!
Keyword Example:
A common usage example can be included in the Example:
block. Code
included in this block will be formatted as MATLAB
formatted code.
Leave one empty line before the keyword Example:
, after the keyword,
and after the properly indented (4 spaces) code snippet.
% the previous block ends here
%
% Example:
%
% result = someFunction(input1, input2)
% %additional comment if necessary
%
% another block begins here
Keyword ..note::
Important information, such as common errors, can be included in the
block that starts with the keyword ..note::
. A ..note::
block is
formatted in a dedicated and highlighted box in the documentation.
Leave one empty line before the keyword ..note::
, after the keyword,
and after the properly indented text (indent of 4 spaces). The keyword needs to start with two dots followed by two colons after the name.
Normally formatted text can be left at the with one space after the
comment sign. An example of a ..note::
block reads:
%
% ..note::
%
% This is a note that contains a important information.
% It will be clearly visible in the documentation online.
%
% This is an additional final comment that can be added and that is
% only relevant to the code itself
Keyword :Authors:
.
In the :Authors:
block, the author(s) that have written or
contributed to the function are listed. Authors are shown in the
documentation. For multiple authers use a list with a dash.
%
% :Authors: - Name, date, additional information if needed
% Author Name - Short description
x = 5; % here the body of the function begins
If there are 2 or more authors, format as follows:
%
% :Authors:
%
% - Author Name - Short description
% - Author2 Name - Short description
x = 5; % here the body of the function begins
Example¶
A complete example of a function is provided here. Please remember that colons, indentations, and keywords are important to guarantee pretty formatting.
function [output1, output2] = someFunction(input1, input2, input3, varargin)
% SOMEFUNCTION. This is a description of the function that helps understand how the function works
% Here the description continues, then we leave an empty comment line
%
% Example:
%
% [output1, output2] = someFunction(input1, input2, input3, input4)
%
% Args:
% input1 (:obj:`int`): Description of input1
% input2 (:obj:`str`): Description of input2
% varargin (:obj:`str varchar`):
%
% * **opt input 1** (:obj:`float`): Description of optional argument1.
% * **opt input 1** (:obj:`float`): Description of optional argument1.
%
% Returns
% -------
% output1 :obj:`unit8` NxM
% Description of output
% output2 :obj:`unit8` NxM
% Description of output
%
% Example:
%
% % this could be an example that can be copied from the documentation to MATLAB
% [output1, output2] = someFunction(11, '22', structure, [1;2])
% % without optional values
% output1 = someFunction(11, '22')
%
% ..note::
%
% This is a very important information to be highlighted
%
% This is a final comment that cannot be in the description but can be useful
%
% :Authors:
% Name - some information
x = 5; % here the body of the function begins
Style guide¶
A comprehensive MATLAB style guide written by Richard Jonson can be found here. This guide is adopted from here.
Code¶
Spacing
Write
if singleCondition
, and notif (singleCondition)
. Use brackets only for multiple conditions.Use spaces around operators, e.g.,
i + 1
instead ofi+1
Use spaces after commas (unless separated by newlines)
Avoid spaces inside the curly-braces of cells:
{a, b}
instead of{ a, b }
Use spaces after commas in lists, after operands, after names, etc. This also improves readability. e.g.
a = [1, 2, 3; 4, 5, 6];
instead ofa=[1,2,3;4,5,6]
;Include a single line of whitespace between blocks of code
Include a whitespace after a comment sign
%
Variable names
When using mixed words, separate with capital letters (with no intervening spaces or punctuation), e.g.
calculateKineticFlux
Avoid ambiguity when naming variables: be as specific as possible
All variable names must be written in English
Use verb-noun structure for functions: allows to explain the operations performed
Append meaningful prefixes when possible, e.g.
Av
,Sum
,Min
,Max
, etcBoolean type variables, i.e. with only
true/false
values, withIs
oris
to stress this fact, e.g.if dataIsLoaded
Reuse names for short-life and variables with local scope, such as indexes of loops
Only use
i
,j
, etc., as indexes for very short loops
Miscellaneous
Add sanity checks to the code, e.g., if something does not work as expected, there should be code to check for this and either issue a
warning
or anerror
if there is a problem.Do not encode the absolute position of any files within any function: use relative paths, where possible
Indent the code: really improves readability.
Fix a maximum line length: break large ones if needed. Ensure that it is clear that the sentence is separated through different lines, e.g.:
function [parameter1, parameter2, parameter3, parameter4] = functionManyParameters...
(InputParameter1, InputParameter2, InputParameter3, InputParameter3, ...
InputParameter4, InputParameter5)
Divide the code in separate functional files whenever it is possible (and logical). Latest at ~1.5k lines of code seperate files should be used. Only exception are documentation strings for varargins and class properties which would not be rendered correctly otherwise.
Platform independent code
Use
pwd
to get the current directoryUse
filesep
for paths (e.g.,['myPath' filesep 'myFile.m']
)
Documentation and comments¶
Make sure the code is fully documented and commented, especially parts of the code that might be difficult to understand for beginner users.
Header for each file with the following elements:
Brief description (easy and short functions) or more detailed explanations (more complicated functions).
Description of
INPUT
andOUTPUT
variablesAuthors, co-authors, contributors (and the contribution of each of them)
Date of first fully operative version, and dates of consequent modifications with the corresponding number of version, e.g.
v1 - 11/06/2014 / v2 - 12/08/2014
Description of modifications in later versions, e.g.
v2: the efficiency has been improved by substituting the loops with matrices operations
Throughout the file:
Comment smartly. Not every line, but enough to allow tracking the execution
Try to use brief comments.
In case you believe a more complicated part requires a more comprehensive explanation, describe
What are you doing
andHow it is done through a more detailed paragraph
.If the code is divided in blocks, you can also introduce briefly what is the function of each block beforehand.
Format the comments with a whitespace after the
%
sign. Try to use lowercase letters for comments.
Tests¶
Annotate the individual tests extensively for review
Use
assert(computedResult == expectedResult)
to logically test thecomputedResult
and theexpectedResult
(you may also use<
or>
)For testing all entries of a vector, use
assert(all(vector1 == vector2))
Only use equality
assert
tests for integer valuesMake sure that equality
assert
tests within a given tolerance, e.g.,tol = 1e-9; assert(condition < tol);
Test, if possible, your contribution on cross platform such as
OSX
,Linux
andWIN
.Make sure to limit the output of the function to a minimum - only print the necessary information
Use
verbose
orprintLevel
to switch the verbose modeEnsure that the solution of optimization problems is actually a solution (test that the solution vector satisfies the imposed constraints)
Git commit messages¶
Use the present tense (“Add feature” not “Added feature”)
Be as specific and concise as possible
Reference issues and pull requests liberally
When only changing documentation, include
[documentation]
in the commit description
Changelog guide¶
The Changelog of Tracx contains a curated, chronologically ordered list of notable changes for each version of Tracx to make it easier for users and contributors to see what changes have been made. This is especially important in terms of reproducibility of Biomedical analysis.
We follow the guidelines described here in detail:
Keep in mind that:
Changelogs are for humans, not machines.
There should be an entry for every single version.
The same types of changes should be grouped.
Versions and sections should be linkable (i.e. used in git tags).
The latest version comes first.
The release date of each version is displayed. We use the isodata format ISO 8601.
YYYY-MM-DD
Label changes as follows:
Added for new features.
Changed for changes in existing functionality.
Deprecated for soon-to-be removed features.
Removed for now removed features.
Fixed for any bug fixes.
Security in case of vulnerabilities.
We stick to Semantic versioning
The version number is therefore structured as MAJOR.MINOR.PATCH, with:
- MAJOR version when you make incompatible API changes,
- MINOR version when you add functionality in a backwards compatible manner, and
- PATCH version when you make backwards compatible bug fixes.
Additional labels for pre-release and build metadata are available as extensions to the MAJOR.MINOR.PATCH format.
More details here