Backend code style¶
RuboCop and Easy style¶
The repository .rubocop.yml inherits the easy_style configuration, which is already in the Gemfile. Run RuboCop on the Ruby files you change:
Fix offenses in the files you touch. Two files hold exemptions:
.rubocop_todo.yml: fixable offenses that are tolerated for now. Regenerate it withbundle exec rubocop --regenerate-todo..rubocop_ignore.yml: offenses that are kept on purpose. Add exceptions here instead of inline disabling.
Beyond what RuboCop checks, these conventions apply to Easy8 code.
Do not change Redmine¶
Easy8 is a fork of Redmine, and Redmine upgrades replace Redmine files. Do not edit them directly. Put customer code in your modification plugin (see Repository structure) and extend the platform with patches and hooks.
Existing code and comments¶
Before you add something, look for an existing solution in models, controllers and views, and follow its syntax and style.
Write self-explanatory code. Comment complex parts using YARD.
Migrations¶
Schema migrations live in db/migrate and data migrations in db/data. See Database and data migrations.
Overwriting templates and partials¶
A plugin can replace a template or partial of the platform or of a plugin that is loaded before it. Do this only when you rewrite more than half of the content.
For small additions, use or add a hook. Hooks belong to the component that owns the view, usually the platform.
Prefixes¶
Prefix names to avoid conflicts. For a plugin Abc:
AbcHelperinstead ofHelperlabel_abc_sum:instead oflabel_sum:in language files
For new Easy8-owned entities, prefer the Easy prefix over generic names and over the Easy:: namespace. Use EasyPortfolio and easy_portfolios instead of Portfolio, portfolios or Easy::Portfolio. See ADR 0001.
Localisation¶
All user-visible text goes through I18n and must be translated at least to English. Do not overwrite language keys from Redmine or Easy8.
Common key prefixes: button_, error_, field_, label_, text_, title_.
Ruby conventions¶
Prefer def self.method_name over class << self:
# BAD
class << self
def project_scope(scope, options, _event_type)
scope
end
end
# GOOD
def self.project_scope(scope, options, _event_type)
scope
end
Combine delegations to the same target:
# BAD
delegate :branches, to: :scm
delegate :tags, to: :scm
# GOOD
delegate :branches, :tags, to: :scm
Declare optional: true on every belongs_to that is not required:
HTML and CSS¶
Use BEM for the class attribute: block__element_modifier, with words inside a name separated by -:
Use _ as the separator in the id attribute: