activesupport_path = "#{File.dirname(__FILE__)}/../../activesupport/lib"
$:.unshift(activesupport_path) if File.directory?(activesupport_path)
require 'active_support/all'
# TODO Use vendored Thor
require 'rubygems'
gem 'josevalim-thor'
require 'thor'
$:.unshift(File.dirname(__FILE__))
require 'rails/version' unless defined?(Rails::VERSION)
require 'generators/base'
require 'generators/named_base'
require 'generators/active_record' # We will need ActionORM from ActiveRecord, but just it.
module Rails
module Generators
mattr_accessor :load_path
# Generators load paths. First search on generators in the RAILS_ROOT, then
# look for them in rails generators.
#
def self.load_path
@@load_path ||= begin
paths = []
paths << File.expand_path(File.join(File.dirname(__FILE__), "generators"))
paths << File.join(RAILS_ROOT, "lib", "generators") if defined?(RAILS_ROOT)
paths
end
end
load_path # Cache load paths
# Receives paths in an array and tries to find generators for it in the load
# path.
#
def self.lookup(attempts)
generators_path = []
# Traverse attempts into directory lookups. For example:
#
# rails:generators:model
#
# Becomes:
#
# generators/rails/model/model_generator.rb
# generators/rails/model_generator.rb
# generators/model_generator.rb
#
attempts.each do |attempt|
paths = attempt.gsub(':generators:', ':').split(':')
paths << "#{paths.last}_generator.rb"
until paths.empty?
generators_path << File.join(*paths)
paths.delete_at(-1) unless paths.delete_at(-2)
end
end
generators_path.uniq!
generators_path.each do |generator_path|
self.load_path.each do |path|
Dir[File.join(path, generator_path)].each do |file|
require file
end
end
end
end
# Keep builtin generators in an Array[Array[group, name]].
#
def self.builtin
Dir[File.dirname(__FILE__) + '/generators/*/*'].collect do |file|
file.split('/')[-2, 2]
end
end
# Remove the color from output.
#
def self.no_color!
Thor::Base.shell = Thor::Shell::Basic
end
# Receives a namespace and tries different combinations to find a generator.
#
# ==== Examples
#
# find_by_namespace :webrat, :rails, :integration
#
# Will search for the following generators:
#
# "rails:generators:webrat", "webrat:generators:integration", "webrat"
#
# If the namespace has ":" included we consider that a absolute namespace
# was given and the lookup above does not happen. Just the name is searched.
#
# Finally, it deals with one kind of shortcut:
#
# find_by_namespace "test_unit:model"
#
# It will search for generators at:
#
# "test_unit:generators:model", "test_unit:model"
#
def self.find_by_namespace(name, base=nil, context=nil)
name, attempts = name.to_s, []
if name.count(':') == 0
attempts << "#{base}:generators:#{name}" if base
attempts << "#{name}:generators:#{context}" if context
end
attempts << name.sub(':', ':generators:') if name.count(':') == 1
attempts << name
unless klass = find_many_by_namespace(attempts)
lookup(attempts)
klass = find_many_by_namespace(attempts)
end
klass
end
# Show help message with available generators.
#
def self.help
rails = Rails::Generators.builtin.map do |group, name|
name if group == "rails"
end
rails.compact!
rails.sort!
puts "Please select a generator."
puts "Builtin: #{rails.join(', ')}."
# TODO Show others after lookup is implemented
# puts "Others: #{others.join(', ')}."
end
# 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, behavior=:invoke)
if klass = find_by_namespace(namespace, "rails")
args << "--help" if klass.arguments.any? { |a| a.required? } && args.empty?
klass.start args, :behavior => behavior
else
puts "Could not find generator #{namespace}."
end
end
protected
def self.find_many_by_namespace(attempts)
attempts.each do |namespace|
klass = Thor::Util.find_by_namespace(namespace)
return klass if klass
end
nil
end
end
end