From ce8aa666c11739ce7e94b962b1e011f53cf23097 Mon Sep 17 00:00:00 2001 From: Bozhidar Batsov Date: Sat, 14 Feb 2026 12:55:48 +0200 Subject: [PATCH 01/17] Add examples for the one-line cases rule --- README.adoc | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/README.adoc b/README.adoc index 31f31578..7de53e31 100644 --- a/README.adoc +++ b/README.adoc @@ -1421,6 +1421,35 @@ result = Use `when x then ...` for one-line cases. +[source,ruby] +---- +# bad +case year +when 1850..1889 + 'Blues' +when 1890..1909 + 'Ragtime' +when 1910..1929 + 'New Orleans Jazz' +when 1930..1939 + 'Swing' +when 1940..1950 + 'Bebop' +else + 'Jazz' +end + +# good +case year +when 1850..1889 then 'Blues' +when 1890..1909 then 'Ragtime' +when 1910..1929 then 'New Orleans Jazz' +when 1930..1939 then 'Swing' +when 1940..1950 then 'Bebop' +else 'Jazz' +end +---- + NOTE: The alternative syntax `when x: ...` has been removed as of Ruby 1.9. === Semicolon in `when` [[no-when-semicolons]] From 3b45ab69e0846aa096969b23ff4eade3e13bc1f9 Mon Sep 17 00:00:00 2001 From: Bozhidar Batsov Date: Sat, 14 Feb 2026 12:55:58 +0200 Subject: [PATCH 02/17] Add examples for the semicolon in when rule --- README.adoc | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/README.adoc b/README.adoc index 7de53e31..b1f14b60 100644 --- a/README.adoc +++ b/README.adoc @@ -1456,6 +1456,23 @@ NOTE: The alternative syntax `when x: ...` has been removed as of Ruby 1.9. Do not use `when x; ...`. See the previous rule. +[source,ruby] +---- +# bad +case year +when 1850..1889; 'Blues' +when 1890..1909; 'Ragtime' +else; 'Jazz' +end + +# good +case year +when 1850..1889 then 'Blues' +when 1890..1909 then 'Ragtime' +else 'Jazz' +end +---- + === Semicolon in `in` [[no-in-pattern-semicolons]] Do not use `in pattern; ...`. Use `in pattern then ...` for one-line `in` pattern branches. From 2ac4497e0e3087ec8caa2889d2a1308a54e382c7 Mon Sep 17 00:00:00 2001 From: Bozhidar Batsov Date: Sat, 14 Feb 2026 12:56:07 +0200 Subject: [PATCH 03/17] Add examples for the multi-line ternary operator rule --- README.adoc | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/README.adoc b/README.adoc index b1f14b60..e569efd3 100644 --- a/README.adoc +++ b/README.adoc @@ -1627,6 +1627,22 @@ false || true && false # => false (it's effectively false || (true && false)) Avoid multi-line `?:` (the ternary operator); use `if`/`unless` instead. +[source,ruby] +---- +# bad +result = some_condition ? + something : + something_else + +# good +result = + if some_condition + something + else + something_else + end +---- + === `if` as a Modifier [[if-as-a-modifier]] Prefer modifier `if`/`unless` usage when you have a single-line body. From 8f0c0e380b106a4019a611d269995172f662edb6 Mon Sep 17 00:00:00 2001 From: Bozhidar Batsov Date: Sat, 14 Feb 2026 12:56:19 +0200 Subject: [PATCH 04/17] Add examples for the BEGIN blocks rule --- README.adoc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/README.adoc b/README.adoc index e569efd3..8dfc0b2e 100644 --- a/README.adoc +++ b/README.adoc @@ -1954,6 +1954,15 @@ end Avoid the use of `BEGIN` blocks. +[source,ruby] +---- +# bad +BEGIN { puts 'Initializing...' } + +# good +puts 'Initializing...' +---- + === `END` Blocks [[no-END-blocks]] Do not use `END` blocks. Use `Kernel#at_exit` instead. From 202c362cd4d034de4601ba1ed359a89c068e01fa Mon Sep 17 00:00:00 2001 From: Bozhidar Batsov Date: Sat, 14 Feb 2026 12:56:33 +0200 Subject: [PATCH 05/17] Add examples for the too many params rule --- README.adoc | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/README.adoc b/README.adoc index 8dfc0b2e..9bbe5a41 100644 --- a/README.adoc +++ b/README.adoc @@ -3200,6 +3200,18 @@ IMPORTANT: When calling `super` without arguments, `super` and `super()` mean di Avoid parameter lists longer than three or four parameters. +[source,ruby] +---- +# bad +def create_user(first_name, last_name, email, phone, address, age) + # ... +end + +# good +def create_user(first_name, last_name, email:, phone: nil, address: nil, age: nil) + # ... +end +---- === Optional Arguments [[optional-arguments]] From 4942c528468999c261c6749a4edb14caf32b516b Mon Sep 17 00:00:00 2001 From: Bozhidar Batsov Date: Sat, 14 Feb 2026 12:56:43 +0200 Subject: [PATCH 06/17] Add examples for the private global methods rule --- README.adoc | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/README.adoc b/README.adoc index 9bbe5a41..3239caf1 100644 --- a/README.adoc +++ b/README.adoc @@ -3383,6 +3383,23 @@ end If you really need "global" methods, add them to Kernel and make them private. +[source,ruby] +---- +# bad +def global_helper + # ... +end + +# good +module Kernel + private + + def global_helper + # ... + end +end +---- + == Classes & Modules === Consistent Classes [[consistent-classes]] From 4e08b2e78dfa76b08eee3fe1782bd80c801be01c Mon Sep 17 00:00:00 2001 From: Bozhidar Batsov Date: Sat, 14 Feb 2026 12:56:52 +0200 Subject: [PATCH 07/17] Add examples for the hash space rule --- README.adoc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/README.adoc b/README.adoc index 3239caf1..ab619f31 100644 --- a/README.adoc +++ b/README.adoc @@ -4118,6 +4118,15 @@ Write comments in English. Use one space between the leading `#` character of the comment and the text of the comment. +[source,ruby] +---- +# bad +#some comment + +# good +# some comment +---- + === English Syntax [[english-syntax]] Comments longer than a word are capitalized and use punctuation. From fb36d6262f32e6936da6200bd3ee14a6f8b69336 Mon Sep 17 00:00:00 2001 From: Bozhidar Batsov Date: Sat, 14 Feb 2026 12:57:07 +0200 Subject: [PATCH 08/17] Add examples for the no mutable keys rule --- README.adoc | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/README.adoc b/README.adoc index ab619f31..1338a668 100644 --- a/README.adoc +++ b/README.adoc @@ -4447,6 +4447,18 @@ hash = { one: 1, two: 2, three: 3 } Avoid the use of mutable objects as hash keys. +[source,ruby] +---- +# bad +hash = { 'name' => 'John' } + +# good +hash = { name: 'John' } + +# good - frozen string key when symbols won't do +hash = { 'name'.freeze => 'John' } +---- + === No Mutable Defaults [[no-mutable-defaults]] Avoid the use of shared mutable objects as hash default values. From 01c2a4f777dea66432fbefda4e0c24f6135b0d4f Mon Sep 17 00:00:00 2001 From: Bozhidar Batsov Date: Sat, 14 Feb 2026 12:57:18 +0200 Subject: [PATCH 09/17] Add examples for the no modifying collections rule --- README.adoc | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/README.adoc b/README.adoc index 1338a668..6bf422f2 100644 --- a/README.adoc +++ b/README.adoc @@ -4692,6 +4692,17 @@ Rely on the fact that as of Ruby 1.9 hashes are ordered. Do not modify a collection while traversing it. +[source,ruby] +---- +# bad +numbers = [1, 2, 3, 4, 5] +numbers.each { |n| numbers.delete(n) if n.even? } + +# good +numbers = [1, 2, 3, 4, 5] +odd_numbers = numbers.reject(&:even?) +---- + === Accessing Elements Directly [[accessing-elements-directly]] When accessing elements of a collection, avoid direct access via `[n]` by using an alternate form of the reader method if it is supplied. From a61a2cc149d73ae9dda2311afc5d46bc0769f3e8 Mon Sep 17 00:00:00 2001 From: Bozhidar Batsov Date: Sat, 14 Feb 2026 12:57:31 +0200 Subject: [PATCH 10/17] Add examples for the map/find/select/reduce/include?/size rule --- README.adoc | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/README.adoc b/README.adoc index 6bf422f2..51e84d52 100644 --- a/README.adoc +++ b/README.adoc @@ -4745,6 +4745,25 @@ This is not a hard requirement; if the use of the alias enhances readability, it The rhyming methods are inherited from Smalltalk and are not common in other programming languages. The reason the use of `select` is encouraged over `find_all` is that it goes together nicely with `reject` and its name is pretty self-explanatory. +[source,ruby] +---- +# bad +items.collect { |item| item.name } +items.detect(&:active?) +items.find_all(&:valid?) +items.inject(0) { |sum, i| sum + i } +items.member?(value) +items.length + +# good +items.map { |item| item.name } +items.find(&:active?) +items.select(&:valid?) +items.reduce(0) { |sum, i| sum + i } +items.include?(value) +items.size +---- + === `count` vs `size` [[count-vs-size]] Don't use `count` as a substitute for `size`. From ef94824bec3ecd2749952ddf63a355b5717fb068 Mon Sep 17 00:00:00 2001 From: Bozhidar Batsov Date: Sat, 14 Feb 2026 12:57:42 +0200 Subject: [PATCH 11/17] Add examples for the Time.now rule --- README.adoc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/README.adoc b/README.adoc index 51e84d52..ace4e8f7 100644 --- a/README.adoc +++ b/README.adoc @@ -5421,6 +5421,15 @@ SQL Prefer `Time.now` over `Time.new` when retrieving the current system time. +[source,ruby] +---- +# bad +Time.new + +# good +Time.now +---- + === No `DateTime` [[no-datetime]] Don't use `DateTime` unless you need to account for historical calendar reform - and if you do, explicitly specify the `start` argument to clearly state your intentions. From 2d8ba841ce26cf16f2f8c20dfe95c107298013cf Mon Sep 17 00:00:00 2001 From: Bozhidar Batsov Date: Sat, 14 Feb 2026 12:57:52 +0200 Subject: [PATCH 12/17] Add examples for the %s rule --- README.adoc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/README.adoc b/README.adoc index ace4e8f7..d30fb2b4 100644 --- a/README.adoc +++ b/README.adoc @@ -5724,6 +5724,15 @@ echo = %x(echo `date`) Avoid the use of `%s`. It seems that the community has decided `:"some string"` is the preferred way to create a symbol with spaces in it. +[source,ruby] +---- +# bad +%s(some symbol) + +# good +:"some symbol" +---- + === Percent Literal Braces [[percent-literal-braces]] Use the braces that are the most appropriate for the various kinds of percent literals. From 2d5bca35070e37b70b8acaab174b6deb224125f9 Mon Sep 17 00:00:00 2001 From: Bozhidar Batsov Date: Sat, 14 Feb 2026 12:58:06 +0200 Subject: [PATCH 13/17] Add examples for the no needless metaprogramming rule --- README.adoc | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/README.adoc b/README.adoc index d30fb2b4..7f3cff3a 100644 --- a/README.adoc +++ b/README.adoc @@ -5773,6 +5773,21 @@ Use the braces that are the most appropriate for the various kinds of percent li Avoid needless metaprogramming. +[source,ruby] +---- +# bad +class Person + %i[name age email].each do |attr| + define_method(attr) { instance_variable_get("@#{attr}") } + end +end + +# good +class Person + attr_reader :name, :age, :email +end +---- + === No Monkey Patching [[no-monkey-patching]] Do not mess around in core classes when writing libraries (do not monkey-patch them). From c755d7485bc6177ab0abc6a5b73220f0a2233779 Mon Sep 17 00:00:00 2001 From: Bozhidar Batsov Date: Sat, 14 Feb 2026 12:58:16 +0200 Subject: [PATCH 14/17] Add examples for the no monkey patching rule --- README.adoc | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/README.adoc b/README.adoc index 7f3cff3a..9bedf38f 100644 --- a/README.adoc +++ b/README.adoc @@ -5792,6 +5792,25 @@ end Do not mess around in core classes when writing libraries (do not monkey-patch them). +[source,ruby] +---- +# bad +class String + def to_hierarchical_date + split('-').map(&:to_i) + end +end + +# good - use refinements instead +module DateParsing + refine String do + def to_hierarchical_date + split('-').map(&:to_i) + end + end +end +---- + === Block `class_eval` [[block-class-eval]] The block form of `class_eval` is preferable to the string-interpolated form. From fa16ae0d77fa73a1bc060f49e4974c746de5c692 Mon Sep 17 00:00:00 2001 From: Bozhidar Batsov Date: Sat, 14 Feb 2026 12:58:30 +0200 Subject: [PATCH 15/17] Add examples for the no param mutations rule --- README.adoc | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/README.adoc b/README.adoc index 9bedf38f..d9865cc5 100644 --- a/README.adoc +++ b/README.adoc @@ -6286,6 +6286,20 @@ Use `OptionParser` for parsing complex command line options and `ruby -s` for tr Do not mutate parameters unless that is the purpose of the method. +[source,ruby] +---- +# bad +def clean(users) + users.reject!(&:disabled?) + users +end + +# good +def clean(users) + users.reject(&:disabled?) +end +---- + === Three is the Number Thou Shalt Count [[three-is-the-number-thou-shalt-count]] Avoid more than three levels of block nesting. From 89151bd991031b8aa8ec254412463cda563b9ff8 Mon Sep 17 00:00:00 2001 From: Bozhidar Batsov Date: Sat, 14 Feb 2026 12:58:43 +0200 Subject: [PATCH 16/17] Add examples for the three is the number thou shalt count rule --- README.adoc | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/README.adoc b/README.adoc index d9865cc5..f6bef7c2 100644 --- a/README.adoc +++ b/README.adoc @@ -6304,6 +6304,33 @@ end Avoid more than three levels of block nesting. +[source,ruby] +---- +# bad +def process(items) + items.each do |item| + item.widgets.each do |widget| + widget.parts.each do |part| + part.update! + end + end + end +end + +# good +def process(items) + items.each do |item| + process_widgets(item.widgets) + end +end + +def process_widgets(widgets) + widgets.each do |widget| + widget.parts.each(&:update!) + end +end +---- + === Functional Code [[functional-code]] Code in a functional way, avoiding mutation when that makes sense. From fbdff3bc62f4d46256a03eb01f726a5b3dd1bc9b Mon Sep 17 00:00:00 2001 From: Bozhidar Batsov Date: Sat, 14 Feb 2026 12:58:56 +0200 Subject: [PATCH 17/17] Add examples for the no optional hash params rule --- README.adoc | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/README.adoc b/README.adoc index f6bef7c2..408e20db 100644 --- a/README.adoc +++ b/README.adoc @@ -6259,6 +6259,21 @@ Write `ruby -w` safe code. Avoid hashes as optional parameters. Does the method do too much? (Object initializers are exceptions for this rule). +[source,ruby] +---- +# bad +def send_email(subject, opts = {}) + to = opts[:to] + cc = opts[:cc] + # ... +end + +# good +def send_email(subject, to:, cc: nil) + # ... +end +---- + === Instance Vars [[instance-vars]] Use module instance variables instead of global variables.