Understand what is available in ruby blocks

This is part of the Semicolon&Sons Code Diary - consisting of lessons learned on the job. You're in the ruby category.

Last Updated: 2021-05-16

I was using an external library to generate a sitemap. It had a block syntax:

SitemapGenerator::Sitemap.create do
  add root_url
end

Adding urls within this block was clean and easy to do initially, but the tidiness wasn't scalable when I got to 500 lines.

I tried refactoring as such:

class GenerateSiteMapService
  def generate
    add root_url
  end
  ....
end

SitemapGenerator::Sitemap.create do
  GenerateSiteMapService.new.generate
end

... but ran into the problem that the function add (part of the Sitemap library API) was not defined. This is because it became out of scope within my GenerateSitemapClass class.

The general rule here seems to be that calling object methods within a block doesn't magically imbue that class with the extra methods that were made available within that block.

My next step was to try passing in a sitemap variable that was explicitly made available by the library maintainers within the create scope

SitemapGenerator::Sitemap.create do
  GenerateSitemapService.new(sitemap).call
end

class MySitemap
  # make url helpers available
  include Rails.application.routes.url_helpers

  def initialize(sitemap)
    @sitemap = sitemap
  end

  def generate
    add root_url
  end
end