Ruby Basics

Variables and Types

Variable types and scoping
# Local variable
name = "Evan"
age = 30

# Constants (uppercase start)
MAX_RETRIES = 3
PI = 3.14159

# Instance variable (object scope)
@hostname = "modestus-aw"

# Class variable (shared across instances)
@@count = 0

# Global variable (avoid these)
$debug = false
Core types
# Integers and Floats
port = 8080
ratio = 0.75
hex = 0xFF           # => 255
binary = 0b1010      # => 10
big = 1_000_000      # underscores for readability

# Strings
single = 'no interpolation here'
double = "port #{port} is open"
heredoc = <<~HEREDOC
  Multi-line string
  with #{name}
HEREDOC

# Symbols — immutable, interned strings
status = :active
config = { host: "localhost", port: 443 }

# Booleans and nil
connected = true
error = nil          # nil is falsy; everything else is truthy except false

# Type checking
port.is_a?(Integer)  # => true
name.class           # => String
port.respond_to?(:even?)  # => true — duck typing

Control Flow

Conditionals
# Standard if/elsif/else
if status == :active
  puts "running"
elsif status == :degraded
  puts "warning"
else
  puts "down"
end

# Inline (modifier form)
puts "open" if port == 443
puts "closed" unless connected

# Ternary
state = connected ? "up" : "down"

# Case/when (pattern matching)
case status
when :active   then "green"
when :degraded then "yellow"
when :down     then "red"
else "unknown"
end

# Case with ranges
case port
when 1..1023    then "privileged"
when 1024..49151 then "registered"
when 49152..65535 then "ephemeral"
end
Loops
# Times
5.times { |i| puts "Attempt #{i + 1}" }

# Each (preferred over for)
[80, 443, 8080].each do |port|
  puts "Scanning port #{port}"
end

# While and until
retries = 0
while retries < MAX_RETRIES
  retries += 1
end

until connected
  attempt_connection
end

# Loop with break
loop do
  result = check_status
  break if result == :ok
end

Methods

Method definition
# Basic method
def greet(name)
  "Hello, #{name}"          # implicit return (last expression)
end

# Default arguments
def connect(host, port = 443)
  puts "Connecting to #{host}:#{port}"
end

# Keyword arguments
def scan(host:, ports: [80, 443], timeout: 5)
  ports.each { |p| probe(host, p, timeout) }
end
scan(host: "10.50.1.20", ports: [22, 443])

# Predicate methods (return boolean, end with ?)
def valid?(input)
  input.is_a?(String) && !input.empty?
end

# Bang methods (modify in place, end with !)
name = "evan"
name.upcase!         # name is now "EVAN"

# Splat (variable args)
def log(*messages)
  messages.each { |m| puts "[LOG] #{m}" }
end

Output and Input

I/O basics
puts "newline added"        # adds \n
print "no newline"          # no \n
p [1, 2, 3]                # inspect output: [1, 2, 3]
pp complex_object           # pretty-print

# String formatting
printf "%-20s %5d\n", hostname, port
sprintf("Host: %s", name)   # returns formatted string

# Input
print "Enter host: "
host = gets.chomp            # chomp removes trailing newline

# ARGV
script_name = $0
first_arg = ARGV[0]