0

I defined this method:

# @return [Array<String>] items
def produce_items
  ["foo", "bar", "baz"]
end

A correct usage would be, obviously,

produce_items.each do |i|
  puts i
end

But I wrote this, which silently does nothing:

produce_items do |i|
  puts i
end

Is there a way to declare produce_items in such a way that my incorrect usage produces an error/exception? If MRI cannot do it, can an alternative interpreter do it? Can a static analysis tool like RuboCop or ruby-lint do it?

I suspect it may be hard because there are common idioms where methods take an optional block:

def block_optional_implicitly
  if block_given?
    puts "Got a block"
    yield
  else
    puts "Did not get a block"
  end
end

def block_optional_explicitly(&block)
  unless block.nil?
    puts "Got a block"
    block.call
  else
    puts "Did not get a block"
  end
end

(This is a reverse of the question How to require a block in Ruby?)

Community
  • 1
  • 1
Martin Vidner
  • 2,307
  • 16
  • 31
  • 1
    You could always `raise YikesBlock if block_given?` – Felixyz Aug 30 '16 at 08:05
  • You can selectively raise an exception when method doesn't expect it. But, you have to be cautious enough to not to do it in those methods which might actually require a block (optionally or otherwise). – kiddorails Aug 30 '16 at 08:06

1 Answers1

5

Yep, no way of doing this in ruby, except the block_given? checks all over the code.

Passing a block to a method that doesn't expect it does no harm. Besides something not happening (because you forgot the .each). This should be covered by unit tests. You kill two birds with one stone: make your code more regression-proof and don't get to insert fail "unexpected block" if block_given? into every method of your app.

Sergio Tulentsev
  • 226,338
  • 43
  • 373
  • 367