class Webby::Renderer - webby-0.9.4 Documentation

# class Webby::Renderer

The Webby::Renderer is used to filter and layout the text found in the resource page files in the content directory.

A page is filtered based on the settings of the ‘filter’ option in the page’s meta-data information. For example, if ‘textile’ is specified as a filter, then the page will be run through the RedCloth markup filter. More than one filter can be used on a page; they will be run in the order specified in the meta-data.

A page is rendered into a layout specified by the ‘layout’ option in the page’s meta-data information.

### Attributes

logger[R]

### Public Class Methods

new( page ) click to toggle source

Create a new renderer for the given page. The renderer will apply the desired filters to the page (from the page’s meta-data) and then render the filtered page into the desired layout.

    # File lib/webby/renderer.rb, line 61
    def initialize( page )
      unless page.instance_of? Resources::Page
        raise ArgumentError,
              "only page resources can be rendered '#{page.path}'"
      end

      @page = page
      @pages = Resources.pages
      @partials = Resources.partials
      @content = nil
      @config = ::Webby.site

      @_bindings = []
      @_content_for = {}
      @logger = Logging::Logger[self]
    end

write( page ) click to toggle source

Render the given page and write the resulting output to the page’s destination. If the page uses pagination, then multiple destination files will be created – one for each paginated data set in the page.

    # File lib/webby/renderer.rb, line 35
    def self.write( page )
      renderer = self.new(page)

      loop {
        dest = page.destination
        FileUtils.mkdir_p ::File.dirname(dest)
        journal.create_or_update(page)

        text = renderer._layout_page
        unless text.nil?
          ::File.open(dest, 'w') {|fd| fd.write(text)}
        end

        break unless renderer._next_page
      }
    end

### Public Instance Methods

_binding() click to toggle source

Returns the binding in the scope of this Renderer object.

    # File lib/webby/renderer.rb, line 380
    def _binding() binding end

_configure_locals( locals ) click to toggle source

Configure local variables in the scope of the current binding returned by the `get_binding` method. The locals should be given as a hash of name / value pairs.

    # File lib/webby/renderer.rb, line 327
    def _configure_locals( locals )
      return if locals.nil?

      locals.each do |k,v|
        Thread.current[:value] = v
        definition = "#{k} = Thread.current[:value]"
        eval(definition, get_binding)
      end
    end

_find_partial( part ) click to toggle source

Attempts to locate a partial by name. If only the partial name is given, then the current directory of the page being rendered is searched for the partial. If a full path is given, then the partial is searched for in that directory.

Raises a Webby::Error if the partial could not be found.

    # File lib/webby/renderer.rb, line 344
    def _find_partial( part )
      case part
      when String
        part_dir = ::File.dirname(part)
        part_dir = @page.dir if part_dir == '.'

        part_fn = ::File.basename(part)
        part_fn = '_' + part_fn unless part_fn =~ /^_/

        p = Resources.partials.find(
            :filename => part_fn, :in_directory => part_dir ) rescue nil
        raise ::Webby::Error, "could not find partial '#{part}'" if p.nil?
        p
      when ::Webby::Resources::Partial
        part
      else raise ::Webby::Error, "expecting a partial or a partial name" end
    end

_guard( str ) click to toggle source

This method will put filter guards around the given input string. This will protect the string from being processed by any remaining filters (specifically the textile filter).

The string is returned unchanged if there are no remaining filters to guard against.

    # File lib/webby/renderer.rb, line 369
    def _guard( str )
      return str unless @_cursor

      if @_cursor.remaining_filters.include? 'textile'
        str = "<notextile>\n%s\n</notextile>" % str
      end
      str
    end

_layout_page → string click to toggle source

Apply the desired filters to the page and then render the filtered page into the desired layout. The filters to apply to the page are determined from the page’s meta-data. The layout to use is also determined from the page’s meta-data.

    # File lib/webby/renderer.rb, line 228
    def _layout_page
      @content = _render_page

      _track_rendering(@page.path) {
        _render_layout_for(@page)
      }
      raise ::Webby::Error, "rendering stack corrupted" unless @@stack.empty?

      @content
    rescue ::Webby::Error => err
      logger.error "while rendering page '#{@page.path}'"
      logger.error err.message
      return nil
    rescue Exception => err
      logger.error "while rendering page '#{@page.path}'"
      logger.fatal err
    ensure
      @content = nil
      @@stack.clear
    end

_next_page → true or false click to toggle source

Returns `true` if there is a next page to render. Returns `false` if there is no next page or if pagination has not been configured for the current page.

    # File lib/webby/renderer.rb, line 273
    def _next_page
      return false unless defined? @pager and @pager

      # go to the next page; break out if there is no next page
      if @pager.next?
        @pager = @pager.next
        @_content_for.clear
        @_bindings.clear
      else
        @pager.pager.reset
        @pager = nil
        return false
      end

      true
    end

_render_layout_for( resource ) click to toggle source

