Filters
Filters are used for transforming an item’s content.
One commonly used filter is :erb, which interprets the item’s content as text with embedded Ruby. Another commonly used filter is :kramdown, which takes Markdown as its input and produces an HTML fragment.
Filters can be applied to both textual and binary items. An example of a binary filter is an image thumbnail filter. Filters can also convert textual content into binary files and vice versa; text-to-speech filters and OCR filters are therefore possible (but perhaps not very useful).
Filters are called within compilation rules. Here is an example rule that applies the :kramdown filter with the :auto_ids option set to false:
compile '/**/*.md' do
filter :kramdown, auto_ids: false
layout '/default.*'
endFor details on compilation rules, see the Rules page.
Nanoc comes with a handful of filters. See the Filters page for a list of filters bundled with Nanoc.
Writing filters
Filters are classes that inherit from Nanoc::Filter. Writing custom filters is done by subclassing this class and overriding the #run method, which is responsible for transforming the content.
Here is an example (textual) filter that replaces any occurrences of “Nanoc sucks” by “Nanoc rocks”:
class CensorFilter < Nanoc::Filter
identifier :censor
def run(content, params = {})
content.gsub('Nanoc sucks', 'Nanoc rocks')
end
endAlternatively, there is a shorthand using Nanoc::Filter.define:
Nanoc::Filter.define(:censor) do |content, params|
content.gsub('Nanoc sucks', 'Nanoc rocks')
endEach filter needs an identifier, so that it can be used in a call to #filter in a compilation rule. A filter identifier is set using #identifier. In the example above, the identifier is set to :censor.
The content argument to the #run method is a string that contains the content to be transformed. The params argument is taken from the #filter call in the compilation rule.
Filters that output textual content should return the filtered content at the end of the method.
Filters have access to @item, @item_rep, @items, @layouts, and @config. For details, see the Variables page.
Binary filters
A filter is marked as a binary filter using the #type method. For example:
class SampleBinaryFilter < Nanoc::Filter
identifier :sample_binary
type :binary
# (other code here)
endThe #run method for binary filters takes a filename argument, rather than a content argument. This filename argument contains the path to the file to be filtered. For example:
class SampleBinaryFilter < Nanoc::Filter
identifier :sample_binary
type :binary
def run(filename, params = {})
# (filter code here)
end
endFilters that output binary content should not return content, but rather write it to the location returned by the #output_filename method.
When writing filters that apply to binary data, make sure that you check the exit code and any errors generated by the sub-process that you are invoking (if any). If the sub-process exits with an error, you should raise an error in the filter.
Here is an example of a filter that resizes images to a given width:
class ResizeFilter < Nanoc::Filter
identifier :resize
type :binary
def run(filename, params = {})
system(
'sips',
'--resampleWidth', params[:width],
'--out', output_filename,
filename
)
end
endText-to-binary and binary-to-text filters
Filters that convert textual content to binary content or vice versa have the type declaration type :text => :binary or type :binary => :text, respectively. For example:
class SampleTextualToBinaryFilter < Nanoc::Filter
identifier :sample_textual_to_binary
type :text => :binary
# (other code here)
endA text-to-binary filter will receive a content string as its first argument, and should write the generated binary content to #output_filename. A binary-to-text filter will receive a filename string argument, and should return the filtered content.
Here is an example of an audio synthesis filter:
class SynthesiseAudio < Nanoc::Filter
identifier :synthesize_audio
type :text => :binary
def run(content, params = {})
system('say', content, '-o', output_filename)
end
end