We will want to add new rules to this validator as the GTFS spec and the surrounding applications and tools change. This page outlines the process of adding new rules to this tool.
- Check the list of currently implemented rules to make sure the rule doesn't already exist.
- Check the list of planned future rules to see if an issue already exists for the proposed rule.
- If no existing issue exists, open a new issue with the "new rule" label.
- Discuss the rule with the community via the Github issue and come to a general consensus on the exact logic, and if it should be an
ERROR
orWARNING
. Generally, errors are behavior that directly violate the GTFS documentation. Warnings are behavior that is not advised (e.g., against best practices) but not explicitly forbidden in the GTSF documentation. - Implement new rule using the process below
For the below example, let's look at implementing a new rule that verify that entries in calendar.txt does not have end_date before start_date
If you want to take a look at a complete set of changes that implement this new rule before diving into the instructions, see this commit on Github.
II. Add the rule to RULES.md
- Add the rule to the error or warnings table at the top of
RULES.md
:
| [E032](#E032) | `calendar.txt` `end_date` is before `start_date` |
- Add a definition of that rule at the bottom of the errors or warnings section:
<a name="E032"/>
### E032 - `calendar.txt` `end_date` is before `start_date`
In `calendar.txt`, the `end_date` of a service record must not be earlier than the `start_date`.
#### References:
* [calendar.txt specification](https://gtfs.org/reference/static/#calendartxt)
All classes that implements rules output are under the notice
package of the domain layer.
They must extend either ErrorNotice
or WarningNotice
and fit the *Notice
format.
-
Add the error code definition to either
ErrorNotice
orWarningNotice
class located in thebase
package:protected static final String E_013 = 13;
-
Add your new class in the
error
orwarning
package accordingly -
Override and define an
export
method:
@Override
public void export(final NoticeExporter exporter) throws IOException {
exporter.export(this);
}
Note: you will have a compiler warning "Cannot resolve method" until you complete step III
- Implement your own constructor, calling
super
and passing itfilename
,code
,title
,description
andentityId
Optional: if your Notice has specific data, you have to do the following for each piece of data:
- Add a key in the form of a static String in Notice.java
- In your class constructor, call the method
putNoticeSpecific
, passing it as parameters the newly defined key and the data
Here an example with CannotParseDateNotice
public class CannotParseDateNotice extends ErrorNotice {
public CannotParseDateNotice(String filename, String fieldName, int lineNumber, String rawValue) {
super(filename, E_017,
"Invalid date value",
"Value: '" + rawValue + "' of field: " + fieldName +
" with type date can't be parsed in file: " + filename + " at row: " + lineNumber,
null);
putNoticeSpecific(KEY_FIELD_NAME, fieldName);
putNoticeSpecific(KEY_LINE_NUMBER, lineNumber);
putNoticeSpecific(KEY_RAW_VALUE, rawValue);
}
@Override
public void export(final NoticeExporter exporter) throws IOException {
exporter.export(this);
}
}
-
Add a new definition at the bottom of the
NoticeExporter
interface -
Add the required code to the interface implementations in the
exporter
package located in theadapter
module
Note: JSON export required at a minimum. Leaving the protobuf implementation empty will not lead to your PR being rejected. The mechanism to use the protocol buffer exporter is very similar. At export time, the Notice data must be mapped to a GTFSProblem
Add a new test implementation to the *ExporterTest
classes
All rules in the validator are implemented in self-contained classes in the usecase
package located in its own usecase
module
- Add a class constructor which should take three finalized parameters
- A
GtfsDataRepository
from which the feed content can be pulled - A
ValidationResultRepository
to which any warning or error encountered can be pushed - A
Logger
through which execution progress can be reported
- Implement the verification code in the
execute
method pushing instances of your newNotice
class upon detecting issues. Don't forget to log a meaningful message specifying what rule you are about to validate.
Add a Test class for your new use case in the use case test module Those should test for the following
- Typical execution on valid data
- Each case in which a Notice is built
- The actual content of generated notices
- Null safety regarding fields defined as optional in the GTFS specification
Instantiation is done through the DefaultConfig
class
For the CLI app, retrieval and execution in the Main.java
class