Reason #147 • May 27th, 2026

Using blocks for iteration

The most common use case for blocks is iteration. Anyone who has used Ruby will have encountered blocks in this context, as they are used by methods like each, map, select and many others to perform operations on collections. Let's look at how we can implement a block-based iterator ourselves:

Ruby
require "net/http"
require "json"

class ApiPaginator
  def initialize(resource_uri, per_page: 10)
    @resource_uri = URI(resource_uri)
    @per_page = per_page
  end

  def each
    page = 1

    loop do
      response = Net::HTTP.get_response(@resource_uri + "?page=#{page}&limit=#{@per_page}")
      resources = JSON.parse(response.body)

      break if resources.empty?

      resources.each { |resource| yield resource }
      page += 1
    end
  end
end

paginator = ApiPaginator.new("https://6a174fac1b90031f81b237fe.mockapi.io/loving-ruby/posts")

paginator.each do |post|
  puts post.fetch("title")
end

# Output:
# End of the Road
# Nature Boy
# ...
    

Now that we have each implemented, we can include Enumerable, and all our wildest dreams will come true:

Ruby
ApiPaginator.include(Enumerable)

paginator = ApiPaginator.new("https://6a174fac1b90031f81b237fe.mockapi.io/loving-ruby/posts")

titles = paginator.map { |post| post.fetch("title") }
# => ["End of the Road", "Nature Boy", ... ]

strawberry_fields = paginator.find do |post|
  post.fetch("title").include?("Strawberry")
end

strawberry_fields.fetch("title")
# => "Strawberry Fields Forever"
    

Could this get any more straightforward? ❤️

Reason #148 ?