I use Nanoc, a Ruby static website generator. It is pretty nice and has all the features I need for generating this site. One feature that was missing, however, was the ability to capture content on one page and use it on others. I manage the archive links as a page and the page content is inserted in the left nav bar using the site's layout template. I also reuse my resume content on the printable version of the page.
After inquiring on the Nanoc mail list, I came up with the following hack to solve my problem. Just add the code at the bottom of the page to a .rb file in your lib directory and then you can use it as follows.
<% global_content_for :foo do %>
This is the FOO stuff.
<% end %>
In any page you want to see the :foo content, just use markup like the following.
<%= global_content_for :foo %>
I wrote in a rudimentary ability to detect that one or more pages has unsatisfied global references. This situation arises pretty much whenever you use nanoc to do an update compile. In this case, nanoc will raise an exception with a message that there are unsatisfied global references. The "workaround" is to ensure that you are recompiling not only the pages that print out the global capture, but also the pages where the global capture is made. Because I have so few pages, it is not a problem for me to just recompile the whole site.
The real solution to this problem is smarter dependency resolution. It should be possible in a page's metadata to mark a page as dependent on some other page. If a page were being recompiled, all it's dependencies would be recompiled as well. If Nanoc can't handle it, maybe one of the other static website generators such as Webby will be able to handle it.
# override some stuff module Nanoc #Raised in the event of an unsatisified global capture dependency class UnsatisfiedGlobalCaptureReference < StandardError end class Compiler attr_accessor :recompiles alias :old_run :run def run(objects = nil, params = {}) # Track recursion depth. We allow a depth of no more # than 2. If greater, we have unsatisfied global capture # references (@depth ||= 0) @depth += 1 if @depth > 2 raise UnsatisfiedGlobalCaptureReference.new("The following pages have unsatisfied global capture references: #{@recompiles.join(', ')}") end @recompiles = [] old_run(objects, params) # Recompile stuff that had a global capture miss recompile_pages = @recompiles.map do |path| @site.pages.find do |site_page| check_path = path.gsub('.html', '/') site_page.path == check_path end end if recompile_pages.size > 0 run(recompile_pages, :also_layout => params[:also_layout], :even_when_not_outdated => true, :from_scratch => true) end end end end module GlobalCapturing CAPTURES = {} def global_content_for(name, &block) if !block.nil? global_captures[name] = global_capture(&block) end if !global_captures.has_key?(name) # TODO: Is this possible # Need to somehow signal the compiler that this page should be skipped for now # HACK: For some reason '==' does not work on @page objects, so use the path as the # equality check @site.compiler.recompiles << @page.path end global_captures[name] end def global_captures CAPTURES end private def global_capture(*args, &block) buffer = eval('_erbout', block.binding) pos = buffer.length block.call(*args) data = buffer[pos..-1] buffer[pos..-1] = '' data end end include GlobalCapturing