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

时间:2012-03-05 15:52:14

标签: ruby tags dry jekyll liquid

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

给出以下ruby代码,源自Octopress(一个jekyll fork),它创建一个自定义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)

创建另一个自定义标记以展示[<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>

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

1 个答案:

答案 0 :(得分:4)

我需要做的是创建一个Liquid Block,而不是Liquid Tag。这个解决方案允许人们在理论上嵌套其他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)