Merge pull request #1490 from penibelst/allow-include-read-override
Extract include tag read file in a method
This commit is contained in:
commit
793eb96a77
|
@ -2,20 +2,28 @@ module Jekyll
|
||||||
module Tags
|
module Tags
|
||||||
class IncludeTag < Liquid::Tag
|
class IncludeTag < Liquid::Tag
|
||||||
|
|
||||||
MATCHER = /([\w-]+)\s*=\s*(?:"([^"\\]*(?:\\.[^"\\]*)*)"|'([^'\\]*(?:\\.[^'\\]*)*)'|([\w\.-]+))/
|
SYNTAX_EXAMPLE = "{% include file.ext param='value' param2='value' %}"
|
||||||
|
|
||||||
|
VALID_SYNTAX = /([\w-]+)\s*=\s*(?:"([^"\\]*(?:\\.[^"\\]*)*)"|'([^'\\]*(?:\\.[^'\\]*)*)'|([\w\.-]+))/
|
||||||
|
|
||||||
|
INCLUDES_DIR = '_includes'
|
||||||
|
|
||||||
def initialize(tag_name, markup, tokens)
|
def initialize(tag_name, markup, tokens)
|
||||||
super
|
super
|
||||||
@file, @params = markup.strip.split(' ', 2);
|
@file, @params = markup.strip.split(' ', 2);
|
||||||
|
validate_syntax
|
||||||
|
end
|
||||||
|
|
||||||
|
def validate_syntax
|
||||||
|
validate_file_name
|
||||||
|
validate_params if @params
|
||||||
end
|
end
|
||||||
|
|
||||||
def parse_params(context)
|
def parse_params(context)
|
||||||
validate_syntax
|
|
||||||
|
|
||||||
params = {}
|
params = {}
|
||||||
markup = @params
|
markup = @params
|
||||||
|
|
||||||
while match = MATCHER.match(markup) do
|
while match = VALID_SYNTAX.match(markup) do
|
||||||
markup = markup[match.end(0)..-1]
|
markup = markup[match.end(0)..-1]
|
||||||
|
|
||||||
value = if match[2]
|
value = if match[2]
|
||||||
|
@ -31,32 +39,49 @@ module Jekyll
|
||||||
params
|
params
|
||||||
end
|
end
|
||||||
|
|
||||||
# ensure the entire markup string from start to end is valid syntax, and params are separated by spaces
|
def validate_file_name
|
||||||
def validate_syntax
|
if @file !~ /^[a-zA-Z0-9_\/\.-]+$/ || @file =~ /\.\// || @file =~ /\/\./
|
||||||
full_matcher = Regexp.compile('\A\s*(?:' + MATCHER.to_s + '(?=\s|\z)\s*)*\z')
|
raise ArgumentError.new <<-eos
|
||||||
unless @params =~ full_matcher
|
Invalid syntax for include tag. File contains invalid characters or sequences:
|
||||||
raise SyntaxError.new <<-eos
|
|
||||||
|
#{@file}
|
||||||
|
|
||||||
|
Valid syntax:
|
||||||
|
|
||||||
|
#{SYNTAX_EXAMPLE}
|
||||||
|
|
||||||
|
eos
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def validate_params
|
||||||
|
full_valid_syntax = Regexp.compile('\A\s*(?:' + VALID_SYNTAX.to_s + '(?=\s|\z)\s*)*\z')
|
||||||
|
unless @params =~ full_valid_syntax
|
||||||
|
raise ArgumentError.new <<-eos
|
||||||
Invalid syntax for include tag:
|
Invalid syntax for include tag:
|
||||||
|
|
||||||
#{@params}
|
#{@params}
|
||||||
|
|
||||||
Valid syntax:
|
Valid syntax:
|
||||||
|
|
||||||
{% include file.ext param='value' param2="value" %}
|
#{SYNTAX_EXAMPLE}
|
||||||
|
|
||||||
eos
|
eos
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def render(context)
|
def render(context)
|
||||||
includes_dir = File.join(context.registers[:site].source, '_includes')
|
dir = File.join(context.registers[:site].source, INCLUDES_DIR)
|
||||||
|
if error = validate_dir(dir, context.registers[:site].safe)
|
||||||
if error = validate_file(includes_dir)
|
|
||||||
return error
|
return error
|
||||||
end
|
end
|
||||||
|
|
||||||
source = File.read(File.join(includes_dir, @file))
|
file = File.join(dir, @file)
|
||||||
partial = Liquid::Template.parse(source)
|
if error = validate_file(dir, context.registers[:site].safe)
|
||||||
|
return error
|
||||||
|
end
|
||||||
|
|
||||||
|
partial = Liquid::Template.parse(source(file))
|
||||||
|
|
||||||
context.stack do
|
context.stack do
|
||||||
context['include'] = parse_params(context) if @params
|
context['include'] = parse_params(context) if @params
|
||||||
|
@ -64,26 +89,28 @@ eos
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def validate_file(includes_dir)
|
def validate_dir(dir, safe)
|
||||||
if File.symlink?(includes_dir)
|
if File.symlink?(dir) && safe
|
||||||
return "Includes directory '#{includes_dir}' cannot be a symlink"
|
"Includes directory '#{dir}' cannot be a symlink"
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
if @file !~ /^[a-zA-Z0-9_\/\.-]+$/ || @file =~ /\.\// || @file =~ /\/\./
|
def validate_file(file, safe)
|
||||||
return "Include file '#{@file}' contains invalid characters or sequences"
|
|
||||||
end
|
|
||||||
|
|
||||||
file = File.join(includes_dir, @file)
|
|
||||||
if !File.exists?(file)
|
if !File.exists?(file)
|
||||||
return "Included file #{@file} not found in _includes directory"
|
"Included file '#{@file}' not found in '#{INCLUDES_DIR}' directory"
|
||||||
elsif File.symlink?(file)
|
elsif File.symlink?(file) && safe
|
||||||
return "The included file '_includes/#{@file}' should not be a symlink"
|
"The included file '#{INCLUDES_DIR}/#{@file}' should not be a symlink"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def blank?
|
def blank?
|
||||||
false
|
false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# This method allows to modify the file content by inheriting from the class.
|
||||||
|
def source(file)
|
||||||
|
File.read(file)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -373,7 +373,7 @@ CONTENT
|
||||||
end
|
end
|
||||||
|
|
||||||
context "with invalid parameter syntax" do
|
context "with invalid parameter syntax" do
|
||||||
should "throw a SyntaxError" do
|
should "throw a ArgumentError" do
|
||||||
content = <<CONTENT
|
content = <<CONTENT
|
||||||
---
|
---
|
||||||
title: Invalid parameter syntax
|
title: Invalid parameter syntax
|
||||||
|
@ -381,7 +381,7 @@ title: Invalid parameter syntax
|
||||||
|
|
||||||
{% include params.html param s="value" %}
|
{% include params.html param s="value" %}
|
||||||
CONTENT
|
CONTENT
|
||||||
assert_raise SyntaxError, 'Did not raise exception on invalid "include" syntax' do
|
assert_raise ArgumentError, 'Did not raise exception on invalid "include" syntax' do
|
||||||
create_post(content, {'permalink' => 'pretty', 'source' => source_dir, 'destination' => dest_dir, 'read_posts' => true})
|
create_post(content, {'permalink' => 'pretty', 'source' => source_dir, 'destination' => dest_dir, 'read_posts' => true})
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -392,7 +392,7 @@ title: Invalid parameter syntax
|
||||||
|
|
||||||
{% include params.html params="value %}
|
{% include params.html params="value %}
|
||||||
CONTENT
|
CONTENT
|
||||||
assert_raise SyntaxError, 'Did not raise exception on invalid "include" syntax' do
|
assert_raise ArgumentError, 'Did not raise exception on invalid "include" syntax' do
|
||||||
create_post(content, {'permalink' => 'pretty', 'source' => source_dir, 'destination' => dest_dir, 'read_posts' => true})
|
create_post(content, {'permalink' => 'pretty', 'source' => source_dir, 'destination' => dest_dir, 'read_posts' => true})
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue