Ruby Tricks, Idiomatic Ruby, Refactorings and Best Practices

Conditional assignment.

Ruby is heavily influenced by lisp. One piece of obvious inspiration in its design is that conditional operators return values. This makes assignment based on conditions quite clean and simple to read.

There are quite a number of conditional operators you can use. Optimize for readability, maintainability, and concision.

If you're just assigning based on a boolean, the ternary operator works best (this is not specific to ruby/lisp but still good and in the spirit of the following examples!).

If you need to perform more complex logic based on a conditional or allow for > 2 outcomes, if / elsif / else statements work well.

If you're assigning based on the value of a single variable, use case / when A good barometer is to think if you could represent the assignment in a hash. For example, in the following example you could look up the value of opinion in a hash that looks like {"ANGRY" => comfort, "MEH" => ignore ...}

My Profile Photo

Chris Arcand

Principal Engineer building Terraform at HashiCorp 👨‍💻 Formerly: Red Hat , NBC SportsEngine , RubyMN organizer. Once played the clarinet for a living, now making a living to play hockey. I make pointless connections to Minnesota as a Minnesotan does.

St. Paul, MN

Null Coalescing Operators and Ruby's Conditional Assignments

A long time ago in a galaxy far, far away (not really) I started learning and writing Ruby professionally by diving in to an existing Rails project. Learning in a ‘trial by fire’ sort of setting with other developers more experienced with a language is a great way to pick something up very quickly. I remember the first time coming across something similar to the following:

This is probably the most basic and ubiquitous form of memoization in Ruby. In this case, I was told that with the combination of the ||= operator and Ruby’s implicit return this means:

Assign @something to a new Something object if it isn’t already initialized and return it, otherwise return the preexisting value of @something

It’s a simplistic answer but a sufficient one to tell a newcomer in the middle of a project. Having experience in other languages, I thought to myself Ah! Ruby’s null coalescing operator! I wondered about it but it never really occurred to me why the syntax of such an operator was the double pipe ( || ). Shrug , move on.

After writing Ruby for a quite a while and having written various versions of this same pattern many, many times, I was recently burned by ||= . I had to very quickly come up with a toggle in a class and came up with this:

Note that not only is this a dumb use for using this memoization pattern (there are many ways to create such a toggle with a default value of true - don’t use this one that I rushed to), it also doesn’t work . After a very short investigation of the issue and actually taking a moment to rediscover this operator myself, I quickly realized my (perhaps obvious) misunderstanding.

True Null Coalescing Operators

A true null coalescing operator is “a binary operator that is part of the syntax for a basic conditional expression” where you can both specify a value to be evaluated which is returned if not null and a value to be returned if the first value is null. That mouthful can be seen in this pseudo-code:

‘NOT NULL’ could also just mean ‘undefined’. Some programming languages don’t have an implicit notion of NULL. Many languages implement null coalescing operators. Here are just a few examples:

Perl’s version is //

In C#, the operator is ??

Swift takes a cue from C# and also has ??

From PHP5 and on, you can leave out the middle part of a ternary operator to create a binary one.

Apparently future versions of PHP might have a true ?? operator like C# and Swift.

Groovy took PHP’s thunder and actually made a separate operator out of ?: , calling it the ‘Elvis operator’. Look at it like an emoji. See Elvis’s hair curl?

Of course, all of these examples are null coalescing without implicit assignment; We’re assigning $greeting based on the existence of $more_personal_greeting . In Perl (at least) there’s a variation on // that acts and looks even more like Ruby’s ||= where assigning and checking $greeting is done implicitly:

$greeting is assigned to $greeting if it’s defined (no change) or "Hello." otherwise.

Ruby’s Conditional Assignments

Although it’s often used like it, Ruby’s ||= is not a null coalescing operator but a conditional assignment operator . In my quickly written Ruby example, @some_toggle ||= true always returns true, even if @some_toggle was previously assigned to false .

The reason is because this operator, ‘Or Equals’, coalesces false as well as nil . In Ruby anything that isn’t false or nil is truthy. ‘OrEquals’ is a shortcut for writing the following:

Oh. So that’s why the syntax is ‘double pipe equals’, ||= . All this operator does is take Ruby’s easy || logic operator and combine it with the assignment operator = . In hindsight - after having a lot more experience with Ruby logic and logical operators in general - it makes perfect sense. It’s not wrong, it’s just not a true null coalescing assignment operator. Don’t fall victim!

A Ruby version of what we’re trying to do could look like this:

Lastly, saying ‘ ||= is a conditional assignment operator’ is only a subset of the larger truth. The mix of various operators and assignment is simply referred to as abbreviated assignment . You’ve probably seen this in the form of += to increment a counter or add to a string. In fact, you can mix any of the following operators in the pattern <operator>= : +, -, *, /, %, **, &, &&, |, ||, ^, <<, >> .

Enjoy this post? Please share!

Everything You Need to Know About Destructuring in Ruby 3

January 6, 2021   Permalink

ruby conditional hash assignment

Welcome to our first article in a series all about the exciting new features in Ruby 3 ! Today we’re going to look how improved pattern matching and rightward assignment make it possible to “destructure” hashes and arrays in Ruby 3—much like how you’d accomplish it in, say, JavaScript—and some of the ways it goes far beyond even what you might expect. December 2021: now updated for Ruby 3.1 — see below!

First, a primer: destructuring arrays

For the longest time Ruby has had solid destructuring support for arrays. For example:

So that’s pretty groovy. However, you haven’t been able to use a similar syntax for hashes. This doesn’t work unfortunately:

Now there’s a method for Hash called values_at which you could use to pluck keys out of a hash and return in an array which you could then destructure:

But that feels kind of clunky, y’know? Not very Ruby-like.

So let’s see what we can do now in Ruby 3!

Introducing rightward assignment

In Ruby 3 we now have a “rightward assignment” operator. This flips the script and lets you write an expression before assigning it to a variable. So instead of x = :y , you can write :y => x . (Yay for the hashrocket resurgence!)

What’s so cool about this is the smart folks working on Ruby 3 realized that they could use the same rightward assignment operator for pattern matching as well. Pattern matching was introduced in Ruby 2.7 and lets you write conditional logic to find and extract variables from complex objects. Now we can do that in the context of assignment!

Let’s write a simple method to try this out. We’ll be bringing our A game today, so let’s call it a_game :

Now we can pass some hashes along and see what happens!

But what happens when we pass a hash that doesn’t contain the “a” key?

Darn, we get a runtime error. Now maybe that’s what you want if your code would break horribly with a missing hash key. But if you prefer to fail gracefully, rescue comes to the rescue. You can rescue at the method level, but more likely you’d want to rescue at the statement level. Let’s fix our method:

And try it again:

Now that you have a nil value, you can write defensive code to work around the missing data.

What about all the **rest?

Looking back at our original array destructuring example, we were able to get an array of all the values besides the first ones we pulled out as variables. Wouldn’t it be cool if we could do that with hashes too? Well now we can!

But wait, there’s more! Rightward assignment and pattern matching actually works with arrays as well! We can replicate our original example like so:

In addition, we can do some crazy stuff like pull out array slices before and after certain values:

Rightward assignment within pattern matching 🤯

Ready to go all Inception now?!

You can use rightward assignment techniques within a pattern matching expression to pull out disparate values from an array. In other words, you can pull out everything up to a particular type, grab that type’s value, and then pull out everything after that.

You do this by specifying the type (class name) in the pattern and using => to assign anything of that type to the variable. You can also put types in without rightward assignment to “skip over” those and move on to the next match.

Take a gander at these examples:

Powerful stuff!

And the pièce de rÊsistance: the pin operator

What if you don’t want to hardcode a value in a pattern but have it come from somewhere else? After all, you can’t put existing variables in patterns directly:

But in fact you can! You just need to use the pin operator ^ . Let’s try this again!

You can even use ^ to match variables previously assigned in the same pattern. Yeah, it’s nuts. Check out this example from the Ruby docs :

In case you didn’t follow that mind-bendy syntax, it first assigns the value of school (in this case, "high" ), then it finds the hash within the schools array where level matches school . The id value is then assigned from that hash, in this case, 2 .

So this is all amazingly powerful stuff. Of course you can use pattern matching in conditional logic such as case which is what all the original Ruby 2.7 examples showed, but I tend to think rightward assignment is even more useful for a wide variety of scenarios.

“Restructuring” for hashes and keyword arguments in Ruby 3.1

New with the release of Ruby 3.1 is the ability to use a short-hand syntax to avoid repetition in hash literals or when calling keyword arguments.

First, let’s see this in action for hashes:

What’s going on here is that {a:} is shorthand for {a: a} . For the sake of comparison, JavaScript provides the same feature this way: const a = 1; const obj = {a} .

I like {a:} because it’s a mirror image of the hash destructuring feature we discussed above. Let’s round-trip-it!

Better yet, this new syntax doesn’t just work for hash literals. It also works for keyword arguments when calling methods!

Prior to Ruby 3.1, you would have needed to write say_hello(first_name: first_name) . Now you can DRY up your method calls!

Another goodie: the values you’re passing via a hash literal or keyword arguments don’t have to be merely local variables. They can be method calls themselves. It even works with method_missing !

What’s happening here is we’re instantiating a new MissMe object and calling print_message . That method in turn calls miss_you which actually prints out the message. But wait, where is dear actually being defined?! print_message certainly isn’t defining that before calling miss_me . Instead, what’s actually happening is the reference to dear in print_message is triggering method_missing . That in turn supplies the return value of "my dear" .

Now this all may seem quite magical, but it would have worked virtually the same way in Ruby 3.0 and prior—only you would have had to write miss_you(dear: dear) inside of print_message . Is dear: dear any clearer? I don’t think so.

In summary, the new short-hand hash literals/keyword arguments in Ruby 3.1 feels like we’ve come full circle in making both those language features a lot more ergonomic and—dare I say it—modern.

Topic: Ruby 3 Fundamentals

Ruby Assignments in Conditional Expressions

For around two and a half years, I had been working in a Python 2.x environment at my old job . Since switching companies, Ruby and Rails has replaced Python and Flask. At first glance, the languages don’t seem super different, but there are definitely common Ruby idioms that I needed to learn.

While adding a new feature, I came across code that looked like this:

Intuitively, I guessed this meant “if some_func() returns something, do_something with it.” What took a second was understanding that you could do an assignment conditional expressions.

Coming from Python

In Python 2.x land (and any Python 3 before 3.8), assigning a variable in a conditional expression would return a syntax error:

Most likely, the assignment in a conditional expression is a typo where the programmer meant to do a comparison == instead.

This kind of typo is a big enough issue that there is a programming style called Yoda Conditionals , where the constant portion of a comparison is put on the left side of the operator. This would cause a syntax error if = were used instead of == , like this:

Back to Ruby

Now that I’ve come across this kind of assignment in Ruby for the first time, I searched whether assignments in conditional expressions were good style. Sure enough, the Ruby Style Guide has a section called “Safe Assignment in Condition” . The section and examples are short and straightforward. You should take a look if this Ruby idiom is new to you!

What is interesting about this idiom is that the assignment should be wrapped in parentheses. Take a look at the examples from the Ruby Style Guide:

Why is the first example bad? Well, the Style Guide also says that you shouldn’t put parentheses around conditional expressions . Parentheses around assignments in conditional expressions are specifically called out as an exception to this rule.

My guess is that by enforcing two different conventions, one for pure conditionals and one for assignments in conditionals, the onus is now on the programmer to decide what they want to do. This should prevent typos where an assignment = is used when a comparison == was intended, or vice versa.

The Python Equivalent

As called out above, assignments in conditional expressions are possible in Python 3.8 via PEP 572 . Instead of using an = for these kinds of assignments, the PEP introduced a new operator := . As parentheses are more common in Python expressions, introducing a new operator := (informally known as “the walrus operator”!!) was probably Python’s solution to the typo issue.

