嵌套两个具有可选参数的自定义 Liquid 标签

san*_*ark 5 ruby tags dry liquid jekyll

如果一个类有多个可选标记作为参数传入,是否可以嵌套用 ruby​​ 编写的自定义 Liquid 标签?如果不提供相关示例,我很难描述这个问题。如果这个问题看起来过于具体,请原谅我。

给定以下来自 Octopress(一个 jekyll fork)的 ruby​​ 代码,它创建了一个自定义 Liquid 标签来解析标签。

# Title: Simple Image tag for Jekyll
# Authors: Brandon Mathis http://brandonmathis.com
#          Felix Schäfer, Frederic Hemberger
# Description: Easily output images with optional class names, width, height, title and alt attributes
#
# Syntax {% img [class name(s)] [http[s]:/]/path/to/image [width [height]] [title text | "title text" ["alt text"]] %}
#
# Examples:
# {% img /images/ninja.png Ninja Attack! %}
# {% img left half http://site.com/images/ninja.png Ninja Attack! %}
# {% img left half http://site.com/images/ninja.png 150 150 "Ninja Attack!" "Ninja in attack posture" %}
#
# Output:
# <img src="/images/ninja.png">
# <img class="left half" src="http://site.com/images/ninja.png" title="Ninja Attack!" alt="Ninja Attack!">
# <img class="left half" src="http://site.com/images/ninja.png" width="150" height="150" title="Ninja Attack!" alt="Ninja in attack posture">
#

module Jekyll

class ImageTag < Liquid::Tag
  @img = nil

  def initialize(tag_name, markup, tokens)
    attributes = ['class', 'src', 'width', 'height', 'title']

    if markup =~ /(?<class>\S.*\s+)?(?<src>(?:https?:\/\/|\/|\S+\/)\S+)(?:\s+(?<width>\d+))?(?:\s+(?<height>\d+))?(?<title>\s+.+)?/i
      @img = attributes.reduce({}) { |img, attr| img[attr] = $~[attr].strip if $~[attr]; img }
      if /(?:"|')(?<title>[^"']+)?(?:"|')\s+(?:"|')(?<alt>[^"']+)?(?:"|')/ =~ @img['title']
        @img['title']  = title
        @img['alt']    = alt
      else
        @img['alt']    = @img['title'].gsub!(/"/, '&#34;') if @img['title']
      end
      @img['class'].gsub!(/"/, '') if @img['class']
    end
    super
  end

  def render(context)
    if @img
      "<img #{@img.collect {|k,v| "#{k}=\"#{v}\"" if v}.join(" ")}>"
    else
      "Error processing input, expected syntax: {% img [class name(s)] [http[s]:/]/path/to/image [width [height]] [title text | \"title text\" [\"alt text\"]] %}"
    end
  end
end
end
Liquid::Template.register_tag('img', Jekyll::ImageTag)
Run Code Online (Sandbox Code Playgroud)

创建另一个自定义标记以展示 [ <img>] 元素的相同功能,但嵌套在 [ <figure>] 元素中,并且可能将图像 alt 描述或附加标记显示为 [ ] 元素的最佳方法是什么,该标记<figcaption>可能包含它自己的元素关联?或者甚至可能是元素的一系列类名,说明它是否应该居中。

换句话说,我可能希望输出类似于:

<figure class=center>
  <img src="/contra.jpg" alt="One of the greatest nintendo games of all time">
  <figcaption>Up Up Down Down Left Right Left Right B A B A <a href="http://www.youtube.com/contramoves/">Watch on Youtube</a></figcaption>
</figure>
Run Code Online (Sandbox Code Playgroud)

假设可以嵌套自定义 Liquid 标签是错误的吗?我确信我可以再次重写现有代码并稍微修改它以处理 [ <figcaption>]的附加属性,但这似乎相当多余并且违反了 DRY 原则。就目前而言,鉴于现有类本身采用可选标记,我对如何考虑可能的附加标记感到困惑。

san*_*ark 5

我需要做的是创建一个液体块,而不是一个液体标签。这个解决方案允许人们在理论上嵌套其他 Liquid 标签甚至其他 Liquid 块,这正是人们对 [ <figure>] 标签所期望的。

由于 Markdown 目前不支持 HTML5,这个基于 Liquid 的解决方案是一个很好的折衷方案。

 # Example:
 #
 # {% fig This is my caption! http://site.com/link.html Link Caption %}
 #   {% img center http://site.com/images/mylinks.png A collection of my favorite links %}
 # {% endfig %}
 #
 # Output:
 #
 # <figure class='center'>
 #    <img class="center" src="http://site.com/images/mylinks.png" title="A collection of my favorite links" >
 #    <figcaption>This is my caption!<a href='http://site.com/link.html'>Link Caption </a></figcaption>
 #</figure>
 #
 #

 module Jekyll

   class FigureTag < Liquid::Block
     include TemplateWrapper
     CaptionUrl = /(\S[\S\s]*)\s+(https?:\/\/\S+)\s+(.+)/i
     Caption = /(\S[\S\s]*)/
     def initialize(tag_name, markup, tokens)
       @title = nil
       @caption = nil
       if markup =~ CaptionUrl
         @caption = "\n\t\t<figcaption>#{$1}<a href='#{$2}'>#{$3}</a></figcaption>\n\t"
       elsif markup =~ Caption
         @caption = "\n\t\t<figcaption>#{$1}</figcaption>\n\t"
       end
       super
     end

     def render(context)
       output = super
       fig = super.join
       source = "\t<figure class='center'>\n\t\t"
       markdown = RDiscount.new(fig.lstrip).to_html[/<p>(.+)<\/p>/i]
       source += $1
       source += @caption if @caption
       source += "</figure>"
       source = safe_wrap(source)
       source
     end
   end
 end

 Liquid::Template.register_tag('fig', Jekyll::FigureTag)
Run Code Online (Sandbox Code Playgroud)