mirror of https://github.com/rails/rails
Added a better generator for scaffolding that actually creates the code, so it can be edited bit by bit. See "script/generate scaffold" [bitsweat]. Added a whole new approach to generators that used the shared "script/generate" command. Run with no-args to see help [bitsweat].
git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@63 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
This commit is contained in:
parent
3ee4357b86
commit
2594581e9f
|
@ -21,7 +21,8 @@ TEST_DIRS = %w( fixtures unit functional mocks mocks/development mocks/testing
|
|||
|
||||
LOG_FILES = %w( apache.log development.log test.log production.log )
|
||||
HTML_FILES = %w( 404.html 500.html index.html )
|
||||
SCRIPT_FILES = %w( new_controller new_model new_mailer new_crud )
|
||||
SCRIPT_FILES = %w( generate )
|
||||
GENERATORS = %w( controller mailer model scaffold )
|
||||
|
||||
VENDOR_LIBS = %w( actionpack activerecord actionmailer railties )
|
||||
|
||||
|
@ -136,11 +137,16 @@ task :copy_configs do
|
|||
end
|
||||
|
||||
task :copy_generators do
|
||||
mkdir_p File.join(PKG_DESTINATION, 'script')
|
||||
SCRIPT_FILES.each do |file|
|
||||
dest_file = File.join(PKG_DESTINATION, 'script', file)
|
||||
cp File.join('generators', "#{file}.rb"), dest_file
|
||||
chmod 0755, dest_file
|
||||
end
|
||||
|
||||
GENERATORS.each do |dir|
|
||||
cp_r File.join('generators', dir), File.join(PKG_DESTINATION, 'script', dir)
|
||||
end
|
||||
end
|
||||
|
||||
task :copy_rootfiles do
|
||||
|
|
14
railties/generators/new_controller.rb → railties/generators/controller/USAGE
Executable file → Normal file
14
railties/generators/new_controller.rb → railties/generators/controller/USAGE
Executable file → Normal file
|
@ -1,15 +1,3 @@
|
|||
#!/usr/local/bin/ruby
|
||||
require File.dirname(__FILE__) + '/../config/environment'
|
||||
require 'generator'
|
||||
|
||||
unless ARGV.empty?
|
||||
rails_root = File.dirname(__FILE__) + '/..'
|
||||
name = ARGV.shift
|
||||
actions = ARGV
|
||||
Generator::Controller.new(rails_root, name, actions).generate
|
||||
else
|
||||
puts <<-END_HELP
|
||||
|
||||
NAME
|
||||
new_controller - create controller and view stub files
|
||||
|
||||
|
@ -39,5 +27,3 @@ EXAMPLE
|
|||
|
||||
The BlogController class will have the following methods: list, display, new, edit.
|
||||
Each will default to render the associated template file.
|
||||
END_HELP
|
||||
end
|
|
@ -0,0 +1,22 @@
|
|||
require 'rails_generator'
|
||||
|
||||
class ControllerGenerator < Rails::Generator::Base
|
||||
attr_reader :actions
|
||||
|
||||
def generate
|
||||
@actions = args
|
||||
|
||||
# Controller class, functional test, and helper class.
|
||||
template "controller.rb", "app/controllers/#{file_name}_controller.rb"
|
||||
template "functional_test.rb", "test/functional/#{file_name}_controller_test.rb"
|
||||
template "helper.rb", "app/helpers/#{file_name}_helper.rb"
|
||||
|
||||
# Create the views directory even if there are no actions.
|
||||
FileUtils.mkdir_p "app/views/#{file_name}"
|
||||
|
||||
# Create a view for each action.
|
||||
actions.each do |action|
|
||||
template "view.rhtml", "app/views/#{file_name}/#{action}.rhtml", binding
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,10 @@
|
|||
class <%= class_name %>Controller < AbstractApplicationController
|
||||
<% if options[:scaffold] -%>
|
||||
scaffold :<%= singular_name %>
|
||||
<% end -%>
|
||||
<% for action in actions -%>
|
||||
|
||||
def <%= action %>
|
||||
end
|
||||
<% end -%>
|
||||
end
|
|
@ -10,7 +10,7 @@ class <%= class_name %>ControllerTest < Test::Unit::TestCase
|
|||
@request, @response = ActionController::TestRequest.new, ActionController::TestResponse.new
|
||||
end
|
||||
|
||||
# Replace this with your real tests
|
||||
# Replace this with your real tests.
|
||||
def test_truth
|
||||
assert true
|
||||
end
|
|
@ -0,0 +1,2 @@
|
|||
<h1><%= class_name %>#<%= action %></h1>
|
||||
<p>Find me in app/views/<%= file_name %>/<%= action %>.rhtml</p>
|
|
@ -0,0 +1,41 @@
|
|||
#!/usr/local/bin/ruby
|
||||
require File.dirname(__FILE__) + '/../config/environment'
|
||||
require 'rails_generator'
|
||||
|
||||
unless ARGV.empty?
|
||||
begin
|
||||
name = ARGV.shift
|
||||
Rails::Generator.instance(name, ARGV).generate
|
||||
rescue Rails::Generator::UsageError => e
|
||||
puts e.message
|
||||
end
|
||||
else
|
||||
builtin_generators = Rails::Generator.builtin_generators.join(', ')
|
||||
contrib_generators = Rails::Generator.contrib_generators.join(', ')
|
||||
|
||||
$stderr.puts <<end_usage
|
||||
#{$0} generator [args]
|
||||
|
||||
Rails comes with #{builtin_generators} generators.
|
||||
#{$0} controller Login login logout
|
||||
#{$0} model Account
|
||||
#{$0} mailer AccountMailer
|
||||
#{$0} scaffold Account action another_action
|
||||
|
||||
end_usage
|
||||
|
||||
unless contrib_generators.empty?
|
||||
$stderr.puts " Installed generators (in #{RAILS_ROOT}/generators):"
|
||||
$stderr.puts " #{contrib_generators}"
|
||||
$stderr.puts
|
||||
end
|
||||
|
||||
$stderr.puts <<end_usage
|
||||
More generators are available at http://rubyonrails.org
|
||||
1. Download, for example, auth_controller.zip
|
||||
2. Unzip to directory #{RAILS_ROOT}/generators/auth_controller
|
||||
3. Generate without args for usage information
|
||||
#{$0} auth_controller
|
||||
end_usage
|
||||
exit 0
|
||||
end
|
|
@ -1,15 +1,3 @@
|
|||
#!/usr/local/bin/ruby
|
||||
require File.dirname(__FILE__) + '/../config/environment'
|
||||
require 'generator'
|
||||
|
||||
unless ARGV.empty?
|
||||
rails_root = File.dirname(__FILE__) + '/..'
|
||||
name = ARGV.shift
|
||||
actions = ARGV
|
||||
Generator::Mailer.new(rails_root, name, actions).generate
|
||||
else
|
||||
puts <<-END_HELP
|
||||
|
||||
NAME
|
||||
new_mailer - create mailer and view stub files
|
||||
|
||||
|
@ -39,5 +27,3 @@ EXAMPLE
|
|||
|
||||
The Notifications class will have the following methods: signup,
|
||||
forgot_password, and invoice.
|
||||
END_HELP
|
||||
end
|
|
@ -0,0 +1,22 @@
|
|||
require 'rails_generator'
|
||||
|
||||
class MailerGenerator < Rails::Generator::Base
|
||||
attr_reader :actions
|
||||
|
||||
def generate
|
||||
@actions = args
|
||||
|
||||
# Mailer class and unit test.
|
||||
template "mailer.rb", "app/models/#{file_name}.rb"
|
||||
template "unit_test.rb", "test/unit/#{file_name}_test.rb"
|
||||
|
||||
# Test fixtures directory.
|
||||
FileUtils.mkdir_p "test/fixtures/#{table_name}"
|
||||
|
||||
# View template and fixture for each action.
|
||||
args.each do |action|
|
||||
template "view.rhtml", "app/views/#{file_name}/#{action}.rhtml", binding
|
||||
template "fixture.rhtml", "test/fixtures/#{table_name}/#{action}", binding
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,8 +1,8 @@
|
|||
require 'action_mailer'
|
||||
|
||||
class <%= class_name %> < ActionMailer::Base
|
||||
|
||||
<% for action in actions -%>
|
||||
|
||||
def <%= action %>(sent_on = Time.now)
|
||||
@recipients = ''
|
||||
@from = ''
|
||||
|
@ -10,6 +10,5 @@ class <%= class_name %> < ActionMailer::Base
|
|||
@body = {}
|
||||
@sent_on = sent_on
|
||||
end
|
||||
|
||||
<% end -%>
|
||||
end
|
|
@ -12,11 +12,11 @@ class <%= class_name %>Test < Test::Unit::TestCase
|
|||
@expected = TMail::Mail.new
|
||||
@expected.to = 'test@localhost'
|
||||
@expected.from = 'test@localhost'
|
||||
@expected.subject = '<%= class_name %> test mail'
|
||||
end
|
||||
|
||||
<% for action in actions -%>
|
||||
def test_<%= action %>
|
||||
@expected.subject = '<%= class_name %>#<%= action %> test mail'
|
||||
@expected.body = read_fixture('<%= action %>')
|
||||
@expected.date = Time.now
|
||||
|
|
@ -1,14 +1,3 @@
|
|||
#!/usr/local/bin/ruby
|
||||
require File.dirname(__FILE__) + '/../config/environment'
|
||||
require 'generator'
|
||||
|
||||
if ARGV.size == 1
|
||||
rails_root = File.dirname(__FILE__) + '/..'
|
||||
name = ARGV.shift
|
||||
Generator::Model.new(rails_root, name).generate
|
||||
else
|
||||
puts <<-HELP
|
||||
|
||||
NAME
|
||||
new_model - create model stub files
|
||||
|
||||
|
@ -26,6 +15,3 @@ EXAMPLE
|
|||
This will generate an Account class in app/models/account.rb, an
|
||||
AccountTest in test/unit/account_test.rb, and the directory
|
||||
test/fixtures/account.
|
||||
|
||||
HELP
|
||||
end
|
|
@ -0,0 +1,10 @@
|
|||
require 'rails_generator'
|
||||
|
||||
class ModelGenerator < Rails::Generator::Base
|
||||
def generate
|
||||
# Model class, unit test, and fixtures.
|
||||
template "model.rb", "app/models/#{file_name}.rb"
|
||||
template "unit_test.rb", "test/unit/#{file_name}_test.rb"
|
||||
template "fixtures.yml", "test/fixtures/#{table_name}.yml"
|
||||
end
|
||||
end
|
|
@ -0,0 +1 @@
|
|||
# Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html
|
|
@ -4,8 +4,8 @@ require '<%= file_name %>'
|
|||
class <%= class_name %>Test < Test::Unit::TestCase
|
||||
fixtures :<%= table_name %>
|
||||
|
||||
# Replace this with your real tests
|
||||
# Replace this with your real tests.
|
||||
def test_truth
|
||||
assert true
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,34 +0,0 @@
|
|||
#!/usr/local/bin/ruby
|
||||
require File.dirname(__FILE__) + '/../config/environment'
|
||||
require 'generator'
|
||||
|
||||
unless ARGV.empty?
|
||||
rails_root = File.dirname(__FILE__) + '/..'
|
||||
name = ARGV.shift
|
||||
actions = ARGV
|
||||
Generator::Model.new(rails_root, name).generate
|
||||
Generator::Controller.new(rails_root, name, actions, :scaffold => true).generate
|
||||
else
|
||||
puts <<-END_HELP
|
||||
|
||||
NAME
|
||||
new_crud - create a model and a controller scaffold
|
||||
|
||||
SYNOPSIS
|
||||
new_crud ModelName [action ...]
|
||||
|
||||
DESCRIPTION
|
||||
The new_crud generator takes the name of the new model as the
|
||||
first argument and an optional list of controller actions as the
|
||||
subsequent arguments. All actions may be omitted since the controller
|
||||
will have scaffolding automatically set up for this model.
|
||||
|
||||
EXAMPLE
|
||||
new_crud Account
|
||||
|
||||
This will generate an Account model and controller with scaffolding.
|
||||
Now create the accounts table in your database and browse to
|
||||
http://localhost/account/ -- voila, you're on Rails!
|
||||
|
||||
END_HELP
|
||||
end
|
|
@ -0,0 +1,18 @@
|
|||
NAME
|
||||
new_scaffold - create a model and a skeleton controller
|
||||
|
||||
SYNOPSIS
|
||||
new_scaffold ModelName [action ...]
|
||||
|
||||
DESCRIPTION
|
||||
The new_scaffold generator takes the name of the new model as the
|
||||
first argument and an optional list of controller actions as the
|
||||
subsequent arguments. Any actions with scaffolding code available
|
||||
will be generated in your controller; others will be left as stubs.
|
||||
|
||||
EXAMPLE
|
||||
new_scaffold Account
|
||||
|
||||
This will generate an Account model and controller.
|
||||
Now create the accounts table in your database and browse to
|
||||
http://localhost/account/ -- voila, you're on Rails!
|
|
@ -0,0 +1,53 @@
|
|||
require 'rails_generator'
|
||||
|
||||
class ScaffoldGenerator < Rails::Generator::Base
|
||||
def generate
|
||||
# Model.
|
||||
generator('model').generate
|
||||
|
||||
# Fixtures.
|
||||
template "fixtures.yml", "test/fixtures/#{table_name}.yml"
|
||||
|
||||
# Controller class, functional test, helper, and views.
|
||||
template "controller.rb", "app/controllers/#{file_name}_controller.rb"
|
||||
template "functional_test.rb", "test/functional/#{file_name}_controller_test.rb"
|
||||
template "controller/helper.rb", "app/helpers/#{file_name}_helper.rb"
|
||||
|
||||
# Layout and stylesheet.
|
||||
unless File.file?("app/views/layouts/scaffold.rhtml")
|
||||
template "layout.rhtml", "app/views/layouts/scaffold.rhtml"
|
||||
end
|
||||
unless File.file?("public/stylesheets/scaffold.css")
|
||||
template "style.css", "public/stylesheets/scaffold.css"
|
||||
end
|
||||
|
||||
# Scaffolded views.
|
||||
scaffold_views.each do |action|
|
||||
template "view_#{action}.rhtml", "app/views/#{file_name}/#{action}.rhtml"
|
||||
end
|
||||
|
||||
# Unscaffolded views.
|
||||
unscaffolded_actions.each do |action|
|
||||
template "controller/view.rhtml",
|
||||
"app/views/#{file_name}/#{action}.rhtml",
|
||||
binding
|
||||
end
|
||||
end
|
||||
|
||||
protected
|
||||
def scaffold_views
|
||||
%w(list show new edit)
|
||||
end
|
||||
|
||||
def scaffold_actions
|
||||
scaffold_views + %w(index create update destroy)
|
||||
end
|
||||
|
||||
def unscaffolded_actions
|
||||
args - scaffold_actions
|
||||
end
|
||||
|
||||
def suffix
|
||||
"_#{singular_name}" if options[:suffix]
|
||||
end
|
||||
end
|
|
@ -0,0 +1,58 @@
|
|||
class <%= class_name %>Controller < AbstractApplicationController
|
||||
model :<%= singular_name %>
|
||||
layout 'scaffold'
|
||||
|
||||
<% unless suffix -%>
|
||||
def index
|
||||
list
|
||||
render_action 'list'
|
||||
end
|
||||
<% end -%>
|
||||
|
||||
<% for action in unscaffolded_actions -%>
|
||||
def <%= action %><%= suffix %>
|
||||
end
|
||||
|
||||
<% end -%>
|
||||
def list<%= suffix %>
|
||||
@<%= plural_name %> = <%= class_name %>.find_all
|
||||
end
|
||||
|
||||
def show<%= suffix %>
|
||||
@<%= singular_name %> = <%= class_name %>.find(@params['id'])
|
||||
end
|
||||
|
||||
def new<%= suffix %>
|
||||
@<%= singular_name %> = <%= class_name %>.new
|
||||
end
|
||||
|
||||
def create<%= suffix %>
|
||||
@<%= singular_name %> = <%= class_name %>.new(@params['<%= singular_name %>'])
|
||||
if @<%= singular_name %>.save
|
||||
flash['notice'] = '<%= class_name %> was successfully created.'
|
||||
redirect_to :action => 'list<%= suffix %>'
|
||||
else
|
||||
render_action 'new<%= suffix %>'
|
||||
end
|
||||
end
|
||||
|
||||
def edit<%= suffix %>
|
||||
@<%= singular_name %> = <%= class_name %>.find(@params['id'])
|
||||
end
|
||||
|
||||
def update
|
||||
@<%= singular_name %> = <%= class_name %>.find(@params['<%= singular_name %>']['id'])
|
||||
@<%= singular_name %>.attributes = @params['<%= singular_name %>']
|
||||
if @<%= singular_name %>.save
|
||||
flash['notice'] = '<%= class_name %> was successfully updated.'
|
||||
redirect_to :action => 'show<%= suffix %>', :id => @<%= singular_name %>.id
|
||||
else
|
||||
render_action 'edit<%= suffix %>'
|
||||
end
|
||||
end
|
||||
|
||||
def destroy<%= suffix %>
|
||||
<%= class_name %>.find(@params['id']).destroy
|
||||
redirect_to :action => 'list<%= suffix %>'
|
||||
end
|
||||
end
|
|
@ -0,0 +1,7 @@
|
|||
# Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html
|
||||
|
||||
first_<%= singular_name %>:
|
||||
id: 1
|
||||
|
||||
another_<%= singular_name %>:
|
||||
id: 2
|
|
@ -0,0 +1,109 @@
|
|||
require File.dirname(__FILE__) + '/../test_helper'
|
||||
require '<%= file_name %>_controller'
|
||||
|
||||
# Re-raise errors caught by the controller.
|
||||
class <%= class_name %>Controller; def rescue_action(e) raise e end; end
|
||||
|
||||
class <%= class_name %>ControllerTest < Test::Unit::TestCase
|
||||
fixtures :<%= table_name %>
|
||||
|
||||
def setup
|
||||
@controller = <%= class_name %>Controller.new
|
||||
@request, @response = ActionController::TestRequest.new, ActionController::TestResponse.new
|
||||
end
|
||||
|
||||
<% for action in unscaffolded_actions -%>
|
||||
def test_<%= action %>
|
||||
process :<%= action %>
|
||||
assert_success
|
||||
assert_rendered_file '<%= action %>'
|
||||
end
|
||||
|
||||
<% end -%>
|
||||
<% unless suffix -%>
|
||||
def test_index
|
||||
process :index
|
||||
assert_success
|
||||
assert_rendered_file 'list'
|
||||
end
|
||||
|
||||
<% end -%>
|
||||
def test_list<%= suffix %>
|
||||
process :list<%= suffix %>
|
||||
assert_success
|
||||
assert_rendered_file 'list<%= suffix %>'
|
||||
assert_template_has '<%= plural_name %>'
|
||||
end
|
||||
|
||||
def test_show<%= suffix %>
|
||||
process :show<%= suffix %>, 'id' => 1
|
||||
assert_success
|
||||
assert_rendered_file 'show'
|
||||
assert_template_has '<%= singular_name %>'
|
||||
assert_valid_record '<%= singular_name %>'
|
||||
end
|
||||
|
||||
def test_show_missing_<%= suffix || 'record' %>
|
||||
process :show<%= suffix %>
|
||||
assert_success
|
||||
assert_rendered_file 'error'
|
||||
end
|
||||
|
||||
def test_new<%= suffix %>
|
||||
process :new<%= suffix %>
|
||||
assert_success
|
||||
assert_rendered_file 'new<%= suffix %>'
|
||||
assert_template_has '<%= singular_name %>'
|
||||
end
|
||||
|
||||
def test_create
|
||||
num_<%= plural_name %> = <%= class_name %>.find_all.size
|
||||
|
||||
process :create<%= suffix %>, '<%= singular_name %>' => { }
|
||||
assert_redirected_to :action => 'list<%= suffix %>'
|
||||
|
||||
assert_equal num_<%= plural_name %> + 1, <%= class_name %>.find_all.size
|
||||
end
|
||||
|
||||
def test_edit<%= suffix %>
|
||||
process :edit<%= suffix %>, 'id' => 1
|
||||
assert_success
|
||||
assert_rendered_file 'edit<%= suffix %>'
|
||||
assert_template_has '<%= singular_name %>'
|
||||
assert_valid_record '<%= singular_name %>'
|
||||
end
|
||||
|
||||
def test_edit_missing_<%= suffix || 'record' %>
|
||||
process :edit<%= suffix %>
|
||||
assert_success
|
||||
assert_rendered_file 'error'
|
||||
end
|
||||
|
||||
def test_update<%= suffix %>
|
||||
process :update<%= suffix %>, 'id' => 1
|
||||
assert_redirected_to :action => 'show<%= suffix %>', :id => 1
|
||||
end
|
||||
|
||||
def test_update_missing_<%= suffix || 'record' %>
|
||||
process :update<%= suffix %>, '<%= singular_name %>' => {}
|
||||
assert_success
|
||||
assert_rendered_file 'error'
|
||||
end
|
||||
|
||||
def test_destroy<%= suffix %>
|
||||
assert_not_nil <%= class_name %>.find(1)
|
||||
|
||||
process :destroy, 'id' => 1
|
||||
assert_redirected_to :action => 'list<%= suffix %>'
|
||||
|
||||
assert_raise(ActiveRecord::RecordNotFound) {
|
||||
<%= singular_name %> = <%= class_name %>.find(1)
|
||||
}
|
||||
end
|
||||
|
||||
def test_destroy_missing_<%= suffix || 'record' %>
|
||||
process :destroy<%= suffix %>
|
||||
assert_success
|
||||
assert_rendered_file 'error'
|
||||
end
|
||||
end
|
|
@ -0,0 +1,11 @@
|
|||
<html>
|
||||
<head>
|
||||
<title>Scaffolding: <%%= controller.controller_name %>#<%%= controller.action_name %></title>
|
||||
<link href="/stylesheets/scaffold.css" rel="stylesheet" type="text/css" />
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<%%= @content_for_layout %>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,17 @@
|
|||
body { background-color: #fff; color: #333; }
|
||||
|
||||
body, p, ol, ul, td {
|
||||
font-family: verdana, arial, helvetica, sans-serif;
|
||||
font-size: 13px;
|
||||
line-height: 18px;
|
||||
}
|
||||
|
||||
pre {
|
||||
background-color: #eee;
|
||||
padding: 10px;
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
a { color: #000; }
|
||||
a:visited { color: #666; }
|
||||
a:hover { color: #fff; background-color:#000; }
|
|
@ -0,0 +1,6 @@
|
|||
<h1>Editing <%= singular_name %></h1>
|
||||
|
||||
<%%= form '<%= singular_name %>', :action => 'update<%= suffix %>' %>
|
||||
|
||||
<%%= link_to 'Show', :action => 'show<%= suffix %>', :id => @<%= singular_name %>.id %> |
|
||||
<%%= link_to 'Back', :action => 'list<%= suffix %>' %>
|
|
@ -0,0 +1,24 @@
|
|||
<h1>Listing <%= plural_name %></h1>
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<%% for column in <%= class_name %>.content_columns %>
|
||||
<th><%%= column.human_name %></th>
|
||||
<%% end %>
|
||||
</tr>
|
||||
|
||||
<%% for <%= singular_name %> in @<%= plural_name %> %>
|
||||
<tr>
|
||||
<%% for column in <%= class_name %>.content_columns %>
|
||||
<td><%%=h <%= singular_name %>[column.name] %></td>
|
||||
<%% end %>
|
||||
<td><%%= link_to 'Show', :action => 'show<%= suffix %>', :id => <%= singular_name %>.id %></td>
|
||||
<td><%%= link_to 'Edit', :action => 'edit<%= suffix %>', :id => <%= singular_name %>.id %></td>
|
||||
<td><%%= link_to 'Destroy', :action => 'destroy<%= suffix %>', :id => <%= singular_name %>.id %></td>
|
||||
</tr>
|
||||
<%% end %>
|
||||
</table>
|
||||
|
||||
<br />
|
||||
|
||||
<%%= link_to 'New <%= singular_name %>', :action => 'new<%= suffix %>' %>
|
|
@ -0,0 +1,5 @@
|
|||
<h1>New <%= @singular_name %></h1>
|
||||
|
||||
<%%= form '<%= singular_name %>', :action => 'create<%= suffix %>' %>
|
||||
|
||||
<%%= link_to 'Back', :action => 'list<%= suffix %>' %>
|
|
@ -0,0 +1,8 @@
|
|||
<%% for column in <%= class_name %>.content_columns %>
|
||||
<p>
|
||||
<b><%%= column.human_name %>:</b> <%%= @<%= singular_name %>[column.name] %>
|
||||
</p>
|
||||
<%% end %>
|
||||
|
||||
<%%= link_to 'Edit', :action => 'edit<%= suffix %>', :id => @<%= singular_name %>.id %> |
|
||||
<%%= link_to 'Back', :action => 'list<%= suffix %>' %>
|
|
@ -1,19 +0,0 @@
|
|||
class <%= class_name %>Controller < AbstractApplicationController
|
||||
helper :<%= file_name %>
|
||||
<% if options[:scaffold] -%>
|
||||
model :<%= file_name %>
|
||||
scaffold :<%= options[:scaffold] %>
|
||||
|
||||
<%- for action in actions -%>
|
||||
#def <%= action %>
|
||||
#end
|
||||
|
||||
<%- end -%>
|
||||
<% else -%>
|
||||
<%- for action in actions -%>
|
||||
def <%= action %>
|
||||
end
|
||||
|
||||
<%- end -%>
|
||||
<% end -%>
|
||||
end
|
|
@ -1,10 +0,0 @@
|
|||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
||||
<head>
|
||||
<title><%= class_name %>#<%= action %></title>
|
||||
</head>
|
||||
<body>
|
||||
<h1><%= class_name %>#<%= action %></h1>
|
||||
<p>Find me in app/views/<%= file_name %>/<%= action %>.rhtml</p>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,175 @@
|
|||
require 'fileutils'
|
||||
|
||||
module Rails
|
||||
module Generator
|
||||
class GeneratorError < StandardError; end
|
||||
class UsageError < GeneratorError; end
|
||||
|
||||
CONTRIB_ROOT = "#{RAILS_ROOT}/script/generators"
|
||||
BUILTIN_ROOT = "#{File.dirname(__FILE__)}/../generators"
|
||||
DEFAULT_SEARCH_PATHS = [CONTRIB_ROOT, BUILTIN_ROOT]
|
||||
|
||||
class << self
|
||||
def instance(name, args = [], search_paths = DEFAULT_SEARCH_PATHS)
|
||||
# RAILS_ROOT constant must be set.
|
||||
unless Object.const_get(:RAILS_ROOT)
|
||||
raise GeneratorError, "RAILS_ROOT must be set. Did you require 'config/environment'?"
|
||||
end
|
||||
|
||||
# Force canonical name.
|
||||
name = Inflector.underscore(name.downcase)
|
||||
|
||||
# Search for filesystem path to requested generator.
|
||||
unless path = find_generator_path(name, search_paths)
|
||||
raise GeneratorError, "#{name} generator not found."
|
||||
end
|
||||
|
||||
# Check for templates directory.
|
||||
template_root = "#{path}/templates"
|
||||
unless File.directory?(template_root)
|
||||
raise GeneratorError, "missing template directory #{template_root}"
|
||||
end
|
||||
|
||||
# Require class file according to naming convention.
|
||||
require "#{path}/#{name}_generator.rb"
|
||||
|
||||
# Find class according to naming convention. Allow Nesting::In::Modules.
|
||||
class_name = Inflector.classify("#{name}_generator")
|
||||
unless klass = find_generator_class(name)
|
||||
raise GeneratorError, "no #{class_name} class defined in #{path}/#{name}_generator.rb"
|
||||
end
|
||||
|
||||
# Instantiate and return generator.
|
||||
klass.new(template_root, RAILS_ROOT, search_paths, args)
|
||||
end
|
||||
|
||||
|
||||
def builtin_generators
|
||||
generators([BUILTIN_ROOT])
|
||||
end
|
||||
|
||||
def contrib_generators
|
||||
generators([CONTRIB_ROOT])
|
||||
end
|
||||
|
||||
def generators(search_paths)
|
||||
generator_paths(search_paths).keys.uniq.sort
|
||||
end
|
||||
|
||||
# Find all generator paths.
|
||||
def generator_paths(search_paths)
|
||||
@paths ||= {}
|
||||
unless @paths[search_paths]
|
||||
paths = Hash.new { |h,k| h[k] = [] }
|
||||
search_paths.each do |path|
|
||||
Dir["#{path}/[a-z]*"].each do |dir|
|
||||
paths[File.basename(dir)] << dir if File.directory?(dir)
|
||||
end
|
||||
end
|
||||
@paths[search_paths] = paths
|
||||
end
|
||||
@paths[search_paths]
|
||||
end
|
||||
|
||||
def find_generator_path(name, search_paths)
|
||||
generator_paths(search_paths)[name].first
|
||||
end
|
||||
|
||||
# Find all generator classes.
|
||||
def generator_classes
|
||||
classes = Hash.new { |h,k| h[k] = [] }
|
||||
class_re = /([^:]+)Generator$/
|
||||
ObjectSpace.each_object(Class) do |object|
|
||||
if md = class_re.match(object.name) and object < Rails::Generator::Base
|
||||
classes[Inflector.underscore(md.captures.first)] << object
|
||||
end
|
||||
end
|
||||
classes
|
||||
end
|
||||
|
||||
def find_generator_class(name)
|
||||
generator_classes[name].first
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
# Talk about generators.
|
||||
class Base
|
||||
attr_reader :template_root, :destination_root, :args, :options,
|
||||
:class_name, :singular_name, :plural_name
|
||||
|
||||
alias_method :file_name, :singular_name
|
||||
alias_method :table_name, :plural_name
|
||||
|
||||
def self.generator_name
|
||||
Inflector.underscore(name.gsub('Generator', ''))
|
||||
end
|
||||
|
||||
def initialize(template_root, destination_root, search_paths, args)
|
||||
@template_root, @destination_root = template_root, destination_root
|
||||
usage if args.empty?
|
||||
@search_paths, @original_args = search_paths, args.dup
|
||||
@class_name, @singular_name, @plural_name = inflect_names(args.shift)
|
||||
@options = extract_options!(args)
|
||||
@args = args
|
||||
end
|
||||
|
||||
protected
|
||||
# Look up another generator with the same arguments.
|
||||
def generator(name)
|
||||
Rails::Generator.instance(name, @original_args, @search_paths)
|
||||
end
|
||||
|
||||
# Generate a file for a Rails application using an ERuby template.
|
||||
# Looks up and evalutes a template by name and writes the result
|
||||
# to a file relative to +destination_root+. The template
|
||||
# is evaluated in the context of the optional eval_binding argument.
|
||||
#
|
||||
# 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.
|
||||
def template(template_name, destination_path, eval_binding = nil)
|
||||
# Determine full paths for source and destination files.
|
||||
template_path = find_template_path(template_name)
|
||||
destination_path = File.join(destination_root, destination_path)
|
||||
|
||||
# Create destination directories.
|
||||
FileUtils.mkdir_p(File.dirname(destination_path))
|
||||
|
||||
# Render template and write result.
|
||||
eval_binding ||= binding
|
||||
contents = ERB.new(File.read(template_path), nil, '-').result(eval_binding)
|
||||
File.open(destination_path, 'w') { |file| file.write(contents) }
|
||||
end
|
||||
|
||||
def usage
|
||||
raise UsageError.new, File.read(usage_path)
|
||||
end
|
||||
|
||||
private
|
||||
def find_template_path(template_name)
|
||||
name, path = template_name.split('/', 2)
|
||||
if path.nil?
|
||||
File.join(template_root, name)
|
||||
elsif generator_path = Rails::Generator.find_generator_path(name, @search_paths)
|
||||
File.join(generator_path, 'templates', path)
|
||||
end
|
||||
end
|
||||
|
||||
def inflect_names(name)
|
||||
camel = Inflector.camelize(Inflector.underscore(name))
|
||||
under = Inflector.underscore(camel)
|
||||
plural = Inflector.pluralize(under)
|
||||
[camel, under, plural]
|
||||
end
|
||||
|
||||
def extract_options!(args)
|
||||
if args.last.is_a?(Hash) then args.pop else {} end
|
||||
end
|
||||
|
||||
def usage_path
|
||||
"#{template_root}/../USAGE"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,95 @@
|
|||
$LOAD_PATH.unshift "#{File.dirname(__FILE__)}/../lib"
|
||||
RAILS_ROOT = File.dirname(__FILE__)
|
||||
|
||||
require File.dirname(__FILE__) + '/../../activerecord/lib/active_record/support/inflector'
|
||||
require 'rails_generator'
|
||||
require 'test/unit'
|
||||
|
||||
|
||||
class RailsGeneratorTest < Test::Unit::TestCase
|
||||
BUILTINS = %w(controller mailer model scaffold)
|
||||
|
||||
def test_instance_builtins
|
||||
BUILTINS.each do |name|
|
||||
object = nil
|
||||
assert_nothing_raised { object = Rails::Generator.instance(name, ['foo']) }
|
||||
assert_not_nil object
|
||||
assert_match /#{name.capitalize}Generator/, object.class.name
|
||||
assert_respond_to object, :generate
|
||||
end
|
||||
end
|
||||
|
||||
def test_instance_without_rails_root
|
||||
old_verbose, $VERBOSE = $VERBOSE, nil
|
||||
old_rails_root = Object.const_get(:RAILS_ROOT)
|
||||
begin
|
||||
Object.const_set(:RAILS_ROOT, nil)
|
||||
assert_raise(Rails::Generator::GeneratorError) {
|
||||
Rails::Generator.instance('model', ['name'])
|
||||
}
|
||||
ensure
|
||||
Object.const_set(:RAILS_ROOT, old_rails_root)
|
||||
$VERBOSE = old_verbose
|
||||
end
|
||||
end
|
||||
|
||||
def test_instance_not_found
|
||||
assert_raise(Rails::Generator::GeneratorError) {
|
||||
Rails::Generator.instance('foobar')
|
||||
}
|
||||
end
|
||||
|
||||
def test_instance_missing_templates
|
||||
assert_raise(Rails::Generator::GeneratorError) {
|
||||
Rails::Generator.instance('missing_templates')
|
||||
}
|
||||
end
|
||||
|
||||
def test_instance_missing_generator
|
||||
assert_raise(LoadError) {
|
||||
Rails::Generator.instance('missing_generator')
|
||||
}
|
||||
end
|
||||
|
||||
def test_instance_missing_class
|
||||
assert_raise(Rails::Generator::GeneratorError) {
|
||||
Rails::Generator.instance('missing_class')
|
||||
}
|
||||
end
|
||||
|
||||
def test_builtin_generators
|
||||
assert_nothing_raised {
|
||||
assert_equal [], Rails::Generator.builtin_generators - BUILTINS
|
||||
}
|
||||
end
|
||||
|
||||
def test_generator_name
|
||||
assert_equal 'model', Rails::Generator.instance('model', ['name']).class.generator_name
|
||||
end
|
||||
|
||||
def test_generator_usage
|
||||
assert_raise(Rails::Generator::UsageError) {
|
||||
assert_equal 'model', Rails::Generator.instance('model')
|
||||
}
|
||||
end
|
||||
|
||||
def test_generator_vars
|
||||
model = Rails::Generator.instance('model', ['model'])
|
||||
assert_equal "#{Rails::Generator::BUILTIN_ROOT}/model/templates", model.template_root
|
||||
assert_equal RAILS_ROOT, model.destination_root
|
||||
assert_equal 'Model', model.class_name
|
||||
assert_equal 'model', model.singular_name
|
||||
assert_equal 'models', model.plural_name
|
||||
assert_equal model.singular_name, model.file_name
|
||||
assert_equal model.plural_name, model.table_name
|
||||
assert_equal [], model.args
|
||||
end
|
||||
|
||||
def test_generator_generator
|
||||
assert_nothing_raised {
|
||||
model = Rails::Generator.instance('model', ['name'])
|
||||
mailer = model.send(:generator, 'mailer')
|
||||
assert_equal 'mailer', mailer.class.generator_name
|
||||
}
|
||||
end
|
||||
end
|
Loading…
Reference in New Issue