From da36a91fdfe6ec82122b0703d8ff811e24e87224 Mon Sep 17 00:00:00 2001 From: pablobm Date: Mon, 16 Mar 2009 23:40:29 +0000 Subject: [PATCH] Make scaffold and resource generators work nice with namespaced resources. Also refactored some stuff to avoid going mad in the process. --- railties/lib/rails_generator/base.rb | 48 +++------ railties/lib/rails_generator/commands.rb | 36 ++++-- .../components/resource/resource_generator.rb | 57 +++++----- .../components/resource/templates/controller.rb | 2 +- .../resource/templates/functional_test.rb | 2 +- .../components/resource/templates/helper.rb | 2 +- .../components/resource/templates/helper_test.rb | 2 +- .../components/scaffold/scaffold_generator.rb | 89 ++++++++------- .../components/scaffold/templates/controller.rb | 70 ++++++------ .../scaffold/templates/functional_test.rb | 32 +++--- .../components/scaffold/templates/helper.rb | 2 +- .../components/scaffold/templates/helper_test.rb | 2 +- .../components/scaffold/templates/layout.html.erb | 2 +- .../scaffold/templates/view_edit.html.erb | 9 +- .../scaffold/templates/view_index.html.erb | 15 ++- .../scaffold/templates/view_new.html.erb | 7 +- .../scaffold/templates/view_show.html.erb | 7 +- railties/lib/rails_generator/name_composer.rb | 44 +++++++ railties/test/generators/generator_test_helper.rb | 14 ++- railties/test/generators/name_composer_test.rb | 56 +++++++++ .../test/generators/rails_model_generator_test.rb | 8 ++ .../generators/rails_scaffold_generator_test.rb | 119 +++++++++++++++++--- railties/test/rails_generator_test.rb | 14 +-- 23 files changed, 422 insertions(+), 217 deletions(-) create mode 100644 railties/lib/rails_generator/name_composer.rb create mode 100644 railties/test/generators/name_composer_test.rb diff --git a/railties/lib/rails_generator/base.rb b/railties/lib/rails_generator/base.rb index aa7081f..7a60d76 100644 --- a/railties/lib/rails_generator/base.rb +++ b/railties/lib/rails_generator/base.rb @@ -2,6 +2,7 @@ require File.dirname(__FILE__) + '/options' require File.dirname(__FILE__) + '/manifest' require File.dirname(__FILE__) + '/spec' require File.dirname(__FILE__) + '/generated_attribute' +require File.dirname(__FILE__) + '/name_composer' module Rails # Rails::Generator is a code generation platform tailored for the Rails @@ -198,11 +199,16 @@ module Rails # 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 + attr_reader :name, + :class_name, + :file_path, + :file_name, + :class_path, + :table_name alias_method :actions, :args + include NameComposer + def initialize(runtime_args, runtime_options = {}) super @@ -226,40 +232,14 @@ module Rails 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] + @class_name = camelized_name + @file_path = underscored_name + @file_name = file_path.split('/').last + @class_path = underscored_name.split('/')[0..-2].join('/') rescue '' + @table_name = ((!defined?(ActiveRecord::Base) || ActiveRecord::Base.pluralize_table_names) ? underscored_plural_name : underscored_singular_name).gsub('/', '_') end end end diff --git a/railties/lib/rails_generator/commands.rb b/railties/lib/rails_generator/commands.rb index b684dc9..7dfd186 100644 --- a/railties/lib/rails_generator/commands.rb +++ b/railties/lib/rails_generator/commands.rb @@ -95,6 +95,19 @@ module Rails File.open(path, 'wb') { |file| file.write(content) } end + def route_log_line(resource) + namespace, resource = namespace_and_resource(resource) + line = "#{resource.to_sym.inspect}" + line += " in namespace #{namespace}" + line + end + + def route_line(resource) + namespace, resource = namespace_and_resource(resource) + arguments = namespace.empty? ? resource.to_sym.inspect : ":#{resource}, :path_prefix => '#{namespace}', :name_prefix => '#{namespace.gsub('/', '_')}_', :controller => '#{namespace}/#{resource}'" + "map.resources #{arguments}" + end + private # Ask the user interactively whether to force collision. def force_file_collision?(destination, src, dst, file_options = {}, &block) @@ -151,6 +164,10 @@ HELP def template_part_mark(name, id) "\n" end + + def namespace_and_resource(namespaced_resource) + namespaced_resource.to_s =~ %r{^(.*)/([^/]+)$} ? [$1,$2] : ['',namespaced_resource] + end end # Base class for commands which handle generator actions in reverse, such as Destroy. @@ -360,14 +377,13 @@ HELP 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(', ') + def route_resources(resource) sentinel = 'ActionController::Routing::Routes.draw do |map|' - logger.route "map.resources #{resource_list}" + logger.route route_log_line(resource) unless options[:pretend] gsub_file 'config/routes.rb', /(#{Regexp.escape(sentinel)})/mi do |match| - "#{match}\n map.resources #{resource_list}\n" + "#{match}\n #{route_line(resource)}\n" end end end @@ -529,10 +545,9 @@ end_message 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}" + def route_resources(resource) + look_for = "\n #{route_line(resource)}\n" + logger.route route_log_line(resource) gsub_file 'config/routes.rb', /(#{look_for})/mi, '' end end @@ -573,9 +588,8 @@ end_message 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}" + def route_resources(resource) + logger.route route_log_line(resource) end end diff --git a/railties/lib/rails_generator/generators/components/resource/resource_generator.rb b/railties/lib/rails_generator/generators/components/resource/resource_generator.rb index 4ee2fbf..ac25728 100644 --- a/railties/lib/rails_generator/generators/components/resource/resource_generator.rb +++ b/railties/lib/rails_generator/generators/components/resource/resource_generator.rb @@ -1,58 +1,55 @@ class ResourceGenerator < Rails::Generator::NamedBase default_options :skip_timestamps => false, :skip_migration => false - attr_reader :controller_name, - :controller_class_path, - :controller_file_path, - :controller_class_nesting, - :controller_class_nesting_depth, - :controller_class_name, - :controller_singular_name, - :controller_plural_name - alias_method :controller_file_name, :controller_singular_name - alias_method :controller_table_name, :controller_plural_name + attr_reader :controller_name, + :controller_file_path, + :controller_test_name, + :controller_test_file_path, + :helper_name, + :helper_file_path, + :helper_test_name, + :helper_test_file_path def initialize(runtime_args, runtime_options = {}) super - @controller_name = @name.pluralize - - base_name, @controller_class_path, @controller_file_path, @controller_class_nesting, @controller_class_nesting_depth = extract_modules(@controller_name) - @controller_class_name_without_nesting, @controller_singular_name, @controller_plural_name = inflect_names(base_name) - - if @controller_class_nesting.empty? - @controller_class_name = @controller_class_name_without_nesting - else - @controller_class_name = "#{@controller_class_nesting}::#{@controller_class_name_without_nesting}" - end + @file_path = underscored_plural_name + @controller_name = camelized_plural_name + 'Controller' + @controller_file_path = file_path + '_controller.rb' + @controller_test_name = controller_name + 'Test' + @controller_test_file_path = file_path + '_controller_test.rb' + @helper_name = camelized_plural_name + 'Helper' + @helper_file_path = file_path + '_helper.rb' + @helper_test_name = helper_name + 'Test' + @helper_test_file_path = file_path + '_helper_test.rb' end def manifest record do |m| # Check for class naming collisions. - m.class_collisions("#{controller_class_name}Controller", "#{controller_class_name}Helper") + m.class_collisions(controller_name, helper_name) m.class_collisions(class_name) # Controller, helper, views, and test directories. m.directory(File.join('app/models', class_path)) - m.directory(File.join('app/controllers', controller_class_path)) - m.directory(File.join('app/helpers', controller_class_path)) - m.directory(File.join('app/views', controller_class_path, controller_file_name)) - m.directory(File.join('test/functional', controller_class_path)) + m.directory(File.join('app/controllers', class_path)) + m.directory(File.join('app/helpers', class_path)) + m.directory(File.join('app/views', file_path)) + m.directory(File.join('test/functional', class_path)) m.directory(File.join('test/unit', class_path)) m.directory(File.join('test/unit/helpers', class_path)) m.dependency 'model', [name] + @args, :collision => :skip m.template( - 'controller.rb', File.join('app/controllers', controller_class_path, "#{controller_file_name}_controller.rb") + 'controller.rb', File.join('app/controllers', controller_file_path) ) - m.template('functional_test.rb', File.join('test/functional', controller_class_path, "#{controller_file_name}_controller_test.rb")) - m.template('helper.rb', File.join('app/helpers', controller_class_path, "#{controller_file_name}_helper.rb")) - m.template('helper_test.rb', File.join('test/unit/helpers', controller_class_path, "#{controller_file_name}_helper_test.rb")) + m.template('functional_test.rb', File.join('test/functional', controller_test_file_path)) + m.template('helper.rb', File.join('app/helpers', helper_file_path)) + m.template('helper_test.rb', File.join('test/unit/helpers', helper_test_file_path)) - m.route_resources controller_file_name + m.route_resources file_path end end diff --git a/railties/lib/rails_generator/generators/components/resource/templates/controller.rb b/railties/lib/rails_generator/generators/components/resource/templates/controller.rb index 765a942..77a7026 100644 --- a/railties/lib/rails_generator/generators/components/resource/templates/controller.rb +++ b/railties/lib/rails_generator/generators/components/resource/templates/controller.rb @@ -1,2 +1,2 @@ -class <%= controller_class_name %>Controller < ApplicationController +class <%= controller_name %> < ApplicationController end diff --git a/railties/lib/rails_generator/generators/components/resource/templates/functional_test.rb b/railties/lib/rails_generator/generators/components/resource/templates/functional_test.rb index b1bb1da..9617d03 100644 --- a/railties/lib/rails_generator/generators/components/resource/templates/functional_test.rb +++ b/railties/lib/rails_generator/generators/components/resource/templates/functional_test.rb @@ -1,6 +1,6 @@ require 'test_helper' -class <%= controller_class_name %>ControllerTest < ActionController::TestCase +class <%= controller_test_name %> < ActionController::TestCase # Replace this with your real tests. test "the truth" do assert true diff --git a/railties/lib/rails_generator/generators/components/resource/templates/helper.rb b/railties/lib/rails_generator/generators/components/resource/templates/helper.rb index 9bd821b..43b6e90 100644 --- a/railties/lib/rails_generator/generators/components/resource/templates/helper.rb +++ b/railties/lib/rails_generator/generators/components/resource/templates/helper.rb @@ -1,2 +1,2 @@ -module <%= controller_class_name %>Helper +module <%= helper_name %> end diff --git a/railties/lib/rails_generator/generators/components/resource/templates/helper_test.rb b/railties/lib/rails_generator/generators/components/resource/templates/helper_test.rb index 061f64a..1d87e42 100644 --- a/railties/lib/rails_generator/generators/components/resource/templates/helper_test.rb +++ b/railties/lib/rails_generator/generators/components/resource/templates/helper_test.rb @@ -1,4 +1,4 @@ require 'test_helper' -class <%= controller_class_name %>HelperTest < ActionView::TestCase +class <%= helper_test_name %> < ActionView::TestCase end diff --git a/railties/lib/rails_generator/generators/components/scaffold/scaffold_generator.rb b/railties/lib/rails_generator/generators/components/scaffold/scaffold_generator.rb index 2a5edee..007d1ab 100644 --- a/railties/lib/rails_generator/generators/components/scaffold/scaffold_generator.rb +++ b/railties/lib/rails_generator/generators/components/scaffold/scaffold_generator.rb @@ -1,17 +1,18 @@ class ScaffoldGenerator < Rails::Generator::NamedBase default_options :skip_timestamps => false, :skip_migration => false, :force_plural => false - attr_reader :controller_name, - :controller_class_path, - :controller_file_path, - :controller_class_nesting, - :controller_class_nesting_depth, - :controller_class_name, - :controller_underscore_name, - :controller_singular_name, - :controller_plural_name - alias_method :controller_file_name, :controller_underscore_name - alias_method :controller_table_name, :controller_plural_name + attr_reader :controller_name, + :controller_file_path, + :functional_test_file_path, + :model_name, + :helper_name, + :helper_file_path, + :helper_test_file_path, + :layout_file_path, + :instance_name, + :instance_long_name, + :instances_name, + :instances_long_name def initialize(runtime_args, runtime_options = {}) super @@ -21,57 +22,71 @@ class ScaffoldGenerator < Rails::Generator::NamedBase @name = @name.singularize end - @controller_name = @name.pluralize + @file_path = underscored_plural_name + @class_path = underscored_plural_name.split('/')[0..-2].join('/') rescue '' + @controller_name = camelized_plural_name + 'Controller' + @controller_file_path = file_path + '_controller.rb' + @functional_test_file_path = file_path + '_controller_test.rb' + @layout_file_path = file_path + '.html.erb' + @model_name = camelized_base_name + @helper_name = camelized_plural_name + 'Helper' + @helper_file_path = file_path + '_helper.rb' + @helper_test_file_path = file_path + '_helper_test.rb' + @instance_name = underscored_base_singular_name + @instance_long_name = underscored_singular_name.gsub('/', '_') + @instances_name = underscored_plural_base_name + @instances_long_name = underscored_plural_name.gsub('/', '_') + end - base_name, @controller_class_path, @controller_file_path, @controller_class_nesting, @controller_class_nesting_depth = extract_modules(@controller_name) - @controller_class_name_without_nesting, @controller_underscore_name, @controller_plural_name = inflect_names(base_name) - @controller_singular_name=base_name.singularize - if @controller_class_nesting.empty? - @controller_class_name = @controller_class_name_without_nesting - else - @controller_class_name = "#{@controller_class_nesting}::#{@controller_class_name_without_nesting}" + def instance_location_descriptor(var_type = :instance_variable) + parts = class_path.split('/').collect{|i| "'#{i}'"}.join(', ') + case var_type + when :instance_variable + class_path.empty? ? '@' + instance_name : "[#{parts}, @#{instance_name}]" + when :local_variable + class_path.empty? ? instance_name : "[#{parts}, #{instance_name}]" end end def manifest record do |m| # Check for class naming collisions. - m.class_collisions("#{controller_class_name}Controller", "#{controller_class_name}Helper") - m.class_collisions(class_name) + m.class_collisions(controller_name, helper_name) + m.class_collisions(model_name) # Controller, helper, views, test and stylesheets directories. m.directory(File.join('app/models', class_path)) - m.directory(File.join('app/controllers', controller_class_path)) - m.directory(File.join('app/helpers', controller_class_path)) - m.directory(File.join('app/views', controller_class_path, controller_file_name)) - m.directory(File.join('app/views/layouts', controller_class_path)) - m.directory(File.join('test/functional', controller_class_path)) + m.directory(File.join('app/controllers', class_path)) + m.directory(File.join('app/helpers', class_path)) + m.directory(File.join('app/views', file_path)) + m.directory(File.join('app/views/layouts', class_path)) + m.directory(File.join('test/functional', class_path)) m.directory(File.join('test/unit', class_path)) m.directory(File.join('test/unit/helpers', class_path)) - m.directory(File.join('public/stylesheets', class_path)) + m.directory(File.join('public/stylesheets', file_path)) for action in scaffold_views m.template( "view_#{action}.html.erb", - File.join('app/views', controller_class_path, controller_file_name, "#{action}.html.erb") + File.join('app/views', file_path, "#{action}.html.erb") ) end # Layout and stylesheet. - m.template('layout.html.erb', File.join('app/views/layouts', controller_class_path, "#{controller_file_name}.html.erb")) + m.template('layout.html.erb', 'app/views/layouts/' + layout_file_path) m.template('style.css', 'public/stylesheets/scaffold.css') m.template( - 'controller.rb', File.join('app/controllers', controller_class_path, "#{controller_file_name}_controller.rb") + 'controller.rb', File.join('app/controllers/' + controller_file_path) ) - m.template('functional_test.rb', File.join('test/functional', controller_class_path, "#{controller_file_name}_controller_test.rb")) - m.template('helper.rb', File.join('app/helpers', controller_class_path, "#{controller_file_name}_helper.rb")) - m.template('helper_test.rb', File.join('test/unit/helpers', controller_class_path, "#{controller_file_name}_helper_test.rb")) + m.template('functional_test.rb', 'test/functional/' + functional_test_file_path) + m.template('helper.rb', 'app/helpers/' + helper_file_path) + m.template('helper_test.rb', 'test/unit/helpers/' + helper_test_file_path) - m.route_resources controller_file_name + m.route_resources file_path - m.dependency 'model', [name] + @args, :collision => :skip + m.dependency 'model', [model_name] + @args, :collision => :skip end end @@ -95,8 +110,4 @@ class ScaffoldGenerator < Rails::Generator::NamedBase def scaffold_views %w[ index show new edit ] end - - def model_name - class_name.demodulize - end end diff --git a/railties/lib/rails_generator/generators/components/scaffold/templates/controller.rb b/railties/lib/rails_generator/generators/components/scaffold/templates/controller.rb index 4d190b9..d85bcf1 100644 --- a/railties/lib/rails_generator/generators/components/scaffold/templates/controller.rb +++ b/railties/lib/rails_generator/generators/components/scaffold/templates/controller.rb @@ -1,84 +1,84 @@ -class <%= controller_class_name %>Controller < ApplicationController - # GET /<%= table_name %> - # GET /<%= table_name %>.xml +class <%= controller_name %> < ApplicationController + # GET /<%= file_path %> + # GET /<%= file_path %>.xml def index - @<%= table_name %> = <%= class_name %>.all + @<%= instances_name %> = <%= model_name %>.all respond_to do |format| format.html # index.html.erb - format.xml { render :xml => @<%= table_name %> } + format.xml { render :xml => @<%= instance_name %> } end end - # GET /<%= table_name %>/1 - # GET /<%= table_name %>/1.xml + # GET /<%= file_path %>/1 + # GET /<%= file_path %>/1.xml def show - @<%= file_name %> = <%= class_name %>.find(params[:id]) + @<%= instance_name %> = <%= model_name %>.find(params[:id]) respond_to do |format| format.html # show.html.erb - format.xml { render :xml => @<%= file_name %> } + format.xml { render :xml => @<%= instance_name %> } end end - # GET /<%= table_name %>/new - # GET /<%= table_name %>/new.xml + # GET /<%= file_path %>/new + # GET /<%= file_path %>/new.xml def new - @<%= file_name %> = <%= class_name %>.new + @<%= instance_name %> = <%= model_name %>.new respond_to do |format| format.html # new.html.erb - format.xml { render :xml => @<%= file_name %> } + format.xml { render :xml => @<%= instance_name %> } end end - # GET /<%= table_name %>/1/edit + # GET /<%= file_path %>/1/edit def edit - @<%= file_name %> = <%= class_name %>.find(params[:id]) + @<%= instance_name %> = <%= model_name %>.find(params[:id]) end - # POST /<%= table_name %> - # POST /<%= table_name %>.xml + # POST /<%= file_path %> + # POST /<%= file_path %>.xml def create - @<%= file_name %> = <%= class_name %>.new(params[:<%= file_name %>]) + @<%= instance_name %> = <%= model_name %>.new(params[:<%= instance_name %>]) respond_to do |format| - if @<%= file_name %>.save - flash[:notice] = '<%= class_name %> was successfully created.' - format.html { redirect_to(@<%= file_name %>) } - format.xml { render :xml => @<%= file_name %>, :status => :created, :location => @<%= file_name %> } + if @<%= instance_name %>.save + flash[:notice] = '<%= model_name %> was successfully created.' + format.html { redirect_to(<%= instance_location_descriptor %>) } + format.xml { render :xml => @<%= instance_name %>, :status => :created, :location => <%= instance_location_descriptor %> } else format.html { render :action => "new" } - format.xml { render :xml => @<%= file_name %>.errors, :status => :unprocessable_entity } + format.xml { render :xml => @<%= instance_name %>.errors, :status => :unprocessable_entity } end end end - # PUT /<%= table_name %>/1 - # PUT /<%= table_name %>/1.xml + # PUT /<%= file_path %>/1 + # PUT /<%= file_path %>/1.xml def update - @<%= file_name %> = <%= class_name %>.find(params[:id]) + @<%= instance_name %> = <%= model_name %>.find(params[:id]) respond_to do |format| - if @<%= file_name %>.update_attributes(params[:<%= file_name %>]) - flash[:notice] = '<%= class_name %> was successfully updated.' - format.html { redirect_to(@<%= file_name %>) } + if @<%= instance_name %>.update_attributes(params[:<%= instance_name %>]) + flash[:notice] = '<%= model_name %> was successfully updated.' + format.html { redirect_to(<%= instance_location_descriptor %>) } format.xml { head :ok } else format.html { render :action => "edit" } - format.xml { render :xml => @<%= file_name %>.errors, :status => :unprocessable_entity } + format.xml { render :xml => @<%= instance_name %>.errors, :status => :unprocessable_entity } end end end - # DELETE /<%= table_name %>/1 - # DELETE /<%= table_name %>/1.xml + # DELETE /<%= file_path %>/1 + # DELETE /<%= file_path %>/1.xml def destroy - @<%= file_name %> = <%= class_name %>.find(params[:id]) - @<%= file_name %>.destroy + @<%= instance_name %> = <%= model_name %>.find(params[:id]) + @<%= instance_name %>.destroy respond_to do |format| - format.html { redirect_to(<%= table_name %>_url) } + format.html { redirect_to(<%= instances_long_name %>_url) } format.xml { head :ok } end end diff --git a/railties/lib/rails_generator/generators/components/scaffold/templates/functional_test.rb b/railties/lib/rails_generator/generators/components/scaffold/templates/functional_test.rb index cd2fc57..4e0af1f 100644 --- a/railties/lib/rails_generator/generators/components/scaffold/templates/functional_test.rb +++ b/railties/lib/rails_generator/generators/components/scaffold/templates/functional_test.rb @@ -1,10 +1,10 @@ require 'test_helper' -class <%= controller_class_name %>ControllerTest < ActionController::TestCase +class <%= controller_name %>Test < ActionController::TestCase test "should get index" do get :index assert_response :success - assert_not_nil assigns(:<%= table_name %>) + assert_not_nil assigns(:<%= instances_name %>) end test "should get new" do @@ -12,34 +12,34 @@ class <%= controller_class_name %>ControllerTest < ActionController::TestCase assert_response :success end - test "should create <%= file_name %>" do - assert_difference('<%= class_name %>.count') do - post :create, :<%= file_name %> => { } + test "should create <%= instance_name %>" do + assert_difference('<%= model_name %>.count') do + post :create, :<%= instance_name %> => { } end - assert_redirected_to <%= file_name %>_path(assigns(:<%= file_name %>)) + assert_redirected_to <%= instance_long_name %>_path(assigns(:<%= instance_name %>)) end - test "should show <%= file_name %>" do - get :show, :id => <%= table_name %>(:one).to_param + test "should show <%= instance_name %>" do + get :show, :id => <%= instances_name %>(:one).to_param assert_response :success end test "should get edit" do - get :edit, :id => <%= table_name %>(:one).to_param + get :edit, :id => <%= instances_name %>(:one).to_param assert_response :success end - test "should update <%= file_name %>" do - put :update, :id => <%= table_name %>(:one).to_param, :<%= file_name %> => { } - assert_redirected_to <%= file_name %>_path(assigns(:<%= file_name %>)) + test "should update <%= instance_name %>" do + put :update, :id => <%= instances_name %>(:one).to_param, :<%= instance_name %> => { } + assert_redirected_to <%= instance_long_name %>_path(assigns(:<%= instance_name %>)) end - test "should destroy <%= file_name %>" do - assert_difference('<%= class_name %>.count', -1) do - delete :destroy, :id => <%= table_name %>(:one).to_param + test "should destroy <%= instance_name %>" do + assert_difference('<%= model_name %>.count', -1) do + delete :destroy, :id => <%= instances_name %>(:one).to_param end - assert_redirected_to <%= table_name %>_path + assert_redirected_to <%= instances_long_name %>_path end end diff --git a/railties/lib/rails_generator/generators/components/scaffold/templates/helper.rb b/railties/lib/rails_generator/generators/components/scaffold/templates/helper.rb index 9bd821b..43b6e90 100644 --- a/railties/lib/rails_generator/generators/components/scaffold/templates/helper.rb +++ b/railties/lib/rails_generator/generators/components/scaffold/templates/helper.rb @@ -1,2 +1,2 @@ -module <%= controller_class_name %>Helper +module <%= helper_name %> end diff --git a/railties/lib/rails_generator/generators/components/scaffold/templates/helper_test.rb b/railties/lib/rails_generator/generators/components/scaffold/templates/helper_test.rb index 061f64a..92b6ed3 100644 --- a/railties/lib/rails_generator/generators/components/scaffold/templates/helper_test.rb +++ b/railties/lib/rails_generator/generators/components/scaffold/templates/helper_test.rb @@ -1,4 +1,4 @@ require 'test_helper' -class <%= controller_class_name %>HelperTest < ActionView::TestCase +class <%= helper_name %>Test < ActionView::TestCase end diff --git a/railties/lib/rails_generator/generators/components/scaffold/templates/layout.html.erb b/railties/lib/rails_generator/generators/components/scaffold/templates/layout.html.erb index ebc97f8..f9087c6 100644 --- a/railties/lib/rails_generator/generators/components/scaffold/templates/layout.html.erb +++ b/railties/lib/rails_generator/generators/components/scaffold/templates/layout.html.erb @@ -4,7 +4,7 @@ - <%= controller_class_name %>: <%%= controller.action_name %> + <%= controller_name %>: <%%= controller.action_name %> <%%= stylesheet_link_tag 'scaffold' %> diff --git a/railties/lib/rails_generator/generators/components/scaffold/templates/view_edit.html.erb b/railties/lib/rails_generator/generators/components/scaffold/templates/view_edit.html.erb index cca1d61..7ec9554 100644 --- a/railties/lib/rails_generator/generators/components/scaffold/templates/view_edit.html.erb +++ b/railties/lib/rails_generator/generators/components/scaffold/templates/view_edit.html.erb @@ -1,6 +1,6 @@ -