Hash in Ruby

Learn how to use a hash in Ruby language.

Defining hash in Ruby

To define a hash in a Ruby program, we need to use curly brackets. Remember that we use square brackets for arrays:

We should not name the variable hash because it is a reserved language keyword, but we can enter it into the REPL and see what happens. That’s why the authors usually use obj (object) or hh (double “h” indicates it’s more than just a variable).

Programmers say that the hash is key-value storage , where each key is assigned a value. For example, the key is ball , a string, and the value is the physical object ball itself. The hash is often called a dictionary . This is partly true because the dictionary of words is a perfect example of hash. Each key, or word, has a meaning, or a description of the word or a translation. In Java, language hash used to be called a dictionary too, but since the seventh version, this concept has become obsolete, and the dictionary has been renamed to map .

The key and value in the hash can be any object, but most often, the key is a string or symbol, and the value is the actual object. It is difficult to predict what it will be. It can be a string, a symbol, an array, a number, another hash. So when developers define a hash in a Ruby program, they usually know in advance what type it will keep.

For example, let’s agree that the key in the hash is a symbol, and the value is a number, type integer. We’ll keep the weight of different types of balls in grams inside of our hash:

If we write this program into the REPL and type obj , we will see the following:

The text above is perfectly valid from Ruby’s language perspective, and we could initialize our hash without writing the values and without using assignment operator = :

The operator => in Ruby is called a hash rocket . In JavaScript, it’s known as “fat arrow,” but has a different meaning. However, the hash rocket notation is now obsolete. It would be more correct to write the program this way:

We should notice that even though the record looks different, we will get the same conclusion as above if we write obj in REPL. In other words, the keys, :soccer_ball , :tennis_ball , :golf_ball , are symbol types in this case.

To get the value back from the hash, use the following construction:

Get hands-on with 1200+ tech skills courses.

This forum is now read-only. Please use our new forums! Go to forums

ruby conditional hash assignment

Conditional assignment operator? ||=

Can someone explain a little more about ||=

I see from the example that the conditional assignment operator can change an empty variable in Ruby to a specific value, say if a method where expressed within a block code. Once the ||= is assigned a value, the conditional assignment operator cannot be over written.

Is that a good rundown of ||= ? Thanks in advance

Answer 5149c7c787058869e2002a48

Yes, seems like you got it right. x ||= 1 will give x the value 1 if it does not yet have a value, otherwise it’ll do nothing.

But it’s not quite correct that a second ||= assignment cannot override the first. There are certain exceptions to this:

To understand this, you need to understand what ||= really is. It’s just a shorthand for a longer expression. It works like the += , *= and -= operators:

For example, if a has the value 5 , then after a+=4 it has the new value 9 .

But the || isn’t an arithmetic operator, it works a bit differently:

So if the left-hand variable a is nil , or false (as in the “oops!” example I gave above), or not even defined, then after a ||= x it will have the value of x . Otherwise, it’ll remain unchanged.

This is really handy in many scenarios. For instance, Ruby Hashes and Arrays all have the [] method, which will return nil if no value can be found. You can use that to set that value only if it wasn’t set before:

ruby conditional hash assignment

Answer 55525c4176b8feac1e00044d

A variable assigned a value, by the use of ||= can be overwritten, (by the use of = ). If ||= is used to attempt to give a new value to a variable that has already been assigned a value, it can not be done (value will not be overwrtitten). ||= can only be used to assign a value to a variable that has not been assigned a value, beforehand.

||= assigns a value also if variable is false, but it has’t been discussed in the lessons so far. This article discusses that http://www.rubyinside.com/what-rubys-double-pipe-or-equals-really-does-5488.html

ruby conditional hash assignment

that really helps. thanks :)

Answer 54307e738c1cccded9003494

This section has helped clear up this operator’s performance. Thanks

ruby conditional hash assignment

Popular free courses

Learn javascript.

Ruby Style Guide

Table of contents, guiding principles, a note about consistency, translations, source encoding, tabs or spaces, indentation, maximum line length, no trailing whitespace, line endings, should i terminate files with a newline, should i terminate expressions with ; , one expression per line, operator method call, spaces and operators, safe navigation, spaces and braces, no space after bang, no space inside range literals, indent when to case, indent conditional assignment, empty lines between methods, two or more empty lines, empty lines around attribute accessor, empty lines around access modifier, empty lines around bodies, trailing comma in method arguments, spaces around equals, line continuation in expressions, multi-line method chains, method arguments alignment, implicit options hash, dsl method calls, space in method calls, space in brackets access, multi-line arrays alignment, english for identifiers, snake case for symbols, methods and variables, identifiers with a numeric suffix, capitalcase for classes and modules, snake case for files, snake case for directories, one class per file, screaming snake case for constants, predicate methods suffix, predicate methods prefix, dangerous method suffix, relationship between safe and dangerous methods, unused variables prefix, other parameter, then in multi-line expression, condition placement, ternary operator vs if, nested ternary operators, semicolon in if, case vs if-else, returning result from if / case, one-line cases, semicolon in when, semicolon in in, double negation, multi-line ternary operator, if as a modifier, multi-line if modifiers, nested modifiers, if vs unless, using else with unless, parentheses around condition, multi-line while do, while as a modifier, while vs until, infinite loop, loop with break, explicit return, explicit self, shadowing methods, safe assignment in condition, begin blocks, nested conditionals, raise vs fail, raising explicit runtimeerror, exception class messages, return from ensure, implicit begin, contingency methods, suppressing exceptions, using rescue as a modifier, using exceptions for flow of control, blind rescues, exception rescuing ordering, reading from a file, writing to a file, release external resources, auto-release external resources, atomic file operations, standard exceptions, parallel assignment, values swapping, dealing with trailing underscore variables in destructuring assignment, self-assignment, conditional variable initialization shorthand, existence check shorthand, identity comparison, explicit use of the case equality operator, is_a vs kind_of, is_a vs instance_of, instance_of vs class comparison, proc application shorthand, single-line blocks delimiters, single-line do …​ end block, explicit block argument, trailing comma in block parameters, nested method definitions, multi-line lambda definition, stabby lambda definition with parameters, stabby lambda definition without parameters, proc vs proc.new, short methods, top-level methods, no single-line methods, endless methods, double colons, colon method definition, method definition parentheses, method call parentheses, too many params, optional arguments, keyword arguments order, boolean keyword arguments, keyword arguments vs optional arguments, keyword arguments vs option hashes, arguments forwarding, block forwarding, private global methods, consistent classes, mixin grouping, single-line classes, file classes, namespace definition, modules vs classes, module_function, solid design, define to_s, attr family, accessor/mutator method names, don’t extend struct.new, don’t extend data.define, duck typing, no class vars, leverage access modifiers (e.g. private and protected ), access modifiers indentation, defining class methods, alias method lexically, alias_method, class and self, defining constants within a block, factory methods, disjunctive assignment in constructor, no comments, rationale comments, english comments, english syntax, no superfluous comments, comment upkeep, refactor, don’t comment, annotations placement, annotations keyword format, multi-line annotations indentation, inline annotations, document annotations, magic comments first, below shebang, one magic comment per line, separate magic comments from code, literal array and hash, no trailing array commas, no gappy arrays, first and last, set vs array, symbols as keys, no mutable keys, hash literals, hash literal values, hash literal as last array item, no mixed hash syntaxes, avoid hash[] constructor, hash#fetch defaults, use hash blocks, hash#values_at and hash#fetch_values, hash#transform_keys and hash#transform_values, ordered hashes, no modifying collections, accessing elements directly, provide alternate accessor to collections, map / find / select / reduce / include / size, count vs size, reverse_each, object#yield_self vs object#then, slicing with ranges, underscores in numerics, numeric literal prefixes, integer type checking, random numbers, float division, float comparison, exponential notation, string interpolation, consistent string literals, no character literals, curlies interpolate, string concatenation, don’t abuse gsub, string#chars, named format tokens, long strings, squiggly heredocs, heredoc delimiters, heredoc method calls, heredoc argument closing parentheses, no datetime, plain text search, using regular expressions as string indexes, prefer non-capturing groups, do not mix named and numbered captures, refer named regexp captures by name, avoid perl-style last regular expression group matchers, avoid numbered groups, limit escapes, caret and dollar regexp, multi-line regular expressions, comment complex regular expressions, use gsub with a block or a hash for complex replacements, %q shorthand, percent literal braces, no needless metaprogramming, no monkey patching, block class_eval, eval comment docs, no method_missing, prefer public_send, prefer __send__, rd (block) comments, no ruby_version in the gemspec, add_dependency vs add_runtime_dependency, no flip-flops, no non- nil checks, global input/output streams, array coercion, ranges or between, predicate methods, bitwise predicate methods, no cryptic perlisms, use require_relative whenever possible, always warn, no optional hash params, instance vars, optionparser, no param mutations, three is the number thou shalt count, functional code, no explicit .rb to require, sources of inspiration, how to contribute, spread the word, introduction.

Role models are important.

This Ruby style guide recommends best practices so that real-world Ruby programmers can write code that can be maintained by other real-world Ruby programmers. A style guide that reflects real-world usage gets used, while a style guide that holds to an ideal that has been rejected by the people it is supposed to help risks not getting used at all - no matter how good it is.

The guide is separated into several sections of related guidelines. We’ve tried to add the rationale behind the guidelines (if it’s omitted we’ve assumed it’s pretty obvious).

We didn’t come up with all the guidelines out of nowhere - they are mostly based on the professional experience of the editors, feedback and suggestions from members of the Ruby community and various highly regarded Ruby programming resources, such as "Programming Ruby" and "The Ruby Programming Language" .

This style guide evolves over time as additional conventions are identified and past conventions are rendered obsolete by changes in Ruby itself.

and .

is a static code analyzer (linter) and formatter, based on this style guide.
Programs must be written for people to read, and only incidentally for machines to execute.

It’s common knowledge that code is read much more often than it is written. The guidelines provided here are intended to improve the readability of code and make it consistent across the wide spectrum of Ruby code. They are also meant to reflect real-world usage of Ruby instead of a random ideal. When we had to choose between a very established practice and a subjectively better alternative we’ve opted to recommend the established practice. [ 1 ]

There are some areas in which there is no clear consensus in the Ruby community regarding a particular style (like string literal quoting, spacing inside hash literals, dot position in multi-line method chaining, etc.). In such scenarios all popular styles are acknowledged and it’s up to you to pick one and apply it consistently.

Ruby had existed for over 15 years by the time the guide was created, and the language’s flexibility and lack of common standards have contributed to the creation of numerous styles for just about everything. Rallying people around the cause of community standards took a lot of time and energy, and we still have a lot of ground to cover.

Ruby is famously optimized for programmer happiness. We’d like to believe that this guide is going to help you optimize for maximum programmer happiness.

A foolish consistency is the hobgoblin of little minds, adored by little statesmen and philosophers and divines.

A style guide is about consistency. Consistency with this style guide is important. Consistency within a project is more important. Consistency within one class or method is the most important.

However, know when to be inconsistent — sometimes style guide recommendations just aren’t applicable. When in doubt, use your best judgment. Look at other examples and decide what looks best. And don’t hesitate to ask!

In particular: do not break backwards compatibility just to comply with this guide!

Some other good reasons to ignore a particular guideline:

When applying the guideline would make the code less readable, even for someone who is used to reading code that follows this style guide.

To be consistent with surrounding code that also breaks it (maybe for historic reasons) — although this is also an opportunity to clean up someone else’s mess (in true XP style).

Because the code in question predates the introduction of the guideline and there is no other reason to be modifying that code.

When the code needs to remain compatible with older versions of Ruby that don’t support the feature recommended by the style guide.

Translations of the guide are available in the following languages:

Chinese Simplified

Chinese Traditional

Egyptian Arabic

Portuguese (pt-BR)

These translations are not maintained by our editor team, so their quality and level of completeness may vary. The translated versions of the guide often lag behind the upstream English version.

