跳至内容 跳至搜索
方法
A
B
D
E
G
H
I
M
N
R
S
U
W
包含的模块

类公共方法

add_shebang_option!()

一个小宏,用于向生成器添加 ruby 作为选项,并具有适当的默认值,以及一个名为 shebang 的实例辅助方法。

# 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

banner()

使用 Rails 默认横幅。

# 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

base_name()

设置 base_name,同时考虑到当前类的命名空间。

# 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_root()

返回一组通用生成器的基本根目录。这用于动态猜测默认的源代码根目录。

# File railties/lib/rails/generators/base.rb, line 236
def self.base_root
  __dir__
end

default_aliases_for_option(name, options)

返回给定选项名称的默认别名,在 Rails::Generators.aliases 中进行查找。

# 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

default_for_option(config, name, options, default)

返回给定选项名称的默认值,在 config 中进行查找。

# 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

default_generator_root()

# 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

default_source_root()

返回给定生成器的默认源代码根目录。这在 Rails 内部使用,用于设置其生成器的源代码根目录。如果您想自定义您的源代码根目录,您应该使用 source_root。

# 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

default_value_for_option(name, options)

返回给定选项名称的默认值,在 Rails::Generators.options 中进行查找。

# 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

desc(description = nil)

尝试从源代码根目录上一层的 USAGE 文件中获取描述,否则使用默认描述。

# 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

generator_name()

移除命名空间并获取生成器名称。例如,Rails::Generators::ModelGenerator 将返回 “model” 作为生成器名称。

# 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

hide!()

一个便利方法,用于在运行 rails generator 命令时,将此生成器从可用生成器列表中隐藏。

# File railties/lib/rails/generators/base.rb, line 61
def self.hide!
  Rails::Generators.hide_namespace(namespace)
end

hook_for(*names, &block)

根据用户提供给名为 “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 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

namespace(name = nil)

一个便利方法,用于从类名中获取命名空间。它与 Thor 的默认命名空间相同,只是将类名末尾的 Generator 去掉了。

# 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

remove_hook_for(*names)

移除之前添加的钩子。

remove_hook_for :orm
# 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

source_root(path = nil)

使用 default_source_root 作为默认值,返回此生成器的源代码根目录。

# 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

usage_path()

# 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

实例私有方法

extract_last_module(nesting)

接收一个嵌套模块数组并提取最后一个模块

# 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

indent(content, multiplier = 2)

# 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

module_namespacing(&block)

如果存在命名空间且未跳过,则用当前应用程序的命名空间包装代码块

# 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

namespace()

# File railties/lib/rails/generators/base.rb, line 312
def namespace # :doc:
  Rails::Generators.namespace
end

namespaced?()

# File railties/lib/rails/generators/base.rb, line 316
def namespaced? # :doc:
  !options[:skip_namespace] && namespace
end

namespaced_path()

# File railties/lib/rails/generators/base.rb, line 324
def namespaced_path # :doc:
  @namespaced_path ||= namespace_dirs.join("/")
end

wrap_with_namespace(content)

# 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