Ruby¶
Ruby is designed for programmer happiness — expressive, elegant, optimized for reading. But that expressiveness can become a liability when metaprogramming runs wild, method chains grow unreadable, or monkey-patching mutates core classes. These 11 principles encode the idioms that keep Ruby code joyful to maintain.
Optional External Tool Augmentation¶
Consent-first external tooling
External tool execution is optional and disabled by default. Use
--enable-external-tools (CLI) or enable_external_tools=true (MCP)
to opt in. Missing tools should return recommendations; no automatic
installs occur during analysis.
| Tool | Default invocation | Output |
|---|---|---|
rubocop |
rubocop --stdin stdin.rb --format json |
JSON |
Zen Principles¶
11 principles across 6 categories, drawn from Ruby Style Guide.
Architecture · 2 principles Complexity · 1 principle Error Handling · 1 principle Idioms · 4 principles Readability · 2 principles Structure · 1 principle
| Rule ID | Principle | Category | Severity | Dogma |
|---|---|---|---|---|
ruby-001 |
Convention over configuration | Idioms | 7 | ZEN-RIGHT-ABSTRACTION |
ruby-002 |
DRY (Don't Repeat Yourself) | Architecture | 8 | ZEN-RIGHT-ABSTRACTION |
ruby-003 |
Prefer blocks over lambdas/procs | Idioms | 6 | ZEN-RIGHT-ABSTRACTION, ZEN-PROPORTIONATE-COMPLEXITY |
ruby-004 |
Avoid monkey-patching core classes | Architecture | 9 | ZEN-RIGHT-ABSTRACTION |
ruby-005 |
Use meaningful method names with ?/! convention | Readability | 7 | ZEN-UNAMBIGUOUS-NAME |
ruby-006 |
Keep method chains readable | Readability | 6 | ZEN-UNAMBIGUOUS-NAME |
ruby-007 |
Prefer symbols over strings for keys | Idioms | 5 | ZEN-RIGHT-ABSTRACTION, ZEN-UNAMBIGUOUS-NAME |
ruby-008 |
Use guard clauses | Structure | 6 | ZEN-RETURN-EARLY |
ruby-009 |
Avoid needless metaprogramming | Complexity | 8 | ZEN-PROPORTIONATE-COMPLEXITY |
ruby-010 |
Use Ruby's expressive syntax | Idioms | 6 | ZEN-RIGHT-ABSTRACTION |
ruby-011 |
Prefer fail over raise for exceptions | Error Handling | 5 | ZEN-FAIL-FAST |
ruby-001 — Convention over configuration
Follow Ruby naming and structural conventions
Universal Dogmas: ZEN-RIGHT-ABSTRACTION
Common Violations:
- camelCase instead of snake_case
- Non-standard class naming
- CONSTANTS in lowercase
- Methods starting with capital letters
Thresholds:
| Parameter | Default |
|---|---|
naming_convention |
snake_case for methods/variables, PascalCase for classes |
ruby-002 — DRY (Don't Repeat Yourself)
Eliminate code duplication through abstraction
Universal Dogmas: ZEN-RIGHT-ABSTRACTION
Common Violations:
- Duplicated code blocks (>5 lines)
- Similar methods without extraction
- Repeated conditional logic
- Copy-pasted code
Detectable Patterns:
dup(clone(
ruby-003 — Prefer blocks over lambdas/procs
Use blocks for most iteration and callbacks
Universal Dogmas: ZEN-RIGHT-ABSTRACTION, ZEN-PROPORTIONATE-COMPLEXITY
Common Violations:
- Lambda where block would be clearer
- Proc for simple iterations
- Not using Ruby's block syntax
Detectable Patterns:
lambda { } for simple iterationsProc.new instead of block
ruby-004 — Avoid monkey-patching core classes
Don't modify String, Array, or other core classes
Universal Dogmas: ZEN-RIGHT-ABSTRACTION
Common Violations:
- Reopening String class
- Reopening Array class
- Modifying Integer, Hash
- Adding methods to core classes
Detectable Patterns:
class Stringclass Arrayclass Hash
ruby-005 — Use meaningful method names with ?/! convention
Methods ending in ? return boolean, ! indicate mutation
Universal Dogmas: ZEN-UNAMBIGUOUS-NAME
Common Violations:
- Boolean methods without ?
- Mutating methods without !
- Inconsistent naming patterns
Detectable Patterns:
def isdef has
ruby-006 — Keep method chains readable
Limit method chaining to 3-4 calls
Universal Dogmas: ZEN-UNAMBIGUOUS-NAME
Common Violations:
- Method chains > 4 calls
- Complex chaining without intermediate variables
- Unclear chaining logic
Thresholds:
| Parameter | Default |
|---|---|
max_method_chain_length |
4 |
ruby-007 — Prefer symbols over strings for keys
Use symbols for hash keys and identifiers
Universal Dogmas: ZEN-RIGHT-ABSTRACTION, ZEN-UNAMBIGUOUS-NAME
Common Violations:
- String keys in hashes
- Strings for method names in send
- String identifiers
Detectable Patterns:
=> "=> '
ruby-008 — Use guard clauses
Return early to avoid deep nesting
Universal Dogmas: ZEN-RETURN-EARLY
Common Violations:
- Deep nested if-else
- Not using early returns
- Inverted logic creating nesting
Detectable Patterns:
!return if
Recommended Fix
return unless, return if
ruby-009 — Avoid needless metaprogramming
Use metaprogramming sparingly and only when necessary
Universal Dogmas: ZEN-PROPORTIONATE-COMPLEXITY
Common Violations:
- define_method without clear benefit
- method_missing abuse
- Overly clever class_eval
- Unnecessary send/public_send
Detectable Patterns:
define_methodmethod_missingclass_evalinstance_evalsend(
ruby-010 — Use Ruby's expressive syntax
Leverage Ruby's readable constructs
Universal Dogmas: ZEN-RIGHT-ABSTRACTION
Common Violations:
- for loops instead of .each
- unless with negation
- Not using &: syntax
- Ternary when if/else is clearer
Detectable Patterns:
for item in collectionunless !condition
ruby-011 — Prefer fail over raise for exceptions
Use fail to indicate programmer errors
Universal Dogmas: ZEN-FAIL-FAST
Common Violations:
- Using raise for logic errors
- Not distinguishing error types
Detectable Patterns:
raise
Detector Catalog¶
Architecture¶
| Detector | What It Catches | Rule IDs |
|---|---|---|
| RubyDryDetector | Identifies duplicated code lines that violate Don't Repeat Yourself (DRY) | ruby-002 |
| RubyMonkeyPatchDetector | Detects reopening of core Ruby classes (monkey patching) | ruby-004 |
Complexity¶
| Detector | What It Catches | Rule IDs |
|---|---|---|
| RubyMetaprogrammingDetector | Flags dangerous metaprogramming constructs like method_missing and eval |
ruby-009 |
Error Handling¶
| Detector | What It Catches | Rule IDs |
|---|---|---|
| RubyPreferFailDetector | Flags use of raise where fail is the preferred convention for programmer errors |
ruby-011 |
Idioms¶
| Detector | What It Catches | Rule IDs |
|---|---|---|
| RubyNamingConventionDetector | Flags Ruby methods defined with non-snake_case names | ruby-001 |
| RubyBlockPreferenceDetector | Flags use of lambda/Proc.new where idiomatic blocks would suffice |
ruby-003 |
| RubySymbolKeysDetector | Flags hash literals using string keys instead of idiomatic symbol keys | ruby-007 |
| RubyExpressiveSyntaxDetector | Flags non-idiomatic control flow like C-style for loops and unless ! |
ruby-010 |
Readability¶
| Detector | What It Catches | Rule IDs |
|---|---|---|
| RubyMethodChainDetector | Detects excessively long method chains that reduce readability | ruby-006 |
| RubyMethodNamingDetector | Flags boolean-style methods that lack the conventional trailing ? |
ruby-005 |
Structure¶
| Detector | What It Catches | Rule IDs |
|---|---|---|
| RubyGuardClauseDetector | Detects methods that could benefit from guard clauses to reduce nesting | ruby-008 |
Principle → Detector Wiring
%%{init: {"theme": "base", "flowchart": {"useMaxWidth": false, "htmlLabels": true, "nodeSpacing": 40, "rankSpacing": 60}}}%%
graph TD
ruby_001["ruby-001<br/>Convention over configura..."]
ruby_002["ruby-002<br/>DRY (Don't Repeat Yoursel..."]
ruby_003["ruby-003<br/>Prefer blocks over lambda..."]
ruby_004["ruby-004<br/>Avoid monkey-patching cor..."]
ruby_005["ruby-005<br/>Use meaningful method nam..."]
ruby_006["ruby-006<br/>Keep method chains readab..."]
ruby_007["ruby-007<br/>Prefer symbols over strin..."]
ruby_008["ruby-008<br/>Use guard clauses"]
ruby_009["ruby-009<br/>Avoid needless metaprogra..."]
ruby_010["ruby-010<br/>Use Ruby's expressive syn..."]
ruby_011["ruby-011<br/>Prefer fail over raise fo..."]
det_RubyBlockPreferenceDetector["Ruby Block<br/>Preference"]
ruby_003 --> det_RubyBlockPreferenceDetector
det_RubyDryDetector["Ruby Dry"]
ruby_002 --> det_RubyDryDetector
det_RubyExpressiveSyntaxDetector["Ruby Expressive<br/>Syntax"]
ruby_010 --> det_RubyExpressiveSyntaxDetector
det_RubyGuardClauseDetector["Ruby Guard<br/>Clause"]
ruby_008 --> det_RubyGuardClauseDetector
det_RubyMetaprogrammingDetector["Ruby Metaprogramming"]
ruby_009 --> det_RubyMetaprogrammingDetector
det_RubyMethodChainDetector["Ruby Method<br/>Chain"]
ruby_006 --> det_RubyMethodChainDetector
det_RubyMethodNamingDetector["Ruby Method<br/>Naming"]
ruby_005 --> det_RubyMethodNamingDetector
det_RubyMonkeyPatchDetector["Ruby Monkey<br/>Patch"]
ruby_004 --> det_RubyMonkeyPatchDetector
det_RubyNamingConventionDetector["Ruby Naming<br/>Convention"]
ruby_001 --> det_RubyNamingConventionDetector
det_RubyPreferFailDetector["Ruby Prefer<br/>Fail"]
ruby_011 --> det_RubyPreferFailDetector
det_RubySymbolKeysDetector["Ruby Symbol<br/>Keys"]
ruby_007 --> det_RubySymbolKeysDetector
Detector Class Hierarchy
%%{init: {"theme": "base"}}%%
classDiagram
direction TB
class ViolationDetector {
<<abstract>>
+detect(context, config)
}
class det_01["Ruby Block Preference"]
ViolationDetector <|-- det_01
class det_02["Ruby Dry"]
ViolationDetector <|-- det_02
class det_03["Ruby Expressive Syntax"]
ViolationDetector <|-- det_03
class det_04["Ruby Guard Clause"]
ViolationDetector <|-- det_04
class det_05["Ruby Metaprogramming"]
ViolationDetector <|-- det_05
class det_06["Ruby Method Chain"]
ViolationDetector <|-- det_06
class det_07["Ruby Method Naming"]
ViolationDetector <|-- det_07
class det_08["Ruby Monkey Patch"]
ViolationDetector <|-- det_08
class det_09["Ruby Naming Convention"]
ViolationDetector <|-- det_09
class det_10["Ruby Prefer Fail"]
ViolationDetector <|-- det_10
class det_11["Ruby Symbol Keys"]
ViolationDetector <|-- det_11
Analysis Pipeline
%%{init: {"theme": "base", "flowchart": {"useMaxWidth": false, "htmlLabels": true, "nodeSpacing": 50, "rankSpacing": 70}}}%%
flowchart TD
Source(["Source Code"]) --> Parse["Parse & Tokenize"]
Parse --> Metrics["Compute Metrics"]
Metrics --> Pipeline{"11 Detectors"}
Pipeline --> Collect["Aggregate Violations"]
Collect --> Result(["AnalysisResult<br/>11 principles"])
Analysis States
%%{init: {"theme": "base"}}%%
stateDiagram-v2
[*] --> Ready
Ready --> Parsing : analyze(code)
Parsing --> Computing : AST ready
Computing --> Detecting : metrics ready
Detecting --> Reporting : 11 detectors run
Reporting --> [*] : AnalysisResult
Parsing --> Reporting : parse error (best-effort)
Configuration¶
See Also¶
- Python — Dynamic language with similar expressiveness goals
- Configuration — Per-language pipeline overrides
- Understanding Violations — Severity scale reference