Rootstrap Ruby style conventions. Use when writing, reviewing, or editing any Ruby source file (*.rb, *.rake, Gemfile, Rakefile, *.gemspec, config.ru) to ensure code follows the Rootstrap Ruby style guide — covers layout, syntax, naming, classes/modules, exceptions, collections, strings, regexes, metaprogramming, and general best practices.
Instrucciones de origen · Vista previa de solo lectura
name
ruby-conventions
description
Rootstrap Ruby style conventions. Use when writing, reviewing, or editing any Ruby source file (*.rb, *.rake, Gemfile, Rakefile, *.gemspec, config.ru) to ensure code follows the Rootstrap Ruby style guide — covers layout, syntax, naming, classes/modules, exceptions, collections, strings, regexes, metaprogramming, and general best practices.
Keep comments up to date — an outdated comment is worse than none.
Annotations: TODO: + description, above the relevant code. Add other annotation tags only after documenting them as project conventions.
Magic comments (# frozen_string_literal: true) at top, one per line, blank line before code.
Classes & Modules
Layout order: extend/include → inner classes → constants → attr_* → other macros → public class methods → initialize → public instance methods → protected → private.
Separate include per mixin.
Don't nest multi-line classes; use matching folder structure.
Prefer modules (extend self) over classes with only class methods.
Use def self.method (not def ClassName.method).
Within class methods calling siblings, omit self..
Always supply to_s for domain objects.
Use attr_reader/attr_accessor; avoid attr; don't prefix with get_/set_.
Struct.new for trivial value objects; don't inherit from it.
Avoid class variables (@@var); prefer class instance variables.
Proper visibility (private/protected); indent modifiers at method level with blank lines.
Prefer composition over inheritance. Use duck typing where appropriate.
Apply SOLID principles; respect the Liskov Substitution Principle (subclasses should be substitutable for their parents).
Encourage factory methods for clearer object creation APIs.
Use alias in lexical scope; alias_method for runtime/module aliasing. Note: alias binds at definition time, so subclass overrides won't be picked up unless re-aliased.
Exceptions
Prefer raise over fail; raise SomeException, 'message' (not .new(...), not RuntimeError).
Never return from ensure.
Use implicit begin in method bodies (def foo ... rescue ... end).
Don't suppress exceptions; avoid rescue in modifier form.
No exceptions for flow control.
Never rescue Exception — use rescue StandardError => e or bare rescue => e.
Specific exceptions higher in the rescue chain.
Release resources in ensure or block form (File.open('f') { |f| ... }).
Favor stdlib exceptions over new classes.
Extract repeated rescue patterns into contingency methods (with_io_error_handling { ... }) to DRY up error handling.
Collections
Use literals [] and {} (not Array.new, Hash.new).
%w[one two three] for word arrays, %i[a b c] for symbol arrays (2+ elements).
Prefer first/last over [0]/[-1]; Set for unique collections.
Symbols as hash keys; 1.9 syntax { one: 1 }; don't mix with hash rockets.
Hash#key? not has_key?; Hash#each_key not keys.each.
Hash#fetch for required keys; block form for expensive defaults: hash.fetch(:k) { expensive }.
Hash#values_at for multi-key lookup.
Don't mutate a collection while iterating.
Don't use mutable objects as hash keys.
Rely on ordered hashes (Ruby 1.9+); insertion order is preserved.
When providing collection-returning APIs, offer an alternate accessor to avoid nil[]: prefer Regexp.last_match(1) over Regexp.last_match[1].
Numbers
Integer (not Fixnum/Bignum) for type checks.
rand(1..6) over rand(6) + 1.
Strings
Interpolation "#{x}" over concatenation.
Pick single or double quotes consistently (guide prefers single when no interpolation).
{} around @var/$var in interpolation; don't call .to_s inside.
String#<< to build large strings, not +=.
sub/tr over gsub when simpler.
Squiggly heredocs <<~END for multi-line indented strings.
Date & Time
In Rails code, use Time.current, Time.zone.now, or Time.zone.parse; avoid Time.now and Time.parse.
In non-Rails Ruby code, prefer Time.now over Time.new; use Date or Time, not DateTime.
Regular Expressions
Plain string ops (string['text']) over regex when possible; also string[/regexp/] and string[/text(grp)/, 1] forms.
(?:...) for non-capturing; named groups (?<name>...) over numbered.
Regexp.last_match(n) not $1.
\A / \z (not ^/$) for full-string boundaries.
/x modifier for complex, commented regexes.
In character classes [], only ^, -, \, ] need escaping; don't escape . or brackets.
Use sub/gsub with a block or hash for complex replacements.
Percent Literals
%() only for single-line strings needing both interpolation and ". Heredocs for multi-line.
Avoid %q() unless the string has both ' and ".
%r{...} only when the regex contains /.
Brackets: () for strings, [] for %w/%i, {} for %r.
Avoid %x unless invoking a command whose string contains backticks.
Avoid %s — prefer :"some string" for symbols needing spaces.
Metaprogramming
Avoid needless metaprogramming; don't monkey-patch core classes in libraries.
Prefer block class_eval over string form; prefer define_method.
If you must use string-form class_eval/eval, pass __FILE__ and __LINE__ for sensible backtraces.
Avoid method_missing; if needed, also define respond_to_missing?, call super, and only catch well-defined prefixes (e.g. find_by_*) — delegating to non-magical methods.
public_send over send; __send__ over send when receiver may define send.
Misc
Write ruby -w clean code (run with warnings).
Avoid hashes as optional params (except initializers).
Keep methods small (~10 LOC, ideally <5); params 3–4 max.
Avoid more than 3 levels of block nesting.
Code functionally; don't mutate parameters unless that's the method's purpose.
Prefer module instance variables over globals ($foo).
Use OptionParser for complex CLI options; ruby -s only for trivial cases.
If adding global methods, put them in Kernel and make them private.
Be consistent and use common sense — within a file, prefer matching the surrounding style over strict rule-following.
Use Kernel#loop for infinite loops; prefer loop { ... break unless ... } over begin ... end while for post-condition loops.
Omit outer {} AND parens for internal DSL methods: validates :name, presence: true, length: { within: 1..10 }.
{...} for single-line blocks, do...end for multi-line. Avoid do...end in chains.
Avoid explicit return when unnecessary; avoid self. unless required.
Use ||= to init nil/unset vars; don't use ||= for booleans.
Use &&= to preprocess nullable values.
Avoid === outside case.
Use == not eql? unless strict type comparison is intended.
No space between method name and opening paren: f(x).
No nested method defs; use lambdas.
Lambda: ->(a, b) { ... } with args (parens required); -> { ... } with no args (omit parens); lambda do ... end for multi-line.
Prefer proc over Proc.new; use .call() not [] or .().
Use shorthand self-assignment: x += y, x **= y, etc.
Use explicit &block to forward blocks rather than wrapping them.
Don't shadow methods with local variables (e.g. naming an arg options when an accessor already exists).
Don't use character literals (?x) — use 'x'.
Avoid Perl-style special vars ($;, $,); prefer English library aliases ($LOAD_PATH, etc.).
Don't use BEGIN/END blocks; use Kernel#at_exit instead.
Use warn over $stderr.puts.
Favor sprintf/format over String#%; Array#join over Array#*.
Use Array(var) to coerce possibly-single values into arrays.
Use ranges or between? instead of x >= a && x <= b.
Predicate methods (.even?, .zero?, .nil?) over == 0, == nil.
Avoid !x.nil? when if x suffices.
Guard clauses over nested conditionals; next over if in loops.
Prefer: map over collect, select over find_all, find over detect, reduce over inject, size over length/count (note: count on non-Array Enumerables iterates the full collection).
flat_map over map.flatten(1); reverse_each over reverse.each.