Измените файл с помощью генератора рельсов

Как создать генератор, который изменяет файл.

Я пытаюсь сделать так, чтобы он нашел шаблон в файле и добавил содержимое контента в строку под ним.

Ответ 1

Генератор эстакад Rails делает это, когда он добавляет маршрут к 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

В результате он принимает путь/файл в качестве первого аргумента, за которым следуют шаблон regexp, аргументы 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 прямо под ней.

Остерегайтесь, потому что это самый хрупкий способ добавления контента, поэтому маршрутизация - одно из единственных мест, которое его использует. Приведенный выше пример обычно обрабатывается с помощью микширования.

Ответ 2

Мне нравится ответ Хайме. Но, когда я начал использовать его, я понял, что мне нужно внести некоторые изменения. Вот пример кода, который я использую:

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() для вас.

Теперь, как бы вы использовали это в генераторе рельсов? Вот пример того, как я уверен, что для rspec и огурца установлено 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-er способ сделать это. Мне очень понравилось, как вы можете добавить блок текста примера Jamie. Надеюсь, мой пример добавит немного больше функциональности и проверки ошибок.