Editing <%= singular_name %>

+

Editing <%= instance_name %>

-<%% form_for(@<%= singular_name %>) do |f| %> +<%% form_for(<%= instance_location_descriptor %>) do |f| %> <%%= f.error_messages %> <% for attribute in attributes -%> @@ -14,5 +14,6 @@

<%% end %> -<%%= link_to 'Show', @<%= singular_name %> %> | -<%%= link_to 'Back', <%= plural_name %>_path %> \ No newline at end of file +<%%= link_to 'Show', <%= instance_location_descriptor %> %> | +<%%= link_to 'Back', <%= instances_long_name %>_path %> + diff --git a/railties/lib/rails_generator/generators/components/scaffold/templates/view_index.html.erb b/railties/lib/rails_generator/generators/components/scaffold/templates/view_index.html.erb index 2e603d5..4df075f 100644 --- a/railties/lib/rails_generator/generators/components/scaffold/templates/view_index.html.erb +++ b/railties/lib/rails_generator/generators/components/scaffold/templates/view_index.html.erb @@ -1,4 +1,4 @@ -

Listing <%= plural_name %>

+

Listing <%= instances_name %>

@@ -7,18 +7,19 @@ <% end -%> -<%% @<%= plural_name %>.each do |<%= singular_name %>| %> +<%% @<%= instances_name %>.each do |<%= instance_name %>| %> <% for attribute in attributes -%> - + <% end -%> - - - + + + <%% end %>
<%%=h <%= singular_name %>.<%= attribute.name %> %><%%=h <%= instance_name %>.<%= attribute.name %> %><%%= link_to 'Show', <%= singular_name %> %><%%= link_to 'Edit', edit_<%= singular_name %>_path(<%= singular_name %>) %><%%= link_to 'Destroy', <%= singular_name %>, :confirm => 'Are you sure?', :method => :delete %><%%= link_to 'Show', <%= instance_long_name %>_path(<%= instance_name %>) %><%%= link_to 'Edit', edit_<%= instance_long_name %>_path(<%= instance_name %>) %><%%= link_to 'Destroy', <%= instance_long_name %>_path(<%= instance_name %>), :confirm => 'Are you sure?', :method => :delete %>

