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.*'
end
For 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
end
Alternatively, there is a shorthand using Nanoc::Filter.define
:
Nanoc::Filter.define(:censor) do |content, params|
content.gsub('Nanoc sucks', 'Nanoc rocks')
end
Each 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)
end
The #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
end
Filters 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
end
Text-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)
end
A 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