使用Rails生成器修改文件

14

如何制作一个修改文件的生成器。

我正在尝试使它查找文件中的模式,并在其下一行添加某些内容。

2个回答

18

Rails的脚手架生成器在向 config/routes.rb 添加路由时会执行此操作。它通过调用一个非常简单的方法来实现:

Rails的scaffold生成器会在添加一条路由到config/routes.rb时进行这个操作。它会调用一个非常简单的方法:

def gsub_file(relative_destination, regexp, *args, &block)
  path = destination_path(relative_destination)
  content = File.read(path).gsub(regexp, *args, &block)
  File.open(path, 'wb') { |file| file.write(content) }
end

这个方法的作用是将路径/文件作为第一个参数,然后是正则表达式模式、gsub参数和块。这是一个受保护的方法,你需要重新创建才能使用。我不确定是否可以访问destination_path,所以你可能需要传递准确的路径并跳过任何转换。

要使用gsub_file,假设您想向用户模型添加标签。以下是如何实现:

line = "class User < ActiveRecord::Base"
gsub_file 'app/models/user.rb', /(#{Regexp.escape(line)})/mi do |match|
  "#{match}\n  has_many :tags\n"
end

你正在查找文件中的特定行、类的开头,并在下面添加你的has_many代码。

但要小心,这是最容易出错的添加内容的方式,这也是为什么路由是唯一使用它的地方之一。上面的示例通常会使用mix-in来处理。


2

我喜欢Jaime的答案。但是,当我开始使用它时,我意识到需要进行一些修改。以下是我正在使用的示例代码:

private

  def destination_path(path)
    File.join(destination_root, path)
  end

  def sub_file(relative_file, search_text, replace_text)
    path = destination_path(relative_file)
    file_content = File.read(path)

    unless file_content.include? replace_text
      content = file_content.sub(/(#{Regexp.escape(search_text)})/mi, replace_text)
      File.open(path, 'wb') { |file| file.write(content) }
    end

  end

首先,gsub 将替换所有搜索文本的实例;我只需要一个。因此,我使用 sub
其次,我需要检查替换字符串是否已经就位。否则,如果我的 rails 生成器运行多次,我将重复插入。因此,我将代码包装在一个 unless 块中。
最后,我为您添加了 def destination_path()
现在,您如何在 rails 生成器中使用它?以下是我确保 rspec 和 cucumber 安装 simplecov 的示例:
  def configure_simplecov
    code = "#Simple Coverage\nrequire 'simplecov'\nSimpleCov.start"

    sub_file 'spec/spec_helper.rb', search = "ENV[\"RAILS_ENV\"] ||= 'test'", "#{search}\n\n#{code}\n"
    sub_file 'features/support/env.rb', search = "require 'cucumber/rails'", "#{search}\n\n#{code}\n"
  end

可能有更加优雅和DRY的方法来实现这个功能。我很喜欢Jamie示例中如何添加文本块的方式。希望我的示例增加了更多的功能和错误检查。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接