# frozen-string-literal: true # class Roda module RodaPlugins # The content_for plugin is designed to be used with the # render plugin, allowing you to store content inside one # template, and retrieve that content inside a separate # template. Most commonly, this is so view templates # can set content for the layout template to display outside # of the normal content pane. # # In the template in which you want to store content, call # content_for with a block: # # <% content_for :foo do %> # Some content here. # <% end %> # # or: # # <% content_for :foo do "Some content here." end %> # # You can also set the raw content as the second argument, # instead of passing a block: # # <% content_for :foo, "Some content" %> # # In the template in which you want to retrieve content, # call content_for without the block or argument: # # <%= content_for :foo %> # # Note that when storing content by calling content_for # with a block and embedding template code, the return # value of the block is used as the content (after being # converted to a string). This can cause issues in some # cases, such as: # # <% content_for :foo do %> # <% [1,2,3].each do |i| %> # Content <%= i %> # <% end %> # <% end %> # # In the above example, the return value of the block is # [1,2,3], as Array#each returns the receiver. # If whitespace is not important, you can work around this by # adding an empty line before the end of the content_for block. # # If content_for is used multiple times with the same key, # by default, the last call will append previous calls. # If you want to overwrite the previous content, pass the # append: false option when loading the plugin: # # plugin :content_for, append: false module ContentFor # Depend on the render plugin, since this plugin only makes # sense when the render plugin is used. def self.load_dependencies(app, _opts = OPTS) app.plugin :render end # Configure whether to append or overwrite if content_for # is called multiple times with the same key. def self.configure(app, opts = OPTS) app.opts[:append_content_for] = opts.fetch(:append, true) end module InstanceMethods # If called with a block, store content enclosed by block # under the given key. If called without a block, retrieve # stored content with the given key, or return nil if there # is no content stored with that key. def content_for(key, value=nil) append = opts[:append_content_for] if defined?(yield) || value if defined?(yield) outvar = render_opts[:template_opts][:outvar] buf_was = instance_variable_get(outvar) # Use temporary output buffer for ERB-based rendering systems instance_variable_set(outvar, String.new) value = yield.to_s instance_variable_set(outvar, buf_was) end @_content_for ||= {} if append (@_content_for[key] ||= []) << value else @_content_for[key] = value end elsif @_content_for && (value = @_content_for[key]) if append value = value.join end value end end end end register_plugin(:content_for, ContentFor) end end