How can I "close" an enumerator in Ruby?

283 Views Asked by At

I have an enumerator that loops on data from an external API. The API requests that I notify it when I'm done looping. This is pretty easy when the enumerator is allowed to go until it runs out of data:

def api_enum
  return enum_for(:api_enum) unless block_given?
  loop_on_api_calls { |thing| yield thing }
  notify_api_that_i_am_done
end

But what about this case?

api_enum.each do |thing|
  do_stuff(thing)
  break
end

The break means I'm never going to call notify_api_that_i_am_done. How could I structure this to guarantee that notify_api_that_i_am_done gets called? Is there a good pattern to for this?

2

There are 2 best solutions below

0
On

In your api_enum method, you can use ensure to always execute cleanup code, regardless of any exception being thrown or the user breaking. This is a good idea to use for any cleanup code since only tht way you can ensure that the it us run even if something raises an exception in the user-supplied block.

This can be used like this:

def api_enum
  return enum_for(:api_enum) unless block_given?
  loop_on_api_calls { |thing| yield thing }
ensure
  notify_api_that_i_am_done
end

With that pattern, you don't need to follow any special call conventions.

0
On

You can just call break with an argument:

api_enum.each do |thing|
  do_stuff(thing)
  break(notify_api_that_i_am_done)
end