Ruby ERB - 创建一个 content_for 方法
Ruby ERB - Create a content_for method
我目前正在为 gem 开发 ERB 视图 class。有了这个 class 我想为 ERB 模板提供一些辅助方法。
h(string)
这样的基本助手没问题。我发现 erbh
gem 帮助我更多地了解上下文的工作原理。
但现在我正在尝试创建一个 content_for
方法,就像 Rails 或 Sinatra 中的方法一样。
我第一次使用简单的 Proc
来捕获视图块,然后调用 call
方法来打印它。刚开始的时候还可以。
但是看完之后我看到wired thinks,有些内容打印了很多次。
所以我看了一下 Sinatra ContentFor helper 以了解他们是如何做到的,并且我复制了这个助手的一些方法。我没有错误,但是块 return 总是空的......我真的不知道为什么。
我对 ERB 的了解还不足以了解 ERB 缓冲的工作原理。
代码
这是解释我的代码状态的要点。我从我的库中提取了代码并稍微简化了它。
我想要什么?
我只是想让 content_for
方法像 Rails 和 Sinatra 那样工作。
谢谢!
读完这篇 blog article 我终于找到了为什么它不起作用。我不知道我是否以最佳方式和更简洁的方式完成了它,但它确实有效。
所以错误主要来自 ERB
初始化。通过使用 属性 而不是局部变量 eoutvar
它现在可以工作了。
erb = ERB.new(str, nil, "<>", "@_erbout")
我也稍微改变了 content_for
助手使用的 capture
方法。
现在看起来像这样(gist)
def content_for(key, content = nil, &block)
block ||= proc { |*| content }
content_blocks[key.to_sym] << capture_later(&block)
end
def content_for?(key)
content_blocks[key.to_sym].any?
end
def yield_content(key, default = nil)
return default if content_blocks[key.to_sym].empty?
content_blocks[key.to_sym].map { |b| capture(&b) }.join
end
def capture(&block)
@capture = nil
@_erbout, _buf_was = '', @_erbout
result = yield
@_erbout = _buf_was
result.strip.empty? && @capture ? @capture : result
end
def capture_later(&block)
proc { |*| @capture = capture(&block) }
end
我目前正在为 gem 开发 ERB 视图 class。有了这个 class 我想为 ERB 模板提供一些辅助方法。
h(string)
这样的基本助手没问题。我发现 erbh
gem 帮助我更多地了解上下文的工作原理。
但现在我正在尝试创建一个 content_for
方法,就像 Rails 或 Sinatra 中的方法一样。
我第一次使用简单的 Proc
来捕获视图块,然后调用 call
方法来打印它。刚开始的时候还可以。
但是看完之后我看到wired thinks,有些内容打印了很多次。
所以我看了一下 Sinatra ContentFor helper 以了解他们是如何做到的,并且我复制了这个助手的一些方法。我没有错误,但是块 return 总是空的......我真的不知道为什么。
我对 ERB 的了解还不足以了解 ERB 缓冲的工作原理。
代码
这是解释我的代码状态的要点。我从我的库中提取了代码并稍微简化了它。
我想要什么?
我只是想让 content_for
方法像 Rails 和 Sinatra 那样工作。
谢谢!
读完这篇 blog article 我终于找到了为什么它不起作用。我不知道我是否以最佳方式和更简洁的方式完成了它,但它确实有效。
所以错误主要来自 ERB
初始化。通过使用 属性 而不是局部变量 eoutvar
它现在可以工作了。
erb = ERB.new(str, nil, "<>", "@_erbout")
我也稍微改变了 content_for
助手使用的 capture
方法。
现在看起来像这样(gist)
def content_for(key, content = nil, &block)
block ||= proc { |*| content }
content_blocks[key.to_sym] << capture_later(&block)
end
def content_for?(key)
content_blocks[key.to_sym].any?
end
def yield_content(key, default = nil)
return default if content_blocks[key.to_sym].empty?
content_blocks[key.to_sym].map { |b| capture(&b) }.join
end
def capture(&block)
@capture = nil
@_erbout, _buf_was = '', @_erbout
result = yield
@_erbout = _buf_was
result.strip.empty? && @capture ? @capture : result
end
def capture_later(&block)
proc { |*| @capture = capture(&block) }
end