module Rails::Generators
def add_generated_file(file) # :nodoc:
def add_generated_file(file) # :nodoc: (@@generated_files ||= []) << file file end
def after_generate_callbacks # :nodoc:
def after_generate_callbacks # :nodoc: @after_generate_callbacks ||= [] end
def aliases # :nodoc:
def aliases # :nodoc: @aliases ||= DEFAULT_ALIASES.dup end
def api_only!
migration generators, and completely disable helpers and assets
everything that is usually browser related, such as assets and session
Configure generators for API only applications. It basically hides
def api_only! hide_namespaces "assets", "helper", "css", "js" options[:rails].merge!( api: true, assets: false, helper: false, template_engine: nil ) options[:mailer] ||= {} options[:mailer][:template_engine] ||= :erb end
def command_type # :doc:
def command_type # :doc: @command_type ||= "generator" end
def configure!(config) # :nodoc:
def configure!(config) # :nodoc: api_only! if config.api_only no_color! unless config.colorize_logging aliases.deep_merge! config.aliases options.deep_merge! config.options fallbacks.merge! config.fallbacks templates_path.concat config.templates templates_path.uniq! hide_namespaces(*config.hidden_namespaces) after_generate_callbacks.replace config.after_generate_callbacks end
def fallbacks
some of them are not available by adding a fallback:
Shoulda then can tell generators to search for +test_unit+ generators when
+test_unit+ ones.
of +test_unit+. However, most part of shoulda generators are similar to
For example, shoulda is considered a +test_framework+ and is an extension
they can add a fallback.
generator group to fall back to another group in case of missing generators,
Hold configured generators fallbacks. If a plugin developer wants a
def fallbacks @fallbacks ||= {} end
def file_lookup_paths # :doc:
def file_lookup_paths # :doc: @file_lookup_paths ||= [ "{#{lookup_paths.join(',')}}", "**", "*_generator.rb" ] end
def find_by_namespace(name, base = nil, context = nil) # :nodoc:
Rails looks for is the first and last parts of the namespace.
Notice that "rails:generators:webrat" could be loaded as well, what
"rails:webrat", "webrat:integration", "webrat"
Will search for the following generators:
find_by_namespace :webrat, :rails, :integration
looks in load paths and loads the generator just before it's going to be used.
Generators names must end with "_generator.rb". This is required because Rails
Rails finds namespaces similar to Thor, it only adds one rule:
def find_by_namespace(name, base = nil, context = nil) # :nodoc: lookups = [] lookups << "#{base}:#{name}" if base lookups << "#{name}:#{context}" if context unless base || context unless name.to_s.include?(?:) lookups << "#{name}:#{name}" lookups << "rails:#{name}" end lookups << "#{name}" end lookup(lookups) namespaces = subclasses.index_by(&:namespace) lookups.each do |namespace| klass = namespaces[namespace] return klass if klass end invoke_fallbacks_for(name, base) || invoke_fallbacks_for(context, name) end
def help(command = "generate")
def help(command = "generate") puts "Usage:" puts " bin/rails #{command} GENERATOR [args] [options]" puts puts "General options:" puts " -h, [--help] # Print generator's options and usage" puts " -p, [--pretend] # Run but do not make any changes" puts " -f, [--force] # Overwrite files that already exist" puts " -s, [--skip] # Skip files that already exist" puts " -q, [--quiet] # Suppress status output" puts puts "Please choose a generator below." puts print_generators end
def hidden_namespaces
Some are aliased such as "rails:migration" and can be
Generator namespaces may be hidden for a variety of reasons.
Returns an array of generator namespaces that are hidden.
def hidden_namespaces @hidden_namespaces ||= begin orm = options[:rails][:orm] test = options[:rails][:test_framework] template = options[:rails][:template_engine] [ "rails", "resource_route", "#{orm}:migration", "#{orm}:model", "#{test}:controller", "#{test}:helper", "#{test}:integration", "#{test}:system", "#{test}:mailer", "#{test}:model", "#{test}:scaffold", "#{test}:view", "#{test}:job", "#{template}:controller", "#{template}:scaffold", "#{template}:mailer", "action_text:install", "action_mailbox:install", "devcontainer" ] end end
def hide_namespaces(*namespaces)
def hide_namespaces(*namespaces) hidden_namespaces.concat(namespaces) end
def invoke(namespace, args = ARGV, config = {})
It's used as the default entry point for generate, destroy, and update
Receives a namespace, arguments, and the behavior to invoke the generator.
def invoke(namespace, args = ARGV, config = {}) names = namespace.to_s.split(":") if klass = find_by_namespace(names.pop, names.any? && names.join(":")) args << "--help" if args.empty? && klass.arguments.any?(&:required?) klass.start(args, config) run_after_generate_callback if config[:behavior] == :invoke else options = sorted_groups.flat_map(&:last) error = Command::CorrectableNameError.new("Could not find generator '#{namespace}'.", namespace, options) puts <<~MSG #{error.detailed_message} Run `bin/rails generate --help` for more options. MSG exit 1 end end
def invoke_fallbacks_for(name, base)
def invoke_fallbacks_for(name, base) return nil unless base && fallbacks[base.to_sym] invoked_fallbacks = [] Array(fallbacks[base.to_sym]).each do |fallback| next if invoked_fallbacks.include?(fallback) invoked_fallbacks << fallback klass = find_by_namespace(name, fallback) return klass if klass end nil end
def lookup_paths # :doc:
def lookup_paths # :doc: @lookup_paths ||= %w( rails/generators generators ) end
def options # :nodoc:
def options # :nodoc: @options ||= DEFAULT_OPTIONS.dup end
def print_generators
def print_generators sorted_groups.each { |b, n| print_list(b, n) } end
def print_list(base, namespaces) # :doc:
def print_list(base, namespaces) # :doc: namespaces = namespaces.reject { |n| hidden_namespaces.include?(n) } super end
def public_namespaces
def public_namespaces lookup! subclasses.map(&:namespace) end
def run_after_generate_callback
def run_after_generate_callback if defined?(@@generated_files) && !@@generated_files.empty? after_generate_callbacks.each do |callback| callback.call(@@generated_files) end @@generated_files = [] end end
def sorted_groups
def sorted_groups namespaces = public_namespaces namespaces.sort! groups = Hash.new { |h, k| h[k] = [] } namespaces.each do |namespace| base = namespace.split(":").first groups[base] << namespace end rails = groups.delete("rails") rails.map! { |n| n.delete_prefix("rails:") } rails.delete("app") rails.delete("plugin") rails.delete("encrypted_file") rails.delete("encryption_key_file") rails.delete("master_key") rails.delete("credentials") rails.delete("db:system:change") hidden_namespaces.each { |n| groups.delete(n.to_s) } [[ "rails", rails ]] + groups.sort.to_a end
def templates_path # :nodoc:
def templates_path # :nodoc: @templates_path ||= [] end