From 9e4d47875612ce2b8b92cc038f099e20c082e00a Mon Sep 17 00:00:00 2001 From: Elena Tanasoiu Date: Sun, 28 Aug 2022 18:39:05 +0100 Subject: [PATCH 1/7] Display testing commands on separate lines At the moment they're displayed on a single line. --- README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index b8af92a1..ab466b18 100644 --- a/README.md +++ b/README.md @@ -29,8 +29,10 @@ If you are using a rubocop version < 1.0.0, you can use rubocop-github version ## Testing -`bundle install` -`bundle exec rake test` +``` bash +bundle install +bundle exec rake test +``` ## The Cops From 5622c35630e2f354101bee707424d316fd198abb Mon Sep 17 00:00:00 2001 From: Elena Tanasoiu Date: Sun, 28 Aug 2022 19:02:44 +0100 Subject: [PATCH 2/7] Add table of contents --- STYLEGUIDE.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/STYLEGUIDE.md b/STYLEGUIDE.md index 829f4b2c..cfaf3c6b 100644 --- a/STYLEGUIDE.md +++ b/STYLEGUIDE.md @@ -1,5 +1,23 @@ # Ruby Style Guide +## Table of Contents +1. [Coding Style](#coding-style) +2. [Classes](#classes) +3. [Collections](#collections) +4. [Documentation](#documentation) +5. [Dynamic Dispatch](#dynamic-dispatch) +6. [Exceptions](#exceptions) +7. [Hashes](#hashes) +8. [Keyword Arguments](#keyword-arguments) +9. [Naming](#naming) +10. [Percent Literals](#percent-literals) +11. [Regular Expressions](#regular-expressions) +12. [Requires](#requires) +13. [Strings](#strings) +14. [Syntax](#syntax) + +## Coding Style + * Use soft-tabs with a two space indent. * Keep each line of code to a readable length. Unless you have a reason to, keep lines to a maximum of 118 characters. Why 118? That's the width at which the pull request diff UI needs horizontal scrolling (making pull requests harder to review). From 50f9b94a25edad0dc6de9d3265de38451f7d724f Mon Sep 17 00:00:00 2001 From: Elena Tanasoiu Date: Sun, 28 Aug 2022 19:03:23 +0100 Subject: [PATCH 3/7] Point to Rubocop guide The old styleguide page [1] points to the Rubocop styleguide as a source of inspiration. Let's add it here as well. [1]: https://web.archive.org/web/20160410033955/https://github.com/styleguide/ruby --- STYLEGUIDE.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/STYLEGUIDE.md b/STYLEGUIDE.md index cfaf3c6b..1893ca69 100644 --- a/STYLEGUIDE.md +++ b/STYLEGUIDE.md @@ -1,5 +1,7 @@ # Ruby Style Guide +This is GitHub's Ruby Style Guide, inspired by [RuboCop's guide][rubocop-guide]. + ## Table of Contents 1. [Coding Style](#coding-style) 2. [Classes](#classes) @@ -795,3 +797,5 @@ result = hash.map { |_, v| v + 1 } Instead, use `is_a?` or `kind_of?` if you must. Refactoring is even better. It's worth looking hard at any code that explicitly checks types. + +[rubocop-guide]: https://github.com/rubocop-hq/ruby-style-guide \ No newline at end of file From 2bda235972a35ee44c4484559a49503df44c4a70 Mon Sep 17 00:00:00 2001 From: Elena Tanasoiu Date: Sun, 28 Aug 2022 19:19:02 +0100 Subject: [PATCH 4/7] Re-organise "Coding Style" section This doesn't add or remove any rules, it just groups them together under: Layout - Indentation - Inline - Newlines Maximum Line Length Inspired by the RuboCop [1] and AirBnb [2] styleguides. [1]: https://github.com/rubocop/ruby-style-guide/blob/master/README.adoc [2]: https://github.com/airbnb/ruby/blob/master/README.md --- STYLEGUIDE.md | 102 ++++++++++++++++++++++++++++---------------------- 1 file changed, 57 insertions(+), 45 deletions(-) diff --git a/STYLEGUIDE.md b/STYLEGUIDE.md index 1893ca69..d7237672 100644 --- a/STYLEGUIDE.md +++ b/STYLEGUIDE.md @@ -3,54 +3,31 @@ This is GitHub's Ruby Style Guide, inspired by [RuboCop's guide][rubocop-guide]. ## Table of Contents -1. [Coding Style](#coding-style) -2. [Classes](#classes) -3. [Collections](#collections) -4. [Documentation](#documentation) -5. [Dynamic Dispatch](#dynamic-dispatch) -6. [Exceptions](#exceptions) -7. [Hashes](#hashes) -8. [Keyword Arguments](#keyword-arguments) -9. [Naming](#naming) -10. [Percent Literals](#percent-literals) -11. [Regular Expressions](#regular-expressions) -12. [Requires](#requires) -13. [Strings](#strings) -14. [Syntax](#syntax) - -## Coding Style +1. [Layout](#layout) + 1. [Indentation](#indentation) + 2. [Inline](#inline) + 3. [Newlines](#newlines) +2. [Maximum Line Length](#line-length) +3. [Classes](#classes) +4. [Collections](#collections) +5. [Documentation](#documentation) +6. [Dynamic Dispatch](#dynamic-dispatch) +7. [Exceptions](#exceptions) +8. [Hashes](#hashes) +9. [Keyword Arguments](#keyword-arguments) +10. [Naming](#naming) +11. [Percent Literals](#percent-literals) +12. [Regular Expressions](#regular-expressions) +13. [Requires](#requires) +14. [Strings](#strings) +15. [Syntax](#syntax) + +## Layout + +### Indentation * Use soft-tabs with a two space indent. -* Keep each line of code to a readable length. Unless you have a reason to, keep lines to a maximum of 118 characters. Why 118? That's the width at which the pull request diff UI needs horizontal scrolling (making pull requests harder to review). - -* Never leave trailing whitespace. - -* End each file with a [newline](https://github.com/bbatsov/ruby-style-guide#newline-eof). - -* Use spaces around operators, after commas, colons and semicolons, around `{` - and before `}`. - -``` ruby -sum = 1 + 2 -a, b = 1, 2 -1 > 2 ? true : false; puts "Hi" -[1, 2, 3].each { |e| puts e } -``` - -* No spaces after `(`, `[` or before `]`, `)`. - -``` ruby -some(arg).other -[1, 2, 3].length -``` - -* No spaces after `!`. - -``` ruby -!array.include?(element) -``` - * Indent `when` with the start of the `case` expression. ``` ruby @@ -91,6 +68,37 @@ else end ``` +### Inline + +* Never leave trailing whitespace. + +* Use spaces around operators, after commas, colons and semicolons, around `{` + and before `}`. + +``` ruby +sum = 1 + 2 +a, b = 1, 2 +1 > 2 ? true : false; puts "Hi" +[1, 2, 3].each { |e| puts e } +``` + +* No spaces after `(`, `[` or before `]`, `)`. + +``` ruby +some(arg).other +[1, 2, 3].length +``` + +* No spaces after `!`. + +``` ruby +!array.include?(element) +``` + +### Newlines + +* End each file with a [newline](https://github.com/bbatsov/ruby-style-guide#newline-eof). + * Use empty lines between `def`s and to break up a method into logical paragraphs. @@ -108,6 +116,10 @@ def some_method end ``` +## Maximum Line Length + +* Keep each line of code to a readable length. Unless you have a reason to, keep lines to a maximum of 118 characters. Why 118? That's the width at which the pull request diff UI needs horizontal scrolling (making pull requests harder to review). + ## Classes * Avoid the usage of class (`@@`) variables due to their unusual behavior From fe295a73dd0fb14964fd54daef78f3d29127522b Mon Sep 17 00:00:00 2001 From: Elena Tanasoiu Date: Sun, 28 Aug 2022 19:35:05 +0100 Subject: [PATCH 5/7] Extract method-related rules into own section --- STYLEGUIDE.md | 42 ++++++++++++++++++++++++++---------------- 1 file changed, 26 insertions(+), 16 deletions(-) diff --git a/STYLEGUIDE.md b/STYLEGUIDE.md index d7237672..be4774cd 100644 --- a/STYLEGUIDE.md +++ b/STYLEGUIDE.md @@ -20,7 +20,11 @@ This is GitHub's Ruby Style Guide, inspired by [RuboCop's guide][rubocop-guide]. 12. [Regular Expressions](#regular-expressions) 13. [Requires](#requires) 14. [Strings](#strings) -15. [Syntax](#syntax) +15. [Methods](#methods) + 1. [Method definitions](#method-definitions) + 2. [Method calls](#method-calls) + +16. [Syntax](#syntax) ## Layout @@ -558,7 +562,9 @@ paragraphs.each do |paragraph| end ``` -## Syntax +## Methods + +### Method definitions * Use `def` with parentheses when there are arguments. Omit the parentheses when the method doesn't accept any arguments. @@ -573,6 +579,24 @@ end end ``` +### Method calls + +* If the first argument to a method begins with an open parenthesis, + always use parentheses in the method invocation. For example, write + `f((3 + 2) + 1)`. + +* Never put a space between a method name and the opening parenthesis. + +``` ruby +# bad +f (3 + 2) + 1 + +# good +f(3 + 2) + 1 +``` + +## Syntax + * Never use `for`, unless you know exactly why. Most of the time iterators should be used instead. `for` is implemented in terms of `each` (so you're adding a level of indirection), but with a twist - `for` @@ -779,20 +803,6 @@ enabled = true if enabled.nil? one-liner scripts is discouraged. Prefer long form versions such as `$PROGRAM_NAME`. -* Never put a space between a method name and the opening parenthesis. - -``` ruby -# bad -f (3 + 2) + 1 - -# good -f(3 + 2) + 1 -``` - -* If the first argument to a method begins with an open parenthesis, - always use parentheses in the method invocation. For example, write -`f((3 + 2) + 1)`. - * Use `_` for unused block parameters. ``` ruby From 839223d9b3e4241b56744fafba3af46a423e4cf6 Mon Sep 17 00:00:00 2001 From: Elena Tanasoiu Date: Sun, 28 Aug 2022 19:45:33 +0100 Subject: [PATCH 6/7] Extract "Conditional Expressions" section --- STYLEGUIDE.md | 108 +++++++++++++++++++++++++++----------------------- 1 file changed, 58 insertions(+), 50 deletions(-) diff --git a/STYLEGUIDE.md b/STYLEGUIDE.md index be4774cd..365f68d5 100644 --- a/STYLEGUIDE.md +++ b/STYLEGUIDE.md @@ -23,8 +23,10 @@ This is GitHub's Ruby Style Guide, inspired by [RuboCop's guide][rubocop-guide]. 15. [Methods](#methods) 1. [Method definitions](#method-definitions) 2. [Method calls](#method-calls) - -16. [Syntax](#syntax) +16. [Conditional Expressions](#conditional-expressions) + 1. [Conditional keywords](#conditional-keywords) + 2. [Ternary operator](#ternary-operator) +17. [Syntax](#syntax) ## Layout @@ -595,25 +597,9 @@ f (3 + 2) + 1 f(3 + 2) + 1 ``` -## Syntax +## Conditional Expressions -* Never use `for`, unless you know exactly why. Most of the time iterators - should be used instead. `for` is implemented in terms of `each` (so - you're adding a level of indirection), but with a twist - `for` - doesn't introduce a new scope (unlike `each`) and variables defined - in its block will be visible outside it. - -``` ruby -arr = [1, 2, 3] - -# bad -for elem in arr do - puts elem -end - -# good -arr.each { |elem| puts elem } -``` +### Conditional keywords * Never use `then` for multi-line `if/unless`. @@ -629,38 +615,8 @@ if some_condition end ``` -* Avoid the ternary operator (`?:`) except in cases where all expressions are extremely - trivial. However, do use the ternary operator(`?:`) over `if/then/else/end` constructs - for single line conditionals. - -``` ruby -# bad -result = if some_condition then something else something_else end - -# good -result = some_condition ? something : something_else -``` - -* Use one expression per branch in a ternary operator. This - also means that ternary operators must not be nested. Prefer - `if/else` constructs in these cases. - -``` ruby -# bad -some_condition ? (nested_condition ? nested_something : nested_something_else) : something_else - -# good -if some_condition - nested_condition ? nested_something : nested_something_else -else - something_else -end -``` - * The `and` and `or` keywords are banned. It's just not worth it. Always use `&&` and `||` instead. -* Avoid multi-line `?:` (the ternary operator), use `if/unless` instead. - * Favor modifier `if/unless` usage when you have a single-line body. @@ -706,6 +662,58 @@ if x > 10 end ``` +### Ternary operator + +* Avoid the ternary operator (`?:`) except in cases where all expressions are extremely + trivial. However, do use the ternary operator(`?:`) over `if/then/else/end` constructs + for single line conditionals. + +``` ruby +# bad +result = if some_condition then something else something_else end + +# good +result = some_condition ? something : something_else +``` + +* Avoid multi-line `?:` (the ternary operator), use `if/unless` instead. + +* Use one expression per branch in a ternary operator. This + also means that ternary operators must not be nested. Prefer + `if/else` constructs in these cases. + +``` ruby +# bad +some_condition ? (nested_condition ? nested_something : nested_something_else) : something_else + +# good +if some_condition + nested_condition ? nested_something : nested_something_else +else + something_else +end +``` + +## Syntax + +* Never use `for`, unless you know exactly why. Most of the time iterators + should be used instead. `for` is implemented in terms of `each` (so + you're adding a level of indirection), but with a twist - `for` + doesn't introduce a new scope (unlike `each`) and variables defined + in its block will be visible outside it. + +``` ruby +arr = [1, 2, 3] + +# bad +for elem in arr do + puts elem +end + +# good +arr.each { |elem| puts elem } +``` + * Prefer `{...}` over `do...end` for single-line blocks. Avoid using `{...}` for multi-line blocks (multiline chaining is always ugly). Always use `do...end` for "control flow" and "method From 653e004ea17481b290105650a912af24a56701ab Mon Sep 17 00:00:00 2001 From: Elena Tanasoiu Date: Sun, 28 Aug 2022 20:34:09 +0100 Subject: [PATCH 7/7] Add handy anchor links to items in styleguide I've noticed people point at the styleguide when doing reviews. Let's make their life easier by adding a link to each rule. Spoiler: I am one of those people. --- STYLEGUIDE.md | 65 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/STYLEGUIDE.md b/STYLEGUIDE.md index 365f68d5..b10d59c3 100644 --- a/STYLEGUIDE.md +++ b/STYLEGUIDE.md @@ -33,8 +33,10 @@ This is GitHub's Ruby Style Guide, inspired by [RuboCop's guide][rubocop-guide]. ### Indentation * Use soft-tabs with a two space indent. + [[link](#default-indentation)] * Indent `when` with the start of the `case` expression. + [[link](#indent-when-as-start-of-case)] ``` ruby # bad @@ -77,9 +79,11 @@ end ### Inline * Never leave trailing whitespace. + [[link](#trailing-whitespace)] * Use spaces around operators, after commas, colons and semicolons, around `{` and before `}`. + [[link](#spaces-operators)] ``` ruby sum = 1 + 2 @@ -89,6 +93,7 @@ a, b = 1, 2 ``` * No spaces after `(`, `[` or before `]`, `)`. + [[link](#no-spaces-braces)] ``` ruby some(arg).other @@ -96,6 +101,7 @@ some(arg).other ``` * No spaces after `!`. + [[link](#no-spaces-bang)] ``` ruby !array.include?(element) @@ -104,9 +110,11 @@ some(arg).other ### Newlines * End each file with a [newline](https://github.com/bbatsov/ruby-style-guide#newline-eof). + [[link](#newline-eof)] * Use empty lines between `def`s and to break up a method into logical paragraphs. + [[link](#empty-lines-def)] ``` ruby def some_method @@ -125,11 +133,13 @@ end ## Maximum Line Length * Keep each line of code to a readable length. Unless you have a reason to, keep lines to a maximum of 118 characters. Why 118? That's the width at which the pull request diff UI needs horizontal scrolling (making pull requests harder to review). + [[link](#line-length)] ## Classes * Avoid the usage of class (`@@`) variables due to their unusual behavior in inheritance. + [[link](#class-variables)] ``` ruby class Parent @@ -153,6 +163,7 @@ Parent.print_class_var # => will print "child" * Use `def self.method` to define singleton methods. This makes the methods more resistant to refactoring changes. + [[link](#singleton-methods)] ``` ruby class TestClass @@ -169,6 +180,7 @@ class TestClass * Avoid `class << self` except when necessary, e.g. single accessors and aliased attributes. + [[link](#class-method-definitions)] ``` ruby class TestClass @@ -201,6 +213,7 @@ end * Indent the `public`, `protected`, and `private` methods as much the method definitions they apply to. Leave one blank line above them. + [[link](#access-modifier-identation)] ``` ruby class SomeClass @@ -217,6 +230,7 @@ end * Avoid explicit use of `self` as the recipient of internal class or instance messages unless to specify a method shadowed by a variable. + [[link](#self-messages)] ``` ruby class SomeClass @@ -233,6 +247,7 @@ end * Prefer `%w` to the literal array syntax when you need an array of strings. + [[link](#percent-w)] ``` ruby # bad @@ -246,8 +261,10 @@ STATES = %w(draft open closed) implements a collection of unordered values with no duplicates. This is a hybrid of `Array`'s intuitive inter-operation facilities and `Hash`'s fast lookup. + [[link](#prefer-set)] * Use symbols instead of strings as hash keys. + [[link](#symbols-as-keys)] ``` ruby # bad @@ -260,6 +277,7 @@ hash = { one: 1, two: 2, three: 3 } ## Documentation Use [TomDoc](http://tomdoc.org) to the best of your ability. It's pretty sweet: +[[link](#tomdoc)] ``` ruby # Public: Duplicate some text an arbitrary number of times. @@ -281,6 +299,7 @@ end ## Dynamic Dispatch Avoid calling `send` and its cousins unless you really need it. Metaprogramming can be extremely powerful, but in most cases you can write code that captures your meaning by being explicit: +[[link](#avoid-send)] ``` ruby # avoid @@ -306,6 +325,7 @@ end ## Exceptions * Don't use exceptions for flow of control. + [[link](#exceptions-flow-control)] ``` ruby # bad @@ -324,6 +344,7 @@ end ``` * Rescue specific exceptions, not `StandardError` or its superclasses. + [[link](#specific-exceptions)] ``` ruby # bad @@ -344,6 +365,7 @@ end ## Hashes Use the Ruby 1.9 syntax for hash literals when all the keys are symbols: +[[link](#symbols-as-hash-keys)] ``` ruby # bad @@ -360,6 +382,7 @@ user = { ``` Use the 1.9 syntax when calling a method with Hash options arguments or named arguments: +[[link](#symbols-as-hash-method-arguments)] ``` ruby # bad @@ -372,6 +395,9 @@ link_to("Account", controller: "users", action: "show", id: user) ``` If you have a hash with mixed key types, use the legacy hashrocket style to avoid mixing styles within the same hash: +[[link](#consistent-hash-syntax)] + +``` ruby ``` ruby # bad @@ -390,6 +416,9 @@ hsh = { ## Keyword Arguments [Keyword arguments](http://magazine.rubyist.net/?Ruby200SpecialEn-kwarg) are recommended but not required when a method's arguments may otherwise be opaque or non-obvious when called. Additionally, prefer them over the old "Hash as pseudo-named args" style from pre-2.0 ruby. +[[link](#keyword-arguments)] + +``` ruby So instead of this: ``` ruby @@ -414,23 +443,29 @@ remove_member(user, skip_membership_check: true) ## Naming * Use `snake_case` for methods and variables. + [[link](#snake-case-methods-vars)] * Use `CamelCase` for classes and modules. (Keep acronyms like HTTP, RFC, XML uppercase.) + [[link](#camelcase-classes-modules)] * Use `SCREAMING_SNAKE_CASE` for other constants. + [[link](#screaming-snake-case-constants)] * The names of predicate methods (methods that return a boolean value) should end in a question mark. (i.e. `Array#empty?`). + [[link](#bool-methods-qmark)] * The names of potentially "dangerous" methods (i.e. methods that modify `self` or the arguments, `exit!`, etc.) should end with an exclamation mark. Bang methods should only exist if a non-bang counterpart (method name which does NOT end with !) also exists. + [[link](#dangerous-method-bang)] ## Percent Literals * Use `%w` freely. + [[link](#use-percent-w-freely)] ``` ruby STATES = %w(draft open closed) @@ -438,6 +473,7 @@ STATES = %w(draft open closed) * Use `%()` for single-line strings which require both interpolation and embedded double-quotes. For multi-line strings, prefer heredocs. + [[link](#percent-parens-single-line)] ``` ruby # bad (no interpolation needed) @@ -457,6 +493,7 @@ STATES = %w(draft open closed) ``` * Use `%r` only for regular expressions matching *more than* one '/' character. + [[link](#percent-r-regular-expressions)] ``` ruby # bad @@ -474,6 +511,7 @@ STATES = %w(draft open closed) * Avoid using $1-9 as it can be hard to track what they contain. Named groups can be used instead. + [[link](#capture-with-named-groups)] ``` ruby # bad @@ -489,6 +527,7 @@ process meaningful_var * Be careful with `^` and `$` as they match start/end of line, not string endings. If you want to match the whole string use: `\A` and `\z`. + [[link](#regex-begin-end-markers)] ``` ruby string = "some injection\nusername" @@ -498,6 +537,7 @@ string[/\Ausername\z/] # don't match * Use `x` modifier for complex regexps. This makes them more readable and you can add some useful comments. Just be careful as spaces are ignored. + [[link](#x-modifier-complex-regex)] ``` ruby regexp = %r{ @@ -514,6 +554,7 @@ regexp = %r{ Always `require` dependencies used directly in a script at the start of the same file. Resources that will get autoloaded on first use—such as Rails models, controllers, or helpers—don't need to be required. +[[link](#require-dependencies-directly)] ``` ruby require "set" @@ -529,6 +570,7 @@ documentation about the libraries that the current file uses. ## Strings * Prefer string interpolation instead of string concatenation: + [[link](#string-interpolation)] ``` ruby # bad @@ -541,6 +583,7 @@ email_with_name = "#{user.name} <#{user.email}>" * Use double-quoted strings. Interpolation and escaped characters will always work without a delimiter change, and `'` is a lot more common than `"` in string literals. + [[link](#double-quotes)] ``` ruby # bad @@ -553,6 +596,7 @@ name = "Bozhidar" * Avoid using `String#+` when you need to construct large data chunks. Instead, use `String#<<`. Concatenation mutates the string instance in-place and is always faster than `String#+`, which creates a bunch of new string objects. + [[link](#string-concatenation)] ``` ruby # good and also fast @@ -570,6 +614,7 @@ end * Use `def` with parentheses when there are arguments. Omit the parentheses when the method doesn't accept any arguments. + [[link](#method-parens-when-arguments)] ``` ruby def some_method @@ -586,8 +631,10 @@ end * If the first argument to a method begins with an open parenthesis, always use parentheses in the method invocation. For example, write `f((3 + 2) + 1)`. + [[link](#parens-no-spaces)] * Never put a space between a method name and the opening parenthesis. + [[link](#no-spaces-method-parens)] ``` ruby # bad @@ -602,6 +649,7 @@ f(3 + 2) + 1 ### Conditional keywords * Never use `then` for multi-line `if/unless`. + [[link](#no-then-for-multi-line-if-unless)] ``` ruby # bad @@ -616,9 +664,11 @@ end ``` * The `and` and `or` keywords are banned. It's just not worth it. Always use `&&` and `||` instead. + [[link](#no-and-or-or)] * Favor modifier `if/unless` usage when you have a single-line body. + [[link](#favor-modifier-if-unless)] ``` ruby # bad @@ -631,6 +681,7 @@ do_something if some_condition ``` * Never use `unless` with `else`. Rewrite these with the positive case first. + [[link](#no-else-with-unless)] ``` ruby # bad @@ -649,6 +700,7 @@ end ``` * Don't use parentheses around the condition of an `if/unless/while`. + [[link](#no-parens-if-unless-while)] ``` ruby # bad @@ -667,6 +719,7 @@ end * Avoid the ternary operator (`?:`) except in cases where all expressions are extremely trivial. However, do use the ternary operator(`?:`) over `if/then/else/end` constructs for single line conditionals. + [[link](#trivial-ternary)] ``` ruby # bad @@ -677,10 +730,12 @@ result = some_condition ? something : something_else ``` * Avoid multi-line `?:` (the ternary operator), use `if/unless` instead. + [[link](#no-multiline-ternary)] * Use one expression per branch in a ternary operator. This also means that ternary operators must not be nested. Prefer `if/else` constructs in these cases. + [[link](#one-expression-per-branch)] ``` ruby # bad @@ -701,6 +756,7 @@ end you're adding a level of indirection), but with a twist - `for` doesn't introduce a new scope (unlike `each`) and variables defined in its block will be visible outside it. + [[link](#avoid-for)] ``` ruby arr = [1, 2, 3] @@ -719,6 +775,7 @@ arr.each { |elem| puts elem } ugly). Always use `do...end` for "control flow" and "method definitions" (e.g. in Rakefiles and certain DSLs). Avoid `do...end` when chaining. + [[link](#squiggly-braces)] ``` ruby names = ["Bozhidar", "Steve", "Sarah"] @@ -745,6 +802,7 @@ end.map { |name| name.upcase } nifty methods? * Avoid `return` where not required. + [[link](#avoid-return)] ``` ruby # bad @@ -759,6 +817,7 @@ end ``` * Use spaces around the `=` operator when assigning default values to method parameters: + [[link](#spaces-around-equals)] ``` ruby # bad @@ -776,6 +835,7 @@ While several Ruby books suggest the first style, the second is much more promin in practice (and arguably a bit more readable). * Using the return value of `=` (an assignment) is ok. + [[link](#use-return-value-of-assignment)] ``` ruby # bad @@ -789,6 +849,7 @@ if (v = next_value) == "hello" ... ``` * Use `||=` freely to initialize variables. + [[link](#memoize-away)] ``` ruby # set name to Bozhidar, only if it's nil or false @@ -797,6 +858,7 @@ name ||= "Bozhidar" * Don't use `||=` to initialize boolean variables. (Consider what would happen if the current value happened to be `false`.) + [[link](#no-memoization-for-boolean)] ``` ruby # bad - would set enabled to true even if it was false @@ -810,8 +872,10 @@ enabled = true if enabled.nil? etc. ). They are quite cryptic and their use in anything but one-liner scripts is discouraged. Prefer long form versions such as `$PROGRAM_NAME`. + [[link](#no-cryptic-vars)] * Use `_` for unused block parameters. + [[link](#underscore-unused-vars)] ``` ruby # bad @@ -825,6 +889,7 @@ result = hash.map { |_, v| v + 1 } implementation detail to support Ruby features like `case`, and it's not commutative. For example, `String === "hi"` is true and `"hi" === String` is false. Instead, use `is_a?` or `kind_of?` if you must. + [[link](#type-checking-is-a-kind-of)] Refactoring is even better. It's worth looking hard at any code that explicitly checks types.