класс Rails::Generators::Base
Открытые методы класса
# File railties/lib/rails/generators/base.rb, line 396
def self.add_shebang_option! # :doc:
class_option :ruby, type: :string, aliases: "-r", default: Thor::Util.ruby_command,
desc: "Path to the Ruby binary of your choice", banner: "PATH"
no_tasks {
define_method :shebang do
@shebang ||= begin
command = if options[:ruby] == Thor::Util.ruby_command
"/usr/bin/env #{File.basename(Thor::Util.ruby_command)}"
else
options[:ruby]
end
"#!#{command}"
end
end
}
end Небольшой макрос, добавляющий ruby в качестве опции генератора с подходящим значением по умолчанию, а также вспомогательный метод экземпляра с именем shebang.
# File railties/lib/rails/generators/base.rb, line 329
def self.banner # :doc:
"bin/rails generate #{namespace.delete_prefix("rails:")} #{arguments.map(&:usage).join(' ')} [options]".gsub(/\s+/, " ")
end Использует баннер Rails по умолчанию.
# File railties/lib/rails/generators/base.rb, line 334
def self.base_name # :doc:
@base_name ||= if base = name.to_s.split("::").first
base.underscore
end
end Задаёт base_name с учётом текущего пространства имён класса.
# File railties/lib/rails/generators/base.rb, line 236 def self.base_root __dir__ end
Возвращает корневой каталог для общего набора генераторов. Он используется для динамического определения корневого каталога исходников по умолчанию.
# File railties/lib/rails/generators/base.rb, line 357 def self.default_aliases_for_option(name, options) # :doc: default_for_option(Rails::Generators.aliases, name, options, options[:aliases]) end
Возвращает псевдонимы по умолчанию для заданного имени опции, выполняя поиск в Rails::Generators.aliases.
# File railties/lib/rails/generators/base.rb, line 362
def self.default_for_option(config, name, options, default) # :doc:
if generator_name && (c = config[generator_name.to_sym]) && c.key?(name)
c[name]
elsif base_name && (c = config[base_name.to_sym]) && c.key?(name)
c[name]
elsif config[:rails].key?(name)
config[:rails][name]
else
default
end
end Возвращает значение по умолчанию для заданного имени опции, выполняя поиск в config.
# File railties/lib/rails/generators/base.rb, line 422 def self.default_generator_root # :doc: path = File.expand_path(File.join(base_name, generator_name), base_root) path if File.exist?(path) end
# File railties/lib/rails/generators/base.rb, line 227 def self.default_source_root return unless base_name && generator_name return unless default_generator_root path = File.join(default_generator_root, "templates") path if File.exist?(path) end
Возвращает корневой каталог исходников по умолчанию для заданного генератора. Этот метод используется внутри Rails для задания корневого каталога исходников генератора. Если вы хотите настроить корневой каталог исходников, используйте source_root.
# File railties/lib/rails/generators/base.rb, line 351 def self.default_value_for_option(name, options) # :doc: default_for_option(Rails::Generators.options, name, options, options[:default]) end
Возвращает значение по умолчанию для заданного имени опции, выполняя поиск в Rails::Generators.options.
# File railties/lib/rails/generators/base.rb, line 41
def self.desc(description = nil)
return super if description
@desc ||= if usage_path
ERB.new(File.read(usage_path)).result(binding)
else
"Description:\n Create #{base_name.humanize.downcase} files for #{generator_name} generator."
end
end Пытается получить описание из файла USAGE, расположенного на один уровень выше корневого каталога исходников; если это не удаётся, использует описание по умолчанию.
# File railties/lib/rails/generators/base.rb, line 342
def self.generator_name # :doc:
@generator_name ||= if generator = name.to_s.split("::").last
generator.delete_suffix!("Generator")
generator.underscore
end
end Удаляет пространства имён и возвращает имя генератора. Например, Rails::Generators::ModelGenerator вернёт «model» в качестве имени генератора.
# File railties/lib/rails/generators/base.rb, line 61 def self.hide! Rails::Generators.hide_namespace(namespace) end
Вспомогательный метод, скрывающий этот генератор из списка доступных при запуске команды rails generator.
# File railties/lib/rails/generators/base.rb, line 174
def self.hook_for(*names, &block)
options = names.extract_options!
in_base = options.delete(:in) || base_name
as_hook = options.delete(:as) || generator_name
names.each do |name|
unless class_options.key?(name)
defaults = if options[:type] == :boolean
{}
elsif [true, false].include?(default_value_for_option(name, options))
{ banner: "" }
else
{ desc: "#{name.to_s.humanize} to be invoked", banner: "NAME" }
end
class_option(name, defaults.merge!(options))
end
klass = self
singleton_class.define_method("#{name}_generator") do
value = class_options[name].default
Rails::Generators.find_by_namespace(klass.generator_name, value)
end
hooks[name] = [ in_base, as_hook ]
invoke_from_option(name, options, &block)
end
end Вызывает генератор на основе значения, переданного пользователем для опции с заданным именем «name». При вызове этого метода создаётся опция класса, которую можно настроить с помощью хеша.
Примеры
module Rails::Generators
class ControllerGenerator < Base
hook_for :test_framework, aliases: "-t"
end
end
Пример выше создаёт опцию тестового фреймворка и вызывает генератор на основе значения, переданного пользователем.
Например, если пользователь вызывает генератор контроллера следующим образом:
$ bin/rails generate controller Account --test-framework=test_unit
После этого генератор контроллера попытается вызвать следующие генераторы:
"rails:test_unit", "test_unit:controller", "test_unit"
Обратите внимание: также может быть загружен «rails:generators:test_unit». Rails ищет первую и последнюю части пространства имён. Благодаря этому любой тестовый фреймворк может подключиться к Rails, если предоставляет один из указанных выше хуков.
Опции
Первая и последняя части, используемые для поиска вызываемого генератора, определяются по вызову класса hook_for, как показано в примере выше. Это можно настроить с помощью двух опций: :in и :as.
Предположим, вы создаёте генератор, которому нужно вызвать генератор контроллера из test unit. Ваша первая попытка выглядит так:
class AwesomeGenerator < Rails::Generators::Base hook_for :test_framework end
В этом случае поиск для входного значения test_unit будет выглядеть так:
"test_unit:awesome", "test_unit"
Это не тот результат, который нам нужен. Его можно изменить, указав опцию :as:
class AwesomeGenerator < Rails::Generators::Base hook_for :test_framework, as: :controller end
Теперь поиск будет выполняться так:
"test_unit:controller", "test_unit"
Аналогично, если нужно также выполнять поиск в пространстве имён rails, достаточно указать значение :in:
class AwesomeGenerator < Rails::Generators::Base hook_for :test_framework, in: :rails, as: :controller end
В этом случае поиск будет таким же, как и раньше:
"rails:test_unit", "test_unit:controller", "test_unit"
Флаги
Все хуки имеют флаги для пользовательского интерфейса. Если вы не хотите использовать тестовый фреймворк, можно сделать так:
$ bin/rails generate controller Account --skip-test-framework
Или аналогичным образом:
$ bin/rails generate controller Account --no-test-framework
Логические хуки
В некоторых случаях может понадобиться логический хук. Например, разработчики webrat могут захотеть сделать webrat доступным в генераторе контроллера. Это можно сделать так:
Rails::Generators::ControllerGenerator.hook_for :webrat, type: :boolean
Затем, чтобы вызвать webrat, укажите:
$ bin/rails generate controller Account --webrat
Поиск хуков выполняется так же, как описано выше:
"rails:generators:webrat", "webrat:generators:controller", "webrat"
Пользовательские вызовы
Вы также можете передать блоку hook_for настройку способа вызова хука. Блок принимает два аргумента: экземпляр текущего класса и класс, который нужно вызвать.
Например, в генераторе ресурсов генератор контроллера следует вызывать с именем класса во множественном числе. Однако по умолчанию он вызывается с тем же именем, что и генератор ресурса, то есть в единственном числе. Чтобы изменить это, можно передать блок, задающий способ вызова генератора контроллера.
hook_for :resource_controller do |instance, controller| instance.invoke controller, [ instance.name.pluralize ] end
# File railties/lib/rails/generators/base.rb, line 54
def self.namespace(name = nil)
return super if name
@namespace ||= super.delete_suffix("_generator").sub(/:generators:/, ":")
end Вспомогательный метод для получения пространства имён из имени класса. Он работает так же, как вариант по умолчанию в Thor, за исключением того, что Generator в конце имени класса удаляется.
# File railties/lib/rails/generators/base.rb, line 207
def self.remove_hook_for(*names)
remove_invocation(*names)
names.each do |name|
singleton_class.undef_method("#{name}_generator")
hooks.delete(name)
end
end Удаляет ранее добавленный хук.
remove_hook_for :orm
# File railties/lib/rails/generators/base.rb, line 34 def self.source_root(path = nil) @_source_root = path if path @_source_root ||= default_source_root end
Возвращает корневой каталог исходников этого генератора, используя default_source_root в качестве значения по умолчанию.
# File railties/lib/rails/generators/base.rb, line 414
def self.usage_path # :doc:
paths = [
source_root && File.expand_path("../USAGE", source_root),
default_generator_root && File.join(default_generator_root, "USAGE")
]
paths.compact.detect { |path| File.exist? path }
end Закрытые методы экземпляра
# File railties/lib/rails/generators/base.rb, line 287
def extract_last_module(nesting) # :doc:
nesting.inject(Object) do |last_module, nest|
break unless last_module.const_defined?(nest, false)
last_module.const_get(nest)
end
end Принимает массив вложенных модулей и извлекает последний модуль
# File railties/lib/rails/generators/base.rb, line 302
def indent(content, multiplier = 2) # :doc:
spaces = " " * multiplier
content.each_line.map { |line| line.blank? ? line : "#{spaces}#{line}" }.join
end # File railties/lib/rails/generators/base.rb, line 296 def module_namespacing(&block) # :doc: content = capture(&block) content = wrap_with_namespace(content) if namespaced? concat(content) end
Оборачивает блок в пространство имён текущего приложения, если оно существует и не пропущено
# File railties/lib/rails/generators/base.rb, line 312 def namespace # :doc: Rails::Generators.namespace end
# File railties/lib/rails/generators/base.rb, line 316 def namespaced? # :doc: !options[:skip_namespace] && namespace end
# File railties/lib/rails/generators/base.rb, line 324
def namespaced_path # :doc:
@namespaced_path ||= namespace_dirs.join("/")
end # File railties/lib/rails/generators/base.rb, line 307
def wrap_with_namespace(content) # :doc:
content = indent(content).chomp
"module #{namespace.name}\n#{content}\nend\n"
end
© 2004–2021 David Heinemeier Hansson
Licensed under the MIT License.