The Well-Grounded Rubyist
When I was first learning Ruby, The Well-Grounded Rubyist was hands-down one of the most valuable books I came across. A lot of programming books just walk you through syntax and features, but this book goes deeper—it explains the why behind Ruby’s design and philosophy. It helped me not just write Ruby, but think in Ruby, which made a huge difference in how I approached the language.
Core Ruby Philosophy
- Everything is an object - Even primitives like integers and booleans
- Open classes - Classes can be modified at runtime
- Duck typing - “If it quacks like a duck, it’s a duck” - focus on what objects can do, not what they are
- Blocks and closures - First-class functions and powerful iteration tools
- Metaprogramming - Code that writes code
Ruby Object Model
Objects and Methods
- Every object has a class
- Objects respond to messages (method calls)
obj.methodsshows all methods available to an objectobj.respond_to?(:method_name)checks if an object can respond to a messageobj.send(:method_name, arguments)dynamically calls methods
Classes and Instances
- Classes are objects too (instances of the Class class)
- Instance variables (
@variable) belong to specific objects - Class variables (
@@variable) belong to classes and are shared among all instances - Instance methods vs. Class methods (
def self.method_name)
Inheritance and Modules
- Single inheritance only - A class can only inherit from one superclass
supercalls the parent class’s version of the current method- Modules provide mixins (multiple inheritance-like behavior)
includeadds module methods as instance methodsextendadds module methods as class methods- Method lookup path: instance → included modules → class → superclass → Object → Kernel → BasicObject
Control Flow and Code Blocks
Blocks, Procs, and Lambdas
- Blocks are not objects, but can be converted to
Procobjects yieldexecutes the associated block from within a method&blockparameter captures a block as a Proc- Lambdas are Procs with stricter argument checking and different return behavior
proc {|x| puts x}vslambda {|x| puts x}(or-> (x) { puts x })
Iteration and Collection
each- Basic iterator, returns original collectionmap/collect- Transform each element, returns new collectionselect/find_all- Filter collection based on conditionreject- Opposite of selectreduce/inject- Accumulate values through iteration
Variables and Scope
Variable Types
- Local variables:
my_var - Instance variables:
@my_var(belong to object instances) - Class variables:
@@my_var(shared across a class and all instances) - Global variables:
$my_var(accessible everywhere, rarely used) - Constants:
MY_CONSTorMyClass(uppercase, can be redefined with warning)
Scope
- Methods create their own scope
- Blocks create a new scope but can access outer variables
- Classes and modules create their own scope
- Variables defined outside blocks are accessible inside blocks
- Variables defined inside blocks may not be accessible outside
Methods and Arguments
Method Arguments
- Required arguments:
def method(required) - Optional arguments with defaults:
def method(optional = "default") - Variable-length arguments (splat):
def method(*args) - Keyword arguments:
def method(key: "value") - Required keyword arguments:
def method(required:) - Double splat for variable keyword arguments:
def method(**options)
Method Return Values
- Last evaluated expression is implicitly returned
- Explicit return with
returnkeyword - Multiple return values:
return a, b, c(returns an array)
Modules and Namespaces
Namespacing
- Use modules to organize code:
module MyNamespace; class MyClass; end; end - Access namespaced classes with
:::MyNamespace::MyClass - Prevent name collisions between similar classes/methods
Mix-ins
- Include modules to add functionality to classes
- Common mixins:
Enumerable,Comparable - Custom mixins for shared functionality
includevsprependvsextend
Metaprogramming
Dynamic Method Handling
method_missingcaptures calls to undefined methodsdefine_methodcreates methods dynamicallyinstance_evalandclass_evalexecute code in the context of objects/classes
Class Macros
- Methods that set up other methods or attributes
attr_accessor,attr_reader,attr_writer- Custom macros for domain-specific languages (DSLs)
Reflection
instance_variables- List of instance variable namesinstance_variable_get- Access instance variable valuesinstance_variable_set- Set instance variable valuesconstants- List constants in a class/module
Ruby Idioms
Truthiness
- Everything is truthy except
falseandnil &&,||, and!for logical operationsand,or, andnotfor control flow (lower precedence)
Conditional Assignment
||=assigns only if variable is nil or falsea ||= bis equivalent toa = a || b
Safe Navigation
object&.method- Calls method only if object is not nil- Avoids
nilerrors in method chains
Conversion Methods
to_s- Convert to stringto_i- Convert to integerto_a- Convert to arrayto_h- Convert to hash
Standard Library Highlights
String Manipulation
- String interpolation:
"Hello, #{name}" - Multi-line strings with heredocs:
<<~TEXT ... TEXT - Regular expressions:
/pattern/andString#match,String#scan
Collections
- Arrays: Ordered, indexed collections
- Hashes: Key-value pairs
- Sets: Unique values
- Ranges: Sequences with start and end points
File and I/O
File.open,File.read,File.writeIOstreamsDirfor directory operations
Date and Time
Timeclass for timestampsDateandDateTimefor calendar dates- Conversion between time representations
Testing and Debugging
IRB/Pry
- Interactive Ruby for quick testing
- Inspect objects, test methods
- Debug and explore code
RSpec/MiniTest
- BDD/TDD testing frameworks
- Test methods and behavior
- Expectations and assertions
Debugging
putsdebuggingbyebug/pryfor interactive debuggingpp(pretty print) for complex objects
Gems and Ecosystem
Bundler
- Manage dependencies with Gemfile
bundle install,bundle update- Gemfile.lock ensures consistent environments
RubyGems
- Find and install packages
gem install name- Create your own gems