Skip to content

Ruby Conditional Statements

Conditional statements are fundamental control structures in programming, used to execute different code paths based on different conditions. Ruby provides various conditional statements that enable code to make decisions based on runtime situations. This chapter will introduce in detail the various conditional statements in Ruby and how to use them.

🎯 Conditional Statement Basics

Boolean Values and Truthiness

In Ruby, all values except false and nil are considered truthy:

ruby
# Truthy values
puts !!true        # true
puts !!1           # true (number)
puts !!"Hello"     # true (non-empty string)
puts !![]          # true (empty array)
puts !!{}          # true (empty hash)
puts !!0           # true (zero is also truthy!)

# Falsy values
puts !!false       # false
puts !!nil         # false

Conditional Expressions

ruby
# Basic comparison
puts 5 > 3         # true
puts 5 == 5        # true
puts "apple" < "banana"  # true

# Complex conditions
age = 25
has_license = true

if age >= 18 && has_license
  puts "Can drive"
end

# String and number comparison
puts "10" == 10    # false (different types)
puts "10" == "10"  # true
puts 10 == 10      # true

🔀 if Statements

Basic if Statements

ruby
# Simple conditional check
age = 18

if age >= 18
  puts "You are an adult"
end

# if-else statement
if age >= 18
  puts "Adult"
else
  puts "Minor"
end

# if-elsif-else statement
if age < 13
  puts "Child"
elsif age < 18
  puts "Teenager"
elsif age < 60
  puts "Adult"
else
  puts "Senior"
end

Single-Line if Statements

ruby
# Modifier form of if statement
puts "Adult" if age >= 18

name = "Zhang San"
puts "Welcome, #{name}!" if name

# Multiple conditions
score = 85
puts "Excellent" if score >= 90
puts "Good" if score >= 80 && score < 90
puts "Pass" if score >= 60 && score < 80

if Statement Return Values

ruby
# if statements have return values
result = if age >= 18
  "Adult"
else
  "Minor"
end

puts result  # Adult

# More complex return values
grade = 85
level = if grade >= 90
  "Excellent"
elsif grade >= 80
  "Good"
elsif grade >= 60
  "Pass"
else
  "Fail"
end

puts level  # Good

🔁 unless Statements

Basic unless Statements

ruby
# unless is equivalent to if not
age = 16

unless age >= 18
  puts "Minor"
end

# unless-else statement
unless age >= 18
  puts "Minor"
else
  puts "Adult"
end

# Single-line unless statement
puts "Minor" unless age >= 18

unless Usage Scenarios

ruby
# Suitable for negative condition checks
user = nil
puts "Please log in first" unless user

file_exists = File.exist?("config.txt")
puts "Configuration file does not exist" unless file_exists

# Avoid double negation
# Not recommended: if !user.nil?
# Recommended: unless user.nil? or more concise: if user

🔄 case Statements

Basic case Statements

ruby
# Simple case statement
grade = "B"

case grade
when "A"
  puts "Excellent"
when "B"
  puts "Good"
when "C"
  puts "Pass"
else
  puts "Fail"
end

# case statement return value
score = 85
level = case score
when 90..100
  "Excellent"
when 80...90
  "Good"
when 60...80
  "Pass"
else
  "Fail"
end

puts level  # Good

Multiple Value Matching

ruby
# One when clause matching multiple values
day = "Saturday"

case day
when "Saturday", "Sunday"
  puts "Weekend"
when "Monday", "Tuesday", "Wednesday", "Thursday", "Friday"
  puts "Weekday"
end

# Using arrays for matching
weekend_days = ["Saturday", "Sunday"]
work_days = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"]

case day
when *weekend_days
  puts "Weekend"
when *work_days
  puts "Weekday"
end

Range Matching

ruby
# Use ranges for matching
score = 85

case score
when 90..100
  puts "Excellent"
when 80...90
  puts "Good"
when 70...80
  puts "Average"
when 60...70
  puts "Pass"
else
  puts "Fail"
end

Regular Expression Matching

ruby
# Use regular expressions for matching
email = "user@example.com"

case email
when /\A[\w+\-.]+@[a-z\d\-]+(\.[a-z\d\-]+)*\.[a-z]+\z/i
  puts "Valid email address"
when /\A\d{11}\z/
  puts "Possible phone number"
else
  puts "Unknown format"
end

How case Statements Work

ruby
# case uses === operator for comparison
# Different types of objects have different === implementations

# Number comparison
case 5
when 1..10
  puts "Between 1 and 10"
end

# Type checking
case "Hello"
when String
  puts "This is a string"
when Numeric
  puts "This is a number"
end

# Custom class === method
class Priority
  def self.===(value)
    value.is_a?(Integer) && value > 100
  end
end

case 150
when Priority
  puts "High priority"
else
  puts "Normal priority"
end

🎯 Ternary Operators

Basic Syntax

ruby
# Ternary operator: condition ? value_if_true : value_if_false
age = 20
status = age >= 18 ? "Adult" : "Minor"
puts status  # Adult

