2014-01-03 22:15:02 +01:00
|
|
|
require 'tilt'
|
|
|
|
require 'active_support/core_ext/string/output_safety'
|
2014-07-03 04:04:34 +02:00
|
|
|
require 'active_support/core_ext/module/delegation'
|
|
|
|
require 'middleman-core/contracts'
|
2014-01-03 22:15:02 +01:00
|
|
|
|
2014-07-05 22:41:59 +02:00
|
|
|
::Tilt.mappings.delete('html') # WTF, Tilt?
|
|
|
|
::Tilt.mappings.delete('csv')
|
|
|
|
|
2014-01-03 22:15:02 +01:00
|
|
|
module Middleman
|
|
|
|
class FileRenderer
|
2014-07-05 20:17:41 +02:00
|
|
|
extend Forwardable
|
2014-07-03 04:04:34 +02:00
|
|
|
include Contracts
|
2014-07-05 20:17:41 +02:00
|
|
|
|
2014-01-03 22:15:02 +01:00
|
|
|
def self.cache
|
|
|
|
@_cache ||= ::Tilt::Cache.new
|
|
|
|
end
|
|
|
|
|
2014-07-05 20:17:41 +02:00
|
|
|
def_delegator :"self.class", :cache
|
2014-01-03 22:15:02 +01:00
|
|
|
|
|
|
|
def initialize(app, path)
|
|
|
|
@app = app
|
|
|
|
@path = path.to_s
|
|
|
|
end
|
|
|
|
|
|
|
|
# Render an on-disk file. Used for everything, including layouts.
|
|
|
|
#
|
|
|
|
# @param [Hash] locs
|
|
|
|
# @param [Hash] opts
|
|
|
|
# @param [Class] context
|
|
|
|
# @return [String]
|
2015-02-24 20:06:28 +01:00
|
|
|
Contract Hash, Hash, Any, Maybe[Proc] => String
|
2015-09-17 22:53:43 +02:00
|
|
|
def render(locs, opts, context, &block)
|
2014-01-03 22:15:02 +01:00
|
|
|
path = @path.dup
|
|
|
|
|
|
|
|
# Detect the remdering engine from the extension
|
|
|
|
extension = File.extname(path)
|
|
|
|
engine = extension[1..-1].to_sym
|
|
|
|
|
|
|
|
# Store last engine for later (could be inside nested renders)
|
2015-11-28 00:26:46 +01:00
|
|
|
context.current_engine, engine_was = engine, context.current_engine
|
2014-01-03 22:15:02 +01:00
|
|
|
|
|
|
|
# Save current buffer for later
|
2014-05-24 09:22:09 +02:00
|
|
|
buf_was = context.save_buffer
|
2014-01-03 22:15:02 +01:00
|
|
|
|
|
|
|
# Read from disk or cache the contents of the file
|
|
|
|
body = if opts[:template_body]
|
|
|
|
opts.delete(:template_body)
|
|
|
|
else
|
2014-04-29 20:43:05 +02:00
|
|
|
template_data_for_file
|
2014-01-03 22:15:02 +01:00
|
|
|
end
|
|
|
|
|
|
|
|
# Merge per-extension options from config
|
|
|
|
extension = File.extname(path)
|
2016-01-23 00:57:07 +01:00
|
|
|
options = {}.merge!(opts).merge!(options_for_ext(extension))
|
2014-01-03 22:15:02 +01:00
|
|
|
options[:outvar] ||= '@_out_buf'
|
2015-06-17 01:47:42 +02:00
|
|
|
options[:context] = context
|
2014-01-03 22:15:02 +01:00
|
|
|
options.delete(:layout)
|
|
|
|
|
|
|
|
# Overwrite with frontmatter options
|
|
|
|
options = options.deep_merge(options[:renderer_options]) if options[:renderer_options]
|
|
|
|
|
|
|
|
template_class = ::Tilt[path]
|
2015-05-04 00:38:18 +02:00
|
|
|
|
2014-01-03 22:15:02 +01:00
|
|
|
# Allow hooks to manipulate the template before render
|
2015-05-04 00:38:18 +02:00
|
|
|
body = @app.callbacks_for(:before_render).reduce(body) do |sum, callback|
|
|
|
|
callback.call(sum, path, locs, template_class) || sum
|
2014-01-03 22:15:02 +01:00
|
|
|
end
|
|
|
|
|
|
|
|
# Read compiled template from disk or cache
|
2015-06-17 01:47:42 +02:00
|
|
|
template = ::Tilt.new(path, 1, options) { body }
|
|
|
|
# template = cache.fetch(:compiled_template, extension, options, body) do
|
|
|
|
# ::Tilt.new(path, 1, options) { body }
|
|
|
|
# end
|
2014-01-03 22:15:02 +01:00
|
|
|
|
|
|
|
# Render using Tilt
|
2016-01-22 23:25:02 +01:00
|
|
|
# content = ::Middleman::Util.instrument 'render.tilt', path: path do
|
|
|
|
# template.render(context, locs, &block)
|
|
|
|
# end
|
|
|
|
content = template.render(context, locs, &block)
|
2014-01-03 22:15:02 +01:00
|
|
|
|
|
|
|
# Allow hooks to manipulate the result after render
|
2015-05-06 09:16:30 +02:00
|
|
|
content = @app.callbacks_for(:after_render).reduce(content) do |sum, callback|
|
2015-05-04 00:38:18 +02:00
|
|
|
callback.call(sum, path, locs, template_class) || sum
|
2014-01-03 22:15:02 +01:00
|
|
|
end
|
|
|
|
|
|
|
|
output = ::ActiveSupport::SafeBuffer.new ''
|
|
|
|
output.safe_concat content
|
|
|
|
output
|
|
|
|
ensure
|
|
|
|
# Reset stored buffer
|
2014-05-24 09:22:09 +02:00
|
|
|
context.restore_buffer(buf_was)
|
2014-01-03 22:15:02 +01:00
|
|
|
context.current_engine = engine_was
|
|
|
|
end
|
|
|
|
|
|
|
|
# Get the template data from a path
|
|
|
|
# @param [String] path
|
|
|
|
# @return [String]
|
2015-04-24 19:26:42 +02:00
|
|
|
Contract String
|
2014-04-29 20:43:05 +02:00
|
|
|
def template_data_for_file
|
2016-01-20 22:34:12 +01:00
|
|
|
file = @app.files.find(:source, @path)
|
|
|
|
|
|
|
|
if @app.extensions[:front_matter] || (file && !file[:types].include?(:no_frontmatter))
|
2016-01-20 20:50:25 +01:00
|
|
|
result = @app.extensions[:front_matter].template_data_for_file(@path)
|
|
|
|
return result unless result.nil?
|
2014-01-03 22:15:02 +01:00
|
|
|
end
|
2016-01-20 20:50:25 +01:00
|
|
|
|
|
|
|
file ? file.read : File.read(@path)
|
2014-01-03 22:15:02 +01:00
|
|
|
end
|
|
|
|
|
2014-04-29 19:50:21 +02:00
|
|
|
protected
|
2014-01-03 22:15:02 +01:00
|
|
|
|
|
|
|
# Get a hash of configuration options for a given file extension, from
|
|
|
|
# config.rb
|
|
|
|
#
|
|
|
|
# @param [String] ext
|
|
|
|
# @return [Hash]
|
2014-07-03 04:04:34 +02:00
|
|
|
Contract String => Hash
|
2014-01-03 22:15:02 +01:00
|
|
|
def options_for_ext(ext)
|
|
|
|
# Read options for extension from config/Tilt or cache
|
|
|
|
cache.fetch(:options_for_ext, ext) do
|
|
|
|
options = {}
|
|
|
|
|
|
|
|
# Find all the engines which handle this extension in tilt. Look for
|
|
|
|
# config variables of that name and merge it
|
|
|
|
extension_class = ::Tilt[ext]
|
|
|
|
::Tilt.mappings.each do |mapping_ext, engines|
|
|
|
|
next unless engines.include? extension_class
|
|
|
|
engine_options = @app.config[mapping_ext.to_sym] || {}
|
|
|
|
options.merge!(engine_options)
|
|
|
|
end
|
|
|
|
|
|
|
|
options
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2014-03-30 01:21:49 +01:00
|
|
|
end
|