1

This question is partly answered in How do I remove leading whitespace chars from Ruby HEREDOC?

In Rails 3 there is a method #strip_heredoc, that strips all whitespace. But when inserting lines in an existing file, that already has identation, this doesn't work too well. An example:

begin
  insert_into_file "#{app_name}/config/environments/production.rb", <<-DEVISE_MAILER_STUFF.strip_heredoc, :before => "end\n"
    # for devise
    config.action_mailer.default_url_options = { :protocol => 'https', :host => 'YOURHOSTNAME' }
    config.action_mailer.delivery_method = :smtp
    something.each do |x|
      do stuff
    end
  DEVISE_MAILER_STUFF
end

The 'begin' and 'end' are only added to show that the source code has indentation. The heredoc has 4 spaces before the line '# for devise'. @strip_heredoc will delete all these spaces, but it will maintain the two extra spaces in the line 'do stuff'.

In environments/production.rb this will look like this:

MyApp::Application.configure do
  # Settings specified here will take precedence over those in config/application.rb
  # *** Identation here is two spaces! (We are in a block.) ***

# for devise
config.action_mailer.default_url_options = { :protocol => 'https', :host => 'YOURHOSTNAME' }
config.action_mailer.delivery_method = :smtp
something.each do |x|
  do stuff
end

  # back to original identation of this file
end # MyApp::Application.configure block!

How to solve this? Maybe there are other ways instead of a heredoc? I thought maybe strip_heredoc(min) where min is the minimum of spaces to keep, but that doesn't work well with tabs I guess. Or have the first line of the heredoc determine the left margin, like this:

puts <<-HEREDOC
  FIRST_LINE
    Real code here
HEREDOC

That 'FIRST_LINE' would be deleted by strip_heredoc, but it would also set the number of spaces/whitespace that needs to be deleted. So the output would have 2 spaces in front of 'Real code here'.

Update: Maybe something like this:

String.class_eval do
  def strip_heredoc_with_indent(indent=0)
    new_indent = ( self.empty? ? 0 : ( scan(/^[ \t]*(?=\S)/).min.size - indent ) )
    gsub(/^[ \t]{#{new_indent}}/, '')
  end
end
4

3 回答 3

2

我按照这里strip_heredoc_with_indent(indent)的描述去了。

于 2012-07-16T23:48:18.970 回答
0

您可以使用某种分隔符来指示左边距。

def heredoc_with_margin()
  doc = <<-EOT.gsub(/^\s*\|/, '')
    |top:
    |  sub-one:
    |    sub-sub-one
    |  sub-two:
    |    sub-sub-two
    EOT
  return doc
end
于 2012-12-03T19:04:59.593 回答
0

自己剥。

insert_into_file "#{app_name}/config/environments/production.rb",
                 <<-DEVISE_MAILER_STUFF.gsub(/^  /, ''), :before => "end\n"
  ...
DEVISE_MAILER_STUFF

这表示在每一行的开头,用空字符串替换两个空格。它很简单,很容易理解,很容易修复或改变。


或者,您可以在模板中执行此操作,但我不知道您是否真的在使用模板,或者您是否正在以某种方式解析文件并替换行(提示,您可能应该使用模板)。


“我想也许 strip_heredoc(min) 其中 min 是要保留的最小空间,但我猜这不适用于制表符。”

Ruby 标准是两个空格。即使不是,标签总是把一切搞砸。使用空格。


关于你的更新

情况很复杂。您需要这样的通用解决方案吗?你在很多地方都这样做吗?或者在你不能只看一眼就看gsub多少的地方?此外,扩展核心类是一种危险的游戏,我看到代码库卡在 Rails 1 和定制的 Ruby 1.8 上,因为它们对改变内置行为过于漫不经心。当它改变时,他们无法随之改变。我知道 Rails 可以做到,但 Rails 并不是最佳实践的良好参考。

它也有一些潜在的错误:

  • 当给定这个字符串并且不传递任何参数时,它应该怎么做?" a\n\n b" 我什么也不期待,因为最短的行是空行,所以你的 new_indent 应该是零,但它会是一。
  • 当他们传入的缩进超过 时会发生什么scan(...).min.size
  • 如果他们传递了一些负面的东西会发生什么?

对我来说,它最终似乎是一个复杂的解决方案,永远不可能真正正确,它将使用它的任何代码耦合到这个应用程序,而所有这些实际上可能并不是必需的。

于 2012-07-15T18:27:45.417 回答