Ruby says what you meant

Enumerable, blocks, and why only false and nil are falsy.

Ruby Optimises for the Programmer's Happiness, and That Is a Real Engineering Position

Most languages state their goals in terms of the machine. Fast execution, predictable memory, safety guarantees, portability. Ruby's stated goal is different and slightly startling the first time you read it: its creator designed it to make programmers happy. That is easy to dismiss as marketing. It is not. It is a genuine engineering position with genuine consequences, and the consequences are visible in every corner of the language. Ruby consistently spends machine resources to buy human comfort. It will do more work at run time so that you write less. It will offer three ways to express something because different sentences read better in different contexts. It will let a library reshape the language itself so that using that library feels like writing in a dialect designed for your problem. Whether that trade is worth it depends entirely on what is scarce in your project. If the bottleneck is CPU, Ruby is a poor answer. If the bottleneck is the time and attention of the people writing and reading the code — which, in most business software, it is — the trade looks very different. Everything is an object, with no exceptions at all Many languages claim this. Ruby means it literally. Integers are objects with methods. nil is an object. true and false are objects. Classes are objects. Even the operators are methods: 2 + 3 is a method call on the integer 2, and you can see the machinery by calling it the long way round. This is not a curiosity. It is what makes Ruby's uniformity possible. There is no separate category of primitive values with different rules, no boxing and unboxing, no "this works on objects but not on numbers". Any method you can call on one thing, you can reasonably expect to call on another — 5.times, "text".reverse, [1,2,3].sum, nil.to_a. The practical benefit is that Ruby has very few special cases to remember, and a reader can guess correctly far more often than in a language with two kinds of value. Blocks are the idea that shapes everything else If you understand one Ruby feature deeply, make it blocks. Nearly everything distinctive about the language flows from them. A block is a chunk of code passed to a method. It looks like this: [1, 2, 3].each { |n| puts n }

