> I don't have a definite need [for multiple filters] at this time, but was wondering about the rationale since it always struck me as a rather arbitrary limitation, especially considering the flexibility of the content 'compile' capability. At a more concrete level, not every conceivable transformer is or need be capable of invoking Ruby expressions (unlike ERB and Ruby-based HAML). I can, for instance, imagine crafting a layout in some higher level language and wanting it processed to HTML via one or more simple transformers, followed finally by ERB at layout application time.
>
>> You can run filters after a item is laid out, though. You can mix and match #layout and #filter calls you see fit. For example: [..]
>
> A shortcoming of this approach, with regard to my above theoretical argument, is that it tightly couples the layout processing specification with the content processing rule. Stated differently, the content 'compile' rule normally does not need to know how the layout is processed. Instead, layout processing information is correctly encapsulated with the layout itself (via the 'layout' rule).
Hi,
The reason why layouts work the way they work now is mostly because of simplicity. Being able to specify other filters and even sub-layouts in a layouting rule may be useful for large and complex sites, but I believe that for most sites, it would not be useful and perhaps even annoying to handle layouts this way (depending on how it’s implemented and how the DSL looks).
I have never encountered a use case where being able to specify extra filters and sub-layouts in a layouting rule would be a great advantage. Can you share your use-cases for this feature? If this would turn out to be useful, it may indeed be worth adding to a future version of nanoc.
Regards,
On 12/28/2009 9:29 AM, Denis Defreyne wrote:
> The reason why layouts work the way they work now is mostly because
> of simplicity. Being able to specify other filters and even
> sub-layouts in a layouting rule may be useful for large and complex
> sites, but I believe that for most sites, it would not be useful and
> perhaps even annoying to handle layouts this way (depending on how
> it�s implemented and how the DSL looks).
I would expect that the DSL for a more flexible 'layout' would take its
cue from the existing 'compile' rule. People already understand how a
'compile' rule works, so a similarly-working 'layout' rule would be a
natural fit. Continued support of the present 'layout' rule in
conjunction with the expanded notion is possible: block_given? can
easily distinguish between the two.
> I have never encountered a use case where being able to specify extra
> filters and sub-layouts in a layouting rule would be a great
> advantage. Can you share your use-cases for this feature? If this
> would turn out to be useful, it may indeed be worth adding to a
> future version of nanoc.
I should reiterate that the question was posed out of curiosity, due to
the inconsistency between 'compile' and 'layout', rather than because of
any immediate need. Other features already planned for 3.1.x, such as
generic (binary) asset handling, are far more important than this
(presently) theoretical issue.
Regarding use-cases: Filters allow us to compose resources, including
layouts, at a higher-level than raw HTML or whatever other output format
is needed. Not all filters, however, will be powerful enough to support
the embedded Ruby evaluation needed, at the very least, for the 'yield'
which merges the item content into the layout.
As an example, in the site I am converting, I created several partial
layouts. In some cases, creation and maintenance of these layouts would
be simplified if composed at a level higher than raw HTML or Haml, such
as with Markdown. No Markdown processor, however, supports embedded
Ruby. Consequently, a layout composed in Markdown would first need to be
filtered by a Markdown processor and finally by ERB (to 'yield' the
content).
As another example, I created a simple interpolation filter similar to
the following:
class Interpolator < Nanoc3::Filter
identifiers :interpolator
def run(content, params={})
bindings = params.stringify_keys
content.gsub(/%(?:(\w+)|{(\w+)})/) {|s| bindings[$1||$2] || s}
end
end
This provides basic variable substitution without the syntactic noise
and intrusiveness of ERB. For resources containing many such variables,
the difference in readability and maintainability between the terse
"%foo" and the verbose ERB "<%= foo %>" can be dramatic. Presently, I
employ this filter for some (non-HTML) content, but it is not difficult
to imagine using its use in a layout (HTML or not) for interpolation of
global configuration, or perhaps even item properties. This filter is
not powerful enough to handle embedded Ruby, so for a layout it would
require a pipeline of Interpolator followed by ERB to 'yield' the item
content.
It is true, of course, that such use-cases can be handled by other
mechanisms. Given the above example, an ugly approach would be to employ
Nanoc3::Helpers::Filtering#filter() within the layout itself to invoke
Interpolator upon its own content, though this seems very much a hack.
Alternately, you mentioned that it could be the responsibility of the
'compile' rule to invoke Interpolator on behalf of layouts which require
it. I noted, however, that doing so would incorrectly create a tight
coupling between the compile rule and the layout. Presently, a compile
rule does not need to know how a layout is processed. That information
is correctly encapsulated in the layout rule. Whether a layout is
HTML+ERB or Haml is immaterial to the compile rule which invokes it.
With the above theoretical example, in which a layout may be processed
by multiple filters, such knowledge should remain private to the layout.
It should not be the responsibility of the compile rule to apply the
necessary Interpolator + ERB pipeline.
-- ES