2009-12-16 12:56:51 -05:00
activesupport_path = File . expand_path ( '../../../../activesupport/lib' , __FILE__ )
$: . unshift ( activesupport_path ) if File . directory? ( activesupport_path ) && ! $: . include? ( activesupport_path )
2009-09-14 15:52:28 -04:00
require 'active_support'
require 'active_support/core_ext/object/blank'
2010-04-05 15:15:08 -04:00
require 'active_support/core_ext/kernel/singleton_class'
2009-12-27 17:43:06 -05:00
require 'active_support/core_ext/array/extract_options'
2009-12-27 18:17:14 -05:00
require 'active_support/core_ext/hash/deep_merge'
2009-09-14 15:52:28 -04:00
require 'active_support/core_ext/module/attribute_accessors'
require 'active_support/core_ext/string/inflections'
2009-09-24 17:01:31 -04:00
require 'rails/generators/base'
2009-06-23 10:19:23 -04:00
module Rails
module Generators
2010-02-26 04:44:53 -05:00
autoload :Actions , 'rails/generators/actions'
autoload :ActiveModel , 'rails/generators/active_model'
autoload :Migration , 'rails/generators/migration'
autoload :NamedBase , 'rails/generators/named_base'
autoload :ResourceHelpers , 'rails/generators/resource_helpers'
autoload :TestCase , 'rails/generators/test_case'
2009-07-15 10:53:54 -04:00
DEFAULT_ALIASES = {
2009-07-15 10:20:48 -04:00
:rails = > {
:actions = > '-a' ,
:orm = > '-o' ,
:resource_controller = > '-c' ,
:scaffold_controller = > '-c' ,
2010-04-09 13:04:20 -04:00
:stylesheets = > '-y' ,
2009-07-15 10:20:48 -04:00
:template_engine = > '-e' ,
:test_framework = > '-t'
} ,
:test_unit = > {
:fixture_replacement = > '-r' ,
} ,
:plugin = > {
:generator = > '-g' ,
:tasks = > '-r'
}
2009-07-15 10:53:54 -04:00
}
2009-07-15 10:20:48 -04:00
2009-07-15 10:53:54 -04:00
DEFAULT_OPTIONS = {
2009-07-15 10:20:48 -04:00
:rails = > {
:force_plural = > false ,
:helper = > true ,
2010-01-28 13:45:25 -05:00
:orm = > nil ,
2010-01-28 13:17:41 -05:00
:integration_tool = > nil ,
:performance_tool = > nil ,
2009-07-15 10:20:48 -04:00
:resource_controller = > :controller ,
:scaffold_controller = > :scaffold_controller ,
2010-04-09 13:04:20 -04:00
:stylesheets = > true ,
2010-01-28 13:03:47 -05:00
:test_framework = > nil ,
2010-01-27 20:39:11 -05:00
:template_engine = > :erb
2009-07-15 10:20:48 -04:00
} ,
:plugin = > {
:generator = > false ,
:tasks = > false
}
2009-07-15 10:53:54 -04:00
}
2009-07-08 06:19:17 -04:00
2009-11-03 21:58:40 -05: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
2010-02-01 04:48:59 -05:00
fallbacks . merge! config . fallbacks
2010-02-06 11:32:06 -05:00
templates_path . concat config . templates
2010-06-02 02:45:03 -04:00
templates_path . uniq!
2010-02-06 11:32:06 -05:00
end
def self . templates_path
@templates_path || = [ ]
2009-11-03 21:58:40 -05:00
end
2009-07-15 18:17:28 -04:00
def self . aliases #:nodoc:
2009-08-10 12:29:20 -04:00
@aliases || = DEFAULT_ALIASES . dup
2009-07-08 06:19:17 -04:00
end
2009-07-15 18:17:28 -04:00
def self . options #:nodoc:
2009-08-10 12:29:20 -04:00
@options || = DEFAULT_OPTIONS . dup
2009-07-08 06:19:17 -04:00
end
2009-07-15 18:17:28 -04: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 12:29:20 -04:00
@fallbacks || = { }
2009-07-15 18:17:28 -04:00
end
2009-07-08 06:19:17 -04:00
# Remove the color from output.
def self . no_color!
Thor :: Base . shell = Thor :: Shell :: Basic
end
2009-07-03 06:10:09 -04:00
2010-01-03 06:01:29 -05:00
# Track all generators subclasses.
def self . subclasses
@subclasses || = [ ]
end
# Rails finds namespaces similar to thor, it only adds one rule:
2009-11-03 17:50:39 -05:00
#
2010-01-03 06:01:29 -05: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 13:14:55 -04:00
#
# ==== Examples
#
2009-07-02 05:08:07 -04:00
# find_by_namespace :webrat, :rails, :integration
2009-06-26 13:14:55 -04:00
#
# Will search for the following generators:
#
2010-01-03 06:01:29 -05:00
# "rails:webrat", "webrat:integration", "webrat"
2009-06-26 13:14:55 -04:00
#
2010-01-03 06:01:29 -05: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 13:14:55 -04:00
#
2009-07-15 18:17:28 -04:00
def self . find_by_namespace ( name , base = nil , context = nil ) #:nodoc:
2010-01-18 07:44:32 -05:00
lookups = [ ]
lookups << " #{ base } : #{ name } " if base
lookups << " #{ name } : #{ context } " if context
2010-01-21 08:11:24 -05:00
unless base || context
unless name . to_s . include? ( ?: )
lookups << " #{ name } : #{ name } "
lookups << " rails: #{ name } "
end
lookups << " #{ name } "
end
2010-01-18 07:44:32 -05:00
lookup ( lookups )
2010-01-18 09:04:39 -05:00
2010-01-18 10:14:32 -05:00
namespaces = subclasses . inject ( { } ) do | hash , klass |
hash [ klass . namespace ] = klass
hash
end
lookups . each do | namespace |
klass = namespaces [ namespace ]
return klass if klass
end
2010-01-03 06:01:29 -05:00
invoke_fallbacks_for ( name , base ) || invoke_fallbacks_for ( context , name )
end
2009-07-03 08:55:37 -04:00
2009-07-08 06:19:17 -04: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 06:01:29 -05:00
names = namespace . to_s . split ( ':' )
2010-01-18 04:43:10 -05:00
if klass = find_by_namespace ( names . pop , names . shift )
2010-01-18 09:04:39 -05:00
args << " --help " if args . empty? && klass . arguments . any? { | a | a . required? }
2010-01-03 06:01:29 -05:00
klass . start ( args , config )
2009-07-08 06:19:17 -04:00
else
puts " Could not find generator #{ namespace } . "
end
end
2010-05-05 00:19:42 -04:00
def self . hidden_namespaces
@hidden_namespaces || = begin
orm = options [ :rails ] [ :orm ]
test = options [ :rails ] [ :test_framework ]
template = options [ :rails ] [ :template_engine ]
[
" rails " ,
" #{ orm } :migration " ,
" #{ orm } :model " ,
" #{ orm } :observer " ,
2010-06-08 10:01:11 -04:00
" #{ orm } :session_migration " ,
2010-05-05 00:19:42 -04:00
" #{ test } :controller " ,
" #{ test } :helper " ,
" #{ test } :integration " ,
" #{ test } :mailer " ,
" #{ test } :model " ,
" #{ test } :observer " ,
" #{ test } :scaffold " ,
" #{ test } :view " ,
2010-06-08 10:01:11 -04:00
" #{ test } :performance " ,
" #{ test } :plugin " ,
2010-05-05 00:19:42 -04:00
" #{ template } :controller " ,
2010-06-08 10:01:11 -04:00
" #{ template } :scaffold " ,
" #{ template } :mailer "
2010-05-05 00:19:42 -04:00
]
end
end
class << self
def hide_namespaces ( * namespaces )
hidden_namespaces . concat ( namespaces )
end
alias hide_namespace hide_namespaces
end
2009-07-02 05:08:07 -04:00
# Show help message with available generators.
2010-02-09 08:19:54 -05:00
def self . help ( command = 'generate' )
2010-01-19 12:43:09 -05:00
lookup!
2010-01-18 10:14:32 -05:00
namespaces = subclasses . map { | k | k . namespace }
namespaces . sort!
groups = Hash . new { | h , k | h [ k ] = [ ] }
namespaces . each do | namespace |
base = namespace . split ( ':' ) . first
groups [ base ] << namespace
end
2010-02-09 08:19:54 -05:00
puts " Usage: rails #{ command } GENERATOR [args] [options] "
2010-01-18 17:41:18 -05:00
puts
puts " General options: "
puts " -h, [--help] # Print generators 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] # Supress status output "
puts
puts " Please choose a generator below. "
2010-01-18 10:14:32 -05:00
puts
# Print Rails defaults first.
rails = groups . delete ( " rails " )
rails . map! { | n | n . sub ( / ^rails: / , '' ) }
2010-01-26 06:23:02 -05:00
rails . delete ( " app " )
2010-01-18 10:14:32 -05:00
print_list ( " rails " , rails )
2010-05-05 00:19:42 -04:00
hidden_namespaces . each { | n | groups . delete ( n . to_s ) }
2010-03-12 14:50:36 -05:00
2010-01-18 10:14:32 -05:00
groups . sort . each { | b , n | print_list ( b , n ) }
2009-07-02 05:08:07 -04:00
end
2009-07-03 06:10:09 -04:00
protected
2010-01-18 10:14:32 -05:00
# Prints a list of generators.
def self . print_list ( base , namespaces ) #:nodoc:
2010-05-05 00:19:42 -04:00
namespaces = namespaces . reject do | n |
hidden_namespaces . include? ( n )
end
2010-01-18 10:14:32 -05:00
return if namespaces . empty?
puts " #{ base . camelize } : "
2010-05-05 00:19:42 -04:00
namespaces . each do | namespace |
puts ( " #{ namespace } " )
end
2010-01-18 10:14:32 -05:00
puts
2009-07-08 06:19:17 -04:00
end
2010-01-03 06:01:29 -05:00
# Try fallbacks for the given base.
2009-11-20 06:29:35 -05:00
def self . invoke_fallbacks_for ( name , base ) #:nodoc:
2009-07-21 06:16:25 -04: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 08:55:37 -04:00
# Receives namespaces in an array and tries to find matching generators
2009-08-10 12:29:20 -04:00
# in the load path.
2010-01-18 09:04:39 -05:00
def self . lookup ( namespaces ) #:nodoc:
2010-01-19 12:43:09 -05:00
load_generators_from_railties!
2010-01-18 09:04:39 -05:00
paths = namespaces_to_paths ( namespaces )
2010-01-21 08:11:24 -05:00
paths . each do | raw_path |
2010-03-23 08:40:19 -04:00
[ " rails/generators " , " generators " ] . each do | base |
2010-01-21 08:11:24 -05:00
path = " #{ base } / #{ raw_path } _generator "
2010-01-18 09:04:39 -05:00
begin
require path
return
rescue LoadError = > e
raise unless e . message =~ / #{ Regexp . escape ( path ) } $ /
rescue NameError = > e
raise unless e . message =~ / Rails::Generator([ \ s(::)]|$) /
2010-01-21 08:11:24 -05:00
warn " [WARNING] Could not load generator #{ path . inspect } because it's a Rails 2.x generator, which is not supported anymore. Error: #{ e . message } . \n #{ e . backtrace . join ( " \n " ) } "
2010-01-21 06:10:39 -05:00
rescue Exception = > e
2010-01-21 08:11:24 -05:00
warn " [WARNING] Could not load generator #{ path . inspect } . Error: #{ e . message } . \n #{ e . backtrace . join ( " \n " ) } "
2010-01-18 09:04:39 -05:00
end
end
2010-01-18 07:44:32 -05:00
end
end
2010-01-19 12:43:09 -05:00
# This will try to load any generator in the load path to show in help.
def self . lookup! #:nodoc:
load_generators_from_railties!
$LOAD_PATH . each do | base |
2010-03-23 08:40:19 -04:00
Dir [ File . join ( base , " {rails/generators,generators} " , " ** " , " *_generator.rb " ) ] . each do | path |
2010-01-19 12:43:09 -05:00
begin
require path
rescue Exception = > e
# No problem
end
end
end
end
# Allow generators to be loaded from custom paths.
def self . load_generators_from_railties! #:nodoc:
return if defined? ( @generators_from_railties ) || Rails . application . nil?
@generators_from_railties = true
Rails . application . load_generators
end
2010-01-18 09:04:39 -05: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 ( " : " )
2010-06-13 07:50:40 -04:00
paths << pieces . dup . push ( pieces . last ) . join ( " / " )
2010-01-18 09:04:39 -05:00
paths << pieces . join ( " / " )
2009-07-03 06:10:09 -04:00
end
2010-01-18 09:04:39 -05:00
paths . uniq!
paths
2009-07-03 06:10:09 -04:00
end
2009-06-23 10:19:23 -04:00
end
2010-06-24 11:05:27 -04:00
end