1

我正在制作一个样式指南,我在其中输出左侧显示的右侧代码。

我知道添加 %% 转义 ERB

我编写了一个助手,它获取块的内容并在两个地方呈现代码,一个显示 html,我希望另一个显示创建 html 的源 ERB。

问题是我得到了我想要 ERB 的 HTML。

查看代码

<%= display_code do %>
  <%= link_to "Button", "/style_guide, class: "btn" %>
<% end %>

助手代码

module StyleGuideHelper
  def display_code(&block)
    content = with_output_buffer(&block)
    html = ""
    html << content_tag(:div, content, class: "rendered-code")
    html << content_tag(:div, escape_erb(content), class: "source-code-preview")
    html.html_safe
  end

  def escape_erb(code)
    code = code.gsub("%=", "%%=")
  end
end

预期结果 按钮 <%= link_to "Button", "/style_guide, class: "btn" %>

实际结果 按钮 按钮

干杯

4

2 回答 2

0

问题是这个助手运行块(link_to "Button", ...)——它从不看到块内的源代码,只看到它的输出。您可以替换escape_erbh以捕获生成的 HTML,但这不会弹出到生成它的 ERB。

在我看来,您的选择是:

  1. 将示例分解为部分,然后创建一个助手,a) 呈现部分并 b) 显示基础文件。
  2. 将您的 ERB 片段指定为字符串(heredocs?),将字符串传递给帮助程序,并让帮助程序 a)通过评估它ERB.new(string).result(binding)以呈现结果并 b)显示字符串。
  3. 让助手确定视图的哪个部分调用了它,然后解析 .erb 以找到该块。需要注意的是,由于视图的编译方式,您所看到的内容的精确格式callers如有更改,恕不另行通知。
  4. 制作一个助手,使用疯狂的元编程 juju 来评估 ERB 上下文以及您自己的特殊上下文中的块,该上下文拦截正在评估的代码并将其转换回标记。

...按复杂性和成功几率的大致顺序排序。

于 2012-09-22T04:29:48.650 回答
0

下面的代码将允许您检索给定块的代码。

class ERBSource
  ERB = ::ActionView::Template::Handlers::ERB

  def self.for(block)
    new(block).source
  end

  attr_reader :block, :file, :line_number
  def initialize(block)
    @block = block
    @file, @line_number = *block.source_location
  end

  def source
    lines = File.readlines(file)

    relevant_lines = lines[(line_number - 1)..-1] || []

    extract_first_expression(relevant_lines)
  end

  private

  def extract_first_expression(lines)
    code = lines.slice[0,1].join # add the first two lines so it has to iterate less

    lines.each do |line|
      code << line
      return code if correct_syntax?(compile_erb(code))
    end
    raise SyntaxError, "unexpected $end"
  end

  def correct_syntax?(code)
    stderr = $stderr
    $stderr.reopen(IO::NULL)
    RubyVM::InstructionSequence.compile(code)
    $stderr.reopen(stderr)
    true
  rescue Exception
    $stderr.reopen(stderr)
    false
  end

  def compile_erb(code)
    ERB.erb_implementation.new(
      code,
      :escape => false,
      :trim => (ERB.erb_trim_mode == "-")
    ).src
  end
end

这是助手的样子

module StyleGuideHelper
  def render_example(name, &block)
    code = ERBSource.for(block)
    content_tag(:h2, name) +
      content_tag(:div, &block) +
      content_tag(:pre, content_tag(:code, code))
  end
end
于 2015-04-14T14:53:16.163 回答