Ruby 3 Metaprogramming with define_method — Writing Code That Writes Code in Ruby Metaprogramming gets a reputation for being either magic or dangerous, depending on who you ask. Used carelessly, it produces code that’s impossible to trace and impossible to test. Used deliberately, it eliminates repetitive
Ruby 3 Proc vs Lambda in Ruby — Two Callable Objects, Different Rules Ruby has two closely related callable objects — Proc and lambda — and the difference between them trips up developers more than almost any other Ruby concept. They look similar, they’re both instances
Ruby 3 Range Objects in Ruby — More Than Just Iteration Most Ruby developers use ranges for iteration and not much else. (1..10).each, maybe ('a'..'z') for alphabet work, perhaps a case condition or two. But ranges in Ruby are full objects with a rich
Ruby 3 Struct vs OpenStruct vs Data — Choosing Lightweight Value Objects in Ruby Ruby gives you three tools for creating lightweight objects without the boilerplate of a full class definition: Struct, OpenStruct, and the newer Data (Ruby 3.2+). Each serves a different purpose, and the wrong
Ruby 3 Refinements in Ruby — Scoped Monkey Patching Without the Footguns Monkey patching in Ruby has a reputation — usually deserved — for causing exactly the kind of spooky action-at-a-distance bugs that make senior engineers twitch. Open a class anywhere in the codebase, add
Ruby 3 Object Freezing and Immutability in Ruby — When to Lock Things Down Mutability is the default in Ruby — most objects can be changed after creation, which is convenient right up until you have a hash shared between two parts of a system and one
Ruby 3 Symbol#to_proc and Callable Objects in Ruby — Making Code Do the Talking Ruby has several ways to represent callable behavior — blocks, procs, lambdas, and method references — and the syntactic sugar that connects them is one of the language’s quieter strengths. The &:symbol shorthand
Ruby 3 Enumerator and Lazy Evaluation in Ruby — Processing Large Collections Without Blowing Memory Most Ruby developers reach for map, select, and each without thinking twice — and for small arrays, that’s totally fine. But the moment you’re working with large datasets, external files, API paginated responses,
Ruby 3 Regular Expressions in Ruby — A Practical Guide That Skips the Theory Regular expressions have a reputation for being write-only code — you craft them with intense focus, they work, and three months later neither you nor anyone else can read them. That reputation is
Ruby 3 Exception Handling in Ruby — rescue, ensure, retry, and raise Done Right Exception handling is one of those topics that feels simple until you hit a subtle bug caused by rescuing too broadly, retrying without a limit, or swallowing errors that should surface. Ruby’s exception
Ruby 3 Hash.new With Default Values — Ruby's Underused Shortcut Most Ruby developers initialize hashes with {} and manually check for missing keys before updating them. It works, but Ruby’s Hash.new offers a more expressive alternative: hashes that return a default value for
Ruby 3 each_with_object vs reduce — Choosing the Right Ruby Aggregator Ruby gives you multiple ways to aggregate a collection into a single result: reduce (aliased as inject), each_with_object, and occasionally tally, sum, or group_by for specific cases. Developers tend to reach for reduce
Ruby 3 include, extend, and prepend — Ruby's Three Ways to Use Modules Ruby modules are one of the language’s most flexible tools — they handle namespacing, mixins, and code sharing without the rigidity of inheritance. But include, extend, and prepend are three different operations that
Ruby 3 method_missing and respond_to_missing? — Ruby Metaprogramming That's Actually Useful Metaprogramming has a reputation for being either magical or dangerous, depending on who you ask. Both reactions are earned. Ruby’s method_missing hook lets you intercept calls to methods that don’t exist and handle
Ruby 3 tap, then, and yield_self — Ruby's Method Chaining Toolkit Ruby has three methods that look similar on the surface but solve distinct problems in method chains: tap, then (aliased as yield_self), and itself. Once you understand what each one is actually for,