我正在尝试创建一个返回动态生成的HTML的Sinatra帮助器。我以为我会在这里使用一个字符串作为静态位,使用一个lambda来计算动态部分。
foo_helper.rb
:
require 'erb'
module FooHelper
def tabs(selected)
template = ERB.new <<~HERE
<ul class="nav nav-tabs">
<li class="nav-item"><a class="nav-link <%= 'active' if selected == 'favorites' %>" href="/foo/favorites">Favorites</a></li>
<li class="nav-item"><a class="nav-link <%= 'active' if selected == 'all' %>" href="/foo">All</a></li>
<%= alpha.call %>
</ul>
HERE
# binding to a string works as expected
# alpha = "<li class='nav-item'><a class='nav-link' href='/foo/a'>A</a></li>"
# binding to a lambda, doesn't
alpha = lambda {
('a'..'z').each do |letter|
"<li class='nav-item'><a class='nav-link #{ 'active' if selected == letter }' href='/foo/#{letter}'>#{letter}</a></li>"
end
}
template.result(binding)
end
end
foo_controller.rb
:
class FooController < ApplicationController
helpers FooHelper if defined?(FooHelper)
...
end
index.erb
:
...
<%= tabs('favorites') %>
...
结果:
显示范围,而不是单个li
。
我在lambda中遗漏了什么吗?
**编辑**
纠正了众多错误。
答案 0 :(得分:1)
您的代码中存在太多错误。
@nav
在模块级别定义,但在实例级别访问,因此您在需要时获得nil
。foo.(123)
@nav.foo(binding)
,真的吗?什么是(假设的)@nav
类型?该类型是否具有实例方法foo
?<%= foo %>
不会执行foo
,因为它是局部变量,而不是方法。答案 1 :(得分:0)
之所以渲染a..z
是因为Range#each
方法(从lambda内部调用)对每个元素执行给定的块,然后再次返回范围本身。
您想在这里使用的是Enumerable#map
方法。与#each
类似,它也为每个元素执行一个块,但是该块的返回值将在新数组中返回。
为进行比较:
p ("a".."c").each { |x| x.upcase }
#=> "a".."c"
p ("a".."c").map { |x| x.upcase }
#=> ["A", "B", "C"]