Source Code Layout

Nearly everybody is convinced that every style but their own is ugly and unreadable. Leave out the "but their own" and they’re probably right…​

Use UTF-8 as the source file encoding.

UTF-8 has been the default source file encoding since Ruby 2.0.

Use only spaces for indentation. No hard tabs.

Use two spaces per indentation level (aka soft tabs).

Limit lines to 80 characters.

Most editors and IDEs have configuration options to help you with that. They would typically highlight lines that exceed the length limit.

A lot of people these days feel that a maximum line length of 80 characters is just a remnant of the past and makes little sense today. After all - modern displays can easily fit 200+ characters on a single line. Still, there are some important benefits to be gained from sticking to shorter lines of code.

First, and foremost - numerous studies have shown that humans read much faster vertically and very long lines of text impede the reading process. As noted earlier, one of the guiding principles of this style guide is to optimize the code we write for human consumption.

Additionally, limiting the required editor window width makes it possible to have several files open side-by-side, and works well when using code review tools that present the two versions in adjacent columns.

The default wrapping in most tools disrupts the visual structure of the code, making it more difficult to understand. The limits are chosen to avoid wrapping in editors with the window width set to 80, even if the tool places a marker glyph in the final column when wrapping lines. Some web based tools may not offer dynamic line wrapping at all.

Some teams strongly prefer a longer line length. For code maintained exclusively or primarily by a team that can reach agreement on this issue, it is okay to increase the line length limit up to 100 characters, or all the way up to 120 characters. Please, restrain the urge to go beyond 120 characters.

Avoid trailing whitespace.

Most editors and IDEs have configuration options to visualize trailing whitespace and to remove it automatically on save.

Use Unix-style line endings. [ 2 ]

git config --global core.autocrlf true

End each file with a newline.

This should be done via editor configuration, not manually.

Don’t use ; to terminate statements and expressions.

Use one expression per line.

Avoid dot where not required for operator method calls.

Use spaces around operators, after commas, colons and semicolons. Whitespace might be (mostly) irrelevant to the Ruby interpreter, but its proper use is the key to writing easily readable code.

There are a few exceptions:

Exponent operator:

Slash in rational literals:

Safe navigation operator:

Avoid chaining of &. . Replace with . and an explicit check. E.g. if users are guaranteed to have an address and addresses are guaranteed to have a zip code:

If such a change introduces excessive conditional logic, consider other approaches, such as delegation:

No spaces after ( , [ or before ] , ) . Use spaces around { and before } .

{ and } deserve a bit of clarification, since they are used for block and hash literals, as well as string interpolation.

For hash literals two styles are considered acceptable. The first variant is slightly more readable (and arguably more popular in the Ruby community in general). The second variant has the advantage of adding visual difference between block and hash literals. Whichever one you pick - apply it consistently.

With interpolated expressions, there should be no padded-spacing inside the braces.

No space after ! .

No space inside range literals.

Indent when as deep as case .

This is the style established in both "The Ruby Programming Language" and "Programming Ruby". Historically it is derived from the fact that case and switch statements are not blocks, hence should not be indented, and the when and else keywords are labels (compiled in the C language, they are literally labels for JMP calls).

When assigning the result of a conditional expression to a variable, preserve the usual alignment of its branches.

Use empty lines between method definitions and also to break up methods into logical paragraphs internally.

Don’t use several empty lines in a row.

Use empty lines around attribute accessor.

Use empty lines around access modifier.

Don’t use empty lines around method, class, module, block bodies.

Avoid comma after the last parameter in a method call, especially when the parameters are not on separate lines.

Use spaces around the = operator when assigning default values to method parameters:

While several Ruby books suggest the first style, the second is much more prominent in practice (and arguably a bit more readable).

Avoid line continuation with \ where not required. In practice, avoid using line continuations for anything but string concatenation.

Adopt a consistent multi-line method chaining style. There are two popular styles in the Ruby community, both of which are considered good - leading . and trailing . .

When continuing a chained method call on another line, keep the . on the second line.

When continuing a chained method call on another line, include the . on the first line to indicate that the expression continues.

A discussion on the merits of both alternative styles can be found here .

Align the arguments of a method call if they span more than one line. When aligning arguments is not appropriate due to line-length constraints, single indent for the lines after the first is also acceptable.

As of Ruby 2.7 braces around an options hash are no longer optional.

Omit the outer braces around an implicit options hash.

Omit both the outer braces and parentheses for methods that are part of an internal DSL (e.g., Rake, Rails, RSpec).

Do not put a space between a method name and the opening parenthesis.

Do not put a space between a receiver name and the opening brackets.

Align the elements of array literals spanning multiple lines.

Naming Conventions

The only real difficulties in programming are cache invalidation and naming things.

Name identifiers in English.

Use snake_case for symbols, methods and variables.

Do not separate numbers from letters on symbols, methods and variables.

is also known as , and .

Use CapitalCase for classes and modules. (Keep acronyms like HTTP, RFC, XML uppercase).

Use snake_case for naming files, e.g. hello_world.rb .

Use snake_case for naming directories, e.g. lib/hello_world/hello_world.rb .

Aim to have just a single class/module per source file. Name the file name as the class/module, but replacing CapitalCase with snake_case .

Use SCREAMING_SNAKE_CASE for other constants (those that don’t refer to classes and modules).

