繁体   English   中英

Ruby:捕获一个块中的多行

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM