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.
Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
A direct command skips the review prompt. Inspect the source before running it.
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.
{...} 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.