-<%%= link_to 'New <%= singular_name %>', new_<%= singular_name %>_path %> \ No newline at end of file +<%%= link_to 'New <%= instance_name %>', new_<%= instance_long_name %>_path %> + diff --git a/railties/lib/rails_generator/generators/components/scaffold/templates/view_new.html.erb b/railties/lib/rails_generator/generators/components/scaffold/templates/view_new.html.erb index 96c89fc..1ca975f 100644 --- a/railties/lib/rails_generator/generators/components/scaffold/templates/view_new.html.erb +++ b/railties/lib/rails_generator/generators/components/scaffold/templates/view_new.html.erb @@ -1,6 +1,6 @@ -

New <%= singular_name %>

+

New <%= instance_name %>

-<%% form_for(@<%= singular_name %>) do |f| %> +<%% form_for(<%= instance_location_descriptor %>) do |f| %> <%%= f.error_messages %> <% for attribute in attributes -%> @@ -14,4 +14,5 @@

<%% end %> -<%%= link_to 'Back', <%= plural_name %>_path %> \ No newline at end of file +<%%= link_to 'Back', <%= instances_long_name %>_path %> + diff --git a/railties/lib/rails_generator/generators/components/scaffold/templates/view_show.html.erb b/railties/lib/rails_generator/generators/components/scaffold/templates/view_show.html.erb index adecaf7..eb13749 100644 --- a/railties/lib/rails_generator/generators/components/scaffold/templates/view_show.html.erb +++ b/railties/lib/rails_generator/generators/components/scaffold/templates/view_show.html.erb @@ -1,10 +1,11 @@ <% for attribute in attributes -%>

