Class: Webby::Renderer
- Inherits:
-
Object
- Object
- Webby::Renderer
- Includes:
- ERB::Util
- Defined in:
- lib/webby/renderer.rb
Overview
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.
Constant Summary collapse
- @@stack =
:stopdoc:
[]
Constants included from ERB::Util
Instance Attribute Summary collapse
-
#logger ⇒ Object
readonly
Returns the value of attribute logger.
Class Method Summary collapse
-
.write(page) ⇒ Object
call-seq: Renderer.write( page ).
Instance Method Summary collapse
-
#_binding ⇒ Object
Returns the binding in the scope of this Renderer object.
-
#_configure_locals(locals) ⇒ Object
call-seq: _configure_locals( locals ).
-
#_find_partial(part) ⇒ Object
Attempts to locate a partial by name.
-
#_guard(str) ⇒ Object
This method will put filter guards around the given input string.
-
#_layout_page ⇒ Object
call-seq: _layout_page => string.
-
#_next_page ⇒ Object
call-seq: _next_page => true or false.
-
#_render_layout_for(res) ⇒ Object
call-seq: _render_layout_for( resource ).
-
#_render_page ⇒ Object
call-seq: _render_page => string.
-
#_render_partial(part, opts = {}) ⇒ Object
call-seq: _render_partial( partial, :locals => {} ) => string.
-
#_track_rendering(path) ⇒ Object
call-seq: _track_rendering( path ) block.
-
#get_binding ⇒ Object
call-seq: get_binding => binding.
-
#initialize(page) ⇒ Renderer
constructor
call-seq: Renderer.new( page ).
-
#paginate(items, count, &block) ⇒ Object
call-seq: paginate( items, per_page ) {|item| block}.
-
#render(*args) ⇒ Object
call-seq: render( resource = nil, opts = {} ) => string.
-
#render_page ⇒ Object
call-seq: render_page => string.
-
#render_partial(part, opts = {}) ⇒ Object
call-seq: render_partial( partial, :locals => {} ) => string.
Methods included from ERB::Util
Constructor Details
#initialize(page) ⇒ Renderer
call-seq:
Renderer.new( page )
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.
61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 |
# 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 |
Instance Attribute Details
#logger ⇒ Object (readonly)
Returns the value of attribute logger.
52 53 54 |
# File 'lib/webby/renderer.rb', line 52 def logger @logger end |
Class Method Details
.write(page) ⇒ Object
call-seq:
Renderer.write( page )
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.
35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
# 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 |
Instance Method Details
#_binding ⇒ Object
Returns the binding in the scope of this Renderer object.
381 |
# File 'lib/webby/renderer.rb', line 381 def _binding() binding end |
#_configure_locals(locals) ⇒ Object
call-seq:
_configure_locals( locals )
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.
328 329 330 331 332 333 334 335 336 |
# File 'lib/webby/renderer.rb', line 328 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) ⇒ Object
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.
Raies a Webby::Error if the partial could not be found.
345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 |
# File 'lib/webby/renderer.rb', line 345 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 =~ %r/^_/ 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) ⇒ Object
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.
370 371 372 373 374 375 376 377 |
# File 'lib/webby/renderer.rb', line 370 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 ⇒ Object
call-seq:
_layout_page => string
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.
228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 |
# 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. return nil rescue => err logger.error "while rendering page '#{@page.path}'" logger.fatal err exit 1 ensure @content = nil @@stack.clear end |
#_next_page ⇒ Object
call-seq:
_next_page => true or false
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.
274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 |
# File 'lib/webby/renderer.rb', line 274 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(res) ⇒ Object
call-seq:
_render_layout_for( resource )
Render the layout for the given resource. If the resource does not have a layout, then this method returns immediately.
256 257 258 259 260 261 262 263 264 265 |
# File 'lib/webby/renderer.rb', line 256 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 ⇒ Object
call-seq:
_render_page => string
Apply the desired filters to the page. The filters to apply are determined from the page’s meta-data.
200 201 202 203 204 |
# File 'lib/webby/renderer.rb', line 200 def _render_page _track_rendering(@page.path) { Filters.process(self, @page, @page._read) } end |
#_render_partial(part, opts = {}) ⇒ Object
call-seq:
_render_partial( partial, :locals => {} ) => string
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.
213 214 215 216 217 218 |
# 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) ⇒ Object
call-seq:
_track_rendering( path ) {block}
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.
303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 |
# File 'lib/webby/renderer.rb', line 303 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 ⇒ Object
call-seq:
get_binding => binding
Returns the current binding for the renderer.
190 191 192 |
# File 'lib/webby/renderer.rb', line 190 def get_binding @_bindings.last end |
#paginate(items, count, &block) ⇒ Object
call-seq:
paginate( items, per_page ) {|item| block}
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.
177 178 179 180 181 182 183 |
# 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(*args) ⇒ Object
call-seq:
render( resource = nil, opts = {} ) => string
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"} )
121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 |
# 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 ⇒ Object
call-seq:
render_page => string
This method is being deprecated. It is being made internal to the framework and really shouldn’t be used anymore.
147 148 149 150 |
# 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(part, opts = {}) ⇒ Object
call-seq:
render_partial( partial, :locals => {} ) => string
This method is being deprecated. Please use the render
method instead.
157 158 159 160 161 |
# 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 |