Как создать генератор, который изменяет файл.
Я пытаюсь сделать так, чтобы он нашел шаблон в файле и добавил содержимое контента в строку под ним.
Как создать генератор, который изменяет файл.
Я пытаюсь сделать так, чтобы он нашел шаблон в файле и добавил содержимое контента в строку под ним.
Генератор эстакад 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
прямо под ней.
Остерегайтесь, потому что это самый хрупкий способ добавления контента, поэтому маршрутизация - одно из единственных мест, которое его использует. Приведенный выше пример обычно обрабатывается с помощью микширования.
Мне нравится ответ Хайме. Но, когда я начал использовать его, я понял, что мне нужно внести некоторые изменения. Вот пример кода, который я использую:
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. Надеюсь, мой пример добавит немного больше функциональности и проверки ошибок.