我有一个rails生成器,可以根据某些erb模板创建文件。
我的目标是:
没有太复杂的模板文件。像这样:
# example of erb template file
<%= wrap_in_modules do
"class Engine < ::Rails::Engine"
if mountable?
"isolate_namespace #{modules.first}"
end
"end"
end %>
在解析和创建之后,上面的例子应该变成:
module Naming
module Extension
class Engine < ::Rails::Engine
isolate_namespace Naming
end
end
end
定义wrap_in_modules
的方法应该 all 模板文件中do..end
之间的行,以便使用该模块嵌套来处理它。
但目前却没有。它只需要最后一行。
这是我生成的文件的实际输出(与上面相同的例子)
module Naming
module Extension
end
end
end
正如您所看到的,只有do..end
之间的最后一行被包含在模块中。
好的,现在来了实际的wrap_in_modules
方法。
def wrap_in_modules
modules.reverse.inject(yield) do |content, mod|
"module #{mod}\n" << content.lines.map { |line| " #{line}" }.join << "\nend"
end
end
我知道,它的documented:yield只返回块上计算的最后一个表达式。而proc.call
。
我查看了导轨content_tag
helper的来源,并尝试复制它,因为它与我想要的基本相同。但是将带有&符号的&block
传递给方法并捕获它也不起作用。它只是空的!?
顺便说一下:另一件事是这个表示法将因erb:
的语法错误而失败<%= wrap_in_modules do -%>
Test test
<% end %>
lib/ruby/2.0.0/erb.rb:849:in `eval': (erb):1: syntax error, unexpected ')' (SyntaxError) ...r.concat(( wrap_in_modules do ).to_s); @output_buffer.concat...
... ^
(erb):4: syntax error, unexpected end-of-input, expecting ')'
@ output_buffer.force_encoding(的编码)
我现在已经把我的大脑震撼了好几个小时......我怎么能得到的不仅仅是方法的最后一行...有人有想法吗?
答案 0 :(得分:0)
您无法实现任何Ruby代码来完全按照您所希望的方式使用您的代码块。您有多个文字值但不对它们执行任何操作。这与询问如何执行此操作相同:
sum do
1
2
3
end #=> 6
无法做到。相反,您需要调用某种方法来累积字符串。例如:
# Evaluate the block in a context where `s` is defined to add strings to an array
wrap_in_modules do
s "class Engine < ::Rails::Engine"
if mountable?
s "isolate_namespace #{modules.first}"
end
s "end"
end
或
# Monkeypatch String class unary plus during this block invocation
# to add to your own collection
wrap_in_modules do
+"class Engine < ::Rails::Engine"
if mountable?
+"isolate_namespace #{modules.first}"
end
+"end"
end
以下是使用细化和全局变量(bleah!)的示例:
module UglyAggregator
refine String do
def +@
$all << self
end
end
end
# Do this within your actual scope
using UglyAggregator
def many_strings(&block)
$all = []
yield
$all.join
end
p many_strings{
+"a"
+"b"
}
#=> "ab"
答案 1 :(得分:0)
我自己定制了几个生成器,你基本上使用它们类似于rails视图:所有“固定”的文本只是“按原样”放置。它周围的红宝石意味着创建变量东西
类似的东西:
require 'spec_helper'
<% module_namespacing do -%>
describe <%= class_name %> do
<% for attribute in attributes -%>
it { should validate_presence_of(:<%= attribute.name %>) }
it { should validate_uniqueness_of(:<%= attribute.name %>) }
it { should ensure_length_of(:<%= attribute.name %>).is_at_least(3).is_at_most(255) }
<% end -%>
end
<% end -%>
这是一种完全不同的方法,但更简单,因为您可以简单地编写代码,然后使用ruby“自定义”它...
答案 2 :(得分:0)
这将有效:
<%= wrap_in_modules do
<<-STRING
class Engine < ::Rails::Engine
#{mountable? ? ('isolate_namespace ' + modules.first.to_s) : ''}
end
STRING
end %>