Removed remaining old generators files.

This commit is contained in:
José Valim 2009-07-03 12:32:46 +02:00
parent de68cf7e06
commit 3ca504c966
18 changed files with 10 additions and 1810 deletions

1
.gitignore vendored
View File

@ -14,6 +14,7 @@ activesupport/pkg
railties/pkg
railties/test/500.html
railties/test/fixtures/tmp
railties/test/initializer/root/log
railties/doc/guides/html/images
railties/doc/guides/html/stylesheets
benches

View File

@ -21,6 +21,8 @@ module Rails
# Generators load paths. First search on generators in the RAILS_ROOT, then
# look for them in rails generators.
#
# TODO Add plugins, gems and frozen gems to load path.
#
def self.load_path
@@load_path ||= begin
paths = []

View File

@ -1,38 +0,0 @@
#--
# Copyright (c) 2004 Jeremy Kemper
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#++
activesupport_path = "#{File.dirname(__FILE__)}/../../activesupport/lib"
$:.unshift(activesupport_path) if File.directory?(activesupport_path)
require 'active_support/all'
$:.unshift(File.dirname(__FILE__))
require 'rails_generator/base'
require 'rails_generator/lookup'
require 'rails_generator/commands'
Rails::Generator::Base.send(:include, Rails::Generator::Lookup)
Rails::Generator::Base.send(:include, Rails::Generator::Commands)
# Set up a default logger for convenience.
require 'rails_generator/simple_logger'
Rails::Generator::Base.logger = Rails::Generator::SimpleLogger.new(STDOUT)

View File

@ -1,266 +0,0 @@
require File.dirname(__FILE__) + '/options'
require File.dirname(__FILE__) + '/manifest'
require File.dirname(__FILE__) + '/spec'
require File.dirname(__FILE__) + '/generated_attribute'
module Rails
# Rails::Generator is a code generation platform tailored for the Rails
# web application framework. Generators are easily invoked within Rails
# applications to add and remove components such as models and controllers.
# New generators are easy to create and may be distributed as RubyGems,
# tarballs, or Rails plugins for inclusion system-wide, per-user,
# or per-application.
#
# For actual examples see the rails_generator/generators directory in the
# Rails source (or the +railties+ directory if you have frozen the Rails
# source in your application).
#
# Generators may subclass other generators to provide variations that
# require little or no new logic but replace the template files.
#
# For a RubyGem, put your generator class and templates in the +lib+
# directory. For a Rails plugin, make a +generators+ directory at the
# root of your plugin.
#
# The layout of generator files can be seen in the built-in
# +controller+ generator:
#
# generators/
# components/
# controller/
# controller_generator.rb
# templates/
# controller.rb
# functional_test.rb
# helper.rb
# view.html.erb
#
# The directory name (+controller+) matches the name of the generator file
# (controller_generator.rb) and class (ControllerGenerator). The files
# that will be copied or used as templates are stored in the +templates+
# directory.
#
# The filenames of the templates don't matter, but choose something that
# will be self-explanatory since you will be referencing these in the
# +manifest+ method inside your generator subclass.
#
#
module Generator
class GeneratorError < StandardError; end
class UsageError < GeneratorError; end
# The base code generator is bare-bones. It sets up the source and
# destination paths and tells the logger whether to keep its trap shut.
#
# It's useful for copying files such as stylesheets, images, or
# javascripts.
#
# For more comprehensive template-based passive code generation with
# arguments, you'll want Rails::Generator::NamedBase.
#
# Generators create a manifest of the actions they perform then hand
# the manifest to a command which replays the actions to do the heavy
# lifting (such as checking for existing files or creating directories
# if needed). Create, destroy, and list commands are included. Since a
# single manifest may be used by any command, creating new generators is
# as simple as writing some code templates and declaring what you'd like
# to do with them.
#
# The manifest method must be implemented by subclasses, returning a
# Rails::Generator::Manifest. The +record+ method is provided as a
# convenience for manifest creation. Example:
#
# class StylesheetGenerator < Rails::Generator::Base
# def manifest
# record do |m|
# m.directory('public/stylesheets')
# m.file('application.css', 'public/stylesheets/application.css')
# end
# end
# end
#
# See Rails::Generator::Commands::Create for a list of methods available
# to the manifest.
class Base
include Options
# Declare default options for the generator. These options
# are inherited to subclasses.
default_options :collision => :ask, :quiet => false
# A logger instance available everywhere in the generator.
cattr_accessor :logger
# Every generator that is dynamically looked up is tagged with a
# Spec describing where it was found.
class_inheritable_accessor :spec
attr_reader :source_root, :destination_root, :args
def initialize(runtime_args, runtime_options = {})
@args = runtime_args
parse!(@args, runtime_options)
# Derive source and destination paths.
@source_root = options[:source] || File.join(spec.path, 'templates')
if options[:destination]
@destination_root = options[:destination]
elsif defined? ::RAILS_ROOT
@destination_root = ::RAILS_ROOT
end
# Silence the logger if requested.
logger.quiet = options[:quiet]
# Raise usage error if help is requested.
usage if options[:help]
end
# Generators must provide a manifest. Use the +record+ method to create
# a new manifest and record your generator's actions.
def manifest
raise NotImplementedError, "No manifest for '#{spec.name}' generator."
end
# Return the full path from the source root for the given path.
# Example for source_root = '/source':
# source_path('some/path.rb') == '/source/some/path.rb'
#
# The given path may include a colon ':' character to indicate that
# the file belongs to another generator. This notation allows any
# generator to borrow files from another. Example:
# source_path('model:fixture.yml') = '/model/source/path/fixture.yml'
def source_path(relative_source)
# Check whether we're referring to another generator's file.
name, path = relative_source.split(':', 2)
# If not, return the full path to our source file.
if path.nil?
File.join(source_root, name)
# Otherwise, ask our referral for the file.
else
# FIXME: this is broken, though almost always true. Others'
# source_root are not necessarily the templates dir.
File.join(self.class.lookup(name).path, 'templates', path)
end
end
# Return the full path from the destination root for the given path.
# Example for destination_root = '/dest':
# destination_path('some/path.rb') == '/dest/some/path.rb'
def destination_path(relative_destination)
File.join(destination_root, relative_destination)
end
def after_generate
end
protected
# Convenience method for generator subclasses to record a manifest.
def record
Rails::Generator::Manifest.new(self) { |m| yield m }
end
# Override with your own usage banner.
def banner
"Usage: #{$0} #{spec.name} [options]"
end
# Read USAGE from file in generator base path.
def usage_message
File.read(File.join(spec.path, 'USAGE')) rescue ''
end
end
# The base generator for named components: models, controllers, mailers,
# etc. The target name is taken as the first argument and inflected to
# singular, plural, class, file, and table forms for your convenience.
# The remaining arguments are aliased to +actions+ as an array for
# controller and mailer convenience.
#
# Several useful local variables and methods are populated in the
# +initialize+ method. See below for a list of Attributes and
# External Aliases available to both the manifest and to all templates.
#
# If no name is provided, the generator raises a usage error with content
# optionally read from the USAGE file in the generator's base path.
#
# For example, the +controller+ generator takes the first argument as
# the name of the class and subsequent arguments as the names of
# actions to be generated:
#
# ./script/generate controller Article index new create
#
# See Rails::Generator::Base for a discussion of manifests,
# Rails::Generator::Commands::Create for methods available to the manifest,
# and Rails::Generator for a general discussion of generators.
class NamedBase < Base
attr_reader :name, :class_name, :singular_name, :plural_name, :table_name
attr_reader :class_path, :file_path, :class_nesting, :class_nesting_depth
alias_method :file_name, :singular_name
alias_method :actions, :args
def initialize(runtime_args, runtime_options = {})
super
# Name argument is required.
usage if runtime_args.empty?
@args = runtime_args.dup
base_name = @args.shift
assign_names!(base_name)
end
protected
# Override with your own usage banner.
def banner
"Usage: #{$0} #{spec.name} #{spec.name.camelize}Name [options]"
end
def attributes
@attributes ||= @args.collect do |attribute|
Rails::Generator::GeneratedAttribute.new(*attribute.split(":"))
end
end
private
def assign_names!(name)
@name = name
base_name, @class_path, @file_path, @class_nesting, @class_nesting_depth = extract_modules(@name)
@class_name_without_nesting, @singular_name, @plural_name = inflect_names(base_name)
@table_name = (!defined?(ActiveRecord::Base) || ActiveRecord::Base.pluralize_table_names) ? plural_name : singular_name
@table_name.gsub! '/', '_'
if @class_nesting.empty?
@class_name = @class_name_without_nesting
else
@table_name = @class_nesting.underscore << "_" << @table_name
@class_name = "#{@class_nesting}::#{@class_name_without_nesting}"
end
end
# Extract modules from filesystem-style or ruby-style path:
# good/fun/stuff
# Good::Fun::Stuff
# produce the same results.
def extract_modules(name)
modules = name.include?('/') ? name.split('/') : name.split('::')
name = modules.pop
path = modules.map { |m| m.underscore }
file_path = (path + [name.underscore]).join('/')
nesting = modules.map { |m| m.camelize }.join('::')
[name, path, file_path, nesting, modules.size]
end
def inflect_names(name)
camel = name.camelize
under = camel.underscore
plural = under.pluralize
[camel, under, plural]
end
end
end
end

