Class: Middleman::TemplateRenderer

Inherits:
Object
  • Object
show all
Extended by:
Forwardable
Includes:
Contracts
Defined in:
middleman-core/lib/middleman-core/template_renderer.rb

Defined Under Namespace

Classes: Cache, TemplateNotFound

Constant Summary

Constants included from Contracts

Contracts::PATH_MATCHER

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Contracts

#Contract

Constructor Details

#initialize(app, path) ⇒ TemplateRenderer

Returns a new instance of TemplateRenderer.


108
109
110
111
112
# File 'middleman-core/lib/middleman-core/template_renderer.rb', line 108

def initialize(app, path)
  @app = app
  @path = path
  @vertices = ::Hamster::Set.empty
end

Instance Attribute Details

#verticesObject (readonly)

Returns the value of attribute vertices.


106
107
108
# File 'middleman-core/lib/middleman-core/template_renderer.rb', line 106

def vertices
  @vertices
end

Class Method Details

.cacheObject


31
32
33
# File 'middleman-core/lib/middleman-core/template_renderer.rb', line 31

def self.cache
  @_cache ||= Cache.new
end

.locate_layout(app, name, preferred_engine = nil) ⇒ Object


40
41
42
43
44
45
46
47
48
49
50
51
52
# File 'middleman-core/lib/middleman-core/template_renderer.rb', line 40

def self.locate_layout(app, name, preferred_engine = nil)
  resolve_opts = {}
  resolve_opts[:preferred_engine] = preferred_engine unless preferred_engine.nil?

  # Check layouts folder
  layout_file = resolve_template(app, File.join(app.config[:layouts_dir], name.to_s), resolve_opts)

  # If we didn't find it, check root
  layout_file ||= resolve_template(app, name, resolve_opts)

  # Return the path
  layout_file
end

.resolve_template(app, request_path, options_hash = ::Middleman::EMPTY_HASH) ⇒ Object


59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
# File 'middleman-core/lib/middleman-core/template_renderer.rb', line 59

def self.resolve_template(app, request_path, options_hash = ::Middleman::EMPTY_HASH)
  # Find the path by searching
  relative_path = Util.strip_leading_slash(request_path.to_s)

  # By default, any engine will do
  preferred_engines = []

  # If we're specifically looking for a preferred engine
  if options_hash.key?(:preferred_engine)
    extension_class = ::Middleman::Util.tilt_class(options_hash[:preferred_engine])

    # Get a list of extensions for a preferred engine
    preferred_engines += ::Tilt.default_mapping.extensions_for(extension_class)
  end

  preferred_engines << '*'
  preferred_engines << nil if options_hash[:try_static]

  found_template = nil

  preferred_engines.each do |preferred_engine|
    path_with_ext = relative_path.dup
    path_with_ext = "#{path_with_ext}.#{preferred_engine}" unless preferred_engine.nil?

    globbing = preferred_engine == '*'

    # Cache lookups in build mode only
    file = if app.build?
             cache.fetch(path_with_ext, preferred_engine) do
               app.files.find(:source, path_with_ext, globbing)
             end
           else
             app.files.find(:source, path_with_ext, globbing)
           end

    found_template = file if file && (preferred_engine.nil? || ::Middleman::Util.tilt_class(file[:full_path].to_s))
    break if found_template
  end

  # If we found one, return it
  found_template
end

Instance Method Details

#HashString

Render a template, with layout, given a path

Parameters:

Returns:

  • (String)

119
# File 'middleman-core/lib/middleman-core/template_renderer.rb', line 119

Contract Hash, Hash => String

#render(locals_hash = ::Middleman::EMPTY_HASH, options_hash = ::Middleman::EMPTY_HASH, &block) ⇒ Object


120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
# File 'middleman-core/lib/middleman-core/template_renderer.rb', line 120

def render(locals_hash = ::Middleman::EMPTY_HASH, options_hash = ::Middleman::EMPTY_HASH, &block)
  path = @path.dup

  locals = if locals_hash == ::Middleman::EMPTY_HASH
             locals_hash
           else
             locals_hash.dup.freeze
           end

  options = if options_hash == ::Middleman::EMPTY_HASH
              options_hash
            else
              options_hash.dup
            end

  extension = File.extname(path)
  engine = extension[1..-1].to_sym

  if defined?(::I18n)
    old_locale = ::I18n.locale
    ::I18n.locale = options[:locale] if options[:locale]

    # Backwards compat
    ::I18n.locale = options[:lang] if options[:lang]
  end

  # Sandboxed class for template eval
  context = @app.template_context_class.new(@app, locals, options)

  # Add extension helpers to context.
  @app.extensions.add_exposed_to_context(context)

  known_keys = %i[current_path paginate page_articles blog_controller lang locale data]

  locals.each do |k, _|
    next unless context.respond_to?(k) && !known_keys.include?(k.to_sym)

    msg = "Template local `#{k}` tried to overwrite an existing context value. Please rename the key when passing to `locals`"

    if @app.build?
      throw msg
    else
      @app.logger.error(msg)
    end
  end

  @vertices = ::Hamster::Set.empty

  content = ::Middleman::Util.instrument 'builder.output.resource.render-template', path: File.basename(path) do
    _render_with_all_renderers(path, locals, context, options, &block)
  end

  # If we need a layout and have a layout, use it
  layout_file = fetch_layout(engine, options)

  if layout_file
    layout_file = fetch_layout(engine, options)

    content = if layout_file
                layout_renderer = ::Middleman::FileRenderer.new(@app, layout_file[:relative_path].to_s)

                ::Middleman::Util.instrument 'builder.output.resource.render-layout', path: File.basename(layout_file[:relative_path].to_s) do
                  layout_renderer.render(locals, options, context) { content }.tap do
                    @vertices <<= ::Middleman::Dependencies::FileVertex.from_source_file(@app, layout_file)
                    @vertices |= layout_renderer.vertices
                  end
                end
              else
                content
              end
  end

  @vertices |= context.vertices

  # Return result
  content
ensure
  # Pop all the saved variables from earlier as we may be returning to a
  # previous render (layouts, partials, nested layouts).
  ::I18n.locale = old_locale if defined?(::I18n)
end