diff --git a/railties/lib/generators/base.rb b/railties/lib/generators/base.rb index e7d0ac80eb..d4bce83161 100644 --- a/railties/lib/generators/base.rb +++ b/railties/lib/generators/base.rb @@ -29,6 +29,39 @@ def self.namespace(name=nil) #:nodoc: protected + # 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) + return unless behavior == :invoke + + class_names.flatten.each do |class_name| + class_name = class_name.to_s + next if class_name.strip.empty? + + # Split the class from its module nesting + nesting = class_name.split('::') + last_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) do |last, nest| + break unless last.const_defined?(nest, *extra) + last.const_get(nest) + end + + if last && last.const_defined?(last_name.camelize, *extra) + raise Error, "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 + end + end + # Use Rails default banner. # def self.banner diff --git a/railties/lib/generators/rails/metal/metal_generator.rb b/railties/lib/generators/rails/metal/metal_generator.rb index ba062b30be..f8833ecec3 100644 --- a/railties/lib/generators/rails/metal/metal_generator.rb +++ b/railties/lib/generators/rails/metal/metal_generator.rb @@ -1,7 +1,13 @@ -module Rails::Generators - class MetalGenerator < NamedBase - def create_file - template "metal.rb", "app/metal/#{file_name}.rb" +module Rails + module Generators + class MetalGenerator < NamedBase + def check_class_collision + class_collisions class_name + end + + def create_file + template "metal.rb", "app/metal/#{file_name}.rb" + end end end end diff --git a/railties/lib/generators/rails/observer/observer_generator.rb b/railties/lib/generators/rails/observer/observer_generator.rb index 9a5253a0ad..e5e1be39dc 100644 --- a/railties/lib/generators/rails/observer/observer_generator.rb +++ b/railties/lib/generators/rails/observer/observer_generator.rb @@ -1,8 +1,9 @@ module Rails module Generators class ObserverGenerator < NamedBase - # TODO Check class collisions - # class_collisions "#{class_name}Observer", "#{class_name}ObserverTest" + def check_class_collision + class_collisions "#{class_name}Observer" + end def create_observer_file template 'observer.rb', File.join('app/models', class_path, "#{file_name}_observer.rb") diff --git a/railties/lib/generators/rails/plugin/plugin_generator.rb b/railties/lib/generators/rails/plugin/plugin_generator.rb index eb36cea0f1..4dbb3bfc0d 100644 --- a/railties/lib/generators/rails/plugin/plugin_generator.rb +++ b/railties/lib/generators/rails/plugin/plugin_generator.rb @@ -7,8 +7,9 @@ class PluginGenerator < NamedBase class_option :with_generator, :type => :boolean, :aliases => "-g", :default => false, :desc => "When supplied creates generator base files." - # TODO Check class collision - # class_collision class_name + def check_class_collision + class_collisions class_name + end def create_root self.root = File.expand_path("vendor/plugins/#{file_name}", root) diff --git a/railties/test/generators/generators_test_helper.rb b/railties/test/generators/generators_test_helper.rb index 9462fc2214..1fcfdaebb9 100644 --- a/railties/test/generators/generators_test_helper.rb +++ b/railties/test/generators/generators_test_helper.rb @@ -12,12 +12,8 @@ def destination_root end def setup + rm_rf(destination_root) mkdir_p(destination_root) - rm_rf(destination_root) - end - - def teardown - rm_rf(destination_root) end def test_truth diff --git a/railties/test/generators/metal_generator_test.rb b/railties/test/generators/metal_generator_test.rb index dfa948d14e..4e73883feb 100644 --- a/railties/test/generators/metal_generator_test.rb +++ b/railties/test/generators/metal_generator_test.rb @@ -9,10 +9,15 @@ def test_metal_skeleton_is_created assert_file "app/metal/foo.rb", /class Foo/ end + def test_check_class_collision + content = capture(:stderr){ run_generator ["object"] } + assert_match /The name 'Object' is either already used in your application or reserved/, content + end + protected - def run_generator(args=[]) - silence(:stdout) { Rails::Generators::MetalGenerator.start ["foo"].concat(args), :root => destination_root } + def run_generator(args=["foo"]) + silence(:stdout) { Rails::Generators::MetalGenerator.start args, :root => destination_root } end end diff --git a/railties/test/generators/plugin_generator_test.rb b/railties/test/generators/plugin_generator_test.rb index b4aa39ae5f..3f2b27c518 100644 --- a/railties/test/generators/plugin_generator_test.rb +++ b/railties/test/generators/plugin_generator_test.rb @@ -15,23 +15,28 @@ def test_plugin_skeleton_is_created ).each{ |path| assert_file path } end + def test_check_class_collision + content = capture(:stderr){ run_generator ["object"] } + assert_match /The name 'Object' is either already used in your application or reserved/, content + end + def test_invokes_default_test_framework run_generator assert_file "vendor/plugins/plugin_fu/test/plugin_fu_test.rb" end def test_logs_if_the_test_framework_cannot_be_found - content = run_generator ["--test-framework=unknown"] + content = run_generator ["plugin_fu", "--test-framework=unknown"] assert_match /Could not find and invoke 'unknown:generators:plugin'/, content end def test_creates_tasks_if_required - run_generator ["--with-tasks"] + run_generator ["plugin_fu", "--with-tasks"] assert_file "vendor/plugins/plugin_fu/tasks/plugin_fu_tasks.rake" end def test_creates_generator_if_required - run_generator ["--with-generator"] + run_generator ["plugin_fu", "--with-generator"] assert_file "vendor/plugins/plugin_fu/generators/plugin_fu/templates" flag = /class PluginFuGenerator < Rails::Generators::NamedBase/ @@ -40,8 +45,8 @@ def test_creates_generator_if_required protected - def run_generator(args=[]) - silence(:stdout) { Rails::Generators::PluginGenerator.start ["plugin_fu"].concat(args), :root => destination_root } + def run_generator(args=["plugin_fu"]) + silence(:stdout) { Rails::Generators::PluginGenerator.start args, :root => destination_root } end end