Ruby
Ruby is a dynamic, object-oriented programming language created by Yukihiro "Matz" Matsumoto in 1995 with an explicit goal: make programmers happy. It reads close to English, favors expressive code, and gives developers powerful tools like blocks, open classes, and metaprogramming. Ruby is best known as the language of Ruby on Rails, which powers GitHub, Shopify, Basecamp, GitLab, and many startups, but it's also used for scripting, DevOps tooling (Homebrew, Chef, Vagrant, Fastlane), and static site generators.
Modern Ruby (3.x) is significantly faster than its reputation suggests, thanks to the YJIT just-in-time compiler, and adds pattern matching, a fiber scheduler for async I/O, Ractors for parallelism, and optional type signatures (RBS).
TL;DR
- Everything is an object, including integers and
nil; methods are messages sent to objects. - Blocks (
do ... end,{ }) power iteration and DSLs; Enumerable givesmap,select,reduce, and more. - Modules provide namespacing and mixins instead of multiple inheritance.
- Duck typing and metaprogramming make flexible DSLs possible — use them with restraint.
- Manage dependencies with gems and Bundler (
Gemfile,Gemfile.lock). - Enable YJIT for speed; test with RSpec or Minitest.
Quick Example
Idiomatic Ruby: a value object, a module mixin, blocks, Enumerable, and pattern matching:
Core Concepts
Objects and Messages
Every value is an object with methods: 5.times { }, nil.to_a, "hi".upcase. Method calls are messages; respond_to? checks whether an object understands one. Classes are open, so you can add methods to existing classes (monkey patching) — powerful, but best confined to refinements to limit scope.
Blocks, Procs, and Lambdas
A block is a chunk of code passed to a method and called with yield. Procs and lambdas are block objects you can store and pass around; lambdas check argument counts and return from themselves, procs don't. Blocks are how Ruby builds iterators and DSLs:
Modules and Mixins
Modules serve two roles: namespaces (Payments::Stripe) and mixins (include Comparable). Including Enumerable and defining each gives a class dozens of collection methods. Ruby has single inheritance plus any number of mixins.
Duck Typing and Types
Ruby cares whether an object responds to a method, not its class. For larger codebases, RBS signatures with the Steep type checker or Sorbet (Stripe's gradual type checker) add static typing.
Metaprogramming
define_method, method_missing, send, instance_variable_get, and class macros (attr_accessor, Rails' has_many) let code write code. That's how Rails offers concise DSLs — and why heavy metaprogramming can make code hard to trace.
Gems and Bundler
Libraries are gems from RubyGems.org. A Gemfile declares dependencies and Bundler resolves and locks exact versions in Gemfile.lock. Use version managers like rbenv, asdf, or mise to pin Ruby versions per project.
Performance and Concurrency
YJIT, built by Shopify, is a production-ready JIT that often speeds up real Rails apps by 15–30%. Enable it with RUBY_YJIT_ENABLE=1 or --yjit.
Best Practices
Write Idiomatic, Readable Ruby
Prefer Enumerable methods over manual loops, guard clauses over deep nesting, and small methods with clear names. Follow the community style guide and enforce it with RuboCop (or Standard).
Keep Metaprogramming Contained
Use it for well-tested DSLs, not everyday logic. Prefer explicit methods when readability suffers.
Freeze Strings and Constants
# frozen_string_literal: true at the top of files reduces allocations and prevents accidental mutation.
Test Thoroughly
Dynamic typing means tests carry more of the correctness burden. RSpec and Minitest are both mature; add SimpleCov for coverage.
Enable YJIT in Production
It's a low-effort performance win for most applications on Ruby 3.3+.
Move Slow Work to Background Jobs
Sidekiq, GoodJob, or Solid Queue keep web requests fast. See Background Jobs.
Common Mistakes
Global Monkey Patches
Changing core classes globally can break gems in surprising ways. Use refinements or wrapper objects.
N+1 Queries Hidden by Nice Syntax
Elegant Enumerable chains over ActiveRecord associations can fire a query per item. Preload associations.
Relying on method_missing Without respond_to_missing?
Objects then lie about the methods they support, confusing other code and tools.
Expecting Threads to Parallelize CPU Work
The global VM lock serializes Ruby execution. Use processes or Ractors for CPU-bound parallelism.
Unpinned Ruby and Gem Versions
Different Ruby or gem versions across machines cause "works on my machine" bugs. Commit Gemfile.lock and a .ruby-version file.
Comparison
FAQ
What is Ruby used for?
Mostly web development with Ruby on Rails, plus scripting, automation, DevOps tools, static site generators like Jekyll, and mobile build tooling like Fastlane.
Is Ruby still relevant?
Yes. Large companies like Shopify, GitHub, and GitLab run on Ruby, Rails continues to evolve, and Ruby 3.x with YJIT is much faster than earlier versions.
Ruby or Python for beginners?
Both are beginner-friendly. Python has broader use in data science and education; Ruby shines for productive web development with Rails and expressive code.
What's the difference between a block, a proc, and a lambda?
A block is code passed to a method call. A proc is a block turned into an object. A lambda is a stricter proc that checks argument counts and returns from itself rather than the enclosing method.
Does Ruby have static typing?
Not built into the language, but RBS signatures with Steep, or Sorbet, provide gradual static type checking.
Related Topics
- Ruby on Rails — Ruby's flagship web framework
- Python — The closest comparison in the dynamic-language world
- Testing — Critical for dynamic languages
- Background Jobs — Sidekiq and job processing patterns
- Package Managers — Bundler and dependency locking