# Nested ternary operators (use with caution)
score = 85
grade = score >= 90 ? "Excellent" : 
        score >= 80 ? "Good" : 
        score >= 60 ? "Pass" : "Fail"
puts grade  # Good

Ternary Operator Application Scenarios

ruby
# Simple conditional assignment
user = nil
display_name = user ? user.name : "Anonymous User"
# Or use more concise form
display_name = user&.name || "Anonymous User"

# Conditional output
debug_mode = true
puts "Debug info" if debug_mode

# Conditional method calls
class Calculator
  def initialize(debug = false)
    @debug = debug
  end
  
  def add(a, b)
    result = a + b
    puts "Calculation: #{a} + #{b} = #{result}" if @debug
    result
  end
end

🔄 Modifier Forms

if and unless Modifiers

ruby
# if modifier
puts "Adult" if age >= 18
raise "Invalid age" if age < 0
return unless user

# unless modifier
puts "Please log in" unless user
exit unless ready?

# Multiple modifier combinations
puts "Adult and logged in" if age >= 18 && user
puts "Minor or not logged in" unless age >= 18 && user

while and until Modifiers

ruby
# while modifier
counter = 0
counter += 1 while counter < 5
puts counter  # 5

# until modifier
counter = 5
counter -= 1 until counter <= 0
puts counter  # 0

🎯 Complex Conditional Judgments

Logical Operator Combinations

ruby
# AND operations (&&)
user = {name: "Zhang San", age: 25, active: true}
if user[:age] >= 18 && user[:active]
  puts "#{user[:name]} can access"
end

# OR operations (||)
role = "admin"
if role == "admin" || role == "moderator"
  puts "Has admin permissions"
end

# NOT operations (!)
logged_in = false
puts "Please log in" if !logged_in

# Complex condition combinations
if (user[:age] >= 18 && user[:active]) || user[:role] == "admin"
  puts "Access granted"
end

Short-Circuit Evaluation

ruby
# && short-circuit: If left is false, don't evaluate right
def expensive_check
  puts "Executing expensive check"
  true
end

false && expensive_check  # Won't output "Executing expensive check"

# || short-circuit: If left is true, don't evaluate right
true || expensive_check   # Won't output "Executing expensive check"

# Use short-circuit evaluation for safe access
user = nil
# Safely access nested attributes
name = user && user.profile && user.profile.name
# Or use safe navigation operator (Ruby 2.3+)
name = user&.profile&.name

Conditional Assignment

ruby
# ||= Conditional assignment
cache = nil
cache ||= expensive_computation  # First computation executed
cache ||= another_computation    # Won't execute, uses cached value

# &&= Conditional assignment
value = 10
value &&= value * 2  # value = 20
value = nil
value &&= value * 2  # value remains nil

🧪 Conditional Statement Practice Examples

User Permission Check System

ruby
class PermissionChecker
  def initialize(user)
    @user = user
  end
  
  def can_access?(resource)
    # Admins can access all resources
    return true if admin?
    
    # Check specific permissions
    case resource
    when :public
      true
    when :private
      logged_in?
    when :admin_only
      admin?
    when :premium
      premium_user?
    else
      false
    end
  end
  
  def check_access(resource)
    if can_access?(resource)
      puts "Access granted: #{resource}"
      true
    else
      puts "Access denied: #{resource}"
      false
    end
  end
  
  private
  
  def logged_in?
    !@user.nil?
  end
  
  def admin?
    @user && @user[:role] == :admin
  end
  
  def premium_user?
    @user && (@user[:role] == :premium || @user[:role] == :admin)
  end
end

# Use permission check system
users = [
  nil,  # Not logged in user
  {name: "Regular User", role: :user},
  {name: "Premium User", role: :premium},
  {name: "Admin", role: :admin}
]

resources = [:public, :private, :premium, :admin_only]

checker = PermissionChecker.new(nil)
users.each do |user|
  checker.instance_variable_set(:@user, user)
  user_name = user ? user[:name] : "Guest"
  puts "\n=== #{user_name} ==="
  
  resources.each do |resource|
    checker.check_access(resource)
  end
end

Score Grade Evaluation System

ruby
class GradeEvaluator
  def self.evaluate(score)
    case score
    when 90..100
      "Excellent"
    when 80...90
      "Good"
    when 70...80
      "Average"
    when 60...70
      "Pass"
    when 0...60
      "Fail"
    else
      raise ArgumentError, "Invalid score: #{score}"
    end
  end
  
  def self.detailed_evaluate(score)
    grade = evaluate(score)
    
    description = case grade
    when "Excellent"
      "Excellent performance, keep it up"
    when "Good"
      "Good performance, room for improvement"
    when "Average"
      "Meets basic requirements, needs effort"
    when "Pass"
      "Just passed, need to strengthen study"
    when "Fail"
      "Does not meet requirements, need to retake"
    end
    
    {
      grade: grade,
      score: score,
      description: description
    }
  end
  
  def self.batch_evaluate(scores)
    results = []
    scores.each_with_index do |score, index|
      begin
        result = detailed_evaluate(score)
        result[:student_id] = index + 1
        results << result
      rescue ArgumentError => e
        results << {
          student_id: index + 1,
          error: e.message
        }
      end
    end
    results
  end
