【问题标题】:Ruby metaprogramming with method_missing to make a HTML DSL使用 method_missing 进行 Ruby 元编程以制作 HTML DSL
【发布时间】:2014-06-21 14:22:41
【问题描述】:

我正在学习元编程,并且正在尝试制作一些 DSL 来生成 HTML。 @result 实例变量未生成正确答案,因为当调用 h1 方法时,@result 实例变量被重置。有没有一种优雅的方式来处理这些“嵌套”方法调用(我知道Ruby doesn't technically have nested methods)。这是我的代码:

class HtmlDsl
  attr_reader :result
  def initialize(&block)
    instance_eval(&block)
  end

  private

  def method_missing(name, *args, &block)
    tag = name.to_s
    content = args.first
    @result = "<#{tag}>#{block_given? ? instance_eval(&block) : content}</#{tag}>"
  end
end

html = HtmlDsl.new do
  html do
    head do
      title 'yoyo'
    end
    body do
      h1 'hey'
    end
  end
end
p html.result # => "<html><body><h1>hey</h1></body></html>"
# desired result # => "<html><head><title>yoyo</title></head><body><h1>hey</h1></body></html>"

【问题讨论】:

  • 仅供参考,如果您对在生产级项目中使用 Ruby DSL 生成 HTML 感兴趣,可以查看Erector

标签: ruby metaprogramming method-missing


【解决方案1】:

你的问题不在于@result被重置,只是你将instance_eval(&amp;block)的返回值添加到@result中,这是块中的最后一行,而不是聚合块。这应该会更好(尽管不完美):

class HtmlDsl
  attr_reader :result
  def initialize(&block)
    instance_eval(&block)
  end

  private

  def method_missing(name, *args, &block)
    tag = name.to_s
    content = args.first
    (@result ||= '') << "<#{tag}>"
    if block_given?
      instance_eval(&block)
    else
      @result << content
    end
    @result <<  "</#{tag}>"
  end
end

那么现在:

html = HtmlDsl.new do
  html do
    head do
      title 'yoyo'
    end
    body do
      h1 'hey'
    end
  end
end
p html.result
#=> "<html><head><title>yoyo</title></head><body><h1>hey</h1></body></html>" 

我所做的是每个调用实际上都将一个 fragment 渲染到@result,因此内部调用会渲染内部片段,每个都用标签包装自己的内部片段。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-03-27
    • 2013-11-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-01
    • 1970-01-01
    相关资源
    最近更新 更多