File.open('data.txt') do |f| process(f) end That second example is doing something languages without blocks find awkward. File.open opens the file, hands it to your code, and then closes it — guaranteed, including if your code raises. The resource management lives inside the method, and the caller cannot forget it because there is nothing to forget. This pattern appears everywhere: iterating, transforming, filtering, timing, transactions, locks, retries, temporary state changes. The method owns the setup and teardown; you supply the middle. In most languages that structure requires either a try-finally in every caller or a function passed as an argument with noticeably more ceremony. Once blocks are natural, Ruby's collection methods read like descriptions rather than instructions. users.select(&:active?).map(&:email).sort says what you want in the order you would say it aloud. Expressions, not statements Almost everything in Ruby returns a value, including things that in other languages are statements. An if returns the value of the branch taken. A method returns its last expression without return. Even an assignment returns the assigned value. This is why Ruby code is full of constructions that would need a temporary variable elsewhere, and why the explicit return keyword is comparatively rare — it is there for early exits, not for the normal path. The consequence for style is that Ruby code tends toward composition. You chain, you nest expressions, you assign the result of a conditional. The consequence for reading is that you can usually tell what a method produces by looking at its last line. Duck typing, and the question Ruby asks instead Ruby does not ask what class an object is. It asks whether the object responds to the method being called. If something responds to each, it can be iterated. If it responds to to_s, it can be printed. Nothing needs to declare that it implements an interface; it simply needs to have the methods. This is duck typing, and it makes Ruby code unusually easy to extend and to test — a test double is any object with the right methods, with no framework required to produce it. The cost is equally real and should be stated plainly. Errors that another language would catch when compiling appear at run time, at the moment the missing method is called, which may be deep inside a code path that rarely executes. Ruby's answer is cultural rather than technical: the community's testing discipline is unusually strong, and that is not a coincidence. In a language with no compiler to catch a typo in a method name, the test suite is the compiler. The standard library is designed for reading Ruby's collection methods are large in number and carefully named, and the naming is the point. map transforms. select keeps. reject discards. detect finds. reduce collapses. each_slice chunks. group_by buckets. partition splits in two. tally counts occurrences. sum, min_by, max_by, sort_by, flat_map, each_with_object — all present, all doing one thing. Several have aliases precisely so that the sentence reads well in context: map and collect, select and filter, reduce and inject, include? and member?. A language optimising for the machine would never do that. A language optimising for the sentence does it deliberately. The methods ending in ? return booleans and the ones ending in ! are either destructive or raise on failure. That convention is carried consistently enough that you can predict a method's behaviour from its name, which is a small thing that compounds enormously over a codebase. Metaprogramming, and the discipline it demands Ruby lets a program modify itself while running. Classes can be reopened and changed. Methods can be defined at run time. A call to a method that does not exist can be intercepted and handled. Code can be generated from data. This is the feature that makes Ruby's famous libraries possible. When a web framework lets you write has_many :orders and that one line produces a dozen methods, metaprogramming is what is happening. When a test library lets you write expect(user).to be_active, the same. It is also the feature most capable of producing code nobody can maintain. A method that does not appear anywhere in the source cannot be found by searching. A class whose behaviour changes depending on what was loaded first is a debugging problem with no obvious entry point. Monkey patching — reopening a class you do not own and changing it — can break a library three dependencies away in a manner that takes a day to trace. The honest position is that metaprogramming is a power tool. Libraries use it to build an interface that is pleasant for thousands of users, and that is a good trade. Application code usually should not, because the audience is small and the confusion is permanent. The question worth asking before reaching for it: am I saving more reading than I am costing? Ruby on Rails is not Ruby, and the distinction matters Many people meet Ruby through Rails and never fully separate the two. It is worth doing, because the opinions people hold about Ruby are frequently opinions about Rails. Rails is a web framework with strong conventions. It decides where files live, how they are named, how the database maps to objects, and how a request becomes a response. Those conventions are why a Rails application can be built quickly and why any Rails developer can find their way around an unfamiliar one. The conventions are also why Rails is criticised. A framework that generates behaviour you did not write is a framework where the behaviour is hard to locate when it goes wrong. The magic that makes the first week fast makes the second year slower, and the cost scales with the size of the application. Ruby without Rails is a perfectly good general-purpose language — for scripts, command-line tools, build automation, text processing and glue code. Learning the language first and the framework second produces a considerably better developer than the reverse. Performance, stated honestly Ruby is slow compared with compiled languages, and a dynamic language that resolves every method call at run time cannot be otherwise. Recent versions have improved this substantially with a just-in-time compiler, and the gap is smaller than its reputation, but the direction is not in doubt. Whether that matters depends on what dominates your time. For a typical web application the answer is usually the database, the network, and the external services — and a language that is three times slower than another on CPU work is irrelevant when ninety per cent of a request is spent waiting on a query. For numerical computation, image processing or anything CPU-bound in a tight loop, it matters a great deal and you should use something else or drop into a C extension. The engineering question is never "is this language fast" but "is this language fast enough for this workload, and what am I buying with the difference". Ruby's answer is that you are buying development speed and readable code, and for a large class of software that is the correct trade. Symbols, strings, and a distinction worth getting right early Ruby has two things that look like text. A string, written in quotes, and a symbol, written with a leading colon. A string is mutable and a new object each time it appears. A symbol is immutable and the same object every time — :name anywhere in the program is the identical object. That makes symbols cheap to compare and ideal as identifiers: hash keys, method names, option flags, state values. The rule that serves well: if it is data the user might see, use a string. If it is a name your program uses to refer to something, use a symbol. A person's name is a string. The key you store it under is a symbol. Modules do two jobs, and they are not related The module keyword covers two uses that happen to share syntax. A module can be a namespace, grouping related classes so that two libraries can both define Parser without colliding. A module can also be a mixin, a bundle of methods added to a class with include. This is how Ruby gets shared behaviour without multiple inheritance. The best demonstration is in the standard library itself: Enumerable is a module, and a class that defines each and includes it gains map, select, sort_by, group_by and several dozen more — all built on the single method you wrote. That is worth sitting with, because it is the clearest example of a small contract buying a large capability. Blocks, procs and lambdas Blocks are not objects, which is why a method can only take one. When you need to store one, pass several, or return one, you convert it to an object: a Proc or a lambda. They differ in two ways that matter. A lambda checks its argument count and a proc does not. And return inside a lambda returns from the lambda, while return inside a proc returns from the enclosing method — which is occasionally what you want and more often a surprise. The practical advice is to prefer lambdas unless you specifically need proc behaviour, because argument checking catches mistakes and the return semantics are the ones people expect. Error handling, and the method everyone forgets Ruby uses begin/rescue/ensure, and inside a method definition the begin is implicit — you can rescue at the method level without nesting. Two habits are worth forming. Rescue the narrowest class that fits, because rescue => e catches StandardError and will happily swallow a bug you needed to see. And use retry where the failure is genuinely transient, such as a network call, with a bounded number of attempts — it is a keyword, it restarts the begin block, and it is far clearer than a hand-rolled loop. What to practise

  1. Write a method that takes a block and uses yield, then rewrite something with a before-and-after shape — timing, a transaction, a temporary setting — using it.
  2. Take a loop you wrote with each and an accumulator, and express it with map, select or reduce instead. Compare how they read.
  3. Build a small class using duck typing, then test it with a plain object as a stand-in rather than a mocking library.
  4. Read the Enumerable documentation once through. Most Ruby that looks clever is just someone who knew the method existed.
  5. Resist metaprogramming for a whole project. You will learn where it genuinely helps by noticing where you missed it. Ruby's lasting lesson is that the readability of code is a measurable engineering property with real economic consequences, not a matter of taste. Most of a program's life is spent being read and changed by people who did not write it. A language that takes that seriously is making a defensible bet, and Ruby makes it more openly than any other language in wide use.

ruby enumerable blocks modules mixins value objects pattern matching truthiness exceptions testing