Avoid duplicated names on help description and show proper error message if trying to load a Rails 2.x generator.

Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
This commit is contained in:
José Valim 2009-11-03 20:50:39 -02:00 committed by Jeremy Kemper
parent f950d0b4af
commit e15b5eda2b
3 changed files with 49 additions and 16 deletions

View File

@ -152,7 +152,18 @@ module Rails
end end
load_paths # Cache load paths. Needed to avoid __FILE__ pointing to wrong paths. load_paths # Cache load paths. Needed to avoid __FILE__ pointing to wrong paths.
# Receives a namespace and tries different combinations to find a generator. # Rails finds namespaces exactly as thor, with three conveniences:
#
# 1) If your generator name ends with generator, as WebratGenerator, it sets
# its namespace to "webrat", so it can be invoked as "webrat" and not
# "webrat_generator";
#
# 2) If your generator has a generators namespace, as Rails::Generators::WebratGenerator,
# the namespace is set to "rails:generators:webrat", but Rails allows it
# to be invoked simply as "rails:webrat". The "generators" is added
# automatically when doing the lookup;
#
# 3) Rails looks in load paths and loads the generator just before it's going to be used.
# #
# ==== Examples # ==== Examples
# #
@ -162,30 +173,29 @@ module Rails
# #
# "rails:generators:webrat", "webrat:generators:integration", "webrat" # "rails:generators:webrat", "webrat:generators:integration", "webrat"
# #
# If the namespace has ":" included we consider that a absolute namespace # On the other hand, if "rails:webrat" is given, it will search for:
# was given and the lookup above does not happen. Just the name is searched.
# #
# Finally, it deals with one kind of shortcut: # "rails:generators:webrat", "rails:webrat"
# #
# find_by_namespace "test_unit:model" # Notice that the "generators" namespace is handled automatically by Rails,
# # so you don't need to type it when you want to invoke a generator in specific.
# It will search for generators at:
#
# "test_unit:generators:model", "test_unit:model"
# #
def self.find_by_namespace(name, base=nil, context=nil) #:nodoc: def self.find_by_namespace(name, base=nil, context=nil) #:nodoc:
name, attempts = name.to_s, [] name, attempts = name.to_s, [ ]
case name.count(':') case name.count(':')
when 1 when 1
base, name = name.split(':') base, name = name.split(':')
return find_by_namespace(name, base) return find_by_namespace(name, base)
when 0 when 0
attempts << "#{base}:generators:#{name}" if base attempts += generator_names(base, name) if base
attempts << "#{name}:generators:#{context}" if context attempts += generator_names(name, context) if context
end end
attempts << name attempts << name
attempts += generator_names(name, name) unless name.include?(?:)
attempts.uniq!
unloaded = attempts - namespaces unloaded = attempts - namespaces
lookup(unloaded) lookup(unloaded)
@ -231,7 +241,10 @@ module Rails
until tail.empty? until tail.empty?
others += Dir[File.join(path, *tail)].collect do |file| others += Dir[File.join(path, *tail)].collect do |file|
file.split('/')[-tail.size, 2].join(':').sub(/_generator\.rb$/, '') name = file.split('/')[-tail.size, 2]
name.last.sub!(/_generator\.rb$/, '')
name.uniq!
name.join(':')
end end
tail.shift tail.shift
end end
@ -246,7 +259,7 @@ module Rails
# Return all defined namespaces. # Return all defined namespaces.
# #
def self.namespaces #:nodoc: def self.namespaces #:nodoc:
Thor::Base.subclasses.map{ |klass| klass.namespace } Thor::Base.subclasses.map { |klass| klass.namespace }
end end
# Keep builtin generators in an Array[Array[group, name]]. # Keep builtin generators in an Array[Array[group, name]].
@ -257,6 +270,12 @@ module Rails
end end
end end
# By default, Rails strips the generator namespace to make invocations
# easier. This method generaters the both possibilities names.
def self.generator_names(first, second)
[ "#{first}:generators:#{second}", "#{first}:#{second}" ]
end
# Try callbacks for the given base. # Try callbacks for the given base.
# #
def self.invoke_fallbacks_for(name, base) def self.invoke_fallbacks_for(name, base)
@ -285,6 +304,9 @@ module Rails
Dir[File.join(path, '**', attempts)].each do |file| Dir[File.join(path, '**', attempts)].each do |file|
begin begin
require file require file
rescue NameError => e
raise unless e.message =~ /Rails::Generator/
warn "[WARNING] Could not load generator at #{file.inspect} because it's a Rails 2.x generator, which is not supported anymore"
rescue Exception => e rescue Exception => e
warn "[WARNING] Could not load generator at #{file.inspect}. Error: #{e.message}" warn "[WARNING] Could not load generator at #{file.inspect}. Error: #{e.message}"
end end

View File

@ -0,0 +1,4 @@
module Foobar
class FoobarGenerator < Rails::Generators::Base
end
end

View File

@ -45,6 +45,12 @@ class GeneratorsTest < GeneratorsTestCase
assert_equal "test_unit:generators:model", klass.namespace assert_equal "test_unit:generators:model", klass.namespace
end end
def test_find_by_namespace_with_duplicated_name
klass = Rails::Generators.find_by_namespace(:foobar)
assert klass
assert_equal "foobar:foobar", klass.namespace
end
def test_find_by_namespace_add_generators_to_raw_lookups def test_find_by_namespace_add_generators_to_raw_lookups
klass = Rails::Generators.find_by_namespace("test_unit:model") klass = Rails::Generators.find_by_namespace("test_unit:model")
assert klass assert klass
@ -101,14 +107,15 @@ class GeneratorsTest < GeneratorsTestCase
def test_rails_generators_with_others_information def test_rails_generators_with_others_information
output = capture(:stdout){ Rails::Generators.help }.split("\n").last output = capture(:stdout){ Rails::Generators.help }.split("\n").last
assert_equal "Others: active_record:fixjour, fixjour, mspec, rails:javascripts.", output assert_equal "Others: active_record:fixjour, fixjour, foobar, mspec, rails:javascripts.", output
end end
def test_warning_is_shown_if_generator_cant_be_loaded def test_warning_is_shown_if_generator_cant_be_loaded
Rails::Generators.load_paths << File.join(Rails.root, "vendor", "gems", "gems", "wrong") Rails::Generators.load_paths << File.join(Rails.root, "vendor", "gems", "gems", "wrong")
output = capture(:stderr){ Rails::Generators.find_by_namespace(:wrong) } output = capture(:stderr){ Rails::Generators.find_by_namespace(:wrong) }
assert_match /\[WARNING\] Could not load generator at/, output assert_match /\[WARNING\] Could not load generator at/, output
assert_match /Error: uninitialized constant Rails::Generator/, output assert_match /Rails 2\.x generator/, output
end end
def test_no_color_sets_proper_shell def test_no_color_sets_proper_shell