<%= attribute.column.human_name %>: - <%%=h @<%= singular_name %>.<%= attribute.name %> %> + <%%=h @<%= instance_name %>.<%= attribute.name %> %>

<% end -%> -<%%= link_to 'Edit', edit_<%= singular_name %>_path(@<%= singular_name %>) %> | -<%%= link_to 'Back', <%= plural_name %>_path %> \ No newline at end of file +<%%= link_to 'Edit', edit_<%= instance_long_name %>_path(@<%= instance_name %>) %> | +<%%= link_to 'Back', <%= instances_long_name %>_path %> + diff --git a/railties/lib/rails_generator/name_composer.rb b/railties/lib/rails_generator/name_composer.rb new file mode 100644 index 0000000..8596f33 --- /dev/null +++ b/railties/lib/rails_generator/name_composer.rb @@ -0,0 +1,44 @@ +module NameComposer + + # Group together those names that are mutually exclusive + NAME_DESCRIPTORS = [ + ['base'], + ['camelized', 'underscored'], + ['singular'], ['plural'] + ].freeze + + def method_missing(sym, *args) + if sym.to_s =~ /(.+)_name$/ && args.empty? + compose_name($1) + else + super + end + end + + def compose_name(description) + descriptors = description.split('_') + check_name_descriptors_sanity!(descriptors) + returned_name = name + returned_name = returned_name.split(%r{/|::}).last if descriptors.include?('base') + returned_name = returned_name.singularize if descriptors.include?('singular') + returned_name = returned_name.pluralize if descriptors.include?('plural') + + # The following need to be messed up with a bit, to avoid problems with + # combinations such as name_space::something and NameSpace/Something + returned_name = returned_name.underscore.camelize if descriptors.include?('camelized') + returned_name = returned_name.camelize.underscore if descriptors.include?('underscored') + returned_name + end + + + private + + def check_name_descriptors_sanity!(descriptors) + descriptors.each{|desc| raise "Unkown name description '#{desc}'" if !NAME_DESCRIPTORS.flatten.include?(desc)} + NAME_DESCRIPTORS.each do |set| + incompatibles = descriptors.collect{|desc| set.include?(desc) ? desc : nil}.compact + raise "The name cannot be '#{incompatibles.first}' and '#{incompatibles.second}' at the same time" if incompatibles.size > 1 + end + nil + end +end diff --git a/railties/test/generators/generator_test_helper.rb b/railties/test/generators/generator_test_helper.rb index 01bf1c9..2ff9955 100644 --- a/railties/test/generators/generator_test_helper.rb +++ b/railties/test/generators/generator_test_helper.rb @@ -281,8 +281,18 @@ class GeneratorTestCase < Test::Unit::TestCase # Asserts that the given resource was added to the routes. def assert_added_route_for(name) assert_generated_file("config/routes.rb") do |body| - assert_match /map.resources :#{name.to_s.underscore}/, body, - "should add route for :#{name.to_s.underscore}" + namespace = name.to_s.underscore.split('/') + name = namespace.pop + if namespace.empty? + assert_match /map.resources :#{name}/, body, + "should add route for :#{name}" + else + underscored_ns = namespace.join('_') + slashed_ns = namespace.join('/') + assert_match /map.resources :#{name.underscore}, :path_prefix => '#{slashed_ns}', :name_prefix => '#{underscored_ns}_', :controller => '#{slashed_ns}\/#{name}'/, + body, + "should_add route for #{slashed_ns}/#{name}" + end end end diff --git a/railties/test/generators/name_composer_test.rb b/railties/test/generators/name_composer_test.rb new file mode 100644 index 0000000..1c0bfe1 --- /dev/null +++ b/railties/test/generators/name_composer_test.rb @@ -0,0 +1,56 @@ +require 'generators/generator_test_helper' + +class NameComposerTest < Test::Unit::TestCase + + def test_self_described_names + c = Struct.new(:name).new('product_lines').extend(NameComposer) + assert_equal 'product_lines', c.name + assert_equal 'product_lines', c.underscored_name + assert_equal 'product_line', c.underscored_singular_name + assert_equal 'product_lines', c.plural_base_name + assert_equal 'ProductLines', c.camelized_name + assert_equal 'ProductLines', c.camelized_plural_name + assert_equal 'ProductLines', c.camelized_base_name + assert_equal 'ProductLines', c.camelized_plural_base_name + assert_equal 'product_line', c.singular_name + end + + def test_namespaced_self_described_names + c = Struct.new(:name).new('admin_space/product_line').extend(NameComposer) + assert_equal 'admin_space/product_line', c.name + assert_equal 'admin_space/product_line', c.underscored_name + assert_equal 'admin_space/product_line', c.underscored_singular_name + assert_equal 'product_lines', c.plural_base_name + assert_equal 'AdminSpace::ProductLine', c.camelized_name + assert_equal 'AdminSpace::ProductLines', c.camelized_plural_name + assert_equal 'ProductLine', c.camelized_base_name + assert_equal 'ProductLines', c.camelized_plural_base_name + assert_equal 'admin_space/product_line', c.singular_name + end + + def test_self_desribed_names_with_undersores_and_double_colons + c = Struct.new(:name).new('admin_space::product_line').extend(NameComposer) + assert_equal 'admin_space::product_line', c.name + assert_equal 'admin_space/product_line', c.underscored_name + assert_equal 'admin_space/product_line', c.underscored_singular_name + assert_equal 'product_lines', c.plural_base_name + assert_equal 'AdminSpace::ProductLine', c.camelized_name + assert_equal 'AdminSpace::ProductLines', c.camelized_plural_name + assert_equal 'ProductLine', c.camelized_base_name + assert_equal 'ProductLines', c.camelized_plural_base_name + assert_equal 'admin_space::product_line', c.singular_name + end + + def test_self_described_names_with_camel_case_and_slashes + c = Struct.new(:name).new('AdminSpace/ProductLine').extend(NameComposer) + assert_equal 'AdminSpace/ProductLine', c.name + assert_equal 'admin_space/product_line', c.underscored_name + assert_equal 'admin_space/product_line', c.underscored_singular_name + assert_equal 'ProductLines', c.plural_base_name + assert_equal 'AdminSpace::ProductLine', c.camelized_name + assert_equal 'AdminSpace::ProductLines', c.camelized_plural_name + assert_equal 'ProductLine', c.camelized_base_name + assert_equal 'ProductLines', c.camelized_plural_base_name + assert_equal 'AdminSpace/ProductLine', c.singular_name + end +end diff --git a/railties/test/generators/rails_model_generator_test.rb b/railties/test/generators/rails_model_generator_test.rb index aea2aba..fac310e 100644 --- a/railties/test/generators/rails_model_generator_test.rb +++ b/railties/test/generators/rails_model_generator_test.rb @@ -10,6 +10,14 @@ class RailsModelGeneratorTest < GeneratorTestCase assert_generated_migration :create_products end + def test_namespaced_model_generates_resources + run_generator('model', %w(Admin::Product name:string)) + + assert_generated_model_for 'admin/product' + assert_generated_fixtures_for :admin_products + assert_generated_migration :create_admin_products + end + def test_model_skip_migration_skips_migration run_generator('model', %w(Product name:string --skip-migration)) diff --git a/railties/test/generators/rails_scaffold_generator_test.rb b/railties/test/generators/rails_scaffold_generator_test.rb index 70829a7..556b479 100644 --- a/railties/test/generators/rails_scaffold_generator_test.rb +++ b/railties/test/generators/rails_scaffold_generator_test.rb @@ -2,14 +2,36 @@ require 'generators/generator_test_helper' require 'abstract_unit' class RailsScaffoldGeneratorTest < GeneratorTestCase - def test_scaffolded_names + def test_scaffolded_camel_cased_names g = Rails::Generator::Base.instance('scaffold', %w(ProductLine)) - assert_equal "ProductLines", g.controller_name - assert_equal "ProductLines", g.controller_class_name - assert_equal "ProductLine", g.controller_singular_name - assert_equal "product_lines", g.controller_plural_name - assert_equal "product_lines", g.controller_file_name - assert_equal "product_lines", g.controller_table_name + assert_correct_product_lines_generator g + end + + def test_scaffolded_undercased_names + g = Rails::Generator::Base.instance('scaffold', %w(product_line)) + assert_correct_product_lines_generator g + end + + def test_scaffolded_plural_names + Rails::Generator::Base.logger.expects(:warning) + g = Rails::Generator::Base.instance('scaffold', %w(ProductLines)) + assert_correct_product_lines_generator g + end + + def test_scaffolded_namespaced_names + g = Rails::Generator::Base.instance('scaffold', %w(admin_space/product_line)) + assert_correct_admin_space_product_lines_generator g + end + + def test_scaffolded_plural_namespaced_names + Rails::Generator::Base.logger.expects(:warning) + g = Rails::Generator::Base.instance('scaffold', %w(admin_space/product_lines)) + assert_correct_admin_space_product_lines_generator g + end + + def test_scaffolded_overly_namespaced_names + g = Rails::Generator::Base.instance('scaffold', %w(admin_space/stuff/product_line)) + assert_correct_admin_space_stuff_product_lines_generator g end def test_scaffold_generates_resources @@ -107,17 +129,6 @@ class RailsScaffoldGeneratorTest < GeneratorTestCase assert_added_route_for :products end - def test_scaffolded_plural_names - Rails::Generator::Base.logger.expects(:warning) - g = Rails::Generator::Base.instance('scaffold', %w(ProductLines)) - assert_equal "ProductLines", g.controller_name - assert_equal "ProductLines", g.controller_class_name - assert_equal "ProductLine", g.controller_singular_name - assert_equal "product_lines", g.controller_plural_name - assert_equal "product_lines", g.controller_file_name - assert_equal "product_lines", g.controller_table_name - end - def test_scaffold_plural_model_name_without_force_plural_generates_singular_model run_generator('scaffold', %w(Products name:string)) @@ -147,4 +158,76 @@ class RailsScaffoldGeneratorTest < GeneratorTestCase assert_skipped_migration :create_products assert_added_route_for :products end + + def test_namespaced_scaffold + run_generator('scaffold', %w(AdminSpace::Products name:string --force-plural)) + + assert_generated_model_for :products + assert_generated_functional_test_for 'admin_space/products' + assert_generated_unit_test_for :products + assert_generated_fixtures_for :products + assert_generated_helper_for 'admin_space/products' + assert_generated_helper_test_for 'admin_space/products' + assert_generated_stylesheet :scaffold + assert_generated_views_for 'admin_space/products', "index.html.erb","new.html.erb","edit.html.erb","show.html.erb" + assert_generated_migration :create_products + assert_added_route_for 'admin_space/products' + end + + + private + + def assert_correct_product_lines_generator(g) + assert_equal 'product_lines', g.file_path + assert_equal '', g.class_path + assert_equal 'ProductLinesController', g.controller_name + assert_equal 'product_lines_controller.rb', g.controller_file_path + assert_equal 'product_lines_controller_test.rb', g.functional_test_file_path + assert_equal 'ProductLine', g.model_name + assert_equal 'ProductLinesHelper', g.helper_name + assert_equal 'product_lines_helper.rb', g.helper_file_path + assert_equal 'product_lines_helper_test.rb', g.helper_test_file_path + assert_equal 'product_lines.html.erb', g.layout_file_path + assert_equal 'product_line', g.instance_name + assert_equal 'product_line', g.instance_long_name + assert_equal 'product_lines', g.instances_name + assert_equal 'product_lines', g.instances_long_name + assert_equal '@product_line', g.instance_location_descriptor + end + + def assert_correct_admin_space_product_lines_generator(g) + assert_equal 'admin_space/product_lines', g.file_path + assert_equal 'admin_space', g.class_path + assert_equal 'AdminSpace::ProductLinesController', g.controller_name + assert_equal 'admin_space/product_lines_controller.rb', g.controller_file_path + assert_equal 'admin_space/product_lines_controller_test.rb', g.functional_test_file_path + assert_equal 'ProductLine', g.model_name + assert_equal 'AdminSpace::ProductLinesHelper', g.helper_name + assert_equal 'admin_space/product_lines_helper.rb', g.helper_file_path + assert_equal 'admin_space/product_lines_helper_test.rb', g.helper_test_file_path + assert_equal 'admin_space/product_lines.html.erb', g.layout_file_path + assert_equal 'product_line', g.instance_name + assert_equal 'admin_space_product_line', g.instance_long_name + assert_equal 'product_lines', g.instances_name + assert_equal 'admin_space_product_lines', g.instances_long_name + assert_equal "['admin_space', @product_line]", g.instance_location_descriptor + end + + def assert_correct_admin_space_stuff_product_lines_generator(g) + assert_equal 'admin_space/stuff/product_lines', g.file_path + assert_equal 'admin_space/stuff', g.class_path + assert_equal 'AdminSpace::Stuff::ProductLinesController', g.controller_name + assert_equal 'admin_space/stuff/product_lines_controller.rb', g.controller_file_path + assert_equal 'admin_space/stuff/product_lines_controller_test.rb', g.functional_test_file_path + assert_equal 'ProductLine', g.model_name + assert_equal 'AdminSpace::Stuff::ProductLinesHelper', g.helper_name + assert_equal 'admin_space/stuff/product_lines_helper.rb', g.helper_file_path + assert_equal 'admin_space/stuff/product_lines_helper_test.rb', g.helper_test_file_path + assert_equal 'admin_space/stuff/product_lines.html.erb', g.layout_file_path + assert_equal 'product_line', g.instance_name + assert_equal 'admin_space_stuff_product_line', g.instance_long_name + assert_equal 'product_lines', g.instances_name + assert_equal 'admin_space_stuff_product_lines', g.instances_long_name + assert_equal "['admin_space', 'stuff', @product_line]", g.instance_location_descriptor + end end diff --git a/railties/test/rails_generator_test.rb b/railties/test/rails_generator_test.rb index b2fc2f5..62edde1 100644 --- a/railties/test/rails_generator_test.rb +++ b/railties/test/rails_generator_test.rb @@ -114,20 +114,18 @@ class RailsGeneratorTest < Test::Unit::TestCase def test_named_generator_attributes g = Rails::Generator::Base.instance('working', %w(admin/foo bar baz)) assert_equal 'admin/foo', g.name - assert_equal %w(admin), g.class_path - assert_equal 'Admin', g.class_nesting + assert_equal 'admin', g.class_path assert_equal 'Admin::Foo', g.class_name - assert_equal 'foo', g.singular_name - assert_equal 'foos', g.plural_name - assert_equal g.singular_name, g.file_name - assert_equal "admin_#{g.plural_name}", g.table_name + assert_equal "admin_foos", g.table_name + assert_equal 'admin/foo', g.file_path + assert_equal 'foo', g.file_name assert_equal %w(bar baz), g.args end def test_named_generator_attributes_without_pluralized ActiveRecord::Base.pluralize_table_names = false g = Rails::Generator::Base.instance('working', %w(admin/foo bar baz)) - assert_equal "admin_#{g.singular_name}", g.table_name + assert_equal "admin_#{g.singular_base_name}", g.table_name end def test_session_migration_generator_with_pluralization @@ -140,6 +138,6 @@ class RailsGeneratorTest < Test::Unit::TestCase def test_scaffold_controller_name # Default behaviour is use the model name g = Rails::Generator::Base.instance('scaffold', %w(Product)) - assert_equal "Products", g.controller_name + assert_equal "ProductsController", g.controller_name end end -- 1.5.6.3