David West
David West

Reputation: 2328

Is there a default block argument in Ruby?

I am just starting to do Groovy after mostly doing ruby.

It has a default 'block argument', it, as it were, not officially the terminology for Groovy, but I'm new to Groovy.

(1..10).each {println(it)}

What about Ruby? Is there a default I can use so I don't have to make |my_block_arg| every time?

Thanks!

Upvotes: 2

Views: 509

Answers (3)

Ja͢ck
Ja͢ck

Reputation: 173552

From Ruby 2.7 onwards, you can use numbered block arguments:

(1..10).each { puts _1 }

Granted, this hasn't been very well documented; some references are still using @1, but the above is tested on the official 2.7 version.

Upvotes: 0

3limin4t0r
3limin4t0r

Reputation: 21110

Like Andrey Deinekos answer explained there is no default. You can set the self context using BasicObject#instance_eval or BasicObject#instance_exec. I don't recommend doing this since it can sometimes result in some unexpected results. However if you know what you're doing the following is still an option:

class Enumerator
  def with_ie(&block)
    return to_enum(__method__) { each.size } unless block_given?
    each { |e| e.instance_eval(&block) }
  end
end

(1..10).each.with_ie { puts self }
# 1
# 2
# 3
# 4
# 5
# 6
# 7
# 8
# 9
# 10
#=> 1..10

(1..10).map.with_ie { self * self }
#=> [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
(-5..5).select.with_ie { positive? }
#=> [1, 2, 3, 4, 5]

If you want to call one method you might as well do (-5..5).select(&:positive?), but when the objects you're iterating over have actual attributes it might be worth the trouble. For example:

people.map.with_ie { "#{id}: #{first_name} - #{last_name}" }

Keep in mind that if you have an local variable id, first_name or last_name in scope those are used instead of the methods on the object. This also doesn't quite work for hashes or Enumerable methods that pass more than one block argument. In this case self is set to an array containing the arguments. For example:

{a: 1, b: 2}.map.with_ie { self }
#=> [[:a, 1], [:b, 2]]
{a: 1, b: 2}.map.with_ie { self[0] }
#=> [:a, :b]

Upvotes: 1

Andrey Deineko
Andrey Deineko

Reputation: 52357

No, you don't have a "default" in Ruby.

Though, you can do

(1..10).each(&method(:puts))

Upvotes: 2

Related Questions