What Is It (in Ruby 3.4)?
This post may appear to be about new functionality in Ruby. However, it may instead be an attempt to write an article with the worst possible SEO.
Anyway, hit it.
What Is It? 🔗
As of Ruby 3.4, it
is another way to refer to the first parameter in a block. This may be more obvious by way of an example.
["What is it?"].map { it + " It's it" } * 4
=>
[
"What is it? It's it",
"What is it? It's it",
"What is it? It's it",
"What is it? It's it",
]
The block we pass to map
does not define a name for the parameter to represent the variable we’re manipulating in each iteration. Instead, Ruby knows it
refers to that variable.
Starting in Ruby 2.7, we had access to numbered parameters in a block with an underscore. We can write that same example using numbered parameters.
["What is it?"].map { _1 + " It's it" } * 4
=>
[
"What is it? It's it",
"What is it? It's it",
"What is it? It's it",
"What is it? It's it",
]
Before Ruby 2.7, we would define the name of a variable in a block, which we can still do with more recent versions of Ruby.
["What is it?"].map { |i| i + " It's it" } * 4
=>
[
"What is it? It's it",
"What is it? It's it",
"What is it? It's it",
"What is it? It's it",
]
Handling nested calls 🔗
Should you have nested blocks that refer to it
, Ruby will take it
to refer to the parameter of the innermost block.
[
"You want it all, but you can't have it",
"Yeah",
"It's in your face, but you can't grab it",
"Yeah",
]
.map { it == "Yeah" ? [it, it, it].map { it.upcase }.join(", ") : it }
=>
[
"You want it all, but you can't have it",
"YEAH, YEAH, YEAH",
"It's in your face, but you can't grab it",
"YEAH, YEAH, YEAH",
]
The same is not possible with numbered parameters. An exception is raised due to the ambiguity of what _1
refers to.
[
"You want it all, but you can't have it",
"Yeah",
"It's in your face, but you can't grab it",
"Yeah",
]
.map { _1 == "Yeah" ? [_1, _1, _1].map { _1.upcase }.join(", ") : _1 }
syntax error found (SyntaxError)
5 | "Yeah",
6 | ]
> 7 | ... _1.upcase }.join(", ") : _1 }
| ^~ numbered parameter is already used in outer block
Method names in scope 🔗
Ruby also will infer that it
refers to the block parameter should there be a method called it
in scope.
def it = "This isn't it"
[
"Can you feel it, see it, hear it today?",
"If you can't, then it doesn't matter anyway",
]
.map { it.gsub("it", "IT") }
=>
[
"Can you feel IT, see IT, hear IT today?",
"If you can't, then IT doesn't matter anyway",
]
Variable names in scope 🔗
However, if there is a variable defined as it
, that will take precedence over the block parameter in the block.
it = "This isn't it"
[
"You will never understand it, 'cause it happens too fast",
"And it feels so good, it's like walking on glass",
]
.map { it.gsub("it", "IT") }
=>
[
"This isn't IT",
"This isn't IT",
]
You’ve got to share it, so you dare it 🔗
If you want to learn more about this new feature, check out the proposal and the documentation. Read the Ruby 3.4 changelog to discover all the fun available in Ruby 3.4.
You can touch it, smell it, taste it, so sweet
But it makes no difference ‘cause it knocks you off your feet
That’s it.