ZetCode

Ruby and Keyword

last modified October 18, 2026

This tutorial explains how to use Ruby's and keyword. It serves as both a logical operator and a control flow tool in Ruby programs.

The and keyword evaluates multiple expressions, returning the first falsey value or the last truthy value. It has lower precedence than &&.

Unlike &&, and is useful for control flow rather than boolean logic. It's commonly used for chaining operations where any failure should stop execution.

Basic and Operator

This example shows the basic operation of and. It returns the last operand when both are truthy, and the first falsey operand otherwise.

basic_and.rb
result = (true and false)
puts result  # => false

result = (1 and "hello")
puts result  # => hello

result = (nil and 5)
puts result.inspect  # => nil

result = true and false
puts result  # => true

The and operator evaluates expressions left-to-right. It returns the first falsey value or the last value if all are truthy. The parentheses in the first three examples make the and expression evaluate before assignment. Without them, = binds more tightly: the last line assigns true to result, then evaluates and false and discards that value.

and vs && Precedence

The key difference between and and && is precedence. Both operators are left-associative, but and has much lower precedence, which affects evaluation order.

precedence.rb
x = true && false
puts x  # => false

y = true and false
puts y  # => true

The first example assigns the result of && to x. The second assigns true to y, then evaluates and false. The and expression itself is false, but its value is not assigned. This demonstrates and's lower precedence.

Control Flow with and

and is often used for control flow where operations should continue only if previous ones succeed. This example shows a common pattern.

control_flow.rb
def fetch_data(success)
  success ? "data" : nil
end

def process_data(data)
  puts "Processing: #{data}"
end

data = fetch_data(true) and process_data(data)
puts "Data processed successfully" if data

data = fetch_data(false) and process_data(data)
puts "No data to process" unless data

The process_data method only runs if fetch_data returns a truthy value. When it returns nil, and short-circuits and the second call is skipped. The example prints Processing: data, Data processed successfully, and No data to process.

Multiple Conditions with and

and can chain multiple conditions together. Evaluation stops at the first falsey value due to short-circuit behavior.

multiple_conditions.rb
def valid_user?(user)
  !!(user[:name] and user[:email] and user[:active])
end

user1 = { name: "John", email: "john@example.com", active: true }
user2 = { name: "Alice", email: nil, active: true }

puts valid_user?(user1)  # => true
puts valid_user?(user2)  # => false

The method checks all required user attributes. and returns the first falsey operand, which is nil here, so the double negation converts the result to true or false. Evaluation stops at the first falsey value.

and for Assignment Guarding

and can guard a second assignment when a condition fails. The first assignment still happens, but the second one is skipped, which avoids calling a method on nil.

assignment_guard.rb
def get_config_value(found)
  found ? "admin" : nil
end

role = get_config_value(true) and role = role.upcase
puts role.inspect  # => "ADMIN"

role = get_config_value(false) and role = role.upcase
puts role.inspect  # => nil

The first assignment always happens. The and operator guards only the second assignment, so role is uppercased only when the lookup succeeds. On failure, role is still assigned nil, which prevents calling upcase on nil.

Guarding a Method Call with and

and can guard a method call, so the second call runs only when the first one succeeds. This provides a concise alternative to a nested if.

method_guard.rb
def authenticate(user)
  user[:password] == "secret"
end

def log_in(user)
  puts "Logging in #{user[:name]}"
  user[:authenticated] = true
end

current_user = { name: "John", password: "secret" }

authenticate(current_user) and log_in(current_user)  # prints "Logging in John"

The log_in method only executes if authenticate returns true. This pattern is common in authentication flows. The methods must be defined before the guarded call, because Ruby resolves method calls at runtime.

Error Handling with and

and can chain operations with error handling. Each step executes only if the previous one succeeds.

error_handling.rb
require 'json'

def parse_json(data)
  JSON.parse(data) rescue nil
end

data = '{"name": "John"}' and config = parse_json(data)
puts config ? "Config loaded" : "Failed to load config"  # prints "Config loaded"

data = 'not valid json' and config = parse_json(data)
puts config ? "Config loaded" : "Failed to load config"  # prints "Failed to load config"

Each step proceeds only if the previous one succeeds. parse_json returns nil for invalid input, so the second example prints Failed to load config instead of raising an exception. Because and has lower precedence than =, data is assigned first and config receives the parsed result.

Source

Ruby Keywords Documentation

This tutorial covered Ruby's and keyword with practical examples showing boolean logic, control flow, and error handling patterns.

Author

My name is Jan Bodnar, and I am a passionate programmer with extensive programming experience. I have been writing programming articles since 2007. To date, I have authored over 1,400 articles and 8 e-books. I possess more than ten years of experience in teaching programming.

List all Ruby tutorials.