View File

@ -1,621 +0,0 @@
require 'delegate'
require 'optparse'
require 'fileutils'
require 'tempfile'
require 'erb'
module Rails
module Generator
module Commands
# Here's a convenient way to get a handle on generator commands.
# Command.instance('destroy', my_generator) instantiates a Destroy
# delegate of my_generator ready to do your dirty work.
def self.instance(command, generator)
const_get(command.to_s.camelize).new(generator)
end
# Even more convenient access to commands. Include Commands in
# the generator Base class to get a nice #command instance method
# which returns a delegate for the requested command.
def self.included(base)
base.send(:define_method, :command) do |command|
Commands.instance(command, self)
end
end
# Generator commands delegate Rails::Generator::Base and implement
# a standard set of actions. Their behavior is defined by the way
# they respond to these actions: Create brings life; Destroy brings
# death; List passively observes.
#
# Commands are invoked by replaying (or rewinding) the generator's
# manifest of actions. See Rails::Generator::Manifest and
# Rails::Generator::Base#manifest method that generator subclasses
# are required to override.
#
# Commands allows generators to "plug in" invocation behavior, which
# corresponds to the GoF Strategy pattern.
class Base < DelegateClass(Rails::Generator::Base)
# Replay action manifest. RewindBase subclass rewinds manifest.
def invoke!
manifest.replay(self)
after_generate
end
def dependency(generator_name, args, runtime_options = {})
logger.dependency(generator_name) do
self.class.new(instance(generator_name, args, full_options(runtime_options))).invoke!
end
end
# Does nothing for all commands except Create.
def class_collisions(*class_names)
end
# Does nothing for all commands except Create.
def readme(*args)
end
protected
def current_migration_number
Dir.glob("#{RAILS_ROOT}/#{@migration_directory}/[0-9]*_*.rb").inject(0) do |max, file_path|
n = File.basename(file_path).split('_', 2).first.to_i
if n > max then n else max end
end
end
def next_migration_number
current_migration_number + 1
end
def migration_directory(relative_path)
directory(@migration_directory = relative_path)
end
def existing_migrations(file_name)
Dir.glob("#{@migration_directory}/[0-9]*_*.rb").grep(/[0-9]+_#{file_name}.rb$/)
end
def migration_exists?(file_name)
not existing_migrations(file_name).empty?
end
def next_migration_string(padding = 3)
if ActiveRecord::Base.timestamped_migrations
Time.now.utc.strftime("%Y%m%d%H%M%S")
else
"%.#{padding}d" % next_migration_number
end
end
def gsub_file(relative_destination, regexp, *args, &block)
path = destination_path(relative_destination)
content = File.read(path).gsub(regexp, *args, &block)
File.open(path, 'wb') { |file| file.write(content) }
end
private
# Ask the user interactively whether to force collision.
def force_file_collision?(destination, src, dst, file_options = {}, &block)
$stdout.print "overwrite #{destination}? (enter \"h\" for help) [Ynaqdh] "
case $stdin.gets.chomp
when /\Ad\z/i
Tempfile.open(File.basename(destination), File.dirname(dst)) do |temp|
temp.write render_file(src, file_options, &block)
temp.rewind
$stdout.puts `#{diff_cmd} "#{dst}" "#{temp.path}"`
end
puts "retrying"
raise 'retry diff'
when /\Aa\z/i
$stdout.puts "forcing #{spec.name}"
options[:collision] = :force
when /\Aq\z/i
$stdout.puts "aborting #{spec.name}"
raise SystemExit
when /\An\z/i then :skip
when /\Ay\z/i then :force
else
$stdout.puts <<-HELP
Y - yes, overwrite
n - no, do not overwrite
a - all, overwrite this and all others
q - quit, abort
d - diff, show the differences between the old and the new
h - help, show this help
HELP
raise 'retry'
end
rescue
retry
end
def diff_cmd
ENV['RAILS_DIFF'] || 'diff -u'
end
def render_template_part(template_options)
# Getting Sandbox to evaluate part template in it
part_binding = template_options[:sandbox].call.sandbox_binding
part_rel_path = template_options[:insert]
part_path = source_path(part_rel_path)
# Render inner template within Sandbox binding
rendered_part = ERB.new(File.readlines(part_path).join, nil, '-').result(part_binding)
begin_mark = template_part_mark(template_options[:begin_mark], template_options[:mark_id])
end_mark = template_part_mark(template_options[:end_mark], template_options[:mark_id])
begin_mark + rendered_part + end_mark
end
def template_part_mark(name, id)
"<!--[#{name}:#{id}]-->\n"
end
end
# Base class for commands which handle generator actions in reverse, such as Destroy.
class RewindBase < Base
# Rewind action manifest.
def invoke!
manifest.rewind(self)
end
end
# Create is the premier generator command. It copies files, creates
# directories, renders templates, and more.
class Create < Base
# Check whether the given class names are already taken by
# Ruby or Rails. In the future, expand to check other namespaces
# such as the rest of the user's app.
def class_collisions(*class_names)
path = class_names.shift
class_names.flatten.each do |class_name|
# Convert to string to allow symbol arguments.
class_name = class_name.to_s
# Skip empty strings.
next if class_name.strip.empty?
# Split the class from its module nesting.
nesting = class_name.split('::')
name = nesting.pop
# Hack to limit const_defined? to non-inherited on 1.9.
extra = []
extra << false unless Object.method(:const_defined?).arity == 1
# Extract the last Module in the nesting.
last = nesting.inject(Object) { |last, nest|
break unless last.const_defined?(nest, *extra)
last.const_get(nest)
}
# If the last Module exists, check whether the given
# class exists and raise a collision if so.
if last and last.const_defined?(name.camelize, *extra)
raise_class_collision(class_name)
end
end
end
# Copy a file from source to destination with collision checking.
#
# The file_options hash accepts :chmod and :shebang and :collision options.
# :chmod sets the permissions of the destination file:
# file 'config/empty.log', 'log/test.log', :chmod => 0664
# :shebang sets the #!/usr/bin/ruby line for scripts
# file 'bin/generate.rb', 'script/generate', :chmod => 0755, :shebang => '/usr/bin/env ruby'
# :collision sets the collision option only for the destination file:
# file 'settings/server.yml', 'config/server.yml', :collision => :skip
#
# Collisions are handled by checking whether the destination file
# exists and either skipping the file, forcing overwrite, or asking
# the user what to do.
def file(relative_source, relative_destination, file_options = {}, &block)
# Determine full paths for source and destination files.
source = source_path(relative_source)
destination = destination_path(relative_destination)
destination_exists = File.exist?(destination)
# If source and destination are identical then we're done.
if destination_exists and identical?(source, destination, &block)
return logger.identical(relative_destination)
end
# Check for and resolve file collisions.
if destination_exists
# Make a choice whether to overwrite the file. :force and
# :skip already have their mind made up, but give :ask a shot.
choice = case (file_options[:collision] || options[:collision]).to_sym #|| :ask
when :ask then force_file_collision?(relative_destination, source, destination, file_options, &block)
when :force then :force
when :skip then :skip
else raise "Invalid collision option: #{options[:collision].inspect}"
end
# Take action based on our choice. Bail out if we chose to
# skip the file; otherwise, log our transgression and continue.
case choice
when :force then logger.force(relative_destination)
when :skip then return(logger.skip(relative_destination))
else raise "Invalid collision choice: #{choice}.inspect"
end
# File doesn't exist so log its unbesmirched creation.
else
logger.create relative_destination
end
# If we're pretending, back off now.
return if options[:pretend]
# Write destination file with optional shebang. Yield for content
# if block given so templaters may render the source file. If a
# shebang is requested, replace the existing shebang or insert a
# new one.
File.open(destination, 'wb') do |dest|
dest.write render_file(source, file_options, &block)
end
# Optionally change permissions.
if file_options[:chmod]
FileUtils.chmod(file_options[:chmod], destination)
end
# Optionally add file to subversion or git
system("svn add #{destination}") if options[:svn]
system("git add -v #{relative_destination}") if options[:git]
end
# Checks if the source and the destination file are identical. If
# passed a block then the source file is a template that needs to first
# be evaluated before being compared to the destination.
def identical?(source, destination, &block)
return false if File.directory? destination
source = block_given? ? File.open(source) {|sf| yield(sf)} : IO.read(source)
destination = IO.read(destination)
source == destination
end
# Generate a file for a Rails application using an ERuby template.
# Looks up and evaluates a template by name and writes the result.
#
# The ERB template uses explicit trim mode to best control the
# proliferation of whitespace in generated code. <%- trims leading
# whitespace; -%> trims trailing whitespace including one newline.
#
# A hash of template options may be passed as the last argument.
# The options accepted by the file are accepted as well as :assigns,
# a hash of variable bindings. Example:
# template 'foo', 'bar', :assigns => { :action => 'view' }
#
# Template is implemented in terms of file. It calls file with a
# block which takes a file handle and returns its rendered contents.
def template(relative_source, relative_destination, template_options = {})
file(relative_source, relative_destination, template_options) do |file|
# Evaluate any assignments in a temporary, throwaway binding.
vars = template_options[:assigns] || {}
b = template_options[:binding] || binding
vars.each { |k,v| eval "#{k} = vars[:#{k}] || vars['#{k}']", b }
# Render the source file with the temporary binding.
ERB.new(file.read, nil, '-').result(b)
end
end
def complex_template(relative_source, relative_destination, template_options = {})
options = template_options.dup
options[:assigns] ||= {}
options[:assigns]['template_for_inclusion'] = render_template_part(template_options)
template(relative_source, relative_destination, options)
end
# Create a directory including any missing parent directories.
# Always skips directories which exist.
def directory(relative_path)
path = destination_path(relative_path)
if File.exist?(path)
logger.exists relative_path
else
logger.create relative_path
unless options[:pretend]
FileUtils.mkdir_p(path)
# git doesn't require adding the paths, adding the files later will
# automatically do a path add.
# Subversion doesn't do path adds, so we need to add
# each directory individually.
# So stack up the directory tree and add the paths to
# subversion in order without recursion.
if options[:svn]
stack = [relative_path]
until File.dirname(stack.last) == stack.last # dirname('.') == '.'
stack.push File.dirname(stack.last)
end
stack.reverse_each do |rel_path|
svn_path = destination_path(rel_path)
system("svn add -N #{svn_path}") unless File.directory?(File.join(svn_path, '.svn'))
end
end
end
end
end
# Display a README.
def readme(*relative_sources)
relative_sources.flatten.each do |relative_source|
logger.readme relative_source
puts File.read(source_path(relative_source)) unless options[:pretend]
end
end
# When creating a migration, it knows to find the first available file in db/migrate and use the migration.rb template.
def migration_template(relative_source, relative_destination, template_options = {})
migration_directory relative_destination
migration_file_name = template_options[:migration_file_name] || file_name
raise "Another migration is already named #{migration_file_name}: #{existing_migrations(migration_file_name).first}" if migration_exists?(migration_file_name)
template(relative_source, "#{relative_destination}/#{next_migration_string}_#{migration_file_name}.rb", template_options)
end
def route_resources(*resources)
resource_list = resources.map { |r| r.to_sym.inspect }.join(', ')
sentinel = 'ActionController::Routing::Routes.draw do |map|'
logger.route "map.resources #{resource_list}"
unless options[:pretend]
gsub_file 'config/routes.rb', /(#{Regexp.escape(sentinel)})/mi do |match|
"#{match}\n map.resources #{resource_list}\n"
end
end
end
private
def render_file(path, options = {})
File.open(path, 'rb') do |file|
if block_given?
yield file
else
content = ''
if shebang = options[:shebang]
content << "#!#{shebang}\n"
if line = file.gets
content << "line\n" if line !~ /^#!/
end
end
content << file.read
end
end
end
# Raise a usage error with an informative WordNet suggestion.
# Thanks to Florian Gross (flgr).
def raise_class_collision(class_name)
message = <<end_message
The name '#{class_name}' is either already used in your application or reserved by Ruby on Rails.
Please choose an alternative and run this generator again.
end_message
if suggest = find_synonyms(class_name)
if suggest.any?
message << "\n Suggestions: \n\n"
message << suggest.join("\n")
end
end
raise UsageError, message
end
SYNONYM_LOOKUP_URI = "http://wordnet.princeton.edu/perl/webwn?s=%s"
# Look up synonyms on WordNet. Thanks to Florian Gross (flgr).
def find_synonyms(word)
require 'open-uri'
require 'timeout'
timeout(5) do
open(SYNONYM_LOOKUP_URI % word) do |stream|
# Grab words linked to dictionary entries as possible synonyms
data = stream.read.gsub("&nbsp;", " ").scan(/<a href="webwn.*?">([\w ]*?)<\/a>/s).uniq
end
end
rescue Exception
return nil
end
end
# Undo the actions performed by a generator. Rewind the action
# manifest and attempt to completely erase the results of each action.
class Destroy < RewindBase
# Remove a file if it exists and is a file.
def file(relative_source, relative_destination, file_options = {})
destination = destination_path(relative_destination)
if File.exist?(destination)
logger.rm relative_destination
unless options[:pretend]
if options[:svn]
# If the file has been marked to be added
# but has not yet been checked in, revert and delete
if options[:svn][relative_destination]
system("svn revert #{destination}")
FileUtils.rm(destination)
else
# If the directory is not in the status list, it
# has no modifications so we can simply remove it
system("svn rm #{destination}")
end
elsif options[:git]
if options[:git][:new][relative_destination]
# file has been added, but not committed
system("git reset HEAD #{relative_destination}")
FileUtils.rm(destination)
elsif options[:git][:modified][relative_destination]
# file is committed and modified
system("git rm -f #{relative_destination}")
else
# If the directory is not in the status list, it
# has no modifications so we can simply remove it
system("git rm #{relative_destination}")
end
else
FileUtils.rm(destination)
end
end
else
logger.missing relative_destination
return
end
end
# Templates are deleted just like files and the actions take the
# same parameters, so simply alias the file method.
alias_method :template, :file
# Remove each directory in the given path from right to left.
# Remove each subdirectory if it exists and is a directory.
def directory(relative_path)
parts = relative_path.split('/')
until parts.empty?
partial = File.join(parts)
path = destination_path(partial)
if File.exist?(path)
if Dir[File.join(path, '*')].empty?
logger.rmdir partial
unless options[:pretend]
if options[:svn]
# If the directory has been marked to be added
# but has not yet been checked in, revert and delete
if options[:svn][relative_path]
system("svn revert #{path}")
FileUtils.rmdir(path)
else
# If the directory is not in the status list, it
# has no modifications so we can simply remove it
system("svn rm #{path}")
end
# I don't think git needs to remove directories?..
# or maybe they have special consideration...
else
FileUtils.rmdir(path)
end
end
else
logger.notempty partial
end
else
logger.missing partial
end
parts.pop
end
end
def complex_template(*args)
# nothing should be done here
end
# When deleting a migration, it knows to delete every file named "[0-9]*_#{file_name}".
def migration_template(relative_source, relative_destination, template_options = {})
migration_directory relative_destination
migration_file_name = template_options[:migration_file_name] || file_name
unless migration_exists?(migration_file_name)
puts "There is no migration named #{migration_file_name}"
return
end
existing_migrations(migration_file_name).each do |file_path|
file(relative_source, file_path, template_options)
end
end
def route_resources(*resources)
resource_list = resources.map { |r| r.to_sym.inspect }.join(', ')
look_for = "\n map.resources #{resource_list}\n"
logger.route "map.resources #{resource_list}"
gsub_file 'config/routes.rb', /(#{look_for})/mi, ''
end
end
# List a generator's action manifest.
class List < Base
def dependency(generator_name, args, options = {})
logger.dependency "#{generator_name}(#{args.join(', ')}, #{options.inspect})"
end
def class_collisions(*class_names)
logger.class_collisions class_names.join(', ')
end
def file(relative_source, relative_destination, options = {})
logger.file relative_destination
end
def template(relative_source, relative_destination, options = {})
logger.template relative_destination
end
def complex_template(relative_source, relative_destination, options = {})
logger.template "#{options[:insert]} inside #{relative_destination}"
end
def directory(relative_path)
logger.directory "#{destination_path(relative_path)}/"
end
def readme(*args)
logger.readme args.join(', ')
end
def migration_template(relative_source, relative_destination, options = {})
migration_directory relative_destination
logger.migration_template file_name
end
def route_resources(*resources)
resource_list = resources.map { |r| r.to_sym.inspect }.join(', ')
logger.route "map.resources #{resource_list}"
end
end
# Update generator's action manifest.
class Update < Create
def file(relative_source, relative_destination, options = {})
# logger.file relative_destination
end
def template(relative_source, relative_destination, options = {})
# logger.template relative_destination
end
def complex_template(relative_source, relative_destination, template_options = {})
begin
dest_file = destination_path(relative_destination)
source_to_update = File.readlines(dest_file).join
rescue Errno::ENOENT
logger.missing relative_destination
return
end
logger.refreshing "#{template_options[:insert].gsub(/\.erb/,'')} inside #{relative_destination}"
begin_mark = Regexp.quote(template_part_mark(template_options[:begin_mark], template_options[:mark_id]))
end_mark = Regexp.quote(template_part_mark(template_options[:end_mark], template_options[:mark_id]))
# Refreshing inner part of the template with freshly rendered part.
rendered_part = render_template_part(template_options)
source_to_update.gsub!(/#{begin_mark}.*?#{end_mark}/m, rendered_part)
File.open(dest_file, 'w') { |file| file.write(source_to_update) }
end
def directory(relative_path)
# logger.directory "#{destination_path(relative_path)}/"
end
end
end
end
end

View File

@ -1,46 +0,0 @@
require 'optparse'
module Rails
module Generator
class GeneratedAttribute
attr_accessor :name, :type, :column
def initialize(name, type)
@name, @type = name, type.to_sym
@column = ActiveRecord::ConnectionAdapters::Column.new(name, nil, @type)
end
def field_type
@field_type ||= case type
when :integer, :float, :decimal then :text_field
when :datetime, :timestamp, :time then :datetime_select
when :date then :date_select
when :string then :text_field
when :text then :text_area
when :boolean then :check_box
else
:text_field
end
end
def default
@default ||= case type
when :integer then 1
when :float then 1.5
when :decimal then "9.99"
when :datetime, :timestamp, :time then Time.now.to_s(:db)
when :date then Date.today.to_s(:db)
when :string then "MyString"
when :text then "MyText"
when :boolean then false
else
""
end
end
def reference?
[ :references, :belongs_to ].include?(self.type)
end
end
end
end

View File

@ -1,249 +0,0 @@
require 'pathname'
require File.dirname(__FILE__) + '/spec'
class Object
class << self
# Lookup missing generators using const_missing. This allows any
# generator to reference another without having to know its location:
# RubyGems, ~/.rails/generators, and RAILS_ROOT/generators.
def lookup_missing_generator(class_id)
if md = /(.+)Generator$/.match(class_id.to_s)
name = md.captures.first.demodulize.underscore
Rails::Generator::Base.lookup(name).klass
else
const_missing_before_generators(class_id)
end
end
unless respond_to?(:const_missing_before_generators)
alias_method :const_missing_before_generators, :const_missing
alias_method :const_missing, :lookup_missing_generator
end
end
end
# User home directory lookup adapted from RubyGems.
def Dir.user_home
if ENV['HOME']
ENV['HOME']
elsif ENV['USERPROFILE']
ENV['USERPROFILE']
elsif ENV['HOMEDRIVE'] and ENV['HOMEPATH']
"#{ENV['HOMEDRIVE']}:#{ENV['HOMEPATH']}"
else
File.expand_path '~'
end
end
module Rails
module Generator
# Generator lookup is managed by a list of sources which return specs
# describing where to find and how to create generators. This module
# provides class methods for manipulating the source list and looking up
# generator specs, and an #instance wrapper for quickly instantiating
# generators by name.
#
# A spec is not a generator: it's a description of where to find
# the generator and how to create it. A source is anything that
# yields generators from #each. PathSource and GemGeneratorSource are provided.
module Lookup
def self.included(base)
base.extend(ClassMethods)
base.use_component_sources!
end
# Convenience method to instantiate another generator.
def instance(generator_name, args, runtime_options = {})
self.class.instance(generator_name, args, runtime_options)
end
module ClassMethods
# The list of sources where we look, in order, for generators.
def sources
read_inheritable_attribute(:sources) or use_component_sources!
end
# Add a source to the end of the list.
def append_sources(*args)
sources.concat(args.flatten)
invalidate_cache!
end
# Add a source to the beginning of the list.
def prepend_sources(*args)
write_inheritable_array(:sources, args.flatten + sources)
invalidate_cache!
end
# Reset the source list.
def reset_sources
write_inheritable_attribute(:sources, [])
invalidate_cache!
end
# Use application generators (app, ?).
def use_application_sources!
reset_sources
sources << PathSource.new(:builtin, "#{File.dirname(__FILE__)}/generators/applications")
end
# Use component generators (model, controller, etc).
# 1. Rails application. If RAILS_ROOT is defined we know we're
# generating in the context of a Rails application, so search
# RAILS_ROOT/generators.
# 2. Look in plugins, either for generators/ or rails_generators/
# directories within each plugin
# 3. User home directory. Search ~/.rails/generators.
# 4. RubyGems. Search for gems named *_generator, and look for
# generators within any RubyGem's
# /rails_generators/<generator_name>_generator.rb file.
# 5. Builtins. Model, controller, mailer, scaffold, and so on.
def use_component_sources!
reset_sources
if defined? ::RAILS_ROOT
sources << PathSource.new(:lib, "#{::RAILS_ROOT}/lib/generators")
sources << PathSource.new(:vendor, "#{::RAILS_ROOT}/vendor/generators")
Rails.configuration.plugin_paths.each do |path|
relative_path = Pathname.new(File.expand_path(path)).relative_path_from(Pathname.new(::RAILS_ROOT))
sources << PathSource.new(:"plugins (#{relative_path})", "#{path}/*/**/{,rails_}generators")
end
end
sources << PathSource.new(:user, "#{Dir.user_home}/.rails/generators")
if Object.const_defined?(:Gem)
sources << GemGeneratorSource.new
sources << GemPathSource.new
end
sources << PathSource.new(:builtin, "#{File.dirname(__FILE__)}/generators/components")
end
# Lookup knows how to find generators' Specs from a list of Sources.
# Searches the sources, in order, for the first matching name.
def lookup(generator_name)
@found ||= {}
generator_name = generator_name.to_s.downcase
@found[generator_name] ||= cache.find { |spec| spec.name == generator_name }
unless @found[generator_name]
chars = generator_name.scan(/./).map{|c|"#{c}.*?"}
rx = /^#{chars}$/
gns = cache.select{|spec| spec.name =~ rx }
@found[generator_name] ||= gns.first if gns.length == 1
raise GeneratorError, "Pattern '#{generator_name}' matches more than one generator: #{gns.map{|sp|sp.name}.join(', ')}" if gns.length > 1
end
@found[generator_name] or raise GeneratorError, "Couldn't find '#{generator_name}' generator"
end
# Convenience method to lookup and instantiate a generator.
def instance(generator_name, args = [], runtime_options = {})
lookup(generator_name).klass.new(args, full_options(runtime_options))
end
private
# Lookup and cache every generator from the source list.
def cache
@cache ||= sources.inject([]) { |cache, source| cache + source.to_a }
end
# Clear the cache whenever the source list changes.
def invalidate_cache!
@cache = nil
end
end
end
# Sources enumerate (yield from #each) generator specs which describe
# where to find and how to create generators. Enumerable is mixed in so,
# for example, source.collect will retrieve every generator.
# Sources may be assigned a label to distinguish them.
class Source
include Enumerable
attr_reader :label
def initialize(label)
@label = label
end
# The each method must be implemented in subclasses.
# The base implementation raises an error.
def each
raise NotImplementedError
end
# Return a convenient sorted list of all generator names.
def names
map { |spec| spec.name }.sort
end
end
# PathSource looks for generators in a filesystem directory.
class PathSource < Source
attr_reader :path
def initialize(label, path)
super label
@path = path
end
# Yield each eligible subdirectory.
def each
Dir["#{path}/[a-z]*"].each do |dir|
if File.directory?(dir)
yield Spec.new(File.basename(dir), dir, label)
end
end
end
end
class AbstractGemSource < Source
def initialize
super :RubyGems
end
end
# GemGeneratorSource hits the mines to quarry for generators. The latest versions
# of gems named *_generator are selected.
class GemGeneratorSource < AbstractGemSource
# Yield latest versions of generator gems.
def each
dependency = Gem::Dependency.new(/_generator$/, Gem::Requirement.default)
Gem::cache.search(dependency).inject({}) { |latest, gem|
hem = latest[gem.name]
latest[gem.name] = gem if hem.nil? or gem.version > hem.version
latest
}.values.each { |gem|
yield Spec.new(gem.name.sub(/_generator$/, ''), gem.full_gem_path, label)
}
end
end
# GemPathSource looks for generators within any RubyGem's /rails_generators/<generator_name>_generator.rb file.
class GemPathSource < AbstractGemSource
# Yield each generator within rails_generator subdirectories.
def each
generator_full_paths.each do |generator|
yield Spec.new(File.basename(generator).sub(/_generator.rb$/, ''), File.dirname(generator), label)
end
end
private
def generator_full_paths
@generator_full_paths ||=
Gem::cache.inject({}) do |latest, name_gem|
name, gem = name_gem
hem = latest[gem.name]
latest[gem.name] = gem if hem.nil? or gem.version > hem.version
latest
end.values.inject([]) do |mem, gem|
Dir[gem.full_gem_path + '/{rails_,}generators/**/*_generator.rb'].each do |generator|
mem << generator
end
mem
end
end
end
end
end

View File

@ -1,53 +0,0 @@
module Rails
module Generator
# Manifest captures the actions a generator performs. Instantiate
# a manifest with an optional target object, hammer it with actions,
# then replay or rewind on the object of your choice.
#
# Example:
# manifest = Manifest.new { |m|
# m.make_directory '/foo'
# m.create_file '/foo/bar.txt'
# }
# manifest.replay(creator)
# manifest.rewind(destroyer)
class Manifest
attr_reader :target
# Take a default action target. Yield self if block given.
def initialize(target = nil)
@target, @actions = target, []
yield self if block_given?
end
# Record an action.
def method_missing(action, *args, &block)
@actions << [action, args, block]
end
# Replay recorded actions.
def replay(target = nil)
send_actions(target || @target, @actions)
end
# Rewind recorded actions.
def rewind(target = nil)
send_actions(target || @target, @actions.reverse)
end
# Erase recorded actions.
def erase
@actions = []
end
private
def send_actions(target, actions)
actions.each do |method, args, block|
target.send(method, *args, &block)
end
end
end
end
end

View File

@ -1,150 +0,0 @@
require 'optparse'
module Rails
module Generator
module Options
def self.included(base)
base.extend(ClassMethods)
class << base
if respond_to?(:inherited)
alias_method :inherited_without_options, :inherited
end
alias_method :inherited, :inherited_with_options
end
end
module ClassMethods
def inherited_with_options(sub)
inherited_without_options(sub) if respond_to?(:inherited_without_options)
sub.extend(Rails::Generator::Options::ClassMethods)
end
def mandatory_options(options = nil)
if options
write_inheritable_attribute(:mandatory_options, options)
else
read_inheritable_attribute(:mandatory_options) or write_inheritable_attribute(:mandatory_options, {})
end
end
def default_options(options = nil)
if options
write_inheritable_attribute(:default_options, options)
else
read_inheritable_attribute(:default_options) or write_inheritable_attribute(:default_options, {})
end
end
# Merge together our class options. In increasing precedence:
# default_options (class default options)
# runtime_options (provided as argument)
# mandatory_options (class mandatory options)
def full_options(runtime_options = {})
default_options.merge(runtime_options).merge(mandatory_options)
end
end
# Each instance has an options hash that's populated by #parse.
def options
@options ||= {}
end
attr_writer :options
protected
# Convenient access to class mandatory options.
def mandatory_options
self.class.mandatory_options
end
# Convenient access to class default options.
def default_options
self.class.default_options
end
# Merge together our instance options. In increasing precedence:
# default_options (class default options)
# options (instance options)
# runtime_options (provided as argument)
# mandatory_options (class mandatory options)
def full_options(runtime_options = {})
self.class.full_options(options.merge(runtime_options))
end
# Parse arguments into the options hash. Classes may customize
# parsing behavior by overriding these methods:
# #banner Usage: ./script/generate [options]
# #add_options! Options:
# some options..
# #add_general_options! General Options:
# general options..
def parse!(args, runtime_options = {})
self.options = {}
@option_parser = OptionParser.new do |opt|
opt.banner = banner
add_options!(opt)
add_general_options!(opt)
opt.parse!(args)
end
return args
ensure
self.options = full_options(runtime_options)
end
# Raise a usage error. Override usage_message to provide a blurb
# after the option parser summary.
def usage(message = usage_message)
raise UsageError, "#{@option_parser}\n#{message}"
end
def usage_message
''
end
# Override with your own usage banner.
def banner
"Usage: #{$0} [options]"
end
# Override to add your options to the parser:
# def add_options!(opt)
# opt.on('-v', '--verbose') { |value| options[:verbose] = value }
# end
def add_options!(opt)
end
# Adds general options like -h and --quiet. Usually don't override.
def add_general_options!(opt)
opt.separator ''
opt.separator 'Rails Info:'
opt.on('-v', '--version', 'Show the Rails version number and quit.')
opt.on('-h', '--help', 'Show this help message and quit.') { |v| options[:help] = v }
opt.separator ''
opt.separator 'General Options:'
opt.on('-p', '--pretend', 'Run but do not make any changes.') { |v| options[:pretend] = v }
opt.on('-f', '--force', 'Overwrite files that already exist.') { options[:collision] = :force }
opt.on('-s', '--skip', 'Skip files that already exist.') { options[:collision] = :skip }
opt.on('-q', '--quiet', 'Suppress normal output.') { |v| options[:quiet] = v }
opt.on('-t', '--backtrace', 'Debugging: show backtrace on errors.') { |v| options[:backtrace] = v }
opt.on('-c', '--svn', 'Modify files with subversion. (Note: svn must be in path)') do
options[:svn] = `svn status`.inject({}) do |opt, e|
opt[e.chomp[7..-1]] = true
opt
end
end
opt.on('-g', '--git', 'Modify files with git. (Note: git must be in path)') do
options[:git] = `git status`.inject({:new => {}, :modified => {}}) do |opt, e|
opt[:new][e.chomp[14..-1]] = true if e =~ /new file:/
opt[:modified][e.chomp[14..-1]] = true if e =~ /modified:/
opt
end
end
end
end
end
end

View File

@ -1,89 +0,0 @@
require File.dirname(__FILE__) + '/options'
module Rails
module Generator
module Scripts
# Generator scripts handle command-line invocation. Each script
# responds to an invoke! class method which handles option parsing
# and generator invocation.
class Base
include Options
default_options :collision => :ask, :quiet => false
# Run the generator script. Takes an array of unparsed arguments
# and a hash of parsed arguments, takes the generator as an option
# or first remaining argument, and invokes the requested command.
def run(args = [], runtime_options = {})
begin
parse!(args.dup, runtime_options)
rescue OptionParser::InvalidOption => e
# Don't cry, script. Generators want what you think is invalid.
end
# Generator name is the only required option.
unless options[:generator]
usage if args.empty?
options[:generator] ||= args.shift
end
# Look up generator instance and invoke command on it.
Rails::Generator::Base.instance(options[:generator], args, options).command(options[:command]).invoke!
rescue => e
puts e
puts " #{e.backtrace.join("\n ")}\n" if options[:backtrace]
raise SystemExit
end
protected
# Override with your own script usage banner.
def banner
"Usage: #{$0} generator [options] [args]"
end
def usage_message
usage = "\nInstalled Generators\n"
Rails::Generator::Base.sources.inject([]) do |mem, source|
# Using an association list instead of a hash to preserve order,
# for aesthetic reasons more than anything else.
label = source.label.to_s.capitalize
pair = mem.assoc(label)
mem << (pair = [label, []]) if pair.nil?
pair[1] |= source.names
mem
end.each do |label, names|
usage << " #{label}: #{names.join(', ')}\n" unless names.empty?
end
usage << <<end_blurb
You can also install additional generators for your own use:
1. Download, for example, login_generator.zip
2. Unzip to directory #{Dir.user_home}/.rails/generators/login
to use the generator with all your Rails apps
end_blurb
if Object.const_defined?(:RAILS_ROOT)
usage << <<end_blurb
or to #{File.expand_path(RAILS_ROOT)}/lib/generators/login
to use with this app only.
end_blurb
end
usage << <<end_blurb
3. Run generate with no arguments for usage information
#{$0} login
Generator gems are also available:
1. gem search -r generator
2. gem install login_generator
3. #{$0} login
end_blurb
return usage
end
end # Base
end
end
end

View File

@ -1,29 +0,0 @@
require File.dirname(__FILE__) + '/../scripts'
module Rails::Generator::Scripts
class Destroy < Base
mandatory_options :command => :destroy
protected
def usage_message
usage = "\nInstalled Generators\n"
Rails::Generator::Base.sources.each do |source|
label = source.label.to_s.capitalize
names = source.names
usage << " #{label}: #{names.join(', ')}\n" unless names.empty?
end
usage << <<end_blurb
script/generate command. For instance, 'script/destroy migration CreatePost'
will delete the appropriate XXX_create_post.rb migration file in db/migrate,
while 'script/destroy scaffold Post' will delete the posts controller and
views, post model and migration, all associated tests, and the map.resources
:posts line in config/routes.rb.
For instructions on finding new generators, run script/generate.
end_blurb
return usage
end
end
end

View File

@ -1,7 +0,0 @@
require File.dirname(__FILE__) + '/../scripts'
module Rails::Generator::Scripts
class Generate < Base
mandatory_options :command => :create
end
end

View File

@ -1,12 +0,0 @@
require File.dirname(__FILE__) + '/../scripts'
module Rails::Generator::Scripts
class Update < Base
mandatory_options :command => :update
protected
def banner
"Usage: #{$0} [options] scaffold"
end
end
end

View File

@ -1,46 +0,0 @@
module Rails
module Generator
class SimpleLogger # :nodoc:
attr_reader :out
attr_accessor :quiet
def initialize(out = $stdout)
@out = out
@quiet = false
@level = 0
end
def log(status, message, &block)
@out.print("%12s %s%s\n" % [status, ' ' * @level, message]) unless quiet
indent(&block) if block_given?
end
def indent(&block)
@level += 1
if block_given?
begin
block.call
ensure
outdent
end
end
end
def outdent
@level -= 1
if block_given?
begin
block.call
ensure
indent
end
end
end
private
def method_missing(method, *args, &block)
log(method.to_s, args.first, &block)
end
end
end
end

View File

@ -1,44 +0,0 @@
module Rails
module Generator
# A spec knows where a generator was found and how to instantiate it.
# Metadata include the generator's name, its base path, and the source
# which yielded it (PathSource, GemPathSource, etc.)
class Spec
attr_reader :name, :path, :source
def initialize(name, path, source)
@name, @path, @source = name, path, source
end
# Look up the generator class. Require its class file, find the class
# in ObjectSpace, tag it with this spec, and return.
def klass
unless @klass
require class_file
@klass = lookup_class
@klass.spec = self
end
@klass
end
def class_file
"#{path}/#{name}_generator.rb"
end
def class_name
"#{name.camelize}Generator"
end
private
# Search for the first Class descending from Rails::Generator::Base
# whose name matches the requested class name.
def lookup_class
ObjectSpace.each_object(Class) do |obj|
return obj if obj.ancestors.include?(Rails::Generator::Base) and
obj.name.split('::').last == class_name
end
raise NameError, "Missing #{class_name} class in #{class_file}"
end
end
end
end

View File

@ -1,42 +0,0 @@
require 'plugin_test_helper'
class GeneratorLookupTest < Test::Unit::TestCase
def setup
@fixture_dirs = %w{alternate default}
@configuration = Rails.configuration = Rails::Configuration.new
# We need to add our testing plugin directory to the plugin paths so
# the locator knows where to look for our plugins
@configuration.plugin_paths += @fixture_dirs.map{|fd| plugin_fixture_path(fd)}
@initializer = Rails::Initializer.default
@initializer.config = @configuration
@initializer.run(:add_plugin_load_paths)
@initializer.run(:load_plugins)
@initializer.run(:set_root_path)
load 'rails_generator.rb'
require 'rails_generator/scripts'
end
def test_should_load_from_all_plugin_paths
assert Rails::Generator::Base.lookup('a_generator')
assert Rails::Generator::Base.lookup('stubby_generator')
end
def test_should_create_generator_source_for_each_directory_in_plugin_paths
sources = Rails::Generator::Base.sources
@fixture_dirs.each do |gen_dir|
expected_label = "plugins (fixtures/plugins/#{gen_dir})".to_sym
assert sources.any? {|source| source.label == expected_label }
end
end
def test_should_preserve_order_in_usage_message
msg = Rails::Generator::Scripts::Base.new.send(:usage_message)
positions = @fixture_dirs.map do |gen_dir|
pos = msg.index("Plugins (fixtures/plugins/#{gen_dir})")
assert_not_nil pos
pos
end
assert_equal positions.sort, positions
end
end

View File

@ -1,10 +1,16 @@
require 'test/unit'
require 'fileutils'
require 'mocha'
$LOAD_PATH.unshift "#{File.dirname(__FILE__)}/../../lib"
require 'generators'
fixtures = File.expand_path(File.join(File.dirname(__FILE__), '..', 'fixtures'))
if defined?(RAILS_ROOT)
RAILS_ROOT.replace fixtures
else
RAILS_ROOT = fixtures
end
class GeneratorsTestCase < Test::Unit::TestCase
include FileUtils

View File

@ -1,117 +0,0 @@
require 'test/unit'
# Optionally load RubyGems.
begin
require 'rubygems'
rescue LoadError
end
# Mock out what we need from AR::Base.
module ActiveRecord
class Base
class << self
attr_accessor :pluralize_table_names
end
self.pluralize_table_names = true
end
end
# And what we need from ActionView
module ActionView
module Helpers
module ActiveRecordHelper; end
class InstanceTag; end
end
end
# Must set before requiring generator libs.
if defined?(RAILS_ROOT)
RAILS_ROOT.replace "#{File.dirname(__FILE__)}/fixtures"
else
RAILS_ROOT = "#{File.dirname(__FILE__)}/fixtures"
end
$LOAD_PATH.unshift "#{File.dirname(__FILE__)}/../lib"
require 'initializer'
# Mocks out the configuration
module Rails
def self.configuration
Rails::Configuration.new
end
end
require 'rails_generator'
#class RailsGeneratorTest < Test::Unit::TestCase
# BUILTINS = %w(controller integration_test mailer migration model observer plugin resource scaffold session_migration)
# CAPITALIZED_BUILTINS = BUILTINS.map { |b| b.capitalize }
# def setup
# ActiveRecord::Base.pluralize_table_names = true
# @initializer = Rails::Initializer.default
# @initializer.config = Rails.configuration
# @initializer.run(:set_root_path)
# end
# def test_sources
# expected = [:lib, :vendor,
# "plugins (vendor/plugins)".to_sym, # <plugin>/generators and <plugin>/rails_generators
# :user,
# :RubyGems, :RubyGems, # gems named <x>_generator, gems containing /rails_generator/ folder
# :builtin]
# expected.delete(:RubyGems) unless Object.const_defined?(:Gem)
# assert_equal expected, Rails::Generator::Base.sources.map { |s| s.label }
# end
# def test_lookup_builtins
# (BUILTINS + CAPITALIZED_BUILTINS).each do |name|
# assert_nothing_raised do
# spec = Rails::Generator::Base.lookup(name)
# assert_not_nil spec
# assert_kind_of Rails::Generator::Spec, spec
# klass = spec.klass
# assert klass < Rails::Generator::Base
# assert_equal spec, klass.spec
# end
# end
# end
# def test_autolookup
# assert_nothing_raised { ControllerGenerator }
# assert_nothing_raised { ModelGenerator }
# end
# def test_lookup_missing_generator
# assert_raise Rails::Generator::GeneratorError do
# Rails::Generator::Base.lookup('missing').klass
# end
# end
# def test_lookup_missing_class
# spec = nil
# assert_nothing_raised { spec = Rails::Generator::Base.lookup('missing_class') }
# assert_not_nil spec
# assert_kind_of Rails::Generator::Spec, spec
# assert_raise(NameError) { spec.klass }
# end
# def test_generator_usage
# (BUILTINS - ["session_migration"]).each do |name|
# assert_raise(Rails::Generator::UsageError, "Generator '#{name}' should raise an error without arguments") {
# Rails::Generator::Base.instance(name)
# }
# end
# end
# def test_generator_spec
# spec = Rails::Generator::Base.lookup('working')
# assert_equal 'working', spec.name
# assert_match(/#{spec.path}$/, "#{RAILS_ROOT}/lib/generators/working")
# assert_equal :lib, spec.source
# assert_nothing_raised { assert_match(/WorkingGenerator$/, spec.klass.name) }
# end
#end