From c16a4379caaa9e086aeeb58a9194e511c40921d9 Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Mon, 9 Oct 2006 00:08:13 +0000 Subject: Added script/generate resource which works just like scaffold_resource, but creates empty placeholders instead of predefined [DHH] Added generated attribute options to script/generate model, like the one found in scaffold_resource and resource [DHH] git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@5236 5ecf4fe2-1ee6-0310-87b1-e25e094e27de --- railties/lib/rails_generator/base.rb | 8 ++ .../lib/rails_generator/generated_attribute.rb | 42 +++++++++++ .../generators/components/model/USAGE | 31 +++++--- .../components/model/templates/fixtures.yml | 10 ++- .../components/model/templates/migration.rb | 4 +- .../components/resource/resource_generator.rb | 86 ++++++++++++++++++++++ .../generators/components/resource/templates/USAGE | 18 +++++ .../components/resource/templates/controller.rb | 2 + .../components/resource/templates/fixtures.yml | 11 +++ .../resource/templates/functional_test.rb | 20 +++++ .../components/resource/templates/helper.rb | 2 + .../components/resource/templates/migration.rb | 13 ++++ .../components/resource/templates/model.rb | 2 + .../components/resource/templates/unit_test.rb | 10 +++ .../generators/components/scaffold_resource/USAGE | 2 +- .../scaffold_resource_generator.rb | 45 +---------- 16 files changed, 246 insertions(+), 60 deletions(-) create mode 100644 railties/lib/rails_generator/generated_attribute.rb create mode 100644 railties/lib/rails_generator/generators/components/resource/resource_generator.rb create mode 100644 railties/lib/rails_generator/generators/components/resource/templates/USAGE create mode 100644 railties/lib/rails_generator/generators/components/resource/templates/controller.rb create mode 100644 railties/lib/rails_generator/generators/components/resource/templates/fixtures.yml create mode 100644 railties/lib/rails_generator/generators/components/resource/templates/functional_test.rb create mode 100644 railties/lib/rails_generator/generators/components/resource/templates/helper.rb create mode 100644 railties/lib/rails_generator/generators/components/resource/templates/migration.rb create mode 100644 railties/lib/rails_generator/generators/components/resource/templates/model.rb create mode 100644 railties/lib/rails_generator/generators/components/resource/templates/unit_test.rb (limited to 'railties/lib') diff --git a/railties/lib/rails_generator/base.rb b/railties/lib/rails_generator/base.rb index 6a56f96b1c..f8da8ad032 100644 --- a/railties/lib/rails_generator/base.rb +++ b/railties/lib/rails_generator/base.rb @@ -1,6 +1,7 @@ require File.dirname(__FILE__) + '/options' require File.dirname(__FILE__) + '/manifest' require File.dirname(__FILE__) + '/spec' +require File.dirname(__FILE__) + '/generated_attribute' # Rails::Generator is a code generation platform tailored for the Rails # web application framework. Generators are easily invoked within Rails @@ -165,6 +166,13 @@ module Rails 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) diff --git a/railties/lib/rails_generator/generated_attribute.rb b/railties/lib/rails_generator/generated_attribute.rb new file mode 100644 index 0000000000..25af3931de --- /dev/null +++ b/railties/lib/rails_generator/generated_attribute.rb @@ -0,0 +1,42 @@ +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 + end + end +end diff --git a/railties/lib/rails_generator/generators/components/model/USAGE b/railties/lib/rails_generator/generators/components/model/USAGE index 57156ea535..d9efa7a000 100644 --- a/railties/lib/rails_generator/generators/components/model/USAGE +++ b/railties/lib/rails_generator/generators/components/model/USAGE @@ -1,19 +1,26 @@ Description: The model generator creates stubs for a new model. - The generator takes a model name as its argument. The model name may be - given in CamelCase or under_score and should not be suffixed with 'Model'. + The generator takes a model name as its argument. The model name may be given in CamelCase or under_score and + should not be suffixed with 'Model'. - The generator creates a model class in app/models, a test suite in - test/unit, test fixtures in test/fixtures/singular_name.yml, and a migration - in db/migrate. + As additional parameters, the generator will take attribute pairs described by name and type. These attributes will + be used to prepopulate the migration to create the table for the model and give you a set of predefined fixture. + You don't have to think up all attributes up front, but it's a good idea of adding just the baseline of what's + needed to start really working with the resource. -Example: - ./script/generate model Account + The generator creates a model class in app/models, a test suite in test/unit, test fixtures in + test/fixtures/singular_name.yml, and a migration in db/migrate. - This will create an Account model: - Model: app/models/account.rb - Test: test/unit/account_test.rb - Fixtures: test/fixtures/accounts.yml - Migration: db/migrate/XXX_add_accounts.rb +Examples: + ./script/generate model account + This will create an Account model: + Model: app/models/account.rb + Test: test/unit/account_test.rb + Fixtures: test/fixtures/accounts.yml + Migration: db/migrate/XXX_add_accounts.rb + + ./script/generate model post title:string created_on:date body:text published:boolean + + Creates post model with predefined attributes. diff --git a/railties/lib/rails_generator/generators/components/model/templates/fixtures.yml b/railties/lib/rails_generator/generators/components/model/templates/fixtures.yml index 8794d28ae4..9f5ae29a81 100644 --- a/railties/lib/rails_generator/generators/components/model/templates/fixtures.yml +++ b/railties/lib/rails_generator/generators/components/model/templates/fixtures.yml @@ -1,5 +1,11 @@ # Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html -first: +one: id: 1 -another: +<% for attribute in attributes -%> + <%= attribute.name %>: <%= attribute.default %> +<% end -%> +two: id: 2 +<% for attribute in attributes -%> + <%= attribute.name %>: <%= attribute.default %> +<% end -%> \ No newline at end of file diff --git a/railties/lib/rails_generator/generators/components/model/templates/migration.rb b/railties/lib/rails_generator/generators/components/model/templates/migration.rb index a6954ebd85..2a305a6a9d 100644 --- a/railties/lib/rails_generator/generators/components/model/templates/migration.rb +++ b/railties/lib/rails_generator/generators/components/model/templates/migration.rb @@ -1,7 +1,9 @@ class <%= migration_name %> < ActiveRecord::Migration def self.up create_table :<%= table_name %> do |t| - # t.column :name, :string +<% for attribute in attributes -%> + t.column :<%= attribute.name %>, :<%= attribute.type %> +<% end -%> 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 new file mode 100644 index 0000000000..67805436e9 --- /dev/null +++ b/railties/lib/rails_generator/generators/components/resource/resource_generator.rb @@ -0,0 +1,86 @@ +class ResourceGenerator < Rails::Generator::NamedBase + 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 + + 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 + end + + def manifest + recorded_session = record do |m| + # Check for class naming collisions. + m.class_collisions(controller_class_path, "#{controller_class_name}Controller", "#{controller_class_name}Helper") + m.class_collisions(class_path, "#{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('test/unit', class_path)) + + m.template('model.rb', File.join('app/models', class_path, "#{file_name}.rb")) + + m.template( + 'controller.rb', File.join('app/controllers', controller_class_path, "#{controller_file_name}_controller.rb") + ) + + 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('unit_test.rb', File.join('test/unit', class_path, "#{file_name}_test.rb")) + m.template('fixtures.yml', File.join('test/fixtures', "#{table_name}.yml")) + + unless options[:skip_migration] + m.migration_template( + 'migration.rb', 'db/migrate', + :assigns => { + :migration_name => "Create#{class_name.pluralize.gsub(/::/, '')}", + :attributes => attributes + }, + :migration_file_name => "create_#{file_path.gsub(/\//, '_').pluralize}" + ) + end + end + + puts + puts ("-" * 70) + puts "Don't forget the restful route in config/routes.rb" + puts + puts " map.resources :#{controller_file_name}" + puts + puts ("-" * 70) + puts + + recorded_session + end + + protected + # Override with your own usage banner. + def banner + "Usage: #{$0} resource ModelName [field:type, field:type]" + end + + def model_name + class_name.demodulize + end +end diff --git a/railties/lib/rails_generator/generators/components/resource/templates/USAGE b/railties/lib/rails_generator/generators/components/resource/templates/USAGE new file mode 100644 index 0000000000..39ad0db472 --- /dev/null +++ b/railties/lib/rails_generator/generators/components/resource/templates/USAGE @@ -0,0 +1,18 @@ +Description: + The resource generator creates an empty model and controller for use in a REST-friendly, resource-oriented + application. Say you want to a resource called post. Normally, you could just call "script/generate model post" and + "script/generate controller posts". This generator basically just collapses these two generators into one step. + + The generator takes the name of the model as its first argument. This model name is then pluralized to get the + controller name. So "resource post" will generate a Post model and a PostsController and will be intended + for URLs like /posts and /posts/45. + + As additional parameters, the generator will take attribute pairs described by name and type. These attributes will + be used to prepopulate the migration to create the table for the model and give you a set of predefined fixture. + You don't have to think up all attributes up front, but it's a good idea of adding just the baseline of what's + needed to start really working with the resource. + +Examples: + ./script/generate resource post + ./script/generate resource post title:string created_on:date body:text published:boolean + ./script/generate resource purchase order_id:integer created_at:datetime amount:decimal \ No newline at end of file diff --git a/railties/lib/rails_generator/generators/components/resource/templates/controller.rb b/railties/lib/rails_generator/generators/components/resource/templates/controller.rb new file mode 100644 index 0000000000..153ee1edac --- /dev/null +++ b/railties/lib/rails_generator/generators/components/resource/templates/controller.rb @@ -0,0 +1,2 @@ +class <%= controller_class_name %>Controller < ApplicationController +end \ No newline at end of file diff --git a/railties/lib/rails_generator/generators/components/resource/templates/fixtures.yml b/railties/lib/rails_generator/generators/components/resource/templates/fixtures.yml new file mode 100644 index 0000000000..9f5ae29a81 --- /dev/null +++ b/railties/lib/rails_generator/generators/components/resource/templates/fixtures.yml @@ -0,0 +1,11 @@ +# Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html +one: + id: 1 +<% for attribute in attributes -%> + <%= attribute.name %>: <%= attribute.default %> +<% end -%> +two: + id: 2 +<% for attribute in attributes -%> + <%= attribute.name %>: <%= attribute.default %> +<% end -%> \ No newline at end of file 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 new file mode 100644 index 0000000000..32bc2cab2b --- /dev/null +++ b/railties/lib/rails_generator/generators/components/resource/templates/functional_test.rb @@ -0,0 +1,20 @@ +require File.dirname(__FILE__) + '<%= '/..' * controller_class_nesting_depth %>/../test_helper' +require '<%= controller_file_path %>_controller' + +# Re-raise errors caught by the controller. +class <%= controller_class_name %>Controller; def rescue_action(e) raise e end; end + +class <%= controller_class_name %>ControllerTest < Test::Unit::TestCase + fixtures :<%= table_name %> + + def setup + @controller = <%= controller_class_name %>Controller.new + @request = ActionController::TestRequest.new + @response = ActionController::TestResponse.new + end + + # Replace this with your real tests. + def test_truth + assert true + end +end diff --git a/railties/lib/rails_generator/generators/components/resource/templates/helper.rb b/railties/lib/rails_generator/generators/components/resource/templates/helper.rb new file mode 100644 index 0000000000..9bd821b1b2 --- /dev/null +++ b/railties/lib/rails_generator/generators/components/resource/templates/helper.rb @@ -0,0 +1,2 @@ +module <%= controller_class_name %>Helper +end diff --git a/railties/lib/rails_generator/generators/components/resource/templates/migration.rb b/railties/lib/rails_generator/generators/components/resource/templates/migration.rb new file mode 100644 index 0000000000..2a305a6a9d --- /dev/null +++ b/railties/lib/rails_generator/generators/components/resource/templates/migration.rb @@ -0,0 +1,13 @@ +class <%= migration_name %> < ActiveRecord::Migration + def self.up + create_table :<%= table_name %> do |t| +<% for attribute in attributes -%> + t.column :<%= attribute.name %>, :<%= attribute.type %> +<% end -%> + end + end + + def self.down + drop_table :<%= table_name %> + end +end diff --git a/railties/lib/rails_generator/generators/components/resource/templates/model.rb b/railties/lib/rails_generator/generators/components/resource/templates/model.rb new file mode 100644 index 0000000000..8d4c89e912 --- /dev/null +++ b/railties/lib/rails_generator/generators/components/resource/templates/model.rb @@ -0,0 +1,2 @@ +class <%= class_name %> < ActiveRecord::Base +end diff --git a/railties/lib/rails_generator/generators/components/resource/templates/unit_test.rb b/railties/lib/rails_generator/generators/components/resource/templates/unit_test.rb new file mode 100644 index 0000000000..b464de47a2 --- /dev/null +++ b/railties/lib/rails_generator/generators/components/resource/templates/unit_test.rb @@ -0,0 +1,10 @@ +require File.dirname(__FILE__) + '<%= '/..' * class_nesting_depth %>/../test_helper' + +class <%= class_name %>Test < Test::Unit::TestCase + fixtures :<%= table_name %> + + # Replace this with your real tests. + def test_truth + assert true + end +end diff --git a/railties/lib/rails_generator/generators/components/scaffold_resource/USAGE b/railties/lib/rails_generator/generators/components/scaffold_resource/USAGE index 86d6ec31a9..9ccf4d9938 100644 --- a/railties/lib/rails_generator/generators/components/scaffold_resource/USAGE +++ b/railties/lib/rails_generator/generators/components/scaffold_resource/USAGE @@ -23,7 +23,7 @@ Description: add "map.resources :posts" (notice the plural form) in the routes file. Then your new resource is accessible from /posts. -Example: +Examples: ./script/generate scaffold_resource post # no attributes, view will be anemic ./script/generate scaffold_resource post title:string created_on:date body:text published:boolean ./script/generate scaffold_resource purchase order_id:integer created_at:datetime amount:decimal \ No newline at end of file diff --git a/railties/lib/rails_generator/generators/components/scaffold_resource/scaffold_resource_generator.rb b/railties/lib/rails_generator/generators/components/scaffold_resource/scaffold_resource_generator.rb index 7ea80ea5ac..ca6d997a9a 100644 --- a/railties/lib/rails_generator/generators/components/scaffold_resource/scaffold_resource_generator.rb +++ b/railties/lib/rails_generator/generators/components/scaffold_resource/scaffold_resource_generator.rb @@ -1,41 +1,4 @@ class ScaffoldResourceGenerator < Rails::Generator::NamedBase - class ScaffoldAttribute - 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 - end - attr_reader :controller_name, :controller_class_path, :controller_file_path, @@ -121,7 +84,7 @@ class ScaffoldResourceGenerator < Rails::Generator::NamedBase protected # Override with your own usage banner. def banner - "Usage: #{$0} scaffold_resource ModelName" + "Usage: #{$0} scaffold_resource ModelName [field:type, field:type]" end def scaffold_views @@ -131,10 +94,4 @@ class ScaffoldResourceGenerator < Rails::Generator::NamedBase def model_name class_name.demodulize end - - def attributes - @attributes ||= args.collect do |attribute| - ScaffoldAttribute.new(*attribute.split(":")) - end - end end -- cgit v1.2.3