end

# Use grade evaluation system
scores = [95, 87, 76, 65, 45, 105, -5]
results = GradeEvaluator.batch_evaluate(scores)

results.each do |result|
  if result[:error]
    puts "Student #{result[:student_id]}: #{result[:error]}"
  else
    puts "Student #{result[:student_id]}: #{result[:score]} points - #{result[:grade]} - #{result[:description]}"
  end
end

Configuration File Parser

ruby
class ConfigParser
  def self.parse(config)
    parsed = {}
    
    config.each do |key, value|
      parsed[key] = parse_value(key, value)
    end
    
    parsed
  end
  
  private
  
  def self.parse_value(key, value)
    case key.to_s
    when /_enabled$/, /_active$/
      parse_boolean(value)
    when /_count$/, /_size$/, /_limit$/
      parse_integer(value)
    when /_timeout$/, /_delay$/
      parse_float(value)
    when /_list$/, /_array$/
      parse_array(value)
    when /_path$/
      parse_path(value)
    else
      value  # Keep original value
    end
  end
  
  def self.parse_boolean(value)
    case value
    when true, false
      value
    when String
      case value.downcase
      when "true", "1", "yes", "on"
        true
      when "false", "0", "no", "off"
        false
      else
        raise ArgumentError, "Invalid boolean value: #{value}"
      end
    when Numeric
      value != 0
    else
      !!value
    end
  end
  
  def self.parse_integer(value)
    case value
    when Integer
      value
    when String
      Integer(value)
    when Float
      value.to_i
    else
      raise ArgumentError, "Invalid integer value: #{value}"
    end
  rescue ArgumentError
    raise ArgumentError, "Invalid integer value: #{value}"
  end
  
  def self.parse_float(value)
    case value
    when Float, Integer
      value.to_f
    when String
      Float(value)
    else
      raise ArgumentError, "Invalid float value: #{value}"
    end
  rescue ArgumentError
    raise ArgumentError, "Invalid float value: #{value}"
  end
  
  def self.parse_array(value)
    case value
    when Array
      value
    when String
      value.split(",").map(&:strip)
    else
      [value]
    end
  end
  
  def self.parse_path(value)
    case value
    when String
      # Simple path cleanup
      value.gsub(/[<>:"|?*]/, "")  # Remove illegal characters
    else
      value.to_s
    end
  end
end

# Use configuration parser
config = {
  debug_enabled: "true",
  max_connections: "100",
  request_timeout: "30.5",
  allowed_hosts: "localhost,127.0.0.1,example.com",
  log_path: "/var/log/app.log",
  cache_size: 1024
}

begin
  parsed_config = ConfigParser.parse(config)
  parsed_config.each do |key, value|
    puts "#{key}: #{value} (#{value.class})"
  end
rescue ArgumentError => e
  puts "Configuration parse error: #{e.message}"
end

🎯 Conditional Statement Best Practices

1. Keep Conditions Simple

ruby
# Good practice: Extract complex conditions into methods
class UserValidator
  def self.valid_user?(user)
    user &&
    user.active? &&
    user.email_verified? &&
    user.age >= 18
  end
  
  def self.premium_user?(user)
    valid_user?(user) && user.subscription == "premium"
  end
end

# Use
if UserValidator.premium_user?(user)
  # Handle premium user
end

2. Use case Statements Reasonably

ruby
# Good practice: Use case for multiple discrete values
case action
when "create"
  create_resource
when "update"
  update_resource
when "delete"
  delete_resource
else
  raise ArgumentError, "Unknown action: #{action}"
end

# Avoid: Using case for simple conditions
# Not recommended:
case
when score >= 90
  puts "Excellent"
when score >= 80
  puts "Good"
end

# Recommended:
if score >= 90
  puts "Excellent"
elsif score >= 80
  puts "Good"
end

3. Avoid Deep Nesting

ruby
# Bad practice: Deep nesting
if user
  if user.active?
    if user.age >= 18
      if user.subscription == "premium"
        # Processing logic
      end
    end
  end
end

# Good practice: Early returns
def process_user(user)
  return unless user
  return unless user.active?
  return unless user.age >= 18
  return unless user.subscription == "premium"
  
  # Processing logic
end

# Or merge conditions
def process_user(user)
  if user && user.active? && user.age >= 18 && user.subscription == "premium"
    # Processing logic
  end
end

4. Use Safe Navigation Operators

ruby
# Old way: Multiple nil checks
if user && user.profile && user.profile.address && user.profile.address.city
  puts user.profile.address.city
end

# New way: Safe navigation operator (Ruby 2.3+)
puts user&.profile&.address&.city

# Combine with conditional assignment
city = user&.profile&.address&.city || "Unknown City"

📚 Next Steps

After mastering Ruby conditional statements, it is recommended to continue learning:

Continue your Ruby learning journey!

Content is for learning and research only.