Bra*_*rth 4 ruby ruby-on-rails erb
我正在制作一个样式指南,显示代码和输出.它目前的结构使得代码只需要描述一次,并以原始版本和解释版本显示,如下所示:
<% code = <<PLACE_THE_EXAMPLE_CODE_BETWEEN_THESE_TWO_LINES_EXACTLY_AS_YOU_WANT_IT_TO_APPEAR
<div>
#{ image_tag 'image.png' }
</div>
PLACE_THE_EXAMPLE_CODE_BETWEEN_THESE_TWO_LINES_EXACTLY_AS_YOU_WANT_IT_TO_APPEAR
%>
<%= raw code %>
<%= content_tag :pre, code, class: "prettyprint linenums" %>
Run Code Online (Sandbox Code Playgroud)
这很棒,而且相当容易维护.问题来自rails帮助程序,image_tag如上例所示.视图示例正确显示div中的图像,代码示例显示相关的HTML.在这种情况下,相关的HTML包含一个锚标记 - image_tag方法的结果,而不是调用本身.
我更喜欢代码示例来显示辅助方法,而不是它们的结果.我可以通过在文件中指定示例代码并渲染或读取文件来完成此工作.我更喜欢通过在变量中指定代码来完成这项工作,如上所述,但我似乎无法在erb块内部的字符串内部使用ERB分隔符.即使是最简单的情况<% foo = '<%= bar %>' %>也根本不起作用.我试过的语法(打<%% %%>和% %举例),使用从细节官方文档,但没有成功.
我可以在这里找到的唯一信息就是使用<%= "<" + "%=" %> link_to <%= image.css_tag.humanize %> <%= "%" + ">" %> %>,这在这个用例中是行不通的(如果有的话).
那么,有没有办法在ERB字符串中指定包含ERB end-delimiter(%>)的字符串,或者我使用稍微笨重的文件读取方法?谢谢!
编辑:
我想最终得到的是这个的工作版本:
<%# Idealized code - does not work %>
<% code = <<PLACE_THE_EXAMPLE_CODE_BETWEEN_THESE_TWO_LINES_EXACTLY_AS_YOU_WANT_IT_TO_APPEAR
<div>
<% image_tag 'image.png' %>
</div>
PLACE_THE_EXAMPLE_CODE_BETWEEN_THESE_TWO_LINES_EXACTLY_AS_YOU_WANT_IT_TO_APPEAR
%>
Run Code Online (Sandbox Code Playgroud)
这样<%= raw code %>会(继续)输出:
<div>
<img src="/images/image.png" alt="Image" />
</div>
Run Code Online (Sandbox Code Playgroud)
并<%= content_tag :pre, code, class: "prettyprint linenums" %>输出:
<pre class="prettyprint linenums">
<div>
<% image_tag 'image.png' %>
</div>
</pre>
Run Code Online (Sandbox Code Playgroud)
而不是使用变量时它当前做的事情,它是:
<pre class="prettyprint linenums">
<div>
<img src="/images/image.png" alt="Image" />
</div>
</pre>
Run Code Online (Sandbox Code Playgroud)
我希望用户能够复制代码示例并将其粘贴到新视图中,而无需将HTML转换回生成它们的帮助程序.我认为我基本上需要的是另一种ERB分隔符,就像字符串'和"(甚至%q{})变化一样.似乎即使最终的ERB定界符发生在字符串内部,它实际上也被处理为块的结尾.最简单的案例<% foo = '<%= bar %>' %>展示了我想要实现的目标.在生成器中,您可以使用<% foo = '<%%= bar %>' %>(或类似的东西),告诉它不要当时和那里处理ERB.这在从文件中读取时甚至在纯rb文件(如帮助程序)中都可以正常工作,但是最好将它放在视图中,在这种情况下,因为它很容易被我们操作设计师.
如果我理解你的话,你真正的问题是就插值而言,heredocs的行为就像双引号一样.所以你需要的是一个引用机制,其行为类似于单引号.Ruby有很多字符串引用机制,特别是我们有%q{...}:
<% code = %q{
<div>
#{ image_tag 'image.png' }
</div>
} %>
Run Code Online (Sandbox Code Playgroud)
如果您愿意%q|...|,可以使用其他分隔符:,%q(...)等等.当然仍有变化,但至少您不必担心插值问题.
如果您确实想使用heredoc,可以使用引号指定heredoc终止符,相应的引用样式将应用于内容:
<% code = <<'PLACE_THE_EXAMPLE_CODE_BETWEEN_THESE_TWO_LINES_EXACTLY_AS_YOU_WANT_IT_TO_APPEAR'
<div>
#{ image_tag 'image.png' }
</div>
PLACE_THE_EXAMPLE_CODE_BETWEEN_THESE_TWO_LINES_EXACTLY_AS_YOU_WANT_IT_TO_APPEAR
%>
Run Code Online (Sandbox Code Playgroud)
单引号<<'PLACE...'指定单引号规则(即无插值)适用于heredoc的内容.
当然,这些东西都不适用于嵌入式ERB,如下所示:
<% code = %q{
<div>
<% ... %>
</div>
} %>
Run Code Online (Sandbox Code Playgroud)
因为ERB解析器会将第一个%>看作外部的闭合定界符<% code....不要害怕,我想我有一个计划,可以在不涉及严重黑客或太多工作的情况下工作.
一些预赛:
:pattern其构造函数的选项更改分隔符.pancakes.js.coffee.erb正确的顺序使正确的事情发生.使用上面的方法,你可以添加自己的ERB模板格式,使用不同的分隔符,你可以让Rails使用这种新的格式来处理你的"特殊"部分,然后正常的ERB处理就会搞乱.
首先你需要连接Tilt.如果您lib/tilt/erb.rb在Tilt安装中查看,您会Tilt::ErubisTemplate在底部看到Erubis的内容.你应该能够子类化Tilt::ErubisTemplate并提供一个prepare覆盖,例如,:pattern => '<!--% %-->'向超类添加一个选项和平局.然后使用Rails初始值设定项中的Tilt和Sprockets注册它,如下所示:
Tilt.register(Your::Template::Subclass, 'klerb') # "kl" for "kludge" :)
Rails.application.assets.register_engine('.klerb', Your::Template::Subclass)
Run Code Online (Sandbox Code Playgroud)
现在,您的应用程序应该能够处理.klerb带有<!--% ... %-->模板分隔符的文件.你也可以用erb这样的名字来链接你的klerb,pancakes.html.erb.klerb文件将在ERB之前通过klerb; 这意味着像这样的模板(在一个名为的文件中whatever.html.erb.klerb):
<!--% code = <<PLACE_THE_EXAMPLE_CODE_BETWEEN_THESE_TWO_LINES_EXACTLY_AS_YOU_WANT_IT_TO_APPEAR
<div>
<% image_tag 'image.png' %>
</div>
PLACE_THE_EXAMPLE_CODE_BETWEEN_THESE_TWO_LINES_EXACTLY_AS_YOU_WANT_IT_TO_APPEAR
%-->
<!--%= "code = escape_the_erb_as_needed(%q{#{code}})" %-->
<% do_normal_erb_stuff %>
Run Code Online (Sandbox Code Playgroud)
会做正确的事.
你需要一个帮助器来实现escape_the_erb_as_needed当然的功能; 一些实验应该可以帮助你理清需要逃避的方式和方式.
所有这些看起来有点复杂,但实际上非常简单.我已经使用Tilt和Sprockets添加了自定义模板处理步骤,结果证明它非常简单; 弄清楚哪些简单的事情需要做些工作,但我已经为你完成了这项工作:
Tilt::Template子类,你通过小猪支持得到这个Tilt::ErubisTemplate.Tilt.register.Rails.application.assets.register_engine.