[英]Ruby: Capturing multiple lines in a block
我有一个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
的方法应采用模板文件中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
我知道,它记录在案 :yield只返回在块上求值的最后一个表达式。 proc.call
也是如此。
我查看了rails content_tag
帮助器的源代码,并尝试将其复制,因为它的功能基本上与我在此处想要的相同。 但是,将&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( ENCODING )
我现在已经动脑筋了好几个小时……我不仅能获得方法的最后一线,还能得到更多……有人有想法吗?
您不能实现任何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
这是一个使用优化和全局变量的示例(令人毛骨悚然!):
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"
我自己定制了几个生成器,您基本上使用它们的方式类似于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对其进行“自定义”。
这将起作用:
<%= wrap_in_modules do
<<-STRING
class Engine < ::Rails::Engine
#{mountable? ? ('isolate_namespace ' + modules.first.to_s) : ''}
end
STRING
end %>
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.