Render the layout for the given resource. If the resource does not have a layout, then this method returns immediately.

    # File lib/webby/renderer.rb, line 255
    def _render_layout_for( res )
      return unless res.layout
      lyt = Resources.find_layout(res.layout)
      return if lyt.nil?

      _track_rendering(lyt.path) {
        @content = Filters.process(self, lyt, lyt._read)
        _render_layout_for(lyt)
      }
    end

_render_page → string click to toggle source

Apply the desired filters to the page. The filters to apply are determined from the page’s meta-data.

    # File lib/webby/renderer.rb, line 200
    def _render_page
      _track_rendering(@page.path) {
        Filters.process(self, @page, @page._read)
      }
    end

_render_partial( partial, :locals => {} ) → string click to toggle source

Render the given partial into the current page. The :locals are a hash of key / value pairs that will be set as local variables in the scope of the partial when it is rendered.

    # File lib/webby/renderer.rb, line 213
    def _render_partial( part, opts = {} )
      _track_rendering(part.path) {
        _configure_locals(opts[:locals])
        Filters.process(self, part, part._read)
      }
    end

_track_rendering( path ) {block} click to toggle source

Keep track of the page rendering for the given path. The block is where the the page will be rendered.

This method keeps a stack of the current pages being rendeered. It looks for duplicates in the stack – an indication of a rendering loop. When a rendering loop is detected, an error is raised.

This method returns whatever is returned from the block.

    # File lib/webby/renderer.rb, line 302
    def _track_rendering( path )
      loop_error = @@stack.include? path
      @@stack << path
      @_bindings << _binding

      if loop_error
        msg = "rendering loop detected for '#{path}'\n"
        msg << "    current rendering stack\n\t"
        msg << @@stack.join("\n\t")
        raise ::Webby::Error, msg
      end

      yield
    ensure
      @@stack.pop if path == @@stack.last
      @_bindings.pop
    end

get_binding → binding click to toggle source

Returns the current binding for the renderer.

    # File lib/webby/renderer.rb, line 190
    def get_binding
      @_bindings.last
    end

paginate( items, per_page ) {|item| block} click to toggle source

Iterate the given block for each item selected from the items array using the given number of items per_page. The first time the page is rendered, the items passed to the block are selected using the range (0…per_page). The next rendering selects (per_page…2*per_page). This continues until all items have been paginated.

Calling this method creates a `@pager` object that can be accessed from the page. The `@pager` contains information about the next page, the current page number, the previous page, and the number of items in the current page.

    # File lib/webby/renderer.rb, line 177
    def paginate( items, count, &block )
      @pager ||= Paginator.new(items.length, count, @page) do |offset, per_page|
        items[offset,per_page]
      end.first

      @pager.each(&block)
    end

render( resource = nil, opts = {} ) → string click to toggle source

Render the given resource (a page or a partial) and return the results as a string. If a resource is not given, then the options hash should contain the name of a partial to render (:partial => ‘name’).

When a partial name is given, the partial is found by looking in the directory of the current page being rendered. Otherwise, the full path to the partial can be given.

If a :guard option is given as true, then the resulting string will be protected from processing by subsequent filters. Currently this only protects against the textile filter.

When rendering partials, local variables can be passed to the partial by setting them in hash passed as the :locals option.

#### Options¶ ↑

:partial<String>

  The partial to render

:locals<Hash>

  Locals values to define when rendering a partial

:guard<Boolean>

  Prevents the resulting string from being processed by subsequent filters (only textile for now)

#### Returns¶ ↑

A string that is the rendered page or partial.

#### Examples¶ ↑

    # render the partial "foo" using the given local variables
    render( :partial => "foo", :locals => {:bar => "value for bar"} )

    # find another page and render it into this page and protect the
    # resulting contents from further filters
    page = @pages.find( :title => "Chicken Coop" )
    render( page, :guard => true )

    # find a partial and render it using the given local variables
    partial = @partials.find( :filename => "foo", :in_directory => "/path" )
    render( partial, :locals => {:baz => "baztastic"} )

    # File lib/webby/renderer.rb, line 121
    def render( *args )
      opts = Hash === args.last ? args.pop : {}
      resource = args.first
      resource = _find_partial(opts[:partial]) if resource.nil?

      str = case resource
        when Resources::Page
          ::Webby::Renderer.new(resource)._render_page
        when Resources::Partial
          _render_partial(resource, opts)
        when Resources::Static
          resource._read
        else
          raise ::Webby::Error, "expecting a page or a partial but got '#{resource.class.name}'"
        end

      str = _guard(str) if opts[:guard]
      str
    end

render_page → string click to toggle source

This method is being deprecated. It is being made internal to the framework and really shouldn’t be used anymore.

    # File lib/webby/renderer.rb, line 147
    def render_page
      Webby.deprecated "render_page", "this method is being made internal to the framework"
      _render_page
    end

render_partial( partial, :locals => {} ) → string click to toggle source

This method is being deprecated. Please use the `render` method instead.

    # File lib/webby/renderer.rb, line 157
    def render_partial( part, opts = {} )
      Webby.deprecated "render_partial", "it is being replaced by the Renderer#render() method"
      opts[:partial] = part
      render opts
    end