Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Re-implement handling Liquid blocks in excerpts #7250

Merged
merged 5 commits into from Nov 4, 2018
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
50 changes: 29 additions & 21 deletions lib/jekyll/excerpt.rb
Expand Up @@ -131,36 +131,45 @@ def render_with_liquid?
#
# Returns excerpt String

LIQUID_TAG_REGEX = %r!{%-?\s*(\w+).+\s*-?%}!m
LIQUID_TAG_REGEX = %r!{%-?\s*(\w+)\s*.*?-?%}!m
MKDWN_LINK_REF_REGEX = %r!^ {0,3}\[[^\]]+\]:.+$!

def extract_excerpt(doc_content)
head, _, tail = doc_content.to_s.partition(doc.excerpt_separator)

# append appropriate closing tag (to a Liquid block), to the "head" if the
# partitioning resulted in leaving the closing tag somewhere in the "tail"
# partition.
# append appropriate closing tag(s) (for each Liquid block), to the `head` if the
# partitioning resulted in leaving the closing tag somewhere in the `tail` partition.
if head.include?("{%")
head =~ LIQUID_TAG_REGEX
tag_name = Regexp.last_match(1)

if liquid_block?(tag_name) && head.match(%r!{%-?\s*end#{tag_name}\s*-?%}!).nil?
print_build_warning
modified = false
tag_names = head.scan(LIQUID_TAG_REGEX)
tag_names.flatten!
tag_names.reverse_each do |tag_name|
next unless liquid_block?(tag_name)
next if head =~ endtag_regex_stash(tag_name)

modified = true
head << "\n{% end#{tag_name} %}"
end
print_build_warning if modified
end

if tail.empty?
head
else
head.to_s.dup << "\n\n" << tail.scan(MKDWN_LINK_REF_REGEX).join("\n")
end
return head if tail.empty?

head << "\n\n" << tail.scan(MKDWN_LINK_REF_REGEX).join("\n")
end

private

def endtag_regex_stash(tag_name)
@endtag_regex_stash ||= {}
@endtag_regex_stash[tag_name] ||= %r!{%-?\s*end#{tag_name}.*?\s*-?%}!m
end

def liquid_block?(tag_name)
Liquid::Template.tags[tag_name].superclass == Liquid::Block
return false unless tag_name.is_a?(String)
return false if tag_name.start_with?("end")

Liquid::Template.tags[tag_name].ancestors.include?(Liquid::Block)
rescue NoMethodError
Jekyll.logger.error "Error:",
"A Liquid tag in the excerpt of #{doc.relative_path} couldn't be parsed."
Expand All @@ -169,12 +178,11 @@ def liquid_block?(tag_name)

def print_build_warning
Jekyll.logger.warn "Warning:", "Excerpt modified in #{doc.relative_path}!"
Jekyll.logger.warn "",
"Found a Liquid block containing separator '#{doc.excerpt_separator}'" \
" and has been modified with the appropriate closing tag."
Jekyll.logger.warn "",
"Feel free to define a custom excerpt or excerpt_separator in the" \
" document's Front Matter if the generated excerpt is unsatisfactory."
Jekyll.logger.warn "", "Found a Liquid block containing the excerpt separator" \
" #{doc.excerpt_separator.inspect}. "
Jekyll.logger.warn "", "The block has been modified with the appropriate closing tag."
Jekyll.logger.warn "", "Feel free to define a custom excerpt or excerpt_separator in the"
Jekyll.logger.warn "", "document's Front Matter if the generated excerpt is unsatisfactory."
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are all the same warning, not separate messages, correct?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@pathawks Yes. These calls are for the same warning.
I split them out into separate calls so that the messages appear to be formatted on the CLI.

I can't use a heredoc to emulate the formatting because Jekyll's logger squashes all whitespace into a single space char, which causes heredoc messages to simply print as a single line message.

end
end
end
23 changes: 18 additions & 5 deletions test/source/_posts/2018-01-28-closed-liquid-block-excerpt.markdown
Expand Up @@ -2,10 +2,23 @@
layout: post
---

{% if
page.layout == "post" %}
You’ll find this post in your `_posts` directory.
To add new posts, simply add a file in the `_posts` directory.
{% endif %}
{%
highlight
ruby
%}
{% assign foo = 'foobar' %}
{% raw
%}
def print_hi(name)
puts "Hi, #{name}"
end
print_hi('Tom')
#=> prints 'Hi, Tom' to STDOUT.
{%
endraw
%}
{%
endhighlight
%}

So let's talk business.
20 changes: 15 additions & 5 deletions test/source/_posts/2018-01-28-open-liquid-block-excerpt.markdown
Expand Up @@ -2,10 +2,20 @@
layout: post
---

{% if page.layout == "post" %}
You’ll find this post in your `_posts` directory.
{%
highlight
ruby
%}
{% assign foo = 'foobar' %}
{% raw
%}
def print_hi(name)
puts "Hi, #{name}"
end

{% else %}
print_hi('Tom')
#=> prints 'Hi, Tom' to STDOUT.
{% endraw %}
{% endhighlight %}

To add new posts, simply add a file in the `_posts` directory.
{% endif %}
So let's talk business.
25 changes: 18 additions & 7 deletions test/test_excerpt.rb
Expand Up @@ -184,12 +184,17 @@ def do_render(document)
@post = setup_post("2018-01-28-open-liquid-block-excerpt.markdown")
@excerpt = @post.data["excerpt"]

assert_includes @post.content, "{% if"
refute_includes @post.content.split("\n\n")[0], "{% endif %}"
head = @post.content.split("\n\n")[0]

assert_includes @post.content, "{%\n highlight\n"
assert_includes @post.content, "{% raw"
refute_includes head, "{% endraw %}"
refute_includes head, "{% endhighlight %}"
end

should "be appended to as necessary and generated" do
assert_includes @excerpt.content, "{% endif %}"
assert_includes @excerpt.content, "{% endraw %}"
assert_includes @excerpt.content, "{% endhighlight %}"
assert_equal true, @excerpt.is_a?(Jekyll::Excerpt)
end
end
Expand All @@ -201,13 +206,19 @@ def do_render(document)
@post = setup_post("2018-01-28-closed-liquid-block-excerpt.markdown")
@excerpt = @post.data["excerpt"]

assert_includes @post.content, "{% if"
assert_includes @post.content.split("\n\n")[0], "{% endif %}"
head = @post.content.split("\n\n")[0]

assert_includes @post.content, "{%\n highlight\n"
assert_includes @post.content, "{% raw"
assert_includes head, "{%\n endraw\n%}"
assert_includes head, "{%\n endhighlight\n%}"
end

should "not be appended to but generated as is" do
assert_includes @excerpt.content, "{% endif %}"
refute_includes @excerpt.content, "{% endif %}\n\n{% endif %}"
assert_includes @excerpt.content, "{%\n endraw\n%}"
assert_includes @excerpt.content, "{%\n endhighlight\n%}"
refute_includes @excerpt.content, "{%\n endraw\n%}\n\n{% endraw %}"
refute_includes @excerpt.content, "{%\n endhighlight\n%}\n\n{% endhighlight %}"
assert_equal true, @excerpt.is_a?(Jekyll::Excerpt)
end
end
Expand Down