2009-12-16 17:56:51 +00:00
|
|
|
activesupport_path = File.expand_path('../../../../activesupport/lib', __FILE__)
|
|
|
|
$:.unshift(activesupport_path) if File.directory?(activesupport_path) && !$:.include?(activesupport_path)
|
|
|
|
|
2009-09-14 19:52:28 +00:00
|
|
|
require 'active_support'
|
|
|
|
require 'active_support/core_ext/object/blank'
|
|
|
|
require 'active_support/core_ext/object/metaclass'
|
2009-12-27 22:43:06 +00:00
|
|
|
require 'active_support/core_ext/array/extract_options'
|
2009-12-27 23:17:14 +00:00
|
|
|
require 'active_support/core_ext/hash/deep_merge'
|
2009-09-14 19:52:28 +00:00
|
|
|
require 'active_support/core_ext/module/attribute_accessors'
|
|
|
|
require 'active_support/core_ext/string/inflections'
|
|
|
|
|
2009-09-24 21:01:31 +00:00
|
|
|
# TODO: Do not always push on vendored thor
|
2010-01-02 18:41:00 +00:00
|
|
|
$LOAD_PATH.unshift("#{File.dirname(__FILE__)}/vendor/thor-0.12.3/lib")
|
2009-09-24 21:01:31 +00:00
|
|
|
require 'rails/generators/base'
|
|
|
|
require 'rails/generators/named_base'
|
2009-06-23 14:19:23 +00:00
|
|
|
|
|
|
|
module Rails
|
|
|
|
module Generators
|
2009-07-15 14:53:54 +00:00
|
|
|
DEFAULT_ALIASES = {
|
2009-07-15 14:20:48 +00:00
|
|
|
:rails => {
|
|
|
|
:actions => '-a',
|
|
|
|
:orm => '-o',
|
|
|
|
:resource_controller => '-c',
|
|
|
|
:scaffold_controller => '-c',
|
|
|
|
:stylesheets => '-y',
|
|
|
|
:template_engine => '-e',
|
|
|
|
:test_framework => '-t'
|
|
|
|
},
|
|
|
|
|
|
|
|
:test_unit => {
|
|
|
|
:fixture_replacement => '-r',
|
|
|
|
},
|
|
|
|
|
|
|
|
:plugin => {
|
|
|
|
:generator => '-g',
|
|
|
|
:tasks => '-r'
|
|
|
|
}
|
2009-07-15 14:53:54 +00:00
|
|
|
}
|
2009-07-15 14:20:48 +00:00
|
|
|
|
2009-07-15 14:53:54 +00:00
|
|
|
DEFAULT_OPTIONS = {
|
2009-07-15 14:20:48 +00:00
|
|
|
:active_record => {
|
|
|
|
:migration => true,
|
|
|
|
:timestamps => true
|
|
|
|
},
|
|
|
|
|
|
|
|
:erb => {
|
|
|
|
:layout => true
|
|
|
|
},
|
|
|
|
|
|
|
|
:rails => {
|
|
|
|
:force_plural => false,
|
|
|
|
:helper => true,
|
|
|
|
:layout => true,
|
|
|
|
:orm => :active_record,
|
|
|
|
:integration_tool => :test_unit,
|
|
|
|
:performance_tool => :test_unit,
|
|
|
|
:resource_controller => :controller,
|
|
|
|
:scaffold_controller => :scaffold_controller,
|
|
|
|
:singleton => false,
|
|
|
|
:stylesheets => true,
|
|
|
|
:template_engine => :erb,
|
|
|
|
:test_framework => :test_unit
|
|
|
|
},
|
|
|
|
|
|
|
|
:test_unit => {
|
|
|
|
:fixture => true,
|
|
|
|
:fixture_replacement => nil
|
|
|
|
},
|
|
|
|
|
|
|
|
:plugin => {
|
|
|
|
:generator => false,
|
|
|
|
:tasks => false
|
|
|
|
}
|
2009-07-15 14:53:54 +00:00
|
|
|
}
|
2009-07-08 10:19:17 +00:00
|
|
|
|
2009-11-04 02:58:40 +00:00
|
|
|
def self.configure!(config = Rails.application.config.generators) #:nodoc:
|
|
|
|
no_color! unless config.colorize_logging
|
|
|
|
aliases.deep_merge! config.aliases
|
|
|
|
options.deep_merge! config.options
|
|
|
|
end
|
|
|
|
|
2009-07-15 22:17:28 +00:00
|
|
|
def self.aliases #:nodoc:
|
2009-08-10 16:29:20 +00:00
|
|
|
@aliases ||= DEFAULT_ALIASES.dup
|
2009-07-08 10:19:17 +00:00
|
|
|
end
|
|
|
|
|
2009-07-15 22:17:28 +00:00
|
|
|
def self.options #:nodoc:
|
2009-08-10 16:29:20 +00:00
|
|
|
@options ||= DEFAULT_OPTIONS.dup
|
2009-07-08 10:19:17 +00:00
|
|
|
end
|
|
|
|
|
2009-07-15 22:17:28 +00:00
|
|
|
# Hold configured generators fallbacks. If a plugin developer wants a
|
|
|
|
# generator group to fallback to another group in case of missing generators,
|
|
|
|
# they can add a fallback.
|
|
|
|
#
|
|
|
|
# For example, shoulda is considered a test_framework and is an extension
|
|
|
|
# of test_unit. However, most part of shoulda generators are similar to
|
|
|
|
# test_unit ones.
|
|
|
|
#
|
|
|
|
# Shoulda then can tell generators to search for test_unit generators when
|
|
|
|
# some of them are not available by adding a fallback:
|
|
|
|
#
|
|
|
|
# Rails::Generators.fallbacks[:shoulda] = :test_unit
|
|
|
|
#
|
|
|
|
def self.fallbacks
|
2009-08-10 16:29:20 +00:00
|
|
|
@fallbacks ||= {}
|
2009-07-15 22:17:28 +00:00
|
|
|
end
|
|
|
|
|
2009-07-08 10:19:17 +00:00
|
|
|
# Remove the color from output.
|
|
|
|
def self.no_color!
|
|
|
|
Thor::Base.shell = Thor::Shell::Basic
|
|
|
|
end
|
2009-07-03 10:10:09 +00:00
|
|
|
|
2010-01-03 11:01:29 +00:00
|
|
|
# Track all generators subclasses.
|
|
|
|
def self.subclasses
|
|
|
|
@subclasses ||= []
|
|
|
|
end
|
|
|
|
|
|
|
|
# Rails finds namespaces similar to thor, it only adds one rule:
|
2009-11-03 22:50:39 +00:00
|
|
|
#
|
2010-01-03 11:01:29 +00:00
|
|
|
# Generators names must end with "_generator.rb". This is required because Rails
|
|
|
|
# looks in load paths and loads the generator just before it's going to be used.
|
2009-06-26 17:14:55 +00:00
|
|
|
#
|
|
|
|
# ==== Examples
|
|
|
|
#
|
2009-07-02 09:08:07 +00:00
|
|
|
# find_by_namespace :webrat, :rails, :integration
|
2009-06-26 17:14:55 +00:00
|
|
|
#
|
|
|
|
# Will search for the following generators:
|
|
|
|
#
|
2010-01-03 11:01:29 +00:00
|
|
|
# "rails:webrat", "webrat:integration", "webrat"
|
2009-06-26 17:14:55 +00:00
|
|
|
#
|
2010-01-03 11:01:29 +00:00
|
|
|
# Notice that "rails:generators:webrat" could be loaded as well, what
|
|
|
|
# Rails looks for is the first and last parts of the namespace.
|
2009-06-26 17:14:55 +00:00
|
|
|
#
|
2009-07-15 22:17:28 +00:00
|
|
|
def self.find_by_namespace(name, base=nil, context=nil) #:nodoc:
|
2010-01-18 12:44:32 +00:00
|
|
|
lookups = []
|
|
|
|
lookups << "#{base}:#{name}" if base
|
|
|
|
lookups << "#{name}:#{context}" if context
|
2010-01-18 14:04:39 +00:00
|
|
|
lookups << "#{name}:#{name}" unless name.to_s.include?(?:)
|
2010-01-18 12:44:32 +00:00
|
|
|
lookups << "#{name}"
|
|
|
|
lookups << "rails:#{name}" unless base || context || name.to_s.include?(?:)
|
|
|
|
|
2010-01-03 11:01:29 +00:00
|
|
|
# Check if generator happens to be loaded
|
2010-01-18 14:04:39 +00:00
|
|
|
klass = subclasses.find { |k| lookups.include?(k.namespace) }
|
2010-01-03 11:01:29 +00:00
|
|
|
return klass if klass
|
|
|
|
|
2010-01-18 14:04:39 +00:00
|
|
|
# Try to load generator from $LOAD_PATH
|
|
|
|
checked = subclasses.dup
|
2010-01-18 12:44:32 +00:00
|
|
|
lookup(lookups)
|
2010-01-18 14:04:39 +00:00
|
|
|
|
2010-01-03 11:01:29 +00:00
|
|
|
unchecked = subclasses - checked
|
2010-01-18 14:04:39 +00:00
|
|
|
klass = unchecked.find { |k| lookups.include?(k.namespace) }
|
2010-01-03 11:01:29 +00:00
|
|
|
return klass if klass
|
|
|
|
|
|
|
|
invoke_fallbacks_for(name, base) || invoke_fallbacks_for(context, name)
|
|
|
|
end
|
2009-07-03 12:55:37 +00:00
|
|
|
|
2009-07-08 10:19:17 +00:00
|
|
|
# Receives a namespace, arguments and the behavior to invoke the generator.
|
|
|
|
# It's used as the default entry point for generate, destroy and update
|
|
|
|
# commands.
|
|
|
|
def self.invoke(namespace, args=ARGV, config={})
|
2010-01-03 11:01:29 +00:00
|
|
|
names = namespace.to_s.split(':')
|
2010-01-18 09:43:10 +00:00
|
|
|
if klass = find_by_namespace(names.pop, names.shift)
|
2010-01-18 14:04:39 +00:00
|
|
|
args << "--help" if args.empty? && klass.arguments.any? { |a| a.required? }
|
2010-01-03 11:01:29 +00:00
|
|
|
klass.start(args, config)
|
2009-07-08 10:19:17 +00:00
|
|
|
else
|
|
|
|
puts "Could not find generator #{namespace}."
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2009-07-02 09:08:07 +00:00
|
|
|
# Show help message with available generators.
|
|
|
|
def self.help
|
2010-01-03 11:01:29 +00:00
|
|
|
builtin = Rails::Generators.builtin.each { |n| n.sub!(/^rails:/, '') }
|
|
|
|
builtin.sort!
|
2009-07-03 12:55:37 +00:00
|
|
|
|
2010-01-18 14:04:39 +00:00
|
|
|
# TODO Fix me
|
|
|
|
# lookup("*")
|
2010-01-18 11:28:52 +00:00
|
|
|
others = subclasses.map{ |k| k.namespace }
|
2010-01-03 11:01:29 +00:00
|
|
|
others -= Rails::Generators.builtin
|
2009-07-03 12:55:37 +00:00
|
|
|
others.sort!
|
2010-01-03 11:01:29 +00:00
|
|
|
|
|
|
|
puts "Please select a generator."
|
|
|
|
puts "Builtin: #{builtin.join(', ')}."
|
2009-07-03 12:55:37 +00:00
|
|
|
puts "Others: #{others.join(', ')}." unless others.empty?
|
2009-07-02 09:08:07 +00:00
|
|
|
end
|
|
|
|
|
2009-07-03 10:10:09 +00:00
|
|
|
protected
|
|
|
|
|
2010-01-03 11:01:29 +00:00
|
|
|
# Keep builtin generators in an Array.
|
2009-07-15 22:17:28 +00:00
|
|
|
def self.builtin #:nodoc:
|
2009-07-08 10:19:17 +00:00
|
|
|
Dir[File.dirname(__FILE__) + '/generators/*/*'].collect do |file|
|
2010-01-03 11:01:29 +00:00
|
|
|
file.split('/')[-2, 2].join(':')
|
2009-07-08 10:19:17 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2010-01-03 11:01:29 +00:00
|
|
|
# Try fallbacks for the given base.
|
2009-11-20 11:29:35 +00:00
|
|
|
def self.invoke_fallbacks_for(name, base) #:nodoc:
|
2009-07-21 10:16:25 +00:00
|
|
|
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
|
|
|
|
|
2009-07-03 12:55:37 +00:00
|
|
|
# Receives namespaces in an array and tries to find matching generators
|
2009-08-10 16:29:20 +00:00
|
|
|
# in the load path.
|
2010-01-18 14:04:39 +00:00
|
|
|
def self.lookup(namespaces) #:nodoc:
|
|
|
|
paths = namespaces_to_paths(namespaces)
|
|
|
|
|
|
|
|
paths.each do |path|
|
|
|
|
["generators", "rails_generators"].each do |base|
|
|
|
|
path = "#{base}/#{path}_generator"
|
|
|
|
|
|
|
|
begin
|
|
|
|
require path
|
|
|
|
return
|
|
|
|
rescue LoadError => e
|
|
|
|
raise unless e.message =~ /#{Regexp.escape(path)}$/
|
|
|
|
rescue NameError => e
|
|
|
|
raise unless e.message =~ /Rails::Generator([\s(::)]|$)/
|
|
|
|
warn "[WARNING] Could not load generator #{path.inspect} because it's a Rails 2.x generator, which is not supported anymore. Error: #{e.message}"
|
|
|
|
end
|
|
|
|
end
|
2010-01-18 12:44:32 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2010-01-18 14:04:39 +00:00
|
|
|
# Convert namespaces to paths by replacing ":" for "/" and adding
|
|
|
|
# an extra lookup. For example, "rails:model" should be searched
|
|
|
|
# in both: "rails/model/model_generator" and "rails/model_generator".
|
|
|
|
def self.namespaces_to_paths(namespaces) #:nodoc:
|
|
|
|
paths = []
|
|
|
|
namespaces.each do |namespace|
|
|
|
|
pieces = namespace.split(":")
|
|
|
|
paths << pieces.dup.push(pieces.last).join("/")
|
|
|
|
paths << pieces.join("/")
|
2009-07-03 10:10:09 +00:00
|
|
|
end
|
2010-01-18 14:04:39 +00:00
|
|
|
paths.uniq!
|
|
|
|
paths
|
2009-07-03 10:10:09 +00:00
|
|
|
end
|
|
|
|
|
2009-06-23 14:19:23 +00:00
|
|
|
end
|
|
|
|
end
|
2009-06-23 17:10:42 +00:00
|
|
|
|