Class: Roger::Renderer

Inherits:
Object
  • Object
show all
Defined in:
lib/roger/renderer.rb

Overview

Roger Renderer class

The renderer will set up an environment so you can consistently render templates within that environment

Constant Summary collapse

MAX_ALLOWED_TEMPLATE_NESTING =
10

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(env = {}, options = {}) ⇒ Renderer

Returns a new instance of Renderer.



89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
# File 'lib/roger/renderer.rb', line 89

def initialize(env = {}, options = {})
  @options = options
  @context = prepare_context(env)

  @paths = {
    partials: [@options[:partials_path]].flatten,
    layouts: [@options[:layouts_path]].flatten
  }

  # State data. Whenever we render a new template
  # we need to update:
  #
  # - data from front matter
  # - template_nesting
  # - current_template
  @data = {}
  @template_nesting = []
end

Instance Attribute Details

#dataObject

Returns the value of attribute data.



86
87
88
# File 'lib/roger/renderer.rb', line 86

def data
  @data
end

#template_nestingObject (readonly)

Returns the value of attribute template_nesting.



87
88
89
# File 'lib/roger/renderer.rb', line 87

def template_nesting
  @template_nesting
end

Class Method Details

.helper(mod) ⇒ Object

Register a helper module that should be included in every template context.



16
17
18
19
# File 'lib/roger/renderer.rb', line 16

def helper(mod)
  @helpers ||= []
  @helpers << mod
end

.helpersObject



21
22
23
# File 'lib/roger/renderer.rb', line 21

def helpers
  @helpers || []
end

.source_extension_for(path) ⇒ Object



44
45
46
47
48
49
50
51
# File 'lib/roger/renderer.rb', line 44

def source_extension_for(path)
  parts = File.basename(File.basename(path.to_s)).split(".")
  if parts.size > 2
    parts[-2..-1].join(".")
  else
    File.extname(path.to_s).sub(/^\./, "")
  end
end

.target_extension_for(path) ⇒ Object

Try to infer the final extension of the output file.



31
32
33
34
35
36
37
38
39
40
41
42
# File 'lib/roger/renderer.rb', line 31

def target_extension_for(path)
  if type = MIME::Types[target_mime_type_for(path)].first
    # Dirty little hack to enforce the use of .html instead of .htm
    if type.sub_type == "html"
      "html"
    else
      type.extensions.first
    end
  else
    File.extname(path.to_s).sub(/^\./, "")
  end
end

.target_mime_type_for(path) ⇒ Object

Try to figure out the mime type based on the Tilt class and if that doesn’t work we try to infer the type by looking at extensions (needed for .erb)



55
56
57
58
59
60
61
62
# File 'lib/roger/renderer.rb', line 55

def target_mime_type_for(path)
  mime =
    mime_type_from_template(path) ||
    mime_type_from_filename(path) ||
    mime_type_from_sub_extension(path)

  mime.to_s if mime
end

.will_render?(path) ⇒ Boolean

Will the renderer render this path to something meaningful?

Returns:

  • (Boolean)


26
27
28
# File 'lib/roger/renderer.rb', line 26

def will_render?(path)
  Tilt.templates_for(path.to_s).any?
end

Instance Method Details

#current_templateObject

The current template being rendered



170
171
172
# File 'lib/roger/renderer.rb', line 170

def current_template
  template_nesting.last
end

#parent_templateObject

The parent template in the nesting.



175
176
177
# File 'lib/roger/renderer.rb', line 175

def parent_template
  template_nesting[-2]
end

#render(path, options = {}, &block) ⇒ Object

The render function

The render function will take care of rendering the right thing in the right context. It will:

  • Wrap templates with layouts if it’s defined in the frontmatter and load them from the right layout path.

  • Render only partials if called from within an existing template

If you just want to render an arbitrary file, use #render_file instead

Parameters:

  • options (Hash) (defaults to: {})

    a customizable set of options

Options Hash (options):

  • :locals (Hash)

    Locals to use during rendering

  • :source (String)

    The source for the template

  • :layout (String, nil)

    The default layout to use



122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
# File 'lib/roger/renderer.rb', line 122

def render(path, options = {}, &block)
  template, layout = template_and_layout_for_render(path, options)

  # Set new current template
  template_nesting.push(template)

  # Copy data to our data store. A bit clunky; as this should be inherited
  @data = {}.update(@data).update(template.data)

  # Render the template first so we have access to
  # it's data in the layout.
  render_result = template.render(options[:locals] || {}, &block)

  # Wrap it in a layout
  layout.render do
    render_result
  end
ensure
  # Only pop the template from the nesting if we actually
  # put it on the nesting stack.
  template_nesting.pop if template
end

#render_file(path, options = {}) ⇒ Object

Render any file on disk. No magic. Just rendering.

A couple of things to keep in mind:

  • The file will be rendered in this rendering context

  • Does not have layouts or block style

  • When you pass a relative path and we are within another template it will be relative to that template.



154
155
156
157
158
159
160
161
162
163
164
165
166
167
# File 'lib/roger/renderer.rb', line 154

def render_file(path, options = {})
  pn = absolute_path_from_current_template(path)

  template = template(pn.to_s, nil)

  # Track rendered file also on the rendered stack
  template_nesting.push(template)

  template.render(options[:locals] || {})
ensure
  # Only pop the template from the nesting if we actually
  # put it on the nesting stack.
  template_nesting.pop if template
end