Skip to main content
โšก Calmops

Essential Ruby Articles and Learning Resources

Introduction

Ruby has a rich ecosystem of technical writing. These are the articles and resources that provide the deepest understanding of Ruby’s object model, module system, and metaprogramming capabilities โ€” the topics that separate intermediate from advanced Ruby developers.

Core Ruby Concepts: Essential Reading

Modules: include vs extend

Understanding the difference between include and extend is fundamental to Ruby module design:

  • include adds module methods as instance methods
  • extend adds module methods as class methods (singleton methods on the class)
module Greetable
  def greet
    "Hello from #{self.class}"
  end
end

class Person
  include Greetable  # greet becomes an instance method
end

class Robot
  extend Greetable   # greet becomes a class method
end

Person.new.greet  # => "Hello from Person"
Robot.greet       # => "Hello from Robot"

Deep dive: Including and Extending Modules in Ruby

class_eval, module_eval, and instance_eval

These methods change the context (self) in which code executes:

# class_eval: evaluate code in the context of a class
String.class_eval do
  def shout
    upcase + "!!!"
  end
end

"hello".shout  # => "HELLO!!!"

# instance_eval: evaluate code in the context of an object
obj = Object.new
obj.instance_eval do
  def secret
    "only this object has this method"
  end
end

obj.secret  # => "only this object has this method"

Deep dive: Understanding class_eval, module_eval, and instance_eval

Equality Operators: ==, eql?, equal?, ===

Ruby has five equality operators, each with distinct semantics:

# == : value equality (most common)
1 == 1.0    # => true  (same value, different types)

# eql? : strict equality (used by Hash)
1.eql?(1.0) # => false (different types)

# equal? : object identity (same object_id)
a = "hello"
b = "hello"
a.equal?(b) # => false (different objects)
a.equal?(a) # => true  (same object)

# === : case equality (used by case/when)
(1..10) === 5   # => true  (membership)
/hello/ === "hello world"  # => true  (pattern match)
String === "hi" # => true  (is_a? check)

# =~ : pattern match
"hello" =~ /ell/  # => 1 (position of match)

Deep dive: Ruby Basics: Equality Operators

Ruby Ancestors and the Method Lookup Chain

Understanding how Ruby finds methods is key to understanding modules, inheritance, and metaprogramming:

module M; end
class A; include M; end
class B < A; end

B.ancestors
# => [B, A, M, Object, Kernel, BasicObject]

When you call a method on an object, Ruby walks this chain left to right until it finds the method. This is why include inserts the module after the class, and prepend inserts it before.

Deep dive: Ruby Ancestors, Descendants, and Other Annoying Relatives

Metaprogramming Ruby (Paolo Perrotta)

The definitive guide to Ruby’s metaprogramming capabilities. Covers:

  • The object model (classes, modules, singleton classes)
  • Methods (dynamic dispatch, method_missing, define_method)
  • Blocks, procs, and lambdas
  • Class macros (attr_accessor, validates, etc.)
  • Writing DSLs

Best for: Intermediate to advanced Ruby developers who want to understand how Rails and other frameworks work under the hood.

The Well-Grounded Rubyist (David A. Black)

A comprehensive introduction to Ruby that goes deeper than most beginner books. Covers the object model, modules, and Ruby’s design philosophy.

Effective Ruby (Peter J. Jones)

48 specific ways to write better Ruby code. Particularly good on:

  • Understanding Ruby’s object model
  • Using modules effectively
  • Writing idiomatic Ruby

Programming Ruby (The Pickaxe Book)

The original comprehensive Ruby reference. Still valuable for its depth and coverage of the standard library.

Online Resources

Official Documentation

Learning Platforms

Community

Key Topics for Advanced Ruby

The Object Model

Everything in Ruby is an object, including classes and modules. Understanding this unlocks metaprogramming:

# Classes are objects (instances of Class)
String.class   # => Class
Class.class    # => Class

# Modules are objects (instances of Module)
Enumerable.class  # => Module

# Every object has a singleton class
obj = Object.new
obj.singleton_class  # => #<Class:#<Object:0x...>>

Blocks, Procs, and Lambdas

# Block: anonymous code passed to a method
[1,2,3].each { |n| puts n }

# Proc: a block stored as an object
double = Proc.new { |n| n * 2 }
double.call(5)  # => 10

# Lambda: a proc with strict argument checking
triple = lambda { |n| n * 3 }
triple.call(5)  # => 15

# Method reference as block
[1,2,3].map(&method(:puts))

Open Classes and Monkey Patching

# Reopen any class to add methods
class String
  def palindrome?
    self == self.reverse
  end
end

"racecar".palindrome?  # => true
"hello".palindrome?    # => false

Use with caution โ€” monkey patching can cause unexpected behavior in large codebases. Prefer refinements for scoped modifications.

Resources

Comments