module Webby module Filters class << self # Register a handler for a filter def register( filter, &block ) _handlers[filter.to_s] = block end # Process input through filters def process( renderer, page, input ) # Start a new cursor for this page Cursor.new(renderer, page).start_for(input) end # Access a filter handler def []( name ) _handlers[name] end # The registered filter handlers def _handlers @handlers ||= {} end # Instances of this class handle processing a set of filters # for a given renderer and page. # Note: The instance is passed as the second argument to filters # that require two parameters and can be used to access # information on the renderer, page, or filters being # processed. class Cursor attr_reader :renderer, :page, :filters def initialize(renderer, page) @renderer, @page = renderer, page @filters = Array(page.filter) @log = Logging::Logger[Webby::Renderer] @processed = 0 @prev_cursor = nil end def start_for(input) @prev_cursor = @renderer.instance_variable_get(:@_cursor) @renderer.instance_variable_set(:@_cursor, self) filters.inject(input) do |result, filter| handler = Filters[filter] raise ::Webby::Error, "unknown filter: #{filter.inspect}" if handler.nil? args = [result, self][0, handler.arity] _handle(filter, handler, *args) end ensure @renderer.instance_variable_set(:@_cursor, @prev_cursor) end # The list of filters yet to be processed def remaining_filters filters[@processed..-1] end # The name of the current filter def current_filter filters[@processed] end # Process arguments through a single filter def _handle(filter, handler, *args) result = handler.call(*args) @processed += 1 result rescue StandardError => err raise ::Webby::Error, "#{filter} filter error: #{err.message.inspect}" end end # class Cursor end # class << self end # module Filters end # module Webby Webby.require_all_libs_relative_to(__FILE__) # EOF