In Ruby, what does each link of `raw.strip.squeeze(" ").split(" ").first(8).join(" ")` receive, and is `raw` changed afterwards?
answer
- each return value is the next receiver
- a new object per link
- String, Array, then String again
- the original stays untouched
- nil anywhere breaks the chain
basics
~20 sEach call's return value becomes the receiver of the next call: strip and squeeze return new Strings, split turns one into an Array, first(8) returns a new Array and join builds a String. None of these methods mutates, so raw is unchanged.
solid answer
~40 sA Ruby method chain works because every method returns an object, and the next `.name` is sent to that object. Here `strip` returns a new String without surrounding whitespace, `squeeze(" ")` a new String with runs of spaces collapsed, `split(" ")` an **Array** of words, `first(8)` a new Array of at most eight words, and `join(" ")` a new String. Because these are non-bang methods that return fresh objects, `raw` still holds the original text, which is what makes such chains safe to reorder, extract or reuse. The type can change along the way, so each link must be a method of whatever the previous link returned. The price is one intermediate object per link, usually irrelevant for a title but visible in hot loops.
code
ruby · 8 linesraw = " Red ceramic mug, 350 ml "
short = raw.strip.squeeze(" ").split(" ").first(3).join(" ")
short # => "Red ceramic mug,"
raw # => " Red ceramic mug, 350 ml " unchanged
raw.strip.squeeze(" ").class # => String
raw.strip.squeeze(" ").split(" ").class # => Arraygo deeper
Recall that each call's return value is what the next call runs on, and that non-bang methods like strip return new objects, leaving the original alone.
Trace the type at every link, including where it turns into an Array and back, and name the links that can return nil on edge cases.
Judge when a long chain should be split into named steps for readability or debugging, and when intermediate allocations justify profiling a hot path.
Set expectations for data-cleaning pipelines across a codebase: non-mutating chains by default, measured exceptions where allocation matters.
## How a chain is evaluated A **method chain** is a series of calls where each call is made on the result of the previous one: `a.b.c` means "call `b` on `a`, then call `c` on whatever `b` returned". Ruby evaluates it strictly left to right. There is no special chain syntax; it falls out of two facts: - Every Ruby method returns an object, even if only `nil`. - A `.name` after an expression sends `name` to the object that expression produced. So the question for each link is always the same: **what did the previous link return, and does that object respond to this method?** ## Walking the product-title pipeline Take a messy product title, `raw = " Red ceramic mug, 350 ml "`, and the chain `raw.strip.squeeze(" ").split(" ").first(8).join(" ")`: | Link | Receiver | Returns | |---|---|---| | `strip` | the original String | a new String without leading and trailing whitespace | | `squeeze(" ")` | that new String | a new String with each run of spaces reduced to one | | `split(" ")` | the squeezed String | an Array of words | | `first(8)` | the Array | a new Array of at most 8 elements | | `join(" ")` | the short Array | a new String | 1. The chain starts on a String and ends on a String. 2. In the middle it passes through **Arrays**, so the methods available change: `first(8)` is an Array method, and calling `squeeze` after `split` would raise `NoMethodError`. 3. Each link creates a **new object**; nothing is modified in place. ## Why `raw` is unchanged `strip`, `squeeze`, `split`, `first` and `join` are **non-mutating**: they read their receiver and build a result. After the chain, `raw` still contains the original padding and double spaces. That matters for three reasons: - **Safety.** The same `raw` can feed another pipeline, a log line or an audit record without surprise. - **Refactoring.** Links can be reordered, extracted into a helper, or cut short for debugging, and each prefix of the chain is a valid expression with a meaningful value. - **Predictable values.** Every non-bang link above always returns an object of the documented type, never `nil` "because nothing changed". Many methods have a **bang** twin, such as `strip!` or `squeeze!`, that edits the receiver instead. Those are designed for statements, not chains, because several of them return `nil` when there was nothing to change. ## What a chain costs Each link allocates its result: here three Strings and two Arrays, plus the word Strings that `split` creates. For a single title that is negligible. In a loop over millions of rows, the intermediates become garbage the collector must reclaim, and that is the point where a hot path is profiled and rewritten. Readability is the default reason to chain; allocation is the reason to measure before assuming. ## Where chains break - A link that can return **`nil`** turns the next call into `NoMethodError`. Methods such as `Array#first` with no argument on an empty Array, `Hash#[]` on a missing key or `Array#find` without a match return `nil` rather than raising. - A link that returns a **different type** than you assumed, for example an Array where you expected a String, fails at the next link or, worse, succeeds with a method of the same name that means something else. - A link that mutates, such as a bang method, changes objects other code may share. Knowing each link's return value, including its value on the edge cases, is the whole skill. ## How to answer in an interview Walk the chain aloud, one link at a time, naming the **receiver** and the **return type** of each call, exactly as in the table above. Then state that none of these links mutates, so `raw` is unchanged, and contrast that with the bang twins that edit in place and may return `nil`. Finish with one edge case, for example that an empty or all-whitespace title makes `split` return an empty Array and `join` return an empty String rather than failing. That answer shows you read a chain as a sequence of return values, which is what the question is testing.
- What happens if you append `.capitalize` directly after `.split(" ")` in that chain?`split` returns an Array, and Array has no `capitalize` method, so Ruby raises `NoMethodError` for `capitalize` on the Array. Each link must be a method of the previous link's return value, so capitalizing words means capitalizing each element, or capitalizing the String before splitting or after joining.
- When would you stop chaining and assign an intermediate result to a local variable?When an intermediate value needs a name to be understood, is used twice, or needs checking, such as an empty Array before `first`. A named local also makes a failing link easier to find, because the backtrace line then points at a single call instead of a long expression.
saying these in an interview costs you the question
- Chaining strip and squeeze modifies raw in place.
- Every link in a chain operates on the original object.
- A chain keeps the same type from the first link to the last.
- Non-bang methods return nil when there is nothing to change.
- Ruby needs a special fluent API for calls to be chainable.