The names of predicate methods (methods that return a boolean value) should end in a question mark (i.e. Array#empty? ). Methods that don’t return a boolean, shouldn’t end in a question mark.

Avoid prefixing predicate methods with the auxiliary verbs such as is , does , or can . These words are redundant and inconsistent with the style of boolean methods in the Ruby core library, such as empty? and include? .

The names of potentially dangerous methods (i.e. methods that modify self or the arguments, exit! (doesn’t run the finalizers like exit does), etc) should end with an exclamation mark if there exists a safe version of that dangerous method.

Define the non-bang (safe) method in terms of the bang (dangerous) one if possible.

Prefix with _ unused block parameters and local variables. It’s also acceptable to use just _ (although it’s a bit less descriptive). This convention is recognized by the Ruby interpreter and tools like RuboCop will suppress their unused variable warnings.

When defining binary operators and operator-alike methods, name the parameter other for operators with "symmetrical" semantics of operands. Symmetrical semantics means both sides of the operator are typically of the same or coercible types.

Operators and operator-alike methods with symmetrical semantics (the parameter should be named other ): `, `-`, ` + , / , % , * , == , > , < , | , & , ^ , eql? , equal? .

Operators with non-symmetrical semantics (the parameter should not be named other ): << , [] (collection/item relations between operands), === (pattern/matchable relations).

Note that the rule should be followed only if both sides of the operator have the same semantics. Prominent exception in Ruby core is, for example, Array#*(int) .

Flow of Control

Do not 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.

Do not use then for multi-line if / unless / when / in .

Always put the condition on the same line as the if / unless in a multi-line conditional.

Prefer the ternary operator( ?: ) over if/then/else/end constructs. It’s more common and obviously more concise.

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.

Do not use if x; …​ . Use the ternary operator instead.

Prefer case over if-elsif when compared value is the same in each clause.

Leverage the fact that if and case are expressions which return a result.

Use when x then …​ for one-line cases.

The alternative syntax has been removed as of Ruby 1.9.

Do not use when x; …​ . See the previous rule.

Do not use in pattern; …​ . Use in pattern then …​ for one-line in pattern branches.

Use ! instead of not .

Avoid unnecessary uses of !!

!! converts a value to boolean, but you don’t need this explicit conversion in the condition of a control expression; using it only obscures your intention.

Consider using it only when there is a valid reason to restrict the result true or false . Examples include outputting to a particular format or API like JSON, or as the return value of a predicate? method. In these cases, also consider doing a nil check instead: !something.nil? .

Do not use and and or in boolean context - and and or are control flow operators and should be used as such. They have very low precedence, and can be used as a short form of specifying flow sequences like "evaluate expression 1, and only if it is not successful (returned nil ), evaluate expression 2". This is especially useful for raising errors or early return without breaking the reading flow.

Avoid several control flow operators in one expression, as that quickly becomes confusing:

Whether organizing control flow with and is a good idea has been a controversial topic in the community for a long time. But if you do, prefer these operators over / . As the different operators are meant to have different semantics that makes it easier to reason whether you’re dealing with a logical expression (that will get reduced to a boolean value) or with flow of control.

Simply put - because they add some cognitive overhead, as they don’t behave like similarly named logical operators in other languages.

First of all, and and or operators have lower precedence than the = operator, whereas the && and || operators have higher precedence than the = operator, based on order of operations.

Also && has higher precedence than || , where as and and or have the same one. Funny enough, even though and and or were inspired by Perl, they don’t have different precedence in Perl.

Avoid multi-line ?: (the ternary operator); use if / unless instead.

Prefer modifier if / unless usage when you have a single-line body. Another good alternative is the usage of control flow and / or .

Avoid modifier if / unless usage at the end of a non-trivial multi-line block.

Avoid nested modifier if / unless / while / until usage. Prefer && / || if appropriate.

Prefer unless over if for negative conditions (or control flow || ).

Do not use unless with else . Rewrite these with the positive case first.

Don’t use parentheses around the condition of a control expression.

There is an exception to this rule, namely .

Do not use while/until condition do for multi-line while/until .

Prefer modifier while/until usage when you have a single-line body.

Prefer until over while for negative conditions.

Use Kernel#loop instead of while / until when you need an infinite loop.

Use Kernel#loop with break rather than begin/end/until or begin/end/while for post-loop tests.

Avoid return where not required for flow of control.

Avoid self where not required. (It is only required when calling a self write accessor, methods named after reserved words, or overloadable operators.)

As a corollary, avoid shadowing methods with local variables unless they are both equivalent.

Don’t use the return value of = (an assignment) in conditional expressions unless the assignment is wrapped in parentheses. This is a fairly popular idiom among Rubyists that’s sometimes referred to as safe assignment in condition .

Avoid the use of BEGIN blocks.

Do not use END blocks. Use Kernel#at_exit instead.

Avoid use of nested conditionals for flow of control.

Prefer a guard clause when you can assert invalid data. A guard clause is a conditional statement at the top of a function that bails out as soon as it can.

Prefer next in loops instead of conditional blocks.

Prefer raise over fail for exceptions.

Don’t specify RuntimeError explicitly in the two argument version of raise .

Prefer supplying an exception class and a message as two separate arguments to raise , instead of an exception instance.

Do not return from an ensure block. If you explicitly return from a method inside an ensure block, the return will take precedence over any exception being raised, and the method will return as if no exception had been raised at all. In effect, the exception will be silently thrown away.

Use implicit begin blocks where possible.

Mitigate the proliferation of begin blocks by using contingency methods (a term coined by Avdi Grimm).

Don’t suppress exceptions.

Avoid using rescue in its modifier form.

Don’t use exceptions for flow of control.

Avoid rescuing the Exception class. This will trap signals and calls to exit , requiring you to kill -9 the process.

Put more specific exceptions higher up the rescue chain, otherwise they’ll never be rescued from.

Use the convenience methods File.read or File.binread when only reading a file start to finish in a single operation.

Use the convenience methods File.write or File.binwrite when only opening a file to create / replace its content in a single operation.

Release external resources obtained by your program in an ensure block.

Use versions of resource obtaining methods that do automatic resource cleanup when possible.

When doing file operations after confirming the existence check of a file, frequent parallel file operations may cause problems that are difficult to reproduce. Therefore, it is preferable to use atomic file operations.

Prefer the use of exceptions from the standard library over introducing new exception classes.

Assignment & Comparison

Avoid the use of parallel assignment for defining variables. Parallel assignment is allowed when it is the return of a method call (e.g. Hash#values_at ), used with the splat operator, or when used to swap variable assignment. Parallel assignment is less readable than separate assignment.

Use parallel assignment when swapping 2 values.

Avoid the use of unnecessary trailing underscore variables during parallel assignment. Named underscore variables are to be preferred over underscore variables because of the context that they provide. Trailing underscore variables are necessary when there is a splat variable defined on the left side of the assignment, and the splat variable is not an underscore.

Use shorthand self assignment operators whenever applicable.

Use ||= to initialize variables only if they’re not already initialized.

to initialize boolean variables. (Consider what would happen if the current value happened to be .)

enabled ||= true # good enabled = true if enabled.nil?

Use &&= to preprocess variables that may or may not exist. Using &&= will change the value only if it exists, removing the need to check its existence with if .

Prefer equal? over == when comparing object_id . Object#equal? is provided to compare objects for identity, and in contrast Object#== is provided for the purpose of doing value comparison.

Similarly, prefer using Hash#compare_by_identity than using object_id for keys:

Note that Set also has Set#compare_by_identity available.

Avoid explicit use of the case equality operator === . As its name implies it is meant to be used implicitly by case expressions and outside of them it yields some pretty confusing code.

With direct subclasses of , using is not an option since doesn’t provide that method (it’s defined in ). In those rare cases it’s OK to use .

Prefer is_a? over kind_of? . The two methods are synonyms, but is_a? is the more commonly used name in the wild.

Prefer is_a? over instance_of? .

While the two methods are similar, is_a? will consider the whole inheritance chain (superclasses and included modules), which is what you normally would want to do. instance_of? , on the other hand, only returns true if an object is an instance of that exact class you’re checking for, not a subclass.

Use Object#instance_of? instead of class comparison for equality.

Do not use eql? when using == will do. The stricter comparison semantics provided by eql? are rarely needed in practice.

Blocks, Procs & Lambdas

Use the Proc call shorthand when the called method is the only operation of a block.

Prefer {…​} over do…​end for single-line blocks. Avoid using {…​} for multi-line blocks (multi-line chaining is always ugly). Always use do…​end for "control flow" and "method definitions" (e.g. in Rakefiles and certain DSLs). Avoid do…​end when chaining.

Some will argue that multi-line chaining would look OK with the use of {…​}, but they should ask themselves - is this code really readable and can the blocks' contents be extracted into nifty methods?

Use multi-line do …​ end block instead of single-line do …​ end block.

Consider using explicit block argument to avoid writing block literal that just passes its arguments to another block.

Avoid comma after the last parameter in a block, except in cases where only a single argument is present and its removal would affect functionality (for instance, array destructuring).

Do not use nested method definitions, use lambda instead. Nested method definitions actually produce methods in the same scope (e.g. class) as the outer method. Furthermore, the "nested method" will be redefined every time the method containing its definition is called.

Use the new lambda literal syntax for single-line body blocks. Use the lambda method for multi-line blocks.

Don’t omit the parameter parentheses when defining a stabby lambda with parameters.

Omit the parameter parentheses when defining a stabby lambda with no parameters.

Prefer proc over Proc.new .

Prefer proc.call() over proc[] or proc.() for both lambdas and procs.

Avoid methods longer than 10 LOC (lines of code). Ideally, most methods will be shorter than 5 LOC. Empty lines do not contribute to the relevant LOC.

Avoid top-level method definitions. Organize them in modules, classes or structs instead.

It is fine to use top-level method definitions in scripts.

Avoid single-line methods. Although they are somewhat popular in the wild, there are a few peculiarities about their definition syntax that make their use undesirable. At any rate - there should be no more than one expression in a single-line method.

Ruby 3 introduced an alternative syntax for single-line method definitions, that’s discussed in the next section of the guide.

One exception to the rule are empty-body methods.

Only use Ruby 3.0’s endless method definitions with a single line body. Ideally, such method definitions should be both simple (a single expression) and free of side effects.

It’s important to understand that this guideline doesn’t contradict the previous one. We still caution against the use of single-line method definitions, but if such methods are to be used, prefer endless methods.

Use :: only to reference constants (this includes classes and modules) and constructors (like Array() or Nokogiri::HTML() ). Do not use :: for regular method calls.

Do not use :: to define class methods.

Use def with parentheses when there are parameters. Omit the parentheses when the method doesn’t accept any parameters.

Use parentheses around the arguments of method calls, especially if the first argument begins with an open parenthesis ( , as in f((3 + 2) + 1) .

Method Call with No Arguments

Always omit parentheses for method calls with no arguments.

Methods That Have "keyword" Status in Ruby

Always omit parentheses for methods that have "keyword" status in Ruby.

Unfortunately, it’s not exactly clear methods have "keyword" status. There is agreement that declarative methods have "keyword" status. However, there’s less agreement on which non-declarative methods, if any, have "keyword" status.

Non-Declarative Methods That Have "keyword" Status in Ruby

For non-declarative methods with "keyword" status (e.g., various Kernel instance methods), two styles are considered acceptable. By far the most popular style is to omit parentheses. Rationale: The code reads better, and method calls look more like keywords. A less-popular style, but still acceptable, is to include parentheses. Rationale: The methods have ordinary semantics, so why treat them differently, and it’s easier to achieve a uniform style by not worrying about which methods have "keyword" status. Whichever one you pick, apply it consistently.

Using super with Arguments

Always use parentheses when calling super with arguments:

When calling without arguments, and mean different things. Decide what is appropriate for your usage.

Avoid parameter lists longer than three or four parameters.

Define optional arguments at the end of the list of arguments. Ruby has some unexpected results when calling methods that have optional arguments at the front of the list.

Put required keyword arguments before optional keyword arguments. Otherwise, it’s much harder to spot optional keyword arguments there, if they’re hidden somewhere in the middle.

Use keyword arguments when passing a boolean argument to a method.

Prefer keyword arguments over optional arguments.

Use keyword arguments instead of option hashes.

Use Ruby 2.7’s arguments forwarding.

Use Ruby 3.1’s anonymous block forwarding.

In most cases, block argument is given name similar to &block or &proc . Their names have no information and & will be sufficient for syntactic meaning.

If you really need "global" methods, add them to Kernel and make them private.

Classes & Modules

Use a consistent structure in your class definitions.

Split multiple mixins into separate statements.

Prefer a two-line format for class definitions with no body. It is easiest to read, understand, and modify.

Many editors/tools will fail to understand properly the usage of . Someone trying to locate the class definition might try a grep "class FooError". A final difference is that the name of your class is not available to the callback of the base class with the form. In general it’s better to stick to the basic two-line style.

Don’t nest multi-line classes within classes. Try to have such nested classes each in their own file in a folder named like the containing class.

Define (and reopen) namespaced classes and modules using explicit nesting. Using the scope resolution operator can lead to surprising constant lookups due to Ruby’s lexical scoping , which depends on the module nesting at the point of definition.

Prefer modules to classes with only class methods. Classes should be used only when it makes sense to create instances out of them.

Prefer the use of module_function over extend self when you want to turn a module’s instance methods into class methods.

When designing class hierarchies make sure that they conform to the Liskov Substitution Principle .

Try to make your classes as SOLID as possible.

Always supply a proper to_s method for classes that represent domain objects.

Use the attr family of functions to define trivial accessors or mutators.

For accessors and mutators, avoid prefixing method names with get_ and set_ . It is a Ruby convention to use attribute names for accessors (readers) and attr_name= for mutators (writers).

Avoid the use of attr . Use attr_reader and attr_accessor instead.

Consider using Struct.new , which defines the trivial accessors, constructor and comparison operators for you.

Don’t extend an instance initialized by Struct.new . Extending it introduces a superfluous class level and may also introduce weird errors if the file is required multiple times.

Don’t extend an instance initialized by Data.define . Extending it introduces a superfluous class level.

Prefer duck-typing over inheritance.

Avoid the usage of class ( @@ ) variables due to their "nasty" behavior in inheritance.

As you can see all the classes in a class hierarchy actually share one class variable. Class instance variables should usually be preferred over class variables.

Assign proper visibility levels to methods ( private , protected ) in accordance with their intended usage. Don’t go off leaving everything public (which is the default).

Indent the public , protected , and private methods as much as the method definitions they apply to. Leave one blank line above the visibility modifier and one blank line below in order to emphasize that it applies to all methods below it.

Use def self.method to define class methods. This makes the code easier to refactor since the class name is not repeated.

Prefer alias when aliasing methods in lexical class scope as the resolution of self in this context is also lexical, and it communicates clearly to the user that the indirection of your alias will not be altered at runtime or by any subclass unless made explicit.

Since alias , like def , is a keyword, prefer bareword arguments over symbols or strings. In other words, do alias foo bar , not alias :foo :bar .

Also be aware of how Ruby handles aliases and inheritance: an alias references the method that was resolved at the time the alias was defined; it is not dispatched dynamically.

In this example, Fugitive#given_name would still call the original Westerner#first_name method, not Fugitive#first_name . To override the behavior of Fugitive#given_name as well, you’d have to redefine it in the derived class.

Always use alias_method when aliasing methods of modules, classes, or singleton classes at runtime, as the lexical scope of alias leads to unpredictability in these cases.

When class (or module) methods call other such methods, omit the use of a leading self or own name followed by a . when calling other such methods. This is often seen in "service classes" or other similar concepts where a class is treated as though it were a function. This convention tends to reduce repetitive boilerplate in such classes.

Do not define constants within a block, since the block’s scope does not isolate or namespace the constant in any way.

Define the constant outside of the block instead, or use a variable or method if defining the constant in the outer scope would be problematic.

Classes: Constructors

Consider adding factory methods to provide additional sensible ways to create instances of a particular class.

In constructors, avoid unnecessary disjunctive assignment ( ||= ) of instance variables. Prefer plain assignment. In ruby, instance variables (beginning with an @ ) are nil until assigned a value, so in most cases the disjunction is unnecessary.

Good code is its own best documentation. As you’re about to add a comment, ask yourself, "How can I improve the code so that this comment isn’t needed?". Improve the code and then document it to make it even clearer.

Write self-documenting code and ignore the rest of this section. Seriously!

If the how can be made self-documenting, but not the why (e.g. the code works around non-obvious library behavior, or implements an algorithm from an academic paper), add a comment explaining the rationale behind the code.

Write comments in English.

Use one space between the leading # character of the comment and the text of the comment.

Comments longer than a word are capitalized and use punctuation. Use one space after periods.

Avoid superfluous comments.

Keep existing comments up-to-date. An outdated comment is worse than no comment at all.

Good code is like a good joke: it needs no explanation.

Avoid writing comments to explain bad code. Refactor the code to make it self-explanatory. ("Do or do not - there is no try." Yoda)

Comment Annotations

Annotations should usually be written on the line immediately above the relevant code.

The annotation keyword is followed by a colon and a space, then a note describing the problem.

If multiple lines are required to describe the problem, subsequent lines should be indented three spaces after the # (one general plus two for indentation purposes).

In cases where the problem is so obvious that any documentation would be redundant, annotations may be left at the end of the offending line with no note. This usage should be the exception and not the rule.

Use TODO to note missing features or functionality that should be added at a later date.

Use FIXME to note broken code that needs to be fixed.

Use OPTIMIZE to note slow or inefficient code that may cause performance problems.

Use HACK to note code smells where questionable coding practices were used and should be refactored away.

Use REVIEW to note anything that should be looked at to confirm it is working as intended. For example: REVIEW: Are we sure this is how the client does X currently?

Use other custom annotation keywords if it feels appropriate, but be sure to document them in your project’s README or similar.

Magic Comments

Place magic comments above all code and documentation in a file (except shebangs, which are discussed next).

Place magic comments below shebangs when they are present in a file.

Use one magic comment per line if you need multiple.

Separate magic comments from code and documentation with a blank line.

Collections

Prefer literal array and hash creation notation (unless you need to pass parameters to their constructors, that is).

Prefer %w to the literal array syntax when you need an array of words (non-empty strings without spaces and special characters in them). Apply this rule only to arrays with two or more elements.

Prefer %i to the literal array syntax when you need an array of symbols (and you don’t need to maintain Ruby 1.9 compatibility). Apply this rule only to arrays with two or more elements.

Avoid comma after the last item of an Array or Hash literal, especially when the items are not on separate lines.

Avoid the creation of huge gaps in arrays.

When accessing the first or last element from an array, prefer first or last over [0] or [-1] . first and last take less effort to understand, especially for a less experienced Ruby programmer or someone from a language with different indexing semantics.

Use Set instead of Array when dealing with unique elements. Set 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.

Prefer symbols instead of strings as hash keys.

Avoid the use of mutable objects as hash keys.

Use the Ruby 1.9 hash literal syntax when your hash keys are symbols.

Use the Ruby 3.1 hash literal value syntax when your hash key and value are the same.

Wrap hash literal in braces if it is a last array item.

Don’t mix the Ruby 1.9 hash syntax with hash rockets in the same hash literal. When you’ve got keys that are not symbols stick to the hash rockets syntax.

Hash::[] was a pre-Ruby 2.1 way of constructing hashes from arrays of key-value pairs, or from a flat list of keys and values. It has an obscure semantic and looks cryptic in code. Since Ruby 2.1, Enumerable#to_h can be used to construct a hash from a list of key-value pairs, and it should be preferred. Instead of Hash[] with a list of literal keys and values, just a hash literal should be preferred.

Use Hash#key? instead of Hash#has_key? and Hash#value? instead of Hash#has_value? .

Use Hash#each_key instead of Hash#keys.each and Hash#each_value instead of Hash#values.each .

Use Hash#fetch when dealing with hash keys that should be present.

Introduce default values for hash keys via Hash#fetch as opposed to using custom logic.

Prefer the use of the block instead of the default value in Hash#fetch if the code that has to be evaluated may have side effects or be expensive.

Use Hash#values_at or Hash#fetch_values when you need to retrieve several values consecutively from a hash.

Prefer transform_keys or transform_values over each_with_object or map when transforming just the keys or just the values of a hash.

Rely on the fact that as of Ruby 1.9 hashes are ordered.

Do not modify a collection while traversing it.

When accessing elements of a collection, avoid direct access via [n] by using an alternate form of the reader method if it is supplied. This guards you from calling [] on nil .

When providing an accessor for a collection, provide an alternate form to save users from checking for nil before accessing an element in the collection.

Prefer map over collect , find over detect , select over find_all , reduce over inject , include? over member? and size over length . This is not a hard requirement; if the use of the alias enhances readability, it’s ok to use 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.

Don’t use count as a substitute for size . For Enumerable objects other than Array it will iterate the entire collection in order to determine its size.

Use flat_map instead of map + flatten . This does not apply for arrays with a depth greater than 2, i.e. if users.first.songs == ['a', ['b','c']] , then use map + flatten rather than flat_map . flat_map flattens the array by 1, whereas flatten flattens it all the way.

Prefer reverse_each to reverse.each because some classes that include Enumerable will provide an efficient implementation. Even in the worst case where a class does not provide a specialized implementation, the general implementation inherited from Enumerable will be at least as efficient as using reverse.each .

The method Object#then is preferred over Object#yield_self , since the name then states the intention, not the behavior. This makes the resulting code easier to read.

You can read more about the rationale behind this guideline .

Slicing arrays with ranges to extract some of their elements (e.g ary[2..5] ) is a popular technique. Below you’ll find a few small considerations to keep in mind when using it.

[0..-1] in ary[0..-1] is redundant and simply synonymous with ary .

Ruby 2.6 introduced endless ranges, which provide an easier way to describe a slice going all the way to the end of an array.

Ruby 2.7 introduced beginless ranges, which are also handy in slicing. However, unlike the somewhat obscure -1 in ary[1..-1] , the 0 in ary[0..42] is clear as a starting point. In fact, changing it to ary[..42] could potentially make it less readable. Therefore, using code like ary[0..42] is fine. On the other hand, ary[nil..42] should be replaced with ary[..42] or arr[0..42] .

Add underscores to large numeric literals to improve their readability.

Prefer lowercase letters for numeric literal prefixes. 0o for octal, 0x for hexadecimal and 0b for binary. Do not use 0d prefix for decimal literals.

Use Integer to check the type of an integer number. Since Fixnum is platform-dependent, checking against it will return different results on 32-bit and 64-bit machines.

Prefer to use ranges when generating random numbers instead of integers with offsets, since it clearly states your intentions. Imagine simulating a roll of a dice:

When performing float-division on two integers, either use fdiv or convert one-side integer to float.

Avoid (in)equality comparisons of floats as they are unreliable.

Floating point values are inherently inaccurate, and comparing them for exact equality is almost never the desired semantics. Comparison via the ==/!= operators checks floating-point value representation to be exactly the same, which is very unlikely if you perform any arithmetic operations involving precision loss.

When using exponential notation for numbers, prefer using the normalized scientific notation, which uses a mantissa between 1 (inclusive) and 10 (exclusive). Omit the exponent altogether if it is zero.

The goal is to avoid confusion between powers of ten and exponential notation, as one quickly reading 10e7 could think it’s 10 to the power of 7 (one then 7 zeroes) when it’s actually 10 to the power of 8 (one then 8 zeroes). If you want 10 to the power of 7, you should do 1e7 .

power notation exponential notation output

10 ** 7

1e7

10000000

10 ** 6

1e6

1000000

10 ** 7

10e6

10000000

One could favor the alternative engineering notation, in which the exponent must always be a multiple of 3 for easy conversion to the thousand / million / …​ system.

Alternative : engineering notation:

Prefer string interpolation and string formatting to string concatenation:

Adopt a consistent string literal quoting style. There are two popular styles in the Ruby community, both of which are considered good - single quotes by default and double quotes by default.

The string literals in this guide are using single quotes by default.

Single Quote

Prefer single-quoted strings when you don’t need string interpolation or special symbols such as \t , \n , ' , etc.

Double Quote

Prefer double-quotes unless your string literal contains " or escape characters you want to suppress.

Don’t use the character literal syntax ?x . Since Ruby 1.9 it’s basically redundant - ?x would be interpreted as 'x' (a string with a single character in it).

Don’t leave out {} around instance and global variables being interpolated into a string.

Don’t use Object#to_s on interpolated objects. It’s called on them automatically.

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.

Don’t use String#gsub in scenarios in which you can use a faster and more specialized alternative.

Prefer the use of String#chars over String#split with empty string or regexp literal argument.

These cases have the same behavior since Ruby 2.0.

Prefer the use of sprintf and its alias format over the fairly cryptic String#% method.

When using named format string tokens, favor %<name>s over %{name} because it encodes information about the type of the value.

Break long strings into multiple lines but don’t concatenate them with + . If you want to add newlines, use heredoc. Otherwise use \ :

Use Ruby 2.3’s squiggly heredocs for nicely indented multi-line strings.

Use descriptive delimiters for heredocs. Delimiters add valuable information about the heredoc content, and as an added bonus some editors can highlight code within heredocs if the correct delimiter is used.

Place method calls with heredoc receivers on the first line of the heredoc definition. The bad form has significant potential for error if a new line is added or removed.

Place the closing parenthesis for method calls with heredoc arguments on the first line of the heredoc definition. The bad form has potential for error if the new line before the closing parenthesis is removed.

Date & Time

Prefer Time.now over Time.new when retrieving the current system time.

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.

Regular Expressions

Some people, when confronted with a problem, think "I know, I’ll use regular expressions." Now they have two problems.

Don’t use regular expressions if you just need plain text search in string.

For simple constructions you can use regexp directly through string index.

Use non-capturing groups when you don’t use the captured result.

Do not mix named captures and numbered captures in a Regexp literal. Because numbered capture is ignored if they’re mixed.

Prefer using names to refer named regexp captures instead of numbers.

Don’t use the cryptic Perl-legacy variables denoting last regexp group matches ( $1 , $2 , etc). Use Regexp.last_match(n) instead.

Avoid using numbered groups as it can be hard to track what they contain. Named groups can be used instead.

Character classes have only a few special characters you should care about: ^ , - , \ , ] , so don’t escape . or brackets in [] .

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 (not to be confused with \Z which is the equivalent of /\n?\z/ ).

Use x (free-spacing) modifier for multi-line regexps.

That’s known as . In this mode leading and trailing whitespace is ignored.

Use x modifier for complex regexps. This makes them more readable and you can add some useful comments.

For complex replacements sub / gsub can be used with a block or a hash.

Percent Literals

Use %() (it’s a shorthand for %Q ) for single-line strings which require both interpolation and embedded double-quotes. For multi-line strings, prefer heredocs.

Avoid %() or the equivalent %q() unless you have a string with both ' and " in it. Regular string literals are more readable and should be preferred unless a lot of characters would have to be escaped in them.

Use %r only for regular expressions matching at least one / character.

Avoid the use of %x unless you’re going to execute a command with backquotes in it (which is rather unlikely).

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.

Use the braces that are the most appropriate for the various kinds of percent literals.

() for string literals ( %q , %Q ).

[] for array literals ( %w , %i , %W , %I ) as it is aligned with the standard array literals.

{} for regexp literals ( %r ) since parentheses often appear inside regular expressions. That’s why a less common character with { is usually the best delimiter for %r literals.

() for all other literals (e.g. %s , %x )

Metaprogramming

Avoid needless metaprogramming.

Do not mess around in core classes when writing libraries (do not monkey-patch them).

The block form of class_eval is preferable to the string-interpolated form.

Supply Location

When you use the string-interpolated form, always supply __FILE__ and __LINE__ , so that your backtraces make sense:

define_method

define_method is preferable to class_eval { def …​ }

When using class_eval (or other eval ) with string interpolation, add a comment block showing its appearance if interpolated (a practice used in Rails code):

Avoid using method_missing for metaprogramming because backtraces become messy, the behavior is not listed in #methods , and misspelled method calls might silently work, e.g. nukes.luanch_state = false . Consider using delegation, proxy, or define_method instead. If you must use method_missing :

Be sure to also define respond_to_missing?

Only catch methods with a well-defined prefix, such as find_by_* --make your code as assertive as possible.

Call super at the end of your statement

Delegate to assertive, non-magical methods:

Prefer public_send over send so as not to circumvent private / protected visibility.

Prefer __send__ over send , as send may overlap with existing methods.

API Documentation

Use YARD and its conventions for API documentation.

Don’t use block comments. They cannot be preceded by whitespace and are not as easy to spot as regular comments.

This is not really a block comment syntax, but more of an attempt to emulate Perl’s POD documentation system.

There’s an rdtool for Ruby that’s pretty similar to POD. Basically rdtool scans a file for =begin and =end pairs, and extracts the text between them all. This text is assumed to be documentation in RD format . You can read more about it here .

RD predated the rise of RDoc and YARD and was effectively obsoleted by them. [ 3 ]

Gemfile and Gemspec

The gemspec should not contain RUBY_VERSION as a condition to switch dependencies. RUBY_VERSION is determined by rake release , so users may end up with wrong dependency.

Fix by either:

Post-install messages.

Add both gems as dependency (if permissible).

If development dependencies, move to Gemfile.

Prefer add_dependency over add_runtime_dependency because add_dependency is considered soft-deprecated and the Bundler team recommends add_dependency .

See https://github.com/rubygems/rubygems/issues/7799#issuecomment-2192720316 for details.

Avoid the use of flip-flop operators .

Don’t do explicit non- nil checks unless you’re dealing with boolean values.

Use $stdout/$stderr/$stdin instead of STDOUT/STDERR/STDIN . STDOUT/STDERR/STDIN are constants, and while you can actually reassign (possibly to redirect some stream) constants in Ruby, you’ll get an interpreter warning if you do so.

The only valid use-case for the stream constants is obtaining references to the original streams (assuming you’ve redirected some of the global vars).

Use warn instead of $stderr.puts . Apart from being more concise and clear, warn allows you to suppress warnings if you need to (by setting the warn level to 0 via -W0 ).

Prefer the use of Array#join over the fairly cryptic Array#* with a string argument.

Use Array() instead of explicit Array check or [*var] , when dealing with a variable you want to treat as an Array, but you’re not certain it’s an array.

Use ranges or Comparable#between? instead of complex comparison logic when possible.

Prefer the use of predicate methods to explicit comparisons with == . Numeric comparisons are OK.

Prefer bitwise predicate methods over direct comparison operations.

Avoid using Perl-style special variables (like $: , $; , etc). They are quite cryptic and their use in anything but one-liner scripts is discouraged.

Use the human-friendly aliases provided by the English library if required.

For all your internal dependencies, you should use require_relative . Use of require should be reserved for external dependencies

This way is more expressive (making clear which dependency is internal or not) and more efficient (as require_relative doesn’t have to try all of $LOAD_PATH contrary to require ).

Write ruby -w safe code.

Avoid hashes as optional parameters. Does the method do too much? (Object initializers are exceptions for this rule).

Use module instance variables instead of global variables.

Use OptionParser for parsing complex command line options and ruby -s for trivial command line options.

Do not mutate parameters unless that is the purpose of the method.

Avoid more than three levels of block nesting.

Code in a functional way, avoiding mutation when that makes sense.

Omit the .rb extension for filename passed to require and require_relative .

If the extension is omitted, Ruby tries adding '.rb', '.so', and so on to the name until found. If the file named cannot be found, a will be raised. There is an edge case where file is loaded instead of a if file exists when will be changed to , but that seems harmless.

The method tap can be helpful for debugging purposes but should not be left in production code.

This is simpler and more efficient.

Here are some tools to help you automatically check Ruby code against this guide.

RuboCop is a Ruby static code analyzer and formatter, based on this style guide. RuboCop already covers a significant portion of the guide and has plugins for most popular Ruby editors and IDEs.

RuboCop’s cops (code checks) have links to the guidelines that they are based on, as part of their metadata.

RubyMine 's code inspections are partially based on this guide.

This guide started its life in 2011 as an internal company Ruby coding guidelines (written by Bozhidar Batsov ). Bozhidar had always been bothered as a Ruby developer about one thing - Python developers had a great programming style reference ( PEP-8 ) and Rubyists never got an official guide, documenting Ruby coding style and best practices. Bozhidar firmly believed that style matters. He also believed that a great hacker community, such as Ruby has, should be quite capable of producing this coveted document. The rest is history…​

At some point Bozhidar decided that the work he was doing might be interesting to members of the Ruby community in general and that the world had little need for another internal company guideline. But the world could certainly benefit from a community-driven and community-sanctioned set of practices, idioms and style prescriptions for Ruby programming.

Bozhidar served as the guide’s only editor for a few years, before a team of editors was formed once the project transitioned to RuboCop HQ.

Since the inception of the guide we’ve received a lot of feedback from members of the exceptional Ruby community around the world. Thanks for all the suggestions and the support! Together we can make a resource beneficial to each and every Ruby developer out there.

Many people, books, presentations, articles and other style guides influenced the community Ruby style guide. Here are some of them:

"The Elements of Style"

"The Elements of Programming Style"

The Python Style Guide (PEP-8)

"Programming Ruby"

"The Ruby Programming Language"

Contributing

The guide is still a work in progress - some guidelines are lacking examples, some guidelines don’t have examples that illustrate them clearly enough. Improving such guidelines is a great (and simple way) to help the Ruby community!

In due time these issues will (hopefully) be addressed - just keep them in mind for now.

Nothing written in this guide is set in stone. It’s our desire to work together with everyone interested in Ruby coding style, so that we could ultimately create a resource that will be beneficial to the entire Ruby community.

Feel free to open tickets or send pull requests with improvements. Thanks in advance for your help!

You can also support the project (and RuboCop) with financial contributions via one of the following platforms:

GitHub Sponsors

It’s easy, just follow the contribution guidelines below:

Fork rubocop/ruby-style-guide on GitHub

Make your feature addition or bug fix in a feature branch.

Include a good description of your changes

Push your feature branch to GitHub

Send a Pull Request

This guide is written in AsciiDoc and is published as HTML using AsciiDoctor . The HTML version of the guide is hosted on GitHub Pages.

Originally the guide was written in Markdown, but was converted to AsciiDoc in 2019.

Creative Commons License

A community-driven style guide is of little use to a community that doesn’t know about its existence. Tweet about the guide, share it with your friends and colleagues. Every comment, suggestion or opinion we get makes the guide just a little bit better. And we want to have the best possible guide, don’t we?

  • Std-lib 2.4.2
  •   

Support for the Ruby 2.4 series has ended. See here for reference.

Home Classes Methods

  • ::try_convert
  • #compare_by_identity
  • #compare_by_identity?
  • #default_proc
  • #default_proc=
  • #each_value
  • #fetch_values
  • #has_value?
  • #transform_values
  • #transform_values!

Included Modules

  • grammar.en.rdoc
  • test.ja.rdoc
  • Makefile.in
  • README.EXT.ja
  • configure.in
  • contributing.rdoc
  • contributors.rdoc
  • dtrace_probes.rdoc
  • extension.ja.rdoc
  • extension.rdoc
  • globals.rdoc
  • keywords.rdoc
  • maintainers.rdoc
  • marshal.rdoc
  • regexp.rdoc
  • security.rdoc
  • standard_library.rdoc
  • syntax.rdoc
  • assignment.rdoc
  • calling_methods.rdoc
  • control_expressions.rdoc
  • exceptions.rdoc
  • literals.rdoc
  • methods.rdoc
  • miscellaneous.rdoc
  • modules_and_classes.rdoc
  • precedence.rdoc
  • refinements.rdoc
  • History.rdoc
  • README.rdoc
  • CONTRIBUTING.rdoc
  • command_line_usage.rdoc
  • glossary.rdoc
  • proto_rake.rdoc
  • rakefile.rdoc
  • rational.rdoc
  • node_name.inc
  • README.ja.rdoc
  • vm_call_iseq_optimized.inc

Class/Module Index

  • ArgumentError
  • BasicObject
  • ClosedQueueError
  • Complex::compatible
  • ConditionVariable
  • Continuation
  • Encoding::CompatibilityError
  • Encoding::Converter
  • Encoding::ConverterNotFoundError
  • Encoding::InvalidByteSequenceError
  • Encoding::UndefinedConversionError
  • EncodingError
  • Enumerator::Generator
  • Enumerator::Lazy
  • Enumerator::Yielder
  • File::File::Constants
  • FloatDomainError
  • GC::Profiler
  • IO::EAGAINWaitReadable
  • IO::EAGAINWaitWritable
  • IO::EINPROGRESSWaitReadable
  • IO::EINPROGRESSWaitWritable
  • IO::EWOULDBLOCKWaitReadable
  • IO::EWOULDBLOCKWaitWritable
  • IO::WaitReadable
  • IO::WaitWritable
  • LocalJumpError
  • Math::DomainError
  • NoMemoryError
  • NoMethodError
  • NotImplementedError
  • ObjectSpace
  • ObjectSpace::WeakMap
  • Process::GID
  • Process::Status
  • Process::Sys
  • Process::UID
  • Process::Waiter
  • Random::Formatter
  • Rational::compatible
  • RegexpError
  • RubyVM::InstructionSequence
  • RuntimeError
  • ScriptError
  • SecurityError
  • SignalException
  • StandardError
  • StopIteration
  • SyntaxError
  • SystemCallError
  • SystemStackError
  • Thread::Backtrace::Location
  • Thread::Mutex
  • ThreadError
  • ThreadGroup
  • UnboundMethod
  • UncaughtThrowError
  • ZeroDivisionError

A Hash is a dictionary-like collection of unique keys and their values. Also called associative arrays, they are similar to Arrays, but where an Array uses integers as its index, a Hash allows you to use any object type.

Hashes enumerate their values in the order that the corresponding keys were inserted.

A Hash can be easily created by using its implicit form:

Hashes allow an alternate syntax for keys that are symbols. Instead of

You could write it as:

Each named key is a symbol you can access in hash:

A Hash can also be created through its ::new method:

Hashes have a default value that is returned when accessing keys that do not exist in the hash. If no default is set nil is used. You can set the default value by sending it as an argument to Hash.new :

Or by using the default= method:

Accessing a value in a Hash requires using its key:

Common Uses ¶ ↑

Hashes are an easy way to represent data structures, such as

Hashes are also commonly used as a way to have named parameters in functions. Note that no brackets are used below. If a hash is the last argument on a method call, no braces are needed, thus creating a really clean interface:

Hash Keys ¶ ↑

Two objects refer to the same hash key when their hash value is identical and the two objects are eql? to each other.

A user-defined class may be used as a hash key if the hash and eql? methods are overridden to provide meaningful behavior. By default, separate instances refer to separate hash keys.

A typical implementation of hash is based on the object's data while eql? is usually aliased to the overridden == method:

See also Object#hash and Object#eql?

Public Class Methods

Creates a new hash populated with the given objects.

Similar to the literal { key => value , ... } . In the first form, keys and values occur in pairs, so there must be an even number of arguments.

The second and third form take a single argument which is either an array of key-value pairs or an object convertible to a hash.

Returns a new, empty hash. If this hash is subsequently accessed by a key that doesn't correspond to a hash entry, the value returned depends on the style of new used to create the hash. In the first form, the access returns nil . If obj is specified, this single object will be used for all default values . If a block is specified, it will be called with the hash object and the key, and should return the default value. It is the block's responsibility to store the value in the hash if required.

Try to convert obj into a hash, using to_hash method. Returns converted hash or nil if obj cannot be converted for any reason.

Public Instance Methods

Returns true if hash is subset of other .

Returns true if hash is subset of other or equals to other .

Equality—Two hashes are equal if they each contain the same number of keys and if each key-value pair is equal to (according to Object#== ) the corresponding elements in the other hash.

The orders of each hashes are not compared.

Returns true if other is subset of hash .

Returns true if other is subset of hash or equals to hash .

Element Reference—Retrieves the value object corresponding to the key object. If not found, returns the default value (see Hash::new for details).

Element Assignment ¶ ↑

Associates the value given by value with the key given by key .

key should not have its value changed while it is in use as a key (an unfrozen String passed as a key will be duplicated and frozen).

See also Enumerable#any?

Searches through the hash comparing obj with the key using == . Returns the key-value pair (two elements array) or nil if no match is found. See Array#assoc .

Removes all key-value pairs from hsh .

Returns a new hash with the nil values/key pairs removed

Removes all nil values from the hash. Returns the hash.

Makes hsh compare its keys by their identity, i.e. it will consider exact same objects as same keys.

Returns true if hsh will compare its keys by their identity. Also see Hash#compare_by_identity .

Returns the default value, the value that would be returned by hsh if key did not exist in hsh . See also Hash::new and Hash#default= .

Sets the default value, the value returned for a key that does not exist in the hash. It is not possible to set the default to a Proc that will be executed on each key lookup.

If Hash::new was invoked with a block, return that block, otherwise return nil .

Sets the default proc to be executed on each failed key lookup.

Deletes the key-value pair and returns the value from hsh whose key is equal to key . If the key is not found, it returns nil . If the optional code block is given and the key is not found, pass in the key and return the result of block .

Deletes every key-value pair from hsh for which block evaluates to true .

If no block is given, an enumerator is returned instead.

Extracts the nested value specified by the sequence of key objects by calling dig at each step, returning nil if any intermediate step is nil .

Calls block once for each key in hsh , passing the key-value pair as parameters.

Calls block once for each key in hsh , passing the key as a parameter.

Calls block once for each key in hsh , passing the value as a parameter.

Returns true if hsh contains no key-value pairs.

Returns true if hash and other are both hashes with the same content. The orders of each hashes are not compared.

Returns a value from the hash for the given key. If the key can't be found, there are several options: With no other arguments, it will raise a KeyError exception; if default is given, then that will be returned; if the optional code block is specified, then that will be run and its result returned.

The following example shows that an exception is raised if the key is not found and a default value is not supplied.

Returns an array containing the values associated with the given keys but also raises KeyError when one of keys can't be found. Also see Hash#values_at and Hash#fetch .

Returns a new array that is a one-dimensional flattening of this hash. That is, for every key or value that is an array, extract its elements into the new array. Unlike Array#flatten , this method does not flatten recursively by default. The optional level argument determines the level of recursion to flatten.

Returns true if the given key is present in hsh .

Note that include? and member? do not test member equality using == as do other Enumerables.

See also Enumerable#include?

Returns true if the given value is present for some key in hsh .

Compute a hash-code for this hash. Two hashes with the same content will have the same hash code (and will compare using eql? ).

See also Object#hash .

Return the contents of this hash as a string.

Returns a new hash created by using hsh 's values as keys, and the keys as values. If a key with the same value already exists in the hsh , then the last one defined will be used, the earlier value(s) will be discarded.

If there is no key with the same value, Hash#invert is involutive.

The condition, no key with the same value, can be tested by comparing the size of inverted hash.

Deletes every key-value pair from hsh for which block evaluates to false.

Returns the key of an occurrence of a given value. If the value is not found, returns nil .

Returns a new array populated with the keys from this hash. See also Hash#values .

Returns the number of key-value pairs in the hash.

Returns a new hash containing the contents of other_hash and the contents of hsh . If no block is specified, the value for entries with duplicate keys will be that of other_hash . Otherwise the value for each duplicate key is determined by calling the block with the key, its value in hsh and its value in other_hash .

Adds the contents of other_hash to hsh . If no block is specified, entries with duplicate keys are overwritten with the values from other_hash , otherwise the value of each duplicate key is determined by calling the block with the key, its value in hsh and its value in other_hash .

Searches through the hash comparing obj with the value using == . Returns the first key-value pair (two-element array) that matches. See also Array#rassoc .

Rebuilds the hash based on the current hash values for each key. If values of key objects have changed since they were inserted, this method will reindex hsh . If Hash#rehash is called while an iterator is traversing the hash, a RuntimeError will be raised in the iterator.

Returns a new hash consisting of entries for which the block returns false.

Equivalent to Hash#delete_if , but returns nil if no changes were made.

Replaces the contents of hsh with the contents of other_hash .

Returns a new hash consisting of entries for which the block returns true.

Equivalent to Hash#keep_if , but returns nil if no changes were made.

Removes a key-value pair from hsh and returns it as the two-item array [ key, value ] , or the hash's default value if the hash is empty.

Converts hsh to a nested array of [ key, value ] arrays.

Returns self . If called on a subclass of Hash , converts the receiver to a Hash object.

Returns self .

Return a new with the results of running block once for every value. This method does not change the keys.

Returns a new array populated with the values from hsh . See also Hash#keys .

Return an array containing the values associated with the given keys. Also see Hash.select .

This page was generated for Ruby 2.4.2

Generated with Ruby-doc Rdoc Generator 0.42.0 .

  • Stack Overflow for Teams Where developers & technologists share private knowledge with coworkers
  • Advertising & Talent Reach devs & technologists worldwide about your product, service or employer brand
  • OverflowAI GenAI features for Teams
  • OverflowAPI Train & fine-tune LLMs
  • Labs The future of collective knowledge sharing
  • About the company Visit the blog

Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Get early access and see previews of new features.

How do you assign a variable with the result of a if..else block?

I had an argument with a colleague about the best way to assign a variable in an if..else block. His orignal code was :

I rewrote it this way :

This could also be rewritten with a one-liner using a ternery operator (? :) but let's pretend that product assignment was longer than a 100 character and couldn't fit in one line.

Which of the two is clearer to you? The first solution takes a little less space but I thought that declaring a variable and assigning it three lines after can be more error prone. I also like to see my if and else aligned, makes it easier for my brain to parse it!

  • coding-style

Pierre Olivier Martel's user avatar

  • I'm not a Ruby programmer but I expect you can just stretch a ternary operator (or any) expression over multiple lines. –  Bart van Heukelom Commented May 27, 2010 at 21:58
  • 7 What is with all the answers that start with “I'm not a Ruby programmer but…” ? Okay then, don't answer the question. I know this was asked 5 years ago… but that's still well after Rails 2.0 burst into popularity. I'm honestly downvoting everything that starts with that apology upfront. –  Slipp D. Thompson Commented Apr 14, 2015 at 17:21

16 Answers 16

As an alternative to the syntax in badp's answer , I'd like to propose:

I claim this has two advantages:

  • Uniform indentation: each level of logical nesting is indented by exactly two spaces (OK, maybe this is just a matter of taste)
  • Horizontal compactness: A longer variable name will not push the indented code past the 80 (or whatever) column mark

It does take an extra line of code, which I would normally dislike, but in this case it seems worthwhile to trade vertical minimalism for horizontal minimalism.

Disclaimer: this is my own idiosyncratic approach and I don't know to what extent it is used elsewhere in the Ruby community.

Edit: I should mention that matsadler's answer is also similar to this one. I do think having some indentation is helpful. I hope that's enough to justify making this a separate answer.

Community's user avatar

  • Exactly what I searched for. In most cases it's the best solution. –  Anton Orel Commented Mar 27, 2013 at 6:20
  • 2 Above all else, I love Ruby because it is beautiful and expressive , meaning I can turn ideas into software quickly, and it's actually a joy to read and operate with. This syntax exemplifies this aspect of Ruby - superb! –  Steve Benner Commented Jul 10, 2014 at 3:32

As a Ruby programmer, I find the first clearer. It makes it clear that the whole expression is an assignment with the thing assigned being determined based on some logic, and it reduces duplication. It will look weird to people who aren't used to languages where everything is an expression, but writing your code for people who don't know the language is not that important a goal IMO unless they're specifically your target users. Otherwise people should be expected to have a passing familiarity with it.

I also agree with bp's suggestion that you could make it read more clearly by indenting the whole if-expression so that it is all visually to the right of the assignment. It's totally aesthetic, but I think that makes it more easily skimmable and should be clearer even to someone unfamiliar with the language.

Just as an aside: This sort of if is not at all unique to Ruby. It exists in all the Lisps (Common Lisp, Scheme, Clojure, etc.), Scala, all the MLs (F#, OCaml, SML), Haskell, Erlang and even Ruby's direct predecessor, Smalltalk. It just isn't common in languages based on C (C++, Java, C#, Objective-C), which is what most people use.

Chuck's user avatar

  • 1 Yeah but isn't it more error prone? Especially if over time the if..else blocks grows longer. Ruby is very permissive (dont get me started about optional parenthesis) but that does not make it always better. –  Pierre Olivier Martel Commented May 27, 2010 at 21:35
  • 3 @Pierre: By that logic, functions must also be more error prone because they can also grow larger. Or for that matter, the line containing the assignment could also grow (I have actually seen such things). Ruby code is inherently somewhat error-prone, but I don't see how functional if-expressions are more error-prone than imperative ones. –  Chuck Commented May 27, 2010 at 21:39
  • Python too :) although the syntax is sligthly different: products = Category.find(params["category"]).products() if params["category"] else Products.all() –  badp Commented May 27, 2010 at 22:39

I don't like your use of whitespace in your first block. Yes, I'm a Pythonista, but I believe I make a fair point when I say the first might look confusing in the middle of other code, maybe around other if blocks.

How about...

You could also try...

...but that's a bad idea if Product.all actually is a function-like which could then be needlessly evaluated.

badp's user avatar

  • 1 all in this case would run a db query, so the second is not a great idea. If you were using DataMapper, all would be lazily evaluated, so this would only do one query with that framework. –  BaroqueBobcat Commented May 27, 2010 at 21:59
  • TBH I find your second example less readable than the OP's first block with "wrong" whitespace (which btw is still a valid statement). –  Bart van Heukelom Commented May 27, 2010 at 22:00
  • I wouldn't indent it that way (it's too far from the usual way of writing conditionals to read at a glance), but I agree that indenting it all right of the equals sign is a good idea for readability. –  Chuck Commented May 27, 2010 at 22:06
  • I definitely think so. That reads very clearly to me, even at a glance. –  Chuck Commented May 27, 2010 at 22:17
  • -1 Nope, wrong. This is not how it's done by in Ruby. Not by any core Ruby/stdlib code, not in any Ruby books, not in any popular community-written libs/frameworks. Sorry. You probably just need better syntax highlighting and/or visual inspection retraining. –  Slipp D. Thompson Commented Apr 12, 2015 at 3:04

encapsulation...

Derick Bailey's user avatar

  • 6 If he use it only once I wouldn't recommend adding new method. –  klew Commented May 27, 2010 at 21:40
  • 1 What if the assignment to @products was the only thing that happened in the original method? Seems you're dodging the question. ;-) –  molf Commented May 27, 2010 at 21:45
  • molf - if that's the case, he's got a command / query violation and should refactor the code to what i wrote. –  Derick Bailey Commented May 27, 2010 at 22:03
  • nonsense. Your example would still return data to the caller in addition to changing the state of the object ( and issue a database query while at it). Your refactoring doesn't change a thing. Ruby's implicit return is not your friend if you prefer strict CQS. –  molf Commented May 27, 2010 at 22:24
  • 1 @ klew Why not? This is Ruby. Methods should be used abundantly, to aid the programmer's organization of code to convey the underlying logic— not Smalltalk running on an early-80s mainframe, where every method call is significant performance hit. –  Slipp D. Thompson Commented Apr 14, 2015 at 17:19

Just another approach:

Matías Flores's user avatar

  • Clean, beautiful, separated concerns. This is the kind of Ruby code I like to write & see. –  Slipp D. Thompson Commented Apr 12, 2015 at 3:13

Yet another approach would be using a block to wrap it up.

which solves the assignment issue. Though, it's too many lines for such "complex" code. This approach would be useful in case that we would want to initialize the variable just once:

This is something you can't do with the rewritten code and it is correctly aligned.

Tombart's user avatar

Is another option, it both avoids repeating @products and keeps the if aligned with else .

matsadler's user avatar

  • 1 I've never seen this before, but it's creative! –  molf Commented May 27, 2010 at 22:27

Assuming your models look like this:

you could do something even more crazy, like this:

Or, you could use the sexy, lazily loaded named_scope functionality:

BaroqueBobcat's user avatar

  • That's a cool way to turn the problem around! But I wanted the debate to be more around the syntax than the actual functionality of the code. But I'll make good note of it! –  Pierre Olivier Martel Commented May 27, 2010 at 21:58
  • of the two options you presented, I prefer the first one. –  BaroqueBobcat Commented May 27, 2010 at 22:26
  • I think your named scope is confusing. I would expect Product.all_by_category(nil) to return only those products that belong to no categories, instead of all products. –  molf Commented May 27, 2010 at 22:32
  • I was trying to build a named_scope that acted like Daniel Ribeiro's retrieve_products , but you are right, its behavior is confusing. My thoughts were a) I'd like the finders used to both be on the Product class, since that is what the action is about. b) I generally prefer to push as much behavior into the model as possible. –  BaroqueBobcat Commented May 27, 2010 at 23:00

First if using ternary, second if not.

The first one is near impossible to read.

Nate Noonen's user avatar

  • Yes but do yo do a multiline ternary if it's too long to fit in a line? Doesn't seem right to me! –  Pierre Olivier Martel Commented May 27, 2010 at 21:32
  • Why is it near impossible to read? Do you have much experience writing functional Ruby code, or is this because you're trying to read Ruby as another language? –  Chuck Commented May 27, 2010 at 21:35
  • @Chuck: it is "near impossible to read" for everyone who see it for the first time. –  klew Commented May 27, 2010 at 21:47
  • Near impossible to read is purely an opinion, obviously. I rarely program in Ruby (though I like it a lot), and it looks perfectly clean to me. –  RHSeeger Commented May 27, 2010 at 23:12
  • One of my readability pet peeves is separating declaration from assignment when it doesn't need to be. IMHO variables should be declared as late as possible and assigned as close to their declaration as possible. Here the separation is unnecessary, and is fixed by the whitespace cleanup in the accepted answer. –  Nate Noonen Commented May 28, 2010 at 0:37

I'm not a Ruby person either, but Alarm Bells are instantly ringing for scope of the second command, will that variable even be available after your if block ends?

blissapp's user avatar

  • 1 Yes, it will. It's an instance variable. –  Chuck Commented May 27, 2010 at 21:27
  • 1 In ruby, if you prefix your variable with @, it makes the variable an instance variable that will be available outside the block. –  Pierre Olivier Martel Commented May 27, 2010 at 21:31
  • In addition to that, Ruby does not have block scope (block in the traditional sense, if/then/else in this case). –  molf Commented May 27, 2010 at 22:14

I would say that second version is more readable for people non familiar with that structure in ruby. So + for it! On the other side, first contruction is more DRY.

As I look on it a little bit longer, I find first solution more attractive. I'm a ruby programmer, but I didn't use it earlier. For sure I'll start to!

klew's user avatar

I think the best code is :

The "&" after de find ensure that the method "products" will not evaluate if category is nil.

Julien 'JS''s user avatar

Seems to me that the second one would be more readable to the typical programmer. I'm not a ruby guy so I didn't realize that an if/else returns a value.... So, to take me as an example (and yes, that's my perspective :D), the second one seems like a good choice.

joeslice's user avatar

  • 2 You say yourself that you don't know Ruby, so why should we take you as an example? Do you write your code to cater to people who don't know any programming language and speak only Tibetan? –  Chuck Commented May 27, 2010 at 21:36
  • @Chuck His “hello world” program in Ruby is probably 2000 lines long, just to make sure it's verbose enough that anyone who knows any programming or written language can understand it. You know… rather than 1 line long. –  Slipp D. Thompson Commented Apr 14, 2015 at 17:26

If one is browsing through the code, I'd say the second code block (yours), is definitely the one I find easiest to quickly comprehend.

Your buddy's code is fine, but indentation, as bp pointed out, makes a world of difference in this sense.

Andres's user avatar

I don't like your use of parentheses in your first block. Yes, I'm a LISP user, but I believe I make a fair point when I say the first might look confusing in the middle of other code, maybe around other if blocks.

(^ Tongue in cheek, to exacerbate the issues with @badp's answer )

Slipp D. Thompson's user avatar

  • That's so... lispy... liked it though :) –  YigitOzkavci Commented May 3, 2017 at 12:02
This could also be rewritten with a one-liner using a ternary operator ( ? : ) but let's pretend that product assignment was longer than 100 characters and couldn't fit in one line.

Let's pretend not – because in many cases, it pays off for readability to optimize variable names and condition complexity for length so that the assignment incl. condition fits into one line.

But instead of using the ternary operator (which is unnecessary in Ruby and hard to read), use if … then … else . The then (or a ; ) is necessary when putting it all into one line. Like this:

For readability and self-documenting code, I love it when my programs read like English sentences. Ruby is the best language I found for that, so far.

tanius's user avatar

Your Answer

Reminder: Answers generated by artificial intelligence tools are not allowed on Stack Overflow. Learn more

Sign up or log in

Post as a guest.

Required, but never shown

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy .

Not the answer you're looking for? Browse other questions tagged ruby coding-style or ask your own question .

  • The Overflow Blog
  • One of the best ways to get value for AI coding tools: generating tests
  • The world’s largest open-source business has plans for enhancing LLMs
  • Featured on Meta
  • User activation: Learnings and opportunities
  • Site maintenance - Mon, Sept 16 2024, 21:00 UTC to Tue, Sept 17 2024, 2:00...
  • What does a new user need in a homepage experience on Stack Overflow?
  • Announcing the new Staging Ground Reviewer Stats Widget

Hot Network Questions

  • How to prevent a bash script from running repeatedly at the start of the terminal
  • Why is the area covered by 1 steradian (in a sphere) circular in shape?
  • How can a microcontroller (such as an Arduino Uno) that requires 7-21V input voltage be powered via USB-B which can only run 5V?
  • How to decrease by 1 integers in an expl3's clist?
  • Will "universal" SMPS work at any voltage in the range, even DC?
  • Concerns with newly installed floor tile
  • Negating a multiply quantified statement
  • Drill perpendicular hole through thick lumber using handheld drill
  • Is it feasible to create an online platform to effectively teach college-level math (abstract algebra, real analysis, etc.)?
  • Do i need to replace the iPhone at the store for iPhone upgrade program?
  • Looking for a short story on chess, maybe published in Playboy decades ago?
  • How to apply a squared operator to a function?
  • Do I have to use a new background that's been republished under the 2024 rules?
  • What would the natural diet of Bigfoot be?
  • What are the pros and cons of the classic portfolio by Wealthfront?
  • How can I analyze the anatomy of a humanoid species to create sounds for their language?
  • What would a planet need for rain drops to trigger explosions upon making contact with the ground?
  • Why Pythagorean theorem is all about 2?
  • If Act A repeals another Act B, and Act A is repealed, what happens to the Act B?
  • Creating good tabularx
  • Taylor Swift - Use of "them" in her text "she fights for the rights and causes I believe need a warrior to champion them"
  • Is it possible to draw this picture without lifting the pen? (I actually want to hang string lights this way in a gazebo without doubling up)
  • Why were there so many OSes that had the name "DOS" in them?
  • Is it possible to change the AirDrop location on my Mac without downloading random stuff from the internet?

ruby conditional hash assignment

IMAGES

  1. Ruby Hashes

    ruby conditional hash assignment

  2. Ruby: Hash Assignment/Parse from Text (2 Solutions!!)

    ruby conditional hash assignment

  3. Conditional Assignment in Ruby

    ruby conditional hash assignment

  4. Generating a Hash from Two Arrays in Ruby

    ruby conditional hash assignment

  5. Ruby: Converting An Array To A Hash

    ruby conditional hash assignment

  6. About Ruby Hash#[]= (Assignment)

    ruby conditional hash assignment

VIDEO

  1. Conditional Statement Java (Part 1)

  2. BUSM1008 Presentation Ruby Matthews

  3. Ruby Todman KPB117 2024 n11224258

  4. Ruby understands the assignment (Bfdia 7 re- animated)

  5. Научись Ruby: условные выражения, часть 2 (эпизод 7)

  6. 07_ Ruby basics ( Parallel Assignment)

COMMENTS

  1. Conditional key/value in a ruby hash

    Ruby conditional assignment with a hash. 1. Conditionals with multiple values in a key in a hash. 1. Conditionally set value of key in hash. 1. how can I build a key name of a hash based on a condition. 1. how to access value from hash based on key value. 2. Ruby - how to add a conditional key to a hash?

  2. Ruby conditional assignment with a hash

    ||=is Ruby's conditional assignment operator. a ||= b can usually be taken as short for . a || (a = b) That is, a is assigned b if a is nil or false (i.e., a = b conditional on the falsiness of a). The operator exploits a property of the way || is evaluated. Namely, that the right-hand operand of || is not evaluated unless the left-hand one is truthy (i.e., not false or nil).

  3. Conditional assignment

    Conditional assignment. Ruby is heavily influenced by lisp. One piece of obvious inspiration in its design is that conditional operators return values. ... use case/when A good barometer is to think if you could represent the assignment in a hash. For example, in the following example you could look up the value of opinion in a hash that looks ...

  4. Null Coalescing Operators and Ruby's Conditional Assignments

    Ruby's Conditional Assignments. Although it's often used like it, Ruby's ||= is not a null coalescing operator but a conditional assignment operator. In my quickly written Ruby example, @some_toggle ||= true always returns true, even if @some_toggle was previously assigned to false. The reason is because this operator, 'Or Equals ...

  5. Everything You Need to Know About Destructuring in Ruby 3

    The id value is then assigned from that hash, in this case, 2. So this is all amazingly powerful stuff. Of course you can use pattern matching in conditional logic such as case which is what all the original Ruby 2.7 examples showed, but I tend to think rightward assignment is even more useful for a wide variety of scenarios.

  6. Conditional keys in hash

    monkey patching Hash: Say, I need to pass a hash to a method: mymethod :this => 'green'. Now I'd like to include a second hash member only if a condition is met: mymethod :this => 'green, :that => ('blue' if condition) This of course leaves ":that => nil" in the hash if the condition is not. met - which is no good, the key should ...

  7. Ruby Assignments in Conditional Expressions

    SyntaxError: invalid syntax. Most likely, the assignment in a conditional expression is a typo where the programmer meant to do a comparison == instead. This kind of typo is a big enough issue that there is a programming style called Yoda Conditionals , where the constant portion of a comparison is put on the left side of the operator.

  8. pattern_matching

    Hash patterns match hashes, or objects that respond to deconstruct_keys (see below about the latter). Note that only symbol keys are supported for hash patterns. An important difference between array and hash pattern behavior is that arrays match only a whole array: case [1, 2, 3] in [Integer, Integer] "matched" else "not matched" end #=> "not ...

  9. Return Values

    Working with Hashes (1) Conditionals return values. Another extremely useful aspect about if and unless statements in Ruby is that they return values. Yes, that's right: An if statement, with all of its branches, as a whole, evaluates to the value returned by the statement that was last evaluated, just like a method does.

  10. class Hash

    Hashes have a default value that is returned when accessing keys that do not exist in the hash. If no default is set nil is used. You can set the default value by sending it as an argument to ::new: grades = Hash. new (0) Or by using the default= method: grades = {"Timmy Doe" => 8} grades. default = 0.

  11. Hash in Ruby

    The text above is perfectly valid from Ruby's language perspective, and we could initialize our hash without writing the values and without using assignment operator =: obj = { :soccer_ball => 410, :tennis_ball => 58, :golf_ball => 45 } The operator => in Ruby is called a hash rocket. In JavaScript, it's known as "fat arrow," but has a ...

  12. Conditional assignment operator?

    Can someone explain a little more about `||=` I see from the example that the conditional assignment operator can change an empty variable in Ruby to a specific value, say if a method where expressed within a block code. Once the `||=` is assigned a value, the conditional assignment operator cannot be over written. ... For instance, Ruby Hashes ...

  13. Ruby Style Guide

    As of Ruby 2.7 braces around an options hash are no longer optional. Omit the outer braces around an implicit options hash. # bad user. set ({name: ... Don't use the return value of = (an assignment) in conditional expressions unless the assignment is wrapped in parentheses.

  14. How to Use The Ruby Ternary Operator (?:)

    It's how Ruby knows that you're writing a ternary operator. Next: We have whatever code you want to run if the condition turns out to be true, the first possible outcome. Then a colon (:), another syntax element. Lastly, we have the code you want to run if the condition is false, the second possible outcome. Example:

  15. Method: Hash#merge

    Returns a new Hash object that is the merge of self and each given hash. The given hashes are merged left to right. Each new-key entry is added at the end. For each duplicate key: Calls the block with the key and the old and new values. The block's return value becomes the new value for the entry. Example:

  16. Class: Hash (Ruby 2.4.2)

    A Hash is a dictionary-like collection of unique keys and their values. Also called associative arrays, they are similar to Arrays, but where an Array uses integers as its index, a Hash allows you to use any object type. Hashes enumerate their values in the order that the corresponding keys were inserted.

  17. How do you assign a variable with the result of a if..else block?

    Yes, it will. It's an instance variable. In ruby, if you prefix your variable with @, it makes the variable an instance variable that will be available outside the block. In addition to that, Ruby does not have block scope (block in the traditional sense, if/then/else in this case).