Ruby essentials: 50 cards on blocks, symbols, Enumerable and mixins
Ruby fundamentals with short snippets: blocks, procs and lambdas, symbols, Enumerable, mixins, truthiness, method_missing, gems and Bundler.
Practice now
Study without an account
Scheduled with the default Askesis timings. Progress is saved in this browser.
All 50 cards
- 1What does “everything is an object” mean in Ruby?Every value, including numbers,
nil,trueand classes themselves, is an object with methods:5.even?,nil.to_a,3.times { … }5.classisInteger, andInteger.classisClass. - 2What does this print?ruby
puts 0 ? "yes" : "no"yes: onlynilandfalseare falsy in Ruby;0,""and[]are all truthy - 3
putsvspputsprints theto_sform with a newline and returnsnil;pprints theinspectform (strings keep their quotes) and returns its argument, which makes it handy for debugging - 4Interpolate a value into a stringruby
puts "Hello, #{name}! You have #{items.size} items."Interpolation only works in double-quoted strings; single quotes are literal. - 5What does a Ruby method return when there is no
return?The value of the last expression it evaluatedrubydef full_name "#{first} #{last}" end - 6What do
?and!at the end of a method name signal??marks a predicate that returns a boolean (empty?);!marks a “dangerous” version of a method, usually one that mutates the receiver (sort!vssort) - 7What does
"ABC".upcase!return?nil: many bang methods returnnilwhen they make no change, so don’t chain them"abc".upcase!returns"ABC". - 8Generate a getter and setter for
@namerubyclass User attr_accessor :name endattr_readermakes only the getter,attr_writeronly the setter. - 9What do the prefixes
@,@@and$mean?@nameis an instance variable,@@counta class variable shared with subclasses, and$stdouta global; names starting with a capital letter are constants - 10What is
7 / 2in Ruby?3: dividing two integers is integer division, rounding down7 / 2.0and7.fdiv(2)give3.5. Note that-7 / 2is-4. - 11
ifis an expressionrubylabel = if score >= 50 then "pass" else "fail" endSo arecaseandbeginblocks: they all return their last value. - 12Write a one-line conditionalruby
return if user.nil? puts "Welcome back" unless first_visit?Modifierifandunlessgo after the statement;unlessmeans “if not”. - 13Memoize a value with
||=rubydef config @config ||= load_config endGotcha: if the result isnilorfalse, it is recomputed on every call. - 14Define a method with keyword argumentsruby
def greet(name:, greeting: "Hello") "#{greeting}, #{name}!" end greet(name: "Ada") # => "Hello, Ada!"name:has no default, so it is required. - 15Call a method only if the receiver isn’t
nilrubycity = user&.address&.city&.is the safe navigation operator: it returnsnilinstead of raisingNoMethodError. - 16What is a symbol?An immutable, interned name like
:status: every use of the same symbol is the same object, which makes symbols cheap identifiers for hash keys and method names - 17What does this print?ruby
puts :a.equal?(:a) puts "a".equal?("a")true, then (without frozen string literals)false: there is only one:aobject, but each string literal creates a new stringequal?checks identity;"a" == "a"istrue. - 18What does this print?ruby
h = { name: "Ada" } p h["name"]nil:name:creates a symbol key, so the value is ath[:name], noth["name"]{ name: "Ada" }is shorthand for{ :name => "Ada" }. - 19Are Ruby strings mutable?Yes: methods like
<<andupcase!modify a string in place. The magic comment# frozen_string_literal: truefreezes every string literal in a fileRuby 3.4 can warn (with deprecation warnings enabled) when code mutates a string literal, a step toward frozen literals by default. - 20What is a block?A chunk of code passed to a method call with
{ … }ordo … end; the method runs it withyieldruby[1, 2, 3].each { |n| puts n } File.open("log.txt") do |f| puts f.readline end - 21What does this print?ruby
def twice yield 1 yield 2 end twice { |n| puts n * 10 }10and20on separate lines: eachyieldcalls the block with an argumentblock_given?tells a method whether it received a block. - 22What does this print?ruby
puts [1, 2].map do |x| x * 2 endSomething like#<Enumerator: …>, not2and4: ado … endblock binds to the outermost call (puts), somapgets no block{ … }binds to the nearest call:puts [1, 2].map { |x| x * 2 }prints2and4. - 23Proc vs lambdaA lambda checks its argument count, and
returnexits only the lambda; a proc ignores missing or extra arguments, andreturnreturns from the method where the proc was defined - 24Create and call a lambdaruby
square = ->(x) { x * x } square.call(3) # => 9 square.(3) # => 9 square[3] # => 9 - 25What does
names.map(&:upcase)mean?Shorthand fornames.map { |n| n.upcase }:&turns the symbol into a block viaSymbol#to_procIn a method definition, a&blockparameter does the reverse, capturing the passed block as aProc. - 26Refer to a block’s parameter without naming itruby
[1, 2, 3].map { it * 2 } # Ruby 3.4+ [1, 2, 3].map { _1 * 2 } # Ruby 2.7+ - 27Can a block use local variables from where it was written?Yes. Blocks, procs and lambdas are closures: they capture the surrounding local variables and can change themruby
total = 0 [1, 2, 3].each { |n| total += n } total # => 6 - 28
eachvsmapeachruns the block for its side effects and returns the original collection;mapreturns a new array of the block’s results - 29Common Enumerable one-linersruby
(1..10).select(&:even?) # => [2, 4, 6, 8, 10] [1, 2, 3].reject(&:odd?) # => [2] [1, 2, 3].reduce(:+) # => 6 %w[a bb c].find { _1.size > 1 } # => "bb" - 30Loop with an index, or build a result while iteratingruby
names.each_with_index { |name, i| puts "#{i}: #{name}" } lengths = names.each_with_object({}) { |n, h| h[n] = n.size } - 31How do you get
map,select,sortand friends for your own collection class?Include theEnumerablemodule and defineeach; Enumerable builds dozens of methods on top of itrubyclass Playlist include Enumerable def initialize(songs) @songs = songs end def each(&block) @songs.each(&block) end end - 32Count how often each word appearsruby
%w[a b a c a].tally # => {"a" => 3, "b" => 1, "c" => 1}tallyarrived in Ruby 2.7.group_by { … }instead groups elements into arrays by the block’s result. - 33
1..5vs1...5Two dots include the end (1 to 5); three dots exclude it (1 to 4) - 34Take the first three even squares from an infinite rangeruby
(1..).lazy.map { _1 * _1 }.select(&:even?).first(3) # => [4, 16, 36]lazyprocesses elements one at a time, so infinite or huge sequences work. - 35What is a module?A container for methods and constants that can’t be instantiated: used as a namespace (
Net::HTTP) and as a mixin added to classes - 36
includevsprependvsextendincludeadds a module’s methods as instance methods, looked up after the class’s own;prependputs them before the class’s own, so they can wrap them withsuper;extendadds them to a single object, e.g. as class methods - 37Make objects comparable with
<,>andbetween?rubyclass Version include Comparable attr_reader :major, :minor def <=>(other) [major, minor] <=> [other.major, other.minor] end endTheComparablemixin builds<,<=,==,>,>=,between?andclampfrom<=>. - 38Inheritance and class methodsruby
class Dog < Animal def self.create(name) = new(name) def speak super + " Woof" end endA class has one superclass;def self.xdefines a class method;supercalls the parent’s version of the current method. - 39How does Ruby find a method?It walks the receiver’s ancestor chain (its class, included modules, the superclass and so on) until it finds the method, calling
method_missingif none matchesDog.ancestorsshows the chain, e.g.[Dog, Animal, Object, Kernel, BasicObject]. - 40What are open classes (monkey patching)?Any class, including built-ins like
String, can be reopened to add or replace methods. Powerful but risky; refinements (refineandusing) limit a patch to the files that opt in - 41What is duck typing?Caring about what an object can do rather than its class: call the method, or check
respond_to?(:each), instead of checkingis_a? - 42
==vsequal?vseql?==compares values,equal?checks object identity, andeql?is the stricter equality used for hash keys1 == 1.0is true, but1.eql?(1.0)is false. - 43What is
method_missing?A hook Ruby calls when no method matches a call, letting an object respond to dynamic method names. Pair it withrespond_to_missing?, and callsuperfor names you don’t handlerubyclass Settings def initialize(data) @data = data end def method_missing(name, *args) @data.key?(name) ? @data[name] : super end def respond_to_missing?(name, include_private = false) @data.key?(name) || super end end - 44Call a method whose name is in a variableruby
user.public_send(:name) # respects visibility user.send(:secret_helper) # can call private methods toodefine_method(:name) { … }defines methods dynamically, which is often clearer thanmethod_missing. - 45What is a gem?A packaged Ruby library or tool, published on rubygems.org and installed with
gem install <name> - 46How does Bundler manage a project’s gems?You list dependencies in a
Gemfile;bundle installresolves compatible versions and records them inGemfile.lock;bundle exec <cmd>runs a command with exactly those versionsbundle add <gem>adds a gem to the Gemfile and installs it. - 47What does
gem "rails", "~> 7.1"allow?Versions>= 7.1and< 8.0. With three parts,"~> 7.1.3"allows>= 7.1.3and< 7.2~>is the “pessimistic” version constraint. - 48Should you commit
Gemfile.lock?Yes, for applications: it guarantees that every developer, CI run and server uses the same gem versions - 49Handle an exceptionruby
begin data = JSON.parse(text) rescue JSON::ParserError => e warn "Bad JSON: #{e.message}" data = {} ensure log_attempt endRaise withraise ArgumentError, "message". Inside a method body,rescueworks withoutbegin. - 50Match on the shape of a hashruby
case response in { status: 200, body: } puts body in { status: 404 } puts "Not found" endPattern matching withcase/inis stable since Ruby 3.0;body:binds the value to a local variable.
Frequently asked questions
Which Ruby version does the deck use?
Ruby 3. Recent features are marked, such as pattern matching (3.0) and the it block parameter (3.4).
Should I learn Ruby before Rails?
It helps a lot. Rails code leans on blocks, symbols, mixins and metaprogramming, which is exactly what this deck covers.
What is the difference between a proc and a lambda?
A lambda checks how many arguments it receives, and return leaves only the lambda. A proc is lenient with arguments, and return exits the method that defined it.
More in Programming
JavaScript
Master the JavaScript every developer uses daily: scope, closures, equality, array methods, promises, async/await and the event loop.
50 cardsAdvanced JS
Fifty advanced JavaScript cards: event-loop ordering puzzles, generators and async iteration, this binding, Proxy and Reflect, modules, AbortController and coercion edge cases.
50 cardsTypeScript
Learn the TypeScript you use every day: narrowing, generics, keyof, mapped and conditional types, utility types, satisfies and strict mode, with code on every card.
50 cardsPython
Learn idiomatic Python fast: comprehensions, f-strings, args and kwargs, generators, decorators, context managers and the standard library.
50 cardsGit & terminal
The Git commands and shell skills developers use every day: branching, rebasing, undoing mistakes, pipes, redirects, permissions and processes.
50 cardsJava
Core Java with short snippets: equals vs ==, records, sealed types, collections, generics, exceptions, streams, lambdas and JVM basics.
50 cardsC#
C# and .NET fundamentals with short snippets: value vs reference types, properties, records, nullable reference types, LINQ, async/await and DI.
50 cardsKotlin
Kotlin fundamentals with short snippets: null safety, val vs var, data and sealed classes, extension functions, scope functions and coroutines.
50 cardsSwift
Swift fundamentals with short snippets: optionals, structs vs classes, protocols, enums with associated values, closures, ARC, async/await and SwiftUI.
50 cardsFlutter
Flutter and Dart basics: null safety, futures and streams, stateless vs stateful widgets, setState, hot reload, keys, layout and state management.
50 cardsPHP
Modern PHP 8 with short snippets: strict types, arrays, match, nullsafe and named arguments, enums, readonly, Composer, PDO and password_hash.
50 cardsGo
Go (Golang) fundamentals with short, idiomatic snippets: slices vs arrays, maps, defer, error wrapping, interfaces, goroutines, channels, select and context.
50 cardsRust
Learn the Rust that the compiler keeps asking about: ownership, borrowing, lifetimes, Option and Result, traits, closures, smart pointers and async.
50 cardsC++
Modern C++ in short snippets: references vs pointers, RAII, smart pointers, move semantics, STL containers and algorithms, const, templates and UB.
50 cardsHaskell
Haskell fundamentals with short code: types and type classes, pattern matching, laziness, Maybe and Either, folds, Functor, Applicative and Monad.
50 cardsElixir
Elixir fundamentals with short snippets: immutability, pattern matching, the pipe operator, Enum vs Stream, processes, GenServer, supervisors and mix.
50 cardsx86-64 assembly
x86-64 assembly in Intel syntax: registers and sub-registers, flags, mov and lea, jumps, the stack frame, the System V calling convention and Linux syscalls.
50 cardsRegex
Learn regular expressions for good: anchors, classes, greedy vs lazy quantifiers, groups, lookarounds, flags, replacements and the backtracking trap.
50 cards