Overview
Ruby Cheat Sheet
Introduction
Ruby is a dynamic, object-oriented programming language known for its elegant syntax and developer-friendly philosophy. Combined with Rails framework, it powers major platforms like GitHub, Shopify, and Airbnb. This cheatsheet covers essential Ruby concepts, Rails patterns, and backend development topics frequently tested in technical interviews.
Key Strengths: Developer productivity, readable syntax, rich ecosystem, convention over configuration (Rails), strong testing culture, and excellent metaprogramming capabilities.
Interview Focus Areas: Object-oriented design, metaprogramming, Rails MVC patterns, ActiveRecord queries, performance optimization, testing, and system design with Ruby.
1. Ruby Basics
Variables & Constants
local_var = "local" # Local variable
@instance_var = "instance" # Instance variable
@@class_var = "class" # Class variable
$global_var = "global" # Global variable
CONSTANT = "constant" # Constant
Data Types
# Numbers
int = 42
float = 3.14
bignum = 9999999999999999999
# Strings
str = "Hello"
str = 'World'
str = %q(Single quote string)
str = %Q(Double quote string)
# Symbols (immutable strings)
:symbol_name
# Arrays
arr = [1, 2, 3]
arr = Array.new(3, 0) # [0, 0, 0]
# Hashes
hash = { name: "John", age: 30 }
hash = { "key" => "value" }
# Ranges
(1..5) # 1, 2, 3, 4, 5
(1...5) # 1, 2, 3, 4
String Operations
"hello".upcase # "HELLO"
"WORLD".downcase # "world"
"ruby".capitalize # "Ruby"
" trim ".strip # "trim"
"hello".reverse # "olleh"
"a,b,c".split(',') # ["a", "b", "c"]
["a","b"].join('-') # "a-b"
# String interpolation
name = "Ruby"
"Hello #{name}" # "Hello Ruby"
# Multiline strings
str = <<~HEREDOC
This is a
multiline string
HEREDOC
Control Structures
# If/elsif/else
if x > 0
"positive"
elsif x < 0
"negative"
else
"zero"
end
# Ternary
result = x > 0 ? "positive" : "non-positive"
# Unless
puts "negative" unless x > 0
# Case/when
case grade
when 90..100 then "A"
when 80..89 then "B"
else "C"
end
Loops
# While
while i < 5
i += 1
end
# Until
until i >= 5
i += 1
end
# For
for i in 1..5
puts i
end
# Times
5.times { |i| puts i }
# Each
[1,2,3].each { |n| puts n }
# Map/collect
[1,2,3].map { |n| n * 2 } # [2,4,6]
# Select/filter
[1,2,3,4].select { |n| n.even? } # [2,4]
2. Methods & Blocks
Method Definition
# Basic method
def greet(name)
"Hello #{name}"
end
# Default parameters
def greet(name = "World")
"Hello #{name}"
end
# Variable arguments
def sum(*nums)
nums.reduce(:+)
end
# Keyword arguments
def create_user(name:, age: 18)
{ name: name, age: age }
end
# Method with block
def with_timing
start = Time.now
yield
Time.now - start
end
Blocks, Procs & Lambdas
# Block
[1,2,3].each { |n| puts n }
[1,2,3].each do |n|
puts n
end
# Proc
my_proc = Proc.new { |x| x * 2 }
my_proc.call(5) # 10
# Lambda
my_lambda = ->(x) { x * 2 }
my_lambda.call(5) # 10
# Difference: Lambda checks argument count, Proc doesn't
# Lambda returns to method, Proc returns from method
3. Object-Oriented Programming
Classes & Objects
class Person
attr_accessor :name # getter & setter
attr_reader :age # getter only
attr_writer :email # setter only
@@count = 0 # class variable
def initialize(name, age)
@name = name
@age = age
@@count += 1
end
def self.count # class method
@@count
end
def greet # instance method
"Hi, I'm #{@name}"
end
private
def secret_method
"private"
end
end
person = Person.new("John", 30)
Inheritance
class Employee < Person
def initialize(name, age, salary)
super(name, age) # call parent constructor
@salary = salary
end
def greet
super + " and I work here"
end
end
Modules & Mixins
module Greetable
def hello
"Hello!"
end
end
module Trackable
def self.included(base)
base.extend(ClassMethods)
end
module ClassMethods
def track_method(name)
# class method
end
end
end
class User
include Greetable # instance methods
extend Trackable # class methods
end
Method Visibility
class MyClass
public # default
def public_method; end
protected # accessible by subclasses
def protected_method; end
private # only accessible within class
def private_method; end
end
4. Advanced Ruby Features
Metaprogramming
# Define method dynamically
define_method :dynamic_method do |arg|
"Dynamic #{arg}"
end
# Method missing
def method_missing(method, *args)
"Method #{method} not found"
end
# Send method
object.send(:method_name, args)
# Eval
eval("1 + 1") # 2
# Class eval
MyClass.class_eval do
def new_method
"added"
end
end
Singleton Methods & Classes
# Singleton method
obj = Object.new
def obj.unique_method
"only for this instance"
end
# Singleton class
class << obj
def another_unique
"also unique"
end
end
Duck Typing
# If it walks like a duck and quacks like a duck...
def process(obj)
obj.to_s # works with any object that responds to to_s
end
5. Enumerable & Collections
Common Enumerable Methods
arr = [1, 2, 3, 4, 5]
# Iteration - O(n)
arr.each { |n| puts n }
arr.each_with_index { |n, i| puts "#{i}: #{n}" }
# Transformation - O(n)
arr.map { |n| n * 2 } # [2,4,6,8,10]
arr.select { |n| n.odd? } # [1,3,5]
arr.reject { |n| n.odd? } # [2,4]
arr.reduce(:+) # 15 - O(n)
arr.inject(0) { |sum, n| sum + n } # 15
# Searching - O(n) worst case
arr.find { |n| n > 3 } # 4 - stops at first match
arr.find_all { |n| n > 3 } # [4,5]
arr.any? { |n| n > 3 } # true - stops at first
arr.all? { |n| n > 0 } # true - may check all
arr.none? { |n| n < 0 } # true - may check all
# Grouping & Sorting
[1,2,3,4].group_by { |n| n.odd? } # O(n)
# {true=>[1,3], false=>[2,4]}
arr.sort # O(n log n)
arr.sort_by { |n| -n } # O(n log n)
Array Methods
arr = [1, 2, 3]
arr.push(4) # [1,2,3,4] - O(1)
arr << 5 # [1,2,3,4,5] - O(1)
arr.pop # returns 5 - O(1)
arr.shift # returns 1 - O(n)
arr.unshift(0) # [0,2,3,4] - O(n)
arr.first(2) # [0,2] - O(1)
arr.last(2) # [3,4] - O(1)
arr.include?(3) # true - O(n)
arr.flatten # flattens nested - O(n)
arr.compact # removes nil - O(n)
arr.uniq # removes duplicates - O(n)
Hash Methods
hash = { a: 1, b: 2, c: 3 }
hash.keys # [:a, :b, :c] - O(n)
hash.values # [1, 2, 3] - O(n)
hash.each { |k, v| puts "#{k}: #{v}" } # O(n)
hash.merge({ d: 4 }) # O(n+m)
hash.select { |k, v| v > 1 } # O(n)
hash.fetch(:a, 0) # O(1) average
hash.dig(:a) # O(1) average
hash[:key] = val # O(1) average
hash.delete(:key) # O(1) average
6. Exception Handling
begin
# risky code
result = 10 / 0
rescue ZeroDivisionError => e
puts "Error: #{e.message}"
rescue StandardError => e
puts "General error: #{e.message}"
else
puts "No errors"
ensure
puts "Always runs"
end
# Inline rescue
value = risky_method rescue "default"
# Raising exceptions
raise "Error message"
raise ArgumentError, "Invalid argument"
# Custom exceptions
class CustomError < StandardError; end
7. File I/O & System
File Operations
# Reading
content = File.read("file.txt")
lines = File.readlines("file.txt")
File.open("file.txt", "r") do |file|
file.each_line { |line| puts line }
end
# Writing
File.write("file.txt", "content")
File.open("file.txt", "w") { |f| f.write("text") }
File.open("file.txt", "a") { |f| f.puts("append") }
# File info
File.exist?("file.txt")
File.size("file.txt")
File.directory?("path")
Directory Operations
Dir.pwd # current directory
Dir.entries(".") # list files
Dir.glob("*.rb") # pattern matching
Dir.mkdir("new_dir") # create directory
8. Regular Expressions
# Basic patterns
/pattern/ # basic regex
/pattern/i # case insensitive
/pattern/m # multiline
# Common patterns
/\d+/ # digits
/\w+/ # word characters
/\s+/ # whitespace
/^start/ # beginning of line
/end$/ # end of line
/a.b/ # any character
/a.*b/ # zero or more
/a.+b/ # one or more
/a.?b/ # zero or one
/[aeiou]/ # character class
/(group)/ # capturing group
# Usage
"test".match?(/es/) # true
"test".scan(/[aeiou]/) # ["e"]
"test".gsub(/e/, "3") # "t3st"
"a,b,c".split(/,/) # ["a", "b", "c"]
9. Rails Fundamentals
MVC Architecture
# Model - Business logic and data
class User < ApplicationRecord
has_many :posts
validates :email, presence: true
end
# View - Presentation layer (ERB templates)
<%= @user.name %>
# Controller - Request handling
class UsersController < ApplicationController
def show
@user = User.find(params[:id])
end
end
ActiveRecord Basics
# Model
class User < ApplicationRecord
has_many :posts
belongs_to :company
has_one :profile
has_and_belongs_to_many :groups
validates :email, presence: true, uniqueness: true
validates :age, numericality: { greater_than: 18 }
scope :active, -> { where(active: true) }
scope :recent, -> { order(created_at: :desc) }
before_save :normalize_email
after_create :send_welcome_email
private
def normalize_email
self.email = email.downcase.strip
end
end
# Queries - Performance considerations
User.find(1) # O(1) with index
User.find_by(email: "test@example.com") # O(1) with index
User.where(active: true) # O(n) without index
User.where("age > ?", 18) # O(n) or O(log n) with index
User.joins(:posts).where(posts: { published: true })
User.includes(:posts) # Prevents N+1 queries
User.limit(10).offset(20) # Pagination
User.order(created_at: :desc) # O(n log n) without index
User.group(:status).count # O(n)
Migrations
class CreateUsers < ActiveRecord::Migration[7.0]
def change
create_table :users do |t|
t.string :name, null: false
t.string :email, index: { unique: true }
t.integer :age
t.references :company, foreign_key: true
t.timestamps
end
end
end
Controller Patterns
class UsersController < ApplicationController
before_action :set_user, only: [:show, :edit, :update, :destroy]
def index
@users = User.page(params[:page])
end
def create
@user = User.new(user_params)
if @user.save
redirect_to @user
else
render :new
end
end
private
def set_user
@user = User.find(params[:id])
end
def user_params
params.require(:user).permit(:name, :email)
end
end
Service Objects Pattern
class UserRegistrationService
def initialize(params)
@params = params
end
def call
ActiveRecord::Base.transaction do
user = User.create!(@params)
send_welcome_email(user)
create_default_settings(user)
user
end
rescue => e
OpenStruct.new(success?: false, error: e.message)
end
private
def send_welcome_email(user)
UserMailer.welcome(user).deliver_later
end
def create_default_settings(user)
user.create_settings(theme: 'light')
end
end
# Usage in controller
def create
service = UserRegistrationService.new(user_params)
@user = service.call
if @user.persisted?
redirect_to @user
else
render :new
end
end
Concerns & Modules
# app/models/concerns/trackable.rb
module Trackable
extend ActiveSupport::Concern
included do
has_many :activities, as: :trackable
after_create :log_creation
end
def track_activity(action)
activities.create(action: action, user: Current.user)
end
private
def log_creation
track_activity('created')
end
end
# Usage
class Post < ApplicationRecord
include Trackable
end
Callbacks & Validations
class User < ApplicationRecord
# Callbacks
before_validation :normalize_email
after_create :send_welcome_email
after_update :notify_profile_update, if: :profile_changed?
# Validations
validates :email, presence: true, uniqueness: true, format: URI::MailTo::EMAIL_REGEXP
validates :age, numericality: { greater_than_or_equal_to: 18 }
validates :username, length: { in: 3..20 }
validate :email_not_blacklisted
private
def email_not_blacklisted
errors.add(:email, "is not allowed") if EmailBlacklist.exists?(email: email)
end
end
10. Testing with RSpec
# Model spec
describe User do
it "is valid with valid attributes" do
user = User.new(name: "John", email: "john@example.com")
expect(user).to be_valid
end
it "is invalid without email" do
user = User.new(name: "John")
expect(user).not_to be_valid
end
end
# Controller spec
describe UsersController do
describe "GET #index" do
it "returns success" do
get :index
expect(response).to have_http_status(:success)
end
end
end
# Common matchers
expect(value).to eq(5)
expect(value).to be_truthy
expect(array).to include(1)
expect { code }.to raise_error
expect { code }.to change { User.count }.by(1)
# Factory Bot
FactoryBot.define do
factory :user do
name { Faker::Name.name }
email { Faker::Internet.email }
age { 25 }
trait :admin do
role { 'admin' }
end
end
end
# Usage
user = create(:user)
admin = create(:user, :admin)
users = create_list(:user, 3)
11. Concurrency & Threading
Global Interpreter Lock (GIL/GVL)
# Ruby MRI has a GIL that prevents true parallel execution of Ruby code
# But I/O operations release the GIL, allowing concurrency
# CPU-bound tasks don't benefit from threads in MRI
threads = 4.times.map do
Thread.new { calculate_prime(1000000) } # Won't run in parallel
end
threads.each(&:join)
# I/O-bound tasks DO benefit from threads
threads = urls.map do |url|
Thread.new { fetch_data(url) } # Can run concurrently
end
results = threads.map(&:value)
Thread Safety
# Race condition example - NOT thread-safe
@counter = 0
threads = 10.times.map do
Thread.new { 1000.times { @counter += 1 } }
end
threads.each(&:join)
# @counter might not be 10000!
# Thread-safe with Mutex
@counter = 0
@mutex = Mutex.new
threads = 10.times.map do
Thread.new do
1000.times do
@mutex.synchronize { @counter += 1 }
end
end
end
threads.each(&:join)
# @counter will be 10000
# Thread-safe data structures
require 'concurrent'
safe_array = Concurrent::Array.new
safe_hash = Concurrent::Hash.new
Concurrent Ruby Patterns
# Future for async operations
require 'concurrent'
future = Concurrent::Future.execute { expensive_calculation }
# Do other work...
result = future.value # Blocks until complete
# Thread pool
pool = Concurrent::FixedThreadPool.new(5)
pool.post { perform_task }
pool.shutdown
pool.wait_for_termination
# Actor model
class Counter
include Concurrent::Async
def increment
@count = (@count || 0) + 1
end
end
counter = Counter.new
counter.async.increment
12. Memory Management & Garbage Collection
Ruby Memory Model
# Object allocation
ObjectSpace.count_objects # See object counts
ObjectSpace.memsize_of(obj) # Memory size of object
# Garbage collection
GC.start # Force garbage collection
GC.stat # GC statistics
GC.disable/GC.enable # Control GC
# Memory profiling
require 'objspace'
ObjectSpace.trace_object_allocations_start
# ... code to profile ...
ObjectSpace.trace_object_allocations_stop
Common Memory Issues
# Memory leak - holding references
class Leaky
@@all_instances = []
def initialize
@@all_instances << self # Never released!
end
end
# Fixed version
class NonLeaky
def self.track(instance)
@instances ||= []
@instances << WeakRef.new(instance)
end
end
# String allocation optimization
# Bad - creates new string each time
def bad_method
"status: " + status # New string object
end
# Good - reuses frozen string
FROZEN = "status: ".freeze
def good_method
"#{FROZEN}#{status}" # Less allocation
end
13. Performance & Optimization
Benchmarking
require 'benchmark'
Benchmark.bm do |x|
x.report("method1") { 1000.times { method1 } }
x.report("method2") { 1000.times { method2 } }
end
Memoization
def expensive_calculation
@result ||= begin
# expensive operation
sleep(2)
42
end
end
Database Optimization
# N+1 query problem - BAD
users.each { |user| puts user.posts.count }
# Solution - GOOD
users.includes(:posts).each { |user| puts user.posts.size }
# Use pluck for single columns
User.pluck(:email) # returns array of emails
# Use select for limiting columns
User.select(:id, :name)
# Batch processing
User.find_each(batch_size: 1000) do |user|
# process user
end
12. Common Interview Patterns
Singleton Pattern
class Singleton
def self.instance
@instance ||= new
end
private_class_method :new
end
Factory Pattern
class AnimalFactory
def self.create(type)
case type
when :dog then Dog.new
when :cat then Cat.new
end
end
end
Observer Pattern
module Observable
def observers
@observers ||= []
end
def add_observer(observer)
observers << observer
end
def notify_observers
observers.each { |obs| obs.update(self) }
end
end
Decorator Pattern
class Coffee
def cost; 2; end
def description; "Coffee"; end
end
class MilkDecorator
def initialize(coffee)
@coffee = coffee
end
def cost
@coffee.cost + 0.5
end
def description
@coffee.description + " with milk"
end
end
13. Algorithms & Complexity
Common Algorithm Patterns
Fibonacci Sequence
# Recursive - O(2^n) time, O(n) space
def fibonacci(n)
return n if n <= 1
fibonacci(n - 1) + fibonacci(n - 2)
end
# Memoized - O(n) time, O(n) space
def fibonacci_memo(n, memo = {})
return n if n <= 1
memo[n] ||= fibonacci_memo(n-1, memo) + fibonacci_memo(n-2, memo)
end
# Iterative - O(n) time, O(1) space
def fibonacci_iter(n)
return n if n <= 1
prev, curr = 0, 1
(n - 1).times { prev, curr = curr, prev + curr }
curr
end
String Manipulation
# Palindrome check - O(n) time, O(n) space
def palindrome?(str)
clean = str.downcase.gsub(/\W/, '')
clean == clean.reverse
end
# Anagram check - O(n log n) time
def anagram?(str1, str2)
str1.chars.sort == str2.chars.sort
end
Array Operations
# Flatten nested array - O(n) time for n total elements
def flatten_array(arr)
arr.reduce([]) do |flat, element|
flat + (element.is_a?(Array) ? flatten_array(element) : [element])
end
end
# Find duplicates - O(n) time, O(n) space
def find_duplicates(arr)
seen = Set.new
arr.select { |item| !seen.add?(item) }
end
# Two sum problem - O(n) time, O(n) space
def two_sum(nums, target)
seen = {}
nums.each_with_index do |num, i|
complement = target - num
return [seen[complement], i] if seen.key?(complement)
seen[num] = i
end
nil
end
14. API Development
RESTful Design
# Rails RESTful routes
resources :users do
resources :posts # Nested resources
end
# Creates: GET /users, POST /users, GET /users/:id, etc.
# API versioning
namespace :api do
namespace :v1 do
resources :users
end
end
# Custom routes
get 'search', to: 'products#search'
post 'users/:id/activate', to: 'users#activate'
JSON Serialization
# Active Model Serializers
class UserSerializer < ActiveModel::Serializer
attributes :id, :name, :email
has_many :posts
def email
object.admin? ? object.email : nil
end
end
# Jbuilder
# views/users/show.json.jbuilder
json.user do
json.id @user.id
json.name @user.name
json.posts @user.posts, :id, :title
end
# Manual serialization
def as_json(options = {})
super(options.merge(
only: [:id, :name],
include: { posts: { only: [:id, :title] } }
))
end
API Controllers
class Api::V1::BaseController < ApplicationController
skip_before_action :verify_authenticity_token
before_action :authenticate_api_user!
rescue_from ActiveRecord::RecordNotFound, with: :not_found
rescue_from ActiveRecord::RecordInvalid, with: :unprocessable
private
def authenticate_api_user!
token = request.headers['Authorization']&.split(' ')&.last
@current_user = User.find_by_token(token)
render_unauthorized unless @current_user
end
def render_unauthorized
render json: { error: 'Unauthorized' }, status: :unauthorized
end
def not_found
render json: { error: 'Not found' }, status: :not_found
end
end
Authentication Patterns
# JWT authentication
class JsonWebToken
SECRET_KEY = Rails.application.secrets.secret_key_base
def self.encode(payload, exp = 24.hours.from_now)
payload[:exp] = exp.to_i
JWT.encode(payload, SECRET_KEY)
end
def self.decode(token)
decoded = JWT.decode(token, SECRET_KEY)[0]
HashWithIndifferentAccess.new(decoded)
rescue JWT::DecodeError
nil
end
end
# API key authentication
class ApiKey < ApplicationRecord
before_create :generate_key
private
def generate_key
self.key = SecureRandom.hex(32)
end
end
15. Background Jobs & Caching
Sidekiq Patterns
# Job definition
class EmailWorker
include Sidekiq::Worker
sidekiq_options queue: 'mailers', retry: 3
def perform(user_id)
user = User.find(user_id)
UserMailer.welcome(user).deliver_now
end
end
# Enqueue jobs
EmailWorker.perform_async(user.id)
EmailWorker.perform_in(5.minutes, user.id)
EmailWorker.perform_at(tomorrow, user.id)
# Batch operations
class BatchProcessor
include Sidekiq::Worker
def perform(batch_id)
Batch.find(batch_id).process!
rescue => e
self.class.perform_in(1.hour, batch_id)
raise e
end
end
ActiveJob
class ProcessImageJob < ApplicationJob
queue_as :default
retry_on Net::OpenTimeout, wait: 5.seconds, attempts: 3
def perform(image)
image.process!
image.create_thumbnails!
end
end
# Usage
ProcessImageJob.perform_later(image)
ProcessImageJob.set(wait: 1.hour).perform_later(image)
Rails Caching
# Fragment caching
<% cache @product do %>
<%= render @product %>
<% end %>
# Russian doll caching
<% cache ['v1', @product] do %>
<% cache @product.reviews.maximum(:updated_at) do %>
<%= render @product.reviews %>
<% end %>
<% end %>
# Low-level caching
class Product < ApplicationRecord
def expensive_calculation
Rails.cache.fetch("product/#{id}/calculation", expires_in: 1.hour) do
# Expensive operation
perform_complex_calculation
end
end
end
# Cache stores
Rails.cache.read('key')
Rails.cache.write('key', value, expires_in: 1.hour)
Rails.cache.delete('key')
Rails.cache.clear
# Redis caching
redis = Redis.new
redis.set('key', 'value')
redis.get('key')
redis.setex('key', 3600, 'value') # With expiry
redis.del('key')
16. Security Best Practices
SQL Injection Prevention
# UNSAFE - SQL injection vulnerability
User.where("name = '#{params[:name]}'")
# SAFE - Using placeholders
User.where("name = ?", params[:name])
User.where(name: params[:name])
# SAFE - Named placeholders
User.where("created_at > :date", date: 1.week.ago)
Mass Assignment Protection
# Strong parameters in controllers
def user_params
params.require(:user).permit(:name, :email)
end
# Never do this
User.create(params[:user]) # Dangerous!
# Always use strong parameters
User.create(user_params)
CSRF Protection
class ApplicationController < ActionController::Base
protect_from_forgery with: :exception
# For APIs
protect_from_forgery with: :null_session
end
# In forms
<%= form_with model: @user do |f| %>
# CSRF token automatically included
<% end %>
XSS Prevention
# Automatically escaped in views
<%= @user.bio %> # Safe
# Raw HTML (dangerous if user input)
<%= raw @user.bio %> # Unsafe
<%= @user.bio.html_safe %> # Unsafe
# Sanitize user input
<%= sanitize @user.bio, tags: %w[p br strong em] %>
Authentication & Authorization
# Secure password handling
class User < ApplicationRecord
has_secure_password # Uses bcrypt
validates :password, length: { minimum: 8 }
end
# Session security
class SessionsController < ApplicationController
def create
user = User.find_by(email: params[:email])
if user&.authenticate(params[:password])
session[:user_id] = user.id
redirect_to root_path
else
flash[:alert] = "Invalid credentials"
render :new
end
end
def destroy
session.delete(:user_id)
redirect_to login_path
end
end
# Authorization with Pundit
class PostPolicy
def update?
user.admin? || record.user == user
end
end
17. Ruby Best Practices
Naming Conventions
class ClassName # CamelCase
def method_name # snake_case
CONSTANT_NAME = 1 # SCREAMING_SNAKE_CASE
local_variable = 1 # snake_case
@instance_variable = 1 # snake_case with @
Idiomatic Ruby
# Use symbols for hash keys
{ name: "John" } # Good
{ "name" => "John" } # Less idiomatic
# Use unless for negative conditions
puts "Error" unless valid? # Good
puts "Error" if !valid? # Less idiomatic
# Use ||= for memoization
@user ||= User.find(id)
# Use &: for simple method calls
users.map(&:name) # Good
users.map { |u| u.name } # Verbose
# Use guard clauses
return unless valid? # Good
if valid? # Less clean
# lots of code
end
18. Debugging & Tools
Debugging Techniques
# Print debugging
puts variable.inspect
p variable # shorthand
# Pry - Interactive debugging
require 'pry'
binding.pry # breakpoint
# Byebug - Step-through debugging
require 'byebug'
byebug # breakpoint
# Logger
logger = Logger.new(STDOUT)
logger.info "Information"
logger.error "Error occurred"
Introspection Methods
object.class # Object's class
object.methods # Available methods
object.ancestors # Inheritance chain
object.respond_to?(:method) # Check method exists
defined?(variable) # Check if defined
object.object_id # Unique identifier
19. Quick Reference
Type Checking & Conversions
# Type checking
1.is_a?(Integer) # true
[].is_a?(Array) # true
nil.nil? # true
# Conversions
"5".to_i # 5
5.to_s # "5"
:symbol.to_s # "symbol"
Truth Values
# Only nil and false are falsey
# Everything else is truthy:
0 # truthy
"" # truthy
[] # truthy
Common Pitfalls
# String interpolation only in double quotes
'Hello #{name}' # Literal text
"Hello #{name}" # Interpolated
# Array vs splat
def method(*args) # args is array
def method(args) # args is single param
# Symbol vs String keys
{ a: 1 }[:a] # 1
{ a: 1 }["a"] # nil
# Return in blocks vs lambdas
Proc.new { return }.call # Returns from method
lambda { return }.call # Returns from lambda
Key Takeaways: Ruby prioritizes developer happiness and code readability. Focus on understanding metaprogramming, Rails patterns, and performance optimization for interviews.