aboutsummaryrefslogtreecommitdiffstats
path: root/railties
diff options
context:
space:
mode:
Diffstat (limited to 'railties')
-rw-r--r--railties/guides/source/generators.textile34
-rw-r--r--railties/guides/source/index.html.erb2
-rw-r--r--railties/lib/rails/application.rb4
-rw-r--r--railties/lib/rails/application/bootstrap.rb3
-rw-r--r--railties/lib/rails/application/configuration.rb20
-rw-r--r--railties/lib/rails/commands.rb102
-rw-r--r--railties/lib/rails/commands/application.rb2
-rw-r--r--railties/lib/rails/commands/benchmarker.rb (renamed from railties/lib/rails/commands/performance/benchmarker.rb)0
-rw-r--r--railties/lib/rails/commands/profiler.rb (renamed from railties/lib/rails/commands/performance/profiler.rb)0
-rw-r--r--railties/lib/rails/commands/runner.rb3
-rw-r--r--railties/lib/rails/configuration.rb1
-rw-r--r--railties/lib/rails/engine.rb2
-rw-r--r--railties/lib/rails/generators/base.rb38
-rw-r--r--railties/lib/rails/generators/rails/app/app_generator.rb332
-rw-r--r--railties/lib/rails/generators/rails/app/templates/script/rails7
-rw-r--r--railties/lib/rails/generators/rails/generator/templates/%file_name%_generator.rb.tt4
-rw-r--r--railties/lib/rails/generators/rails/mailer/USAGE15
-rw-r--r--railties/lib/rails/generators/rails/mailer/mailer_generator.rb14
-rw-r--r--railties/lib/rails/generators/rails/mailer/templates/mailer.rb16
-rw-r--r--railties/lib/rails/railtie.rb1
-rw-r--r--railties/railties.gemspec2
-rw-r--r--railties/test/application/middleware_test.rb7
-rw-r--r--railties/test/application/model_initialization_test.rb33
-rw-r--r--railties/test/application/paths_test.rb5
-rw-r--r--railties/test/application/rake_test.rb14
-rw-r--r--railties/test/fixtures/lib/empty_builder.rb2
-rw-r--r--railties/test/fixtures/lib/simple_builder.rb7
-rw-r--r--railties/test/fixtures/lib/tweak_builder.rb7
-rw-r--r--railties/test/generators/actions_test.rb2
-rw-r--r--railties/test/generators/app_generator_test.rb135
-rw-r--r--railties/test/generators/mailer_generator_test.rb3
31 files changed, 521 insertions, 296 deletions
diff --git a/railties/guides/source/generators.textile b/railties/guides/source/generators.textile
index 4387fe3bd5..d3757e9733 100644
--- a/railties/guides/source/generators.textile
+++ b/railties/guides/source/generators.textile
@@ -88,9 +88,7 @@ And it will create a new generator as follow:
<ruby>
class InitializerGenerator < Rails::Generators::NamedBase
- def self.source_root
- @source_root ||= File.expand_path(File.join(File.dirname(__FILE__), 'templates'))
- end
+ source_root File.expand_path("../templates", __FILE__)
end
</ruby>
@@ -115,9 +113,7 @@ And now let's change the generator to copy this template when invoked:
<ruby>
class InitializerGenerator < Rails::Generators::NamedBase
- def self.source_root
- @source_root ||= File.expand_path(File.join(File.dirname(__FILE__), 'templates'))
- end
+ source_root File.expand_path("../templates", __FILE__)
def copy_initializer_file
copy_file "initializer.rb", "config/initializers/#{file_name}.rb"
@@ -135,21 +131,18 @@ We can see that now a initializer named foo was created at +config/initializers/
h3. Generators lookup
-Now that we know how to create generators, we must know where Rails looks for generators before invoking them. When we invoke the initializer generator, Rails looks at the following paths in the given order:
+With our first generator created, we must discuss briefly generators lookup. The way Rails finds generators is exactly the same way Ruby find files, i.e. using +$LOAD_PATHS+.
+
+For instance, when you say +rails g initializer foo+, rails knows you want to invoke the initializer generator and then search for the following generators in the $LOAD_PATHS:
<shell>
-RAILS_APP/lib/generators
-RAILS_APP/lib/rails_generators
-RAILS_APP/vendor/plugins/*/lib/generators
-RAILS_APP/vendor/plugins/*/lib/rails_generators
-GEMS_PATH/*/lib/generators
-GEMS_PATH/*/lib/rails_generators
-~/rails/generators
-~/rails/rails_generators
-RAILS_GEM/lib/rails/generators
+rails/generators/initializer/initializer_generator.rb
+generators/initializer/initializer_generator.rb
+rails/generators/initializer_generator.rb
+generators/initializer_generator.rb
</shell>
-First Rails looks for generators in your application, then in plugins and/or gems, then in your home and finally the builtin generators. One very important thing to keep in mind is that in Rails 3.0 and after it only looks for generators in gems being used in your application. So if you have rspec installed as a gem, but it's not declared in your application, Rails won't be able to invoke it.
+If none of them is found, it raises an error message.
h3. Customizing your workflow
@@ -183,7 +176,6 @@ $ rails generate scaffold User name:string
create app/views/users/show.html.erb
create app/views/users/new.html.erb
create app/views/users/_form.html.erb
- create app/views/layouts/users.html.erb
invoke test_unit
create test/functional/users_controller_test.rb
invoke helper
@@ -284,7 +276,7 @@ end
end
</ruby>
-Now, when the helper generator is invoked and let's say test unit is configured as test framework, it will try to invoke both +MyHelper::Generators::TestUnitGenerator+ and +TestUnit::Generators::MyHelperGenerator+. Since none of those are defined, we can tell our generator to invoke +TestUnit::Generators::HelperGenerator+ instead, which is defined since it's a Rails hook. To do that, we just need to add:
+Now, when the helper generator is invoked and let's say test unit is configured as test framework, it will try to invoke both +MyHelper::Generators::TestUnitGenerator+ and +TestUnit::Generators::MyHelperGenerator+. Since none of those are defined, we can tell our generator to invoke +TestUnit::Generators::HelperGenerator+ instead, which is defined since it's a Rails generator. To do that, we just need to add:
<ruby>
# Search for :helper instead of :my_helper
@@ -375,4 +367,6 @@ h3. Changelog
"Lighthouse Ticket":http://rails.lighthouseapp.com/projects/16213-rails-guides/tickets/102
-* November 20, 2009: First release version by José Valim
+* April 30, 2010: Reviewed by José Valim
+
+* November 20, 2009: First version by José Valim
diff --git a/railties/guides/source/index.html.erb b/railties/guides/source/index.html.erb
index f47975917c..5a715cf9f7 100644
--- a/railties/guides/source/index.html.erb
+++ b/railties/guides/source/index.html.erb
@@ -143,7 +143,7 @@ Ruby on Rails Guides
<%= guide("Adding Generators", 'generators.html') do %>
<p>This guide covers the process of adding a brand new generator to your extension
or providing an alternative to an element of a built-in Rails generator (such as
- providing alternative test stubs for the scaffold generator)</p>
+ providing alternative test stubs for the scaffold generator).</p>
<% end %>
</dl>
diff --git a/railties/lib/rails/application.rb b/railties/lib/rails/application.rb
index 7cec14c738..d39f9a2ae9 100644
--- a/railties/lib/rails/application.rb
+++ b/railties/lib/rails/application.rb
@@ -85,7 +85,7 @@ module Rails
delegate :metal_loader, :to => :config
def require_environment!
- environment = config.paths.config.environment.to_a.first
+ environment = paths.config.environment.to_a.first
require environment if environment
end
@@ -153,7 +153,7 @@ module Rails
require "rails/tasks"
task :environment do
$rails_rake_task = true
- initialize!
+ require_environment!
end
end
diff --git a/railties/lib/rails/application/bootstrap.rb b/railties/lib/rails/application/bootstrap.rb
index 06243f2e5e..022e1a91d8 100644
--- a/railties/lib/rails/application/bootstrap.rb
+++ b/railties/lib/rails/application/bootstrap.rb
@@ -6,7 +6,8 @@ module Rails
include Initializable
initializer :load_environment_config do
- require_environment!
+ environment = config.paths.config.environments.to_a.first
+ require environment if environment
end
initializer :load_all_active_support do
diff --git a/railties/lib/rails/application/configuration.rb b/railties/lib/rails/application/configuration.rb
index 874b3a78b6..1ad77fdfec 100644
--- a/railties/lib/rails/application/configuration.rb
+++ b/railties/lib/rails/application/configuration.rb
@@ -1,3 +1,4 @@
+require 'active_support/deprecation'
require 'rails/engine/configuration'
module Rails
@@ -43,14 +44,15 @@ module Rails
@paths ||= begin
paths = super
paths.app.controllers << builtin_controller if builtin_controller
- paths.config.database "config/database.yml"
- paths.config.environment "config/environments", :glob => "#{Rails.env}.rb"
- paths.lib.templates "lib/templates"
- paths.log "log/#{Rails.env}.log"
- paths.tmp "tmp"
- paths.tmp.cache "tmp/cache"
- paths.vendor "vendor", :load_path => true
- paths.vendor.plugins "vendor/plugins"
+ paths.config.database "config/database.yml"
+ paths.config.environment "config/environment.rb"
+ paths.config.environments "config/environments", :glob => "#{Rails.env}.rb"
+ paths.lib.templates "lib/templates"
+ paths.log "log/#{Rails.env}.log"
+ paths.tmp "tmp"
+ paths.tmp.cache "tmp/cache"
+ paths.vendor "vendor", :load_path => true
+ paths.vendor.plugins "vendor/plugins"
if File.exists?("#{root}/test/mocks/#{Rails.env}")
ActiveSupport::Deprecation.warn "\"Rails.root/test/mocks/#{Rails.env}\" won't be added " <<
@@ -142,7 +144,7 @@ module Rails
middleware.use('::Rack::Runtime')
middleware.use('::Rails::Rack::Logger')
middleware.use('::ActionDispatch::ShowExceptions', lambda { consider_all_requests_local }, :if => lambda { action_dispatch.show_exceptions })
- middleware.use("::ActionDispatch::RemoteIp", lambda { action_dispatch.ip_spoofing_check }, lambda { action_dispatch.trusted_proxies })
+ middleware.use('::ActionDispatch::RemoteIp', lambda { action_dispatch.ip_spoofing_check }, lambda { action_dispatch.trusted_proxies })
middleware.use('::Rack::Sendfile', lambda { action_dispatch.x_sendfile_header })
middleware.use('::ActionDispatch::Callbacks', lambda { !cache_classes })
middleware.use('::ActionDispatch::Cookies')
diff --git a/railties/lib/rails/commands.rb b/railties/lib/rails/commands.rb
index 12748da18b..de93a87615 100644
--- a/railties/lib/rails/commands.rb
+++ b/railties/lib/rails/commands.rb
@@ -1,8 +1,50 @@
-if ARGV.empty?
- ARGV << '--help'
-end
+ARGV << '--help' if ARGV.empty?
-HELP_TEXT = <<-EOT
+aliases = {
+ "g" => "generate",
+ "c" => "console",
+ "s" => "server",
+ "db" => "dbconsole"
+}
+
+command = ARGV.shift
+command = aliases[command] || command
+
+case command
+when 'generate', 'destroy', 'plugin', 'benchmarker', 'profiler'
+ require APP_PATH
+ Rails::Application.require_environment!
+ require "rails/commands/#{command}"
+
+when 'console'
+ require 'rails/commands/console'
+ require APP_PATH
+ Rails::Application.require_environment!
+ Rails::Console.start(Rails::Application)
+
+when 'server'
+ require 'rails/commands/server'
+ Rails::Server.new.tap { |server|
+ require APP_PATH
+ Dir.chdir(Rails::Application.root)
+ server.start
+ }
+
+when 'dbconsole'
+ require 'rails/commands/dbconsole'
+ require APP_PATH
+ Rails::DBConsole.start(Rails::Application)
+
+when 'application', 'runner'
+ require "rails/commands/#{command}"
+
+when '--version', '-v'
+ ARGV.unshift '--version'
+ require 'rails/commands/application'
+
+else
+ puts "Error: Command not recognized" unless %w(-h --help).include?(command)
+ puts <<-EOT
Usage: rails COMMAND [ARGS]
The most common rails commands are:
@@ -21,53 +63,5 @@ In addition to those, there are:
runner Run a piece of code in the application environment
All commands can be run with -h for more information.
-EOT
-
-
-case ARGV.shift
-when 'g', 'generate'
- require ENV_PATH
- require 'rails/commands/generate'
-when 'c', 'console'
- require 'rails/commands/console'
- require ENV_PATH
- Rails::Console.start(Rails::Application)
-when 's', 'server'
- require 'rails/commands/server'
- # Initialize the server first, so environment options are set
- server = Rails::Server.new
- require APP_PATH
-
- Dir.chdir(Rails::Application.root)
- server.start
-when 'db', 'dbconsole'
- require 'rails/commands/dbconsole'
- require APP_PATH
- Rails::DBConsole.start(Rails::Application)
-
-when 'application'
- require 'rails/commands/application'
-when 'destroy'
- require ENV_PATH
- require 'rails/commands/destroy'
-when 'benchmarker'
- require ENV_PATH
- require 'rails/commands/performance/benchmarker'
-when 'profiler'
- require ENV_PATH
- require 'rails/commands/performance/profiler'
-when 'plugin'
- require APP_PATH
- require 'rails/commands/plugin'
-when 'runner'
- require 'rails/commands/runner'
-
-when '--help', '-h'
- puts HELP_TEXT
-when '--version', '-v'
- ARGV.unshift '--version'
- require 'rails/commands/application'
-else
- puts "Error: Command not recognized"
- puts HELP_TEXT
-end
+ EOT
+end \ No newline at end of file
diff --git a/railties/lib/rails/commands/application.rb b/railties/lib/rails/commands/application.rb
index 438c976b35..8a8143e00e 100644
--- a/railties/lib/rails/commands/application.rb
+++ b/railties/lib/rails/commands/application.rb
@@ -10,4 +10,4 @@ require 'rubygems' if ARGV.include?("--dev")
require 'rails/generators'
require 'rails/generators/rails/app/app_generator'
-Rails::Generators::AppGenerator.start \ No newline at end of file
+Rails::Generators::AppGenerator.start
diff --git a/railties/lib/rails/commands/performance/benchmarker.rb b/railties/lib/rails/commands/benchmarker.rb
index 0432261802..0432261802 100644
--- a/railties/lib/rails/commands/performance/benchmarker.rb
+++ b/railties/lib/rails/commands/benchmarker.rb
diff --git a/railties/lib/rails/commands/performance/profiler.rb b/railties/lib/rails/commands/profiler.rb
index 6d9717b5cd..6d9717b5cd 100644
--- a/railties/lib/rails/commands/performance/profiler.rb
+++ b/railties/lib/rails/commands/profiler.rb
diff --git a/railties/lib/rails/commands/runner.rb b/railties/lib/rails/commands/runner.rb
index 1dd11e1241..278548558e 100644
--- a/railties/lib/rails/commands/runner.rb
+++ b/railties/lib/rails/commands/runner.rb
@@ -36,7 +36,8 @@ ARGV.delete(code_or_file)
ENV["RAILS_ENV"] = options[:environment]
-require ENV_PATH
+require APP_PATH
+Rails::Application.require_environment!
begin
if code_or_file.nil?
diff --git a/railties/lib/rails/configuration.rb b/railties/lib/rails/configuration.rb
index dfd849b4bb..bd404f4a14 100644
--- a/railties/lib/rails/configuration.rb
+++ b/railties/lib/rails/configuration.rb
@@ -1,3 +1,4 @@
+require 'active_support/deprecation'
require 'active_support/ordered_options'
require 'rails/paths'
require 'rails/rack'
diff --git a/railties/lib/rails/engine.rb b/railties/lib/rails/engine.rb
index 36fcc896ae..ab0ead65a9 100644
--- a/railties/lib/rails/engine.rb
+++ b/railties/lib/rails/engine.rb
@@ -42,7 +42,7 @@ module Rails
# config.load_paths << File.expand_path("../lib/some/path", __FILE__)
#
# initializer "my_engine.add_middleware" do |app|
- # app.middlewares.use MyEngine::Middleware
+ # app.middleware.use MyEngine::Middleware
# end
# end
#
diff --git a/railties/lib/rails/generators/base.rb b/railties/lib/rails/generators/base.rb
index 0da85ea4a4..766644bbc2 100644
--- a/railties/lib/rails/generators/base.rb
+++ b/railties/lib/rails/generators/base.rb
@@ -20,24 +20,19 @@ module Rails
add_runtime_options!
- # Automatically sets the source root based on the class name.
- #
- def self.source_root
- @_rails_source_root ||= begin
- if base_name && generator_name
- File.expand_path(File.join(base_name, generator_name, 'templates'), File.dirname(__FILE__))
- end
- end
+ # Returns the source root for this generator using default_source_root as default.
+ def self.source_root(path=nil)
+ @_source_root = path if path
+ @_source_root ||= default_source_root
end
# Tries to get the description from a USAGE file one folder above the source
# root otherwise uses a default description.
- #
def self.desc(description=nil)
return super if description
- usage = File.expand_path(File.join(source_root, "..", "USAGE"))
+ usage = source_root && File.expand_path("../USAGE", source_root)
- @desc ||= if File.exist?(usage)
+ @desc ||= if usage && File.exist?(usage)
File.read(usage)
else
"Description:\n Create #{base_name.humanize.downcase} files for #{generator_name} generator."
@@ -47,7 +42,6 @@ module Rails
# Convenience method to get the namespace from the class name. It's the
# same as Thor default except that the Generator at the end of the class
# is removed.
- #
def self.namespace(name=nil)
return super if name
@namespace ||= super.sub(/_generator$/, '').sub(/:generators:/, ':')
@@ -200,7 +194,6 @@ module Rails
end
# Make class option aware of Rails::Generators.options and Rails::Generators.aliases.
- #
def self.class_option(name, options={}) #:nodoc:
options[:desc] = "Indicates when to generate #{name.to_s.humanize.downcase}" unless options.key?(:desc)
options[:aliases] = default_aliases_for_option(name, options)
@@ -208,14 +201,27 @@ module Rails
super(name, options)
end
+ # Returns the default source root for a given generator. This is used internally
+ # by rails to set its generators source root. If you want to customize your source
+ # root, you should use source_root.
+ def self.default_source_root
+ return unless base_name && generator_name
+ path = File.expand_path(File.join(base_name, generator_name, 'templates'), base_root)
+ path if File.exists?(path)
+ end
+
+ # Returns the base root for a common set of generators. This is used to dynamically
+ # guess the default source root.
+ def self.base_root
+ File.dirname(__FILE__)
+ end
+
# Cache source root and add lib/generators/base/generator/templates to
# source paths.
- #
def self.inherited(base) #:nodoc:
super
- # Cache source root, we need to do this, since __FILE__ is a relative value
- # and can point to wrong directions when inside an specified directory.
+ # Invoke source_root so the default_source_root is set.
base.source_root
if base.name && base.name !~ /Base$/
diff --git a/railties/lib/rails/generators/rails/app/app_generator.rb b/railties/lib/rails/generators/rails/app/app_generator.rb
index aa066fe3c4..10d8b8f85a 100644
--- a/railties/lib/rails/generators/rails/app/app_generator.rb
+++ b/railties/lib/rails/generators/rails/app/app_generator.rb
@@ -2,87 +2,61 @@ require 'digest/md5'
require 'active_support/secure_random'
require 'rails/version' unless defined?(Rails::VERSION)
require 'rbconfig'
+require 'open-uri'
+require 'uri'
-module Rails::Generators
- # We need to store the RAILS_DEV_PATH in a constant, otherwise the path
- # can change in Ruby 1.8.7 when we FileUtils.cd.
- RAILS_DEV_PATH = File.expand_path("../../../../../..", File.dirname(__FILE__))
+module Rails
+ module ActionMethods
+ attr_reader :options
- RESERVED_NAMES = %w[generate console server dbconsole
- application destroy benchmarker profiler
- plugin runner test]
-
- class AppGenerator < Base
- DATABASES = %w( mysql oracle postgresql sqlite3 frontbase ibm_db )
-
- attr_accessor :rails_template
- add_shebang_option!
-
- argument :app_path, :type => :string
-
- class_option :database, :type => :string, :aliases => "-d", :default => "sqlite3",
- :desc => "Preconfigure for selected database (options: #{DATABASES.join('/')})"
-
- class_option :template, :type => :string, :aliases => "-m",
- :desc => "Path to an application template (can be a filesystem path or URL)."
-
- class_option :dev, :type => :boolean, :default => false,
- :desc => "Setup the application with Gemfile pointing to your Rails checkout"
-
- class_option :edge, :type => :boolean, :default => false,
- :desc => "Setup the application with Gemfile pointing to Rails repository"
-
- class_option :skip_gemfile, :type => :boolean, :default => false,
- :desc => "Don't create a Gemfile"
-
- class_option :skip_activerecord, :type => :boolean, :aliases => "-O", :default => false,
- :desc => "Skip ActiveRecord files"
-
- class_option :skip_testunit, :type => :boolean, :aliases => "-T", :default => false,
- :desc => "Skip TestUnit files"
-
- class_option :skip_prototype, :type => :boolean, :aliases => "-J", :default => false,
- :desc => "Skip Prototype files"
-
- class_option :skip_git, :type => :boolean, :aliases => "-G", :default => false,
- :desc => "Skip Git ignores and keeps"
-
- # Add bin/rails options
- class_option :version, :type => :boolean, :aliases => "-v", :group => :rails,
- :desc => "Show Rails version number and quit"
+ def initialize(generator)
+ @generator = generator
+ @options = generator.options
+ end
- class_option :help, :type => :boolean, :aliases => "-h", :group => :rails,
- :desc => "Show this help message and quit"
+ private
+ %w(template copy_file directory empty_directory inside
+ empty_directory_with_gitkeep create_file chmod shebang).each do |method|
+ class_eval <<-RUBY
+ def #{method}(*args, &block)
+ @generator.send(:#{method}, *args, &block)
+ end
+ RUBY
+ end
- def initialize(*args)
- super
- if !options[:skip_activerecord] && !DATABASES.include?(options[:database])
- raise Error, "Invalid value for --database option. Supported for preconfiguration are: #{DATABASES.join(", ")}."
+ # TODO: Remove once this is fully in place
+ def method_missing(meth, *args, &block)
+ STDERR.puts "Calling #{meth} with #{args.inspect} with #{block}"
+ @generator.send(meth, *args, &block)
end
+ end
+
+ class AppBuilder
+ def rakefile
+ template "Rakefile"
end
- def create_root
- self.destination_root = File.expand_path(app_path, destination_root)
- valid_app_const?
+ def readme
+ copy_file "README"
+ end
- empty_directory '.'
- set_default_accessors!
- FileUtils.cd(destination_root)
+ def gemfile
+ template "Gemfile"
end
- def create_root_files
- copy_file "README"
- copy_file "gitignore", ".gitignore" unless options[:skip_git]
- template "Rakefile"
+ def configru
template "config.ru"
- template "Gemfile" unless options[:skip_gemfile]
end
- def create_app_files
+ def gitignore
+ copy_file "gitignore", ".gitignore"
+ end
+
+ def app
directory 'app'
end
- def create_config_files
+ def config
empty_directory "config"
inside "config" do
@@ -96,29 +70,24 @@ module Rails::Generators
end
end
- def create_boot_file
- template "config/boot.rb"
+ def database_yml
+ template "config/databases/#{@options[:database]}.yml", "config/database.yml"
end
- def create_activerecord_files
- return if options[:skip_activerecord]
- template "config/databases/#{options[:database]}.yml", "config/database.yml"
- end
-
- def create_db_files
+ def db
directory "db"
end
- def create_doc_files
+ def doc
directory "doc"
end
- def create_lib_files
+ def lib
empty_directory "lib"
empty_directory_with_gitkeep "lib/tasks"
end
- def create_log_files
+ def log
empty_directory "log"
inside "log" do
@@ -129,19 +98,19 @@ module Rails::Generators
end
end
- def create_public_files
- directory "public", "public", :recursive => false # Do small steps, so anyone can overwrite it.
+ def public_directory
+ directory "public", "public", :recursive => false
end
- def create_public_image_files
+ def images
directory "public/images"
end
- def create_public_stylesheets_files
+ def stylesheets
empty_directory_with_gitkeep "public/stylesheets"
end
- def create_prototype_files
+ def javascripts
unless options[:skip_prototype]
directory "public/javascripts"
else
@@ -149,19 +118,18 @@ module Rails::Generators
end
end
- def create_script_files
+ def script
directory "script" do |content|
"#{shebang}\n" + content
end
chmod "script", 0755, :verbose => false
end
- def create_test_files
- return if options[:skip_testunit]
+ def test
directory "test"
end
- def create_tmp_files
+ def tmp
empty_directory "tmp"
inside "tmp" do
@@ -171,20 +139,170 @@ module Rails::Generators
end
end
- def create_vendor_files
+ def vendor_plugins
empty_directory_with_gitkeep "vendor/plugins"
end
+ end
- def apply_rails_template
- apply rails_template if rails_template
- rescue Thor::Error, LoadError, Errno::ENOENT => e
- raise Error, "The template [#{rails_template}] could not be loaded. Error: #{e}"
- end
+ module Generators
+ # We need to store the RAILS_DEV_PATH in a constant, otherwise the path
+ # can change in Ruby 1.8.7 when we FileUtils.cd.
+ RAILS_DEV_PATH = File.expand_path("../../../../../..", File.dirname(__FILE__))
- def bundle_if_dev_or_edge
- bundle_command = File.basename(Thor::Util.ruby_command).sub(/ruby/, 'bundle')
- run "#{bundle_command} install" if dev_or_edge?
- end
+ RESERVED_NAMES = %w[generate console server dbconsole
+ application destroy benchmarker profiler
+ plugin runner test]
+
+ class AppGenerator < Base
+ DATABASES = %w( mysql oracle postgresql sqlite3 frontbase ibm_db )
+
+ attr_accessor :rails_template
+ add_shebang_option!
+
+ argument :app_path, :type => :string
+
+ class_option :database, :type => :string, :aliases => "-d", :default => "sqlite3",
+ :desc => "Preconfigure for selected database (options: #{DATABASES.join('/')})"
+
+ class_option :builder, :type => :string, :aliases => "-b",
+ :desc => "Path to an application builder (can be a filesystem path or URL)"
+
+ class_option :template, :type => :string, :aliases => "-m",
+ :desc => "Path to an application template (can be a filesystem path or URL)."
+
+ class_option :dev, :type => :boolean, :default => false,
+ :desc => "Setup the application with Gemfile pointing to your Rails checkout"
+
+ class_option :edge, :type => :boolean, :default => false,
+ :desc => "Setup the application with Gemfile pointing to Rails repository"
+
+ class_option :skip_gemfile, :type => :boolean, :default => false,
+ :desc => "Don't create a Gemfile"
+
+ class_option :skip_activerecord, :type => :boolean, :aliases => "-O", :default => false,
+ :desc => "Skip ActiveRecord files"
+
+ class_option :skip_testunit, :type => :boolean, :aliases => "-T", :default => false,
+ :desc => "Skip TestUnit files"
+
+ class_option :skip_prototype, :type => :boolean, :aliases => "-J", :default => false,
+ :desc => "Skip Prototype files"
+
+ class_option :skip_git, :type => :boolean, :aliases => "-G", :default => false,
+ :desc => "Skip Git ignores and keeps"
+
+ # Add bin/rails options
+ class_option :version, :type => :boolean, :aliases => "-v", :group => :rails,
+ :desc => "Show Rails version number and quit"
+
+ class_option :help, :type => :boolean, :aliases => "-h", :group => :rails,
+ :desc => "Show this help message and quit"
+
+ def initialize(*args)
+ raise Error, "Options should be given after the application name. For details run: rails --help" if args[0].blank?
+ super
+
+ if !options[:skip_activerecord] && !DATABASES.include?(options[:database])
+ raise Error, "Invalid value for --database option. Supported for preconfiguration are: #{DATABASES.join(", ")}."
+ end
+ end
+
+ def create_root
+ self.destination_root = File.expand_path(app_path, destination_root)
+ valid_app_const?
+
+ empty_directory '.'
+ set_default_accessors!
+ FileUtils.cd(destination_root)
+ end
+
+ def create_root_files
+ build(:readme)
+ build(:rakefile)
+ build(:configru)
+ build(:gitignore) unless options[:skip_git]
+ build(:gemfile) unless options[:skip_gemfile]
+ end
+
+ def create_app_files
+ build(:app)
+ end
+
+ def create_config_files
+ build(:config)
+ end
+
+ def create_boot_file
+ template "config/boot.rb"
+ end
+
+ def create_activerecord_files
+ return if options[:skip_activerecord]
+ build(:database_yml)
+ end
+
+ def create_db_files
+ build(:db)
+ end
+
+ def create_doc_files
+ build(:doc)
+ end
+
+ def create_lib_files
+ build(:lib)
+ end
+
+ def create_log_files
+ build(:log)
+ end
+
+ def create_public_files
+ build(:public_directory)
+ end
+
+ def create_public_image_files
+ build(:images)
+ end
+
+ def create_public_stylesheets_files
+ build(:stylesheets)
+ end
+
+ def create_prototype_files
+ build(:javascripts)
+ end
+
+ def create_script_files
+ build(:script)
+ end
+
+ def create_test_files
+ build(:test) unless options[:skip_testunit]
+ end
+
+ def create_tmp_files
+ build(:tmp)
+ end
+
+ def create_vendor_files
+ build(:vendor_plugins)
+ end
+
+ def finish_template
+ build(:leftovers)
+ end
+
+ def apply_rails_template
+ apply rails_template if rails_template
+ rescue Thor::Error, LoadError, Errno::ENOENT => e
+ raise Error, "The template [#{rails_template}] could not be loaded. Error: #{e}"
+ end
+
+ def bundle_if_dev_or_edge
+ bundle_command = File.basename(Thor::Util.ruby_command).sub(/ruby/, 'bundle')
+ run "#{bundle_command} install" if dev_or_edge?
+ end
protected
@@ -192,6 +310,29 @@ module Rails::Generators
"rails #{self.arguments.map(&:usage).join(' ')} [options]"
end
+ def builder
+ @builder ||= begin
+ if path = options[:builder]
+ if URI(path).is_a?(URI::HTTP)
+ contents = open(path, "Accept" => "application/x-thor-template") {|io| io.read }
+ else
+ contents = open(path) {|io| io.read }
+ end
+
+ prok = eval("proc { #{contents} }", TOPLEVEL_BINDING, path, 1)
+ instance_eval(&prok)
+ end
+
+ builder_class = defined?(::AppBuilder) ? ::AppBuilder : Rails::AppBuilder
+ builder_class.send(:include, ActionMethods)
+ builder_class.new(self)
+ end
+ end
+
+ def build(meth, *args)
+ builder.send(meth, *args) if builder.respond_to?(meth)
+ end
+
def set_default_accessors!
self.rails_template = case options[:template]
when /^http:\/\//
@@ -273,5 +414,6 @@ module Rails::Generators
empty_directory(destination, config)
create_file("#{destination}/.gitkeep") unless options[:skip_git]
end
+ end
end
end
diff --git a/railties/lib/rails/generators/rails/app/templates/script/rails b/railties/lib/rails/generators/rails/app/templates/script/rails
index b01d1ee183..11bc1edde9 100644
--- a/railties/lib/rails/generators/rails/app/templates/script/rails
+++ b/railties/lib/rails/generators/rails/app/templates/script/rails
@@ -1,8 +1,5 @@
# This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application.
-ENV_PATH = File.expand_path('../../config/environment', __FILE__)
-BOOT_PATH = File.expand_path('../../config/boot', __FILE__)
-APP_PATH = File.expand_path('../../config/application', __FILE__)
-
-require BOOT_PATH
+APP_PATH = File.expand_path('../../config/application', __FILE__)
+require File.expand_path('../../config/boot', __FILE__)
require 'rails/commands'
diff --git a/railties/lib/rails/generators/rails/generator/templates/%file_name%_generator.rb.tt b/railties/lib/rails/generators/rails/generator/templates/%file_name%_generator.rb.tt
index d8757460e4..d0575772bc 100644
--- a/railties/lib/rails/generators/rails/generator/templates/%file_name%_generator.rb.tt
+++ b/railties/lib/rails/generators/rails/generator/templates/%file_name%_generator.rb.tt
@@ -1,5 +1,3 @@
class <%= class_name %>Generator < Rails::Generators::NamedBase
- def self.source_root
- @source_root ||= File.expand_path('../templates', __FILE__)
- end
+ source_root File.expand_path('../templates', __FILE__)
end
diff --git a/railties/lib/rails/generators/rails/mailer/USAGE b/railties/lib/rails/generators/rails/mailer/USAGE
deleted file mode 100644
index a08d459739..0000000000
--- a/railties/lib/rails/generators/rails/mailer/USAGE
+++ /dev/null
@@ -1,15 +0,0 @@
-Description:
- Stubs out a new mailer and its views. Pass the mailer name, either
- CamelCased or under_scored, and an optional list of emails as arguments.
-
- This generates a mailer class in app/mailers and invokes your template
- engine and test framework generators.
-
-Example:
- `rails generate mailer Notifications signup forgot_password invoice`
-
- creates a Notifications mailer class, views, test, and fixtures:
- Mailer: app/mailers/notifications.rb
- Views: app/views/notifications/signup.erb [...]
- Test: test/functional/notifications_test.rb
- Fixtures: test/fixtures/notifications/signup [...]
diff --git a/railties/lib/rails/generators/rails/mailer/mailer_generator.rb b/railties/lib/rails/generators/rails/mailer/mailer_generator.rb
deleted file mode 100644
index 8993181d79..0000000000
--- a/railties/lib/rails/generators/rails/mailer/mailer_generator.rb
+++ /dev/null
@@ -1,14 +0,0 @@
-module Rails
- module Generators
- class MailerGenerator < NamedBase
- argument :actions, :type => :array, :default => [], :banner => "method method"
- check_class_collision
-
- def create_mailer_file
- template "mailer.rb", File.join('app/mailers', class_path, "#{file_name}.rb")
- end
-
- hook_for :template_engine, :test_framework
- end
- end
-end
diff --git a/railties/lib/rails/generators/rails/mailer/templates/mailer.rb b/railties/lib/rails/generators/rails/mailer/templates/mailer.rb
deleted file mode 100644
index 7343eb28b3..0000000000
--- a/railties/lib/rails/generators/rails/mailer/templates/mailer.rb
+++ /dev/null
@@ -1,16 +0,0 @@
-class <%= class_name %> < ActionMailer::Base
- default :from => "from@example.com"
-<% for action in actions -%>
-
- # Subject can be set in your I18n file at config/locales/en.yml
- # with the following lookup:
- #
- # en.actionmailer.<%= file_name %>.<%= action %>.subject
- #
- def <%= action %>
- @greeting = "Hi"
-
- mail :to => "to@example.org"
- end
-<% end -%>
-end
diff --git a/railties/lib/rails/railtie.rb b/railties/lib/rails/railtie.rb
index 6ac6be092e..b6b57bc5b5 100644
--- a/railties/lib/rails/railtie.rb
+++ b/railties/lib/rails/railtie.rb
@@ -1,6 +1,7 @@
require 'rails/initializable'
require 'rails/configuration'
require 'active_support/inflector'
+require 'active_support/deprecation'
module Rails
# Railtie is the core of the Rails Framework and provides several hooks to extend
diff --git a/railties/railties.gemspec b/railties/railties.gemspec
index b9278c0399..99537d6d24 100644
--- a/railties/railties.gemspec
+++ b/railties/railties.gemspec
@@ -20,7 +20,7 @@ Gem::Specification.new do |s|
s.has_rdoc = false
s.add_dependency('rake', '>= 0.8.3')
- s.add_dependency('thor', '~> 0.13.4')
+ s.add_dependency('thor', '~> 0.13.6')
s.add_dependency('activesupport', version)
s.add_dependency('actionpack', version)
end
diff --git a/railties/test/application/middleware_test.rb b/railties/test/application/middleware_test.rb
index 27374dcb28..d08f04bddb 100644
--- a/railties/test/application/middleware_test.rb
+++ b/railties/test/application/middleware_test.rb
@@ -20,20 +20,21 @@ module ApplicationTests
assert_equal [
"ActionDispatch::Static",
"Rack::Lock",
+ "ActiveSupport::Cache::Strategy::LocalCache",
"Rack::Runtime",
"Rails::Rack::Logger",
"ActionDispatch::ShowExceptions",
"ActionDispatch::RemoteIp",
"Rack::Sendfile",
"ActionDispatch::Callbacks",
+ "ActiveRecord::ConnectionAdapters::ConnectionManagement",
+ "ActiveRecord::QueryCache",
"ActionDispatch::Cookies",
"ActionDispatch::Session::CookieStore",
"ActionDispatch::Flash",
"ActionDispatch::ParamsParser",
"Rack::MethodOverride",
- "ActionDispatch::Head",
- "ActiveRecord::ConnectionAdapters::ConnectionManagement",
- "ActiveRecord::QueryCache"
+ "ActionDispatch::Head"
], middleware
end
diff --git a/railties/test/application/model_initialization_test.rb b/railties/test/application/model_initialization_test.rb
new file mode 100644
index 0000000000..6a22f8d8df
--- /dev/null
+++ b/railties/test/application/model_initialization_test.rb
@@ -0,0 +1,33 @@
+require 'isolation/abstract_unit'
+
+class PostTest < Test::Unit::TestCase
+ include ActiveSupport::Testing::Isolation
+
+ def setup
+ build_app
+ boot_rails
+ end
+
+ def test_reload_should_reload_constants
+ app_file "app/models/post.rb", <<-MODEL
+ class Post < ActiveRecord::Base
+ validates_acceptance_of :title, :accept => "omg"
+ end
+ MODEL
+
+ require "#{rails_root}/config/environment"
+ ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :database => ":memory:")
+ ActiveRecord::Migration.verbose = false
+ ActiveRecord::Schema.define(:version => 1) do
+ create_table :posts do |t|
+ t.string :title
+ end
+ end
+
+ p = Post.create(:title => 'omg')
+ assert_equal 1, Post.count
+ assert_equal 'omg', p.title
+ p = Post.first
+ assert_equal 'omg', p.title
+ end
+end
diff --git a/railties/test/application/paths_test.rb b/railties/test/application/paths_test.rb
index 5ab558c026..978d677efc 100644
--- a/railties/test/application/paths_test.rb
+++ b/railties/test/application/paths_test.rb
@@ -48,7 +48,8 @@ module ApplicationTests
assert_path @paths.tmp.cache, "tmp", "cache"
assert_path @paths.config, "config"
assert_path @paths.config.locales, "config", "locales", "en.yml"
- assert_path @paths.config.environment, "config", "environments", "development.rb"
+ assert_path @paths.config.environment, "config", "environment.rb"
+ assert_path @paths.config.environments, "config", "environments", "development.rb"
assert_equal root("app", "controllers"), @paths.app.controllers.to_a.first
end
@@ -61,7 +62,7 @@ module ApplicationTests
end
test "environments has a glob equal to the current environment" do
- assert_equal "#{Rails.env}.rb", @paths.config.environment.glob
+ assert_equal "#{Rails.env}.rb", @paths.config.environments.glob
end
test "load path includes each of the paths in config.paths as long as the directories exist" do
diff --git a/railties/test/application/rake_test.rb b/railties/test/application/rake_test.rb
index bf2da866f4..6b7a471494 100644
--- a/railties/test/application/rake_test.rb
+++ b/railties/test/application/rake_test.rb
@@ -19,5 +19,19 @@ module ApplicationTests
::Rails.application.load_tasks
assert $task_loaded
end
+
+ def test_environment_is_required_in_rake_tasks
+ app_file "config/environment.rb", <<-RUBY
+ SuperMiddleware = Struct.new(:app)
+
+ Rails::Application.configure do
+ config.middleware.use SuperMiddleware
+ end
+
+ Rails::Application.initialize!
+ RUBY
+
+ assert_match "SuperMiddleware", Dir.chdir(app_path){ `rake middleware` }
+ end
end
end \ No newline at end of file
diff --git a/railties/test/fixtures/lib/empty_builder.rb b/railties/test/fixtures/lib/empty_builder.rb
new file mode 100644
index 0000000000..babd9c2461
--- /dev/null
+++ b/railties/test/fixtures/lib/empty_builder.rb
@@ -0,0 +1,2 @@
+class AppBuilder
+end \ No newline at end of file
diff --git a/railties/test/fixtures/lib/simple_builder.rb b/railties/test/fixtures/lib/simple_builder.rb
new file mode 100644
index 0000000000..47dcdc0d96
--- /dev/null
+++ b/railties/test/fixtures/lib/simple_builder.rb
@@ -0,0 +1,7 @@
+class AppBuilder
+ def configru
+ create_file "config.ru", <<-R.strip
+run proc { |env| [200, { "Content-Type" => "text/html" }, ["Hello World"]] }
+ R
+ end
+end \ No newline at end of file
diff --git a/railties/test/fixtures/lib/tweak_builder.rb b/railties/test/fixtures/lib/tweak_builder.rb
new file mode 100644
index 0000000000..eed20ecc9b
--- /dev/null
+++ b/railties/test/fixtures/lib/tweak_builder.rb
@@ -0,0 +1,7 @@
+class AppBuilder < Rails::AppBuilder
+ def configru
+ create_file "config.ru", <<-R.strip
+run proc { |env| [200, { "Content-Type" => "text/html" }, ["Hello World"]] }
+ R
+ end
+end \ No newline at end of file
diff --git a/railties/test/generators/actions_test.rb b/railties/test/generators/actions_test.rb
index 44e0640552..e6fab93a87 100644
--- a/railties/test/generators/actions_test.rb
+++ b/railties/test/generators/actions_test.rb
@@ -209,7 +209,7 @@ class ActionsTest < Rails::Generators::TestCase
def test_readme
run_generator
- Rails::Generators::AppGenerator.expects(:source_root).returns(destination_root)
+ Rails::Generators::AppGenerator.expects(:source_root).times(2).returns(destination_root)
assert_match(/Welcome to Rails/, action(:readme, "README"))
end
diff --git a/railties/test/generators/app_generator_test.rb b/railties/test/generators/app_generator_test.rb
index 24e6d541c2..1a93867013 100644
--- a/railties/test/generators/app_generator_test.rb
+++ b/railties/test/generators/app_generator_test.rb
@@ -2,6 +2,40 @@ require 'abstract_unit'
require 'generators/generators_test_helper'
require 'rails/generators/rails/app/app_generator'
+DEFAULT_APP_FILES = %w(
+ .gitignore
+ Gemfile
+ Rakefile
+ config.ru
+ app/controllers
+ app/helpers
+ app/models
+ app/views/layouts
+ config/environments
+ config/initializers
+ config/locales
+ db
+ doc
+ lib
+ lib/tasks
+ log
+ public/images
+ public/javascripts
+ public/stylesheets
+ script/rails
+ test/fixtures
+ test/functional
+ test/integration
+ test/performance
+ test/unit
+ vendor
+ vendor/plugins
+ tmp/sessions
+ tmp/sockets
+ tmp/cache
+ tmp/pids
+)
+
class AppGeneratorTest < Rails::Generators::TestCase
include GeneratorsTestHelper
arguments [destination_root]
@@ -20,35 +54,7 @@ class AppGeneratorTest < Rails::Generators::TestCase
def test_application_skeleton_is_created
run_generator
- %w(
- app/controllers
- app/helpers
- app/models
- app/views/layouts
- config/environments
- config/initializers
- config/locales
- db
- doc
- lib
- lib/tasks
- log
- public/images
- public/javascripts
- public/stylesheets
- script/rails
- test/fixtures
- test/functional
- test/integration
- test/performance
- test/unit
- vendor
- vendor/plugins
- tmp/sessions
- tmp/sockets
- tmp/cache
- tmp/pids
- ).each{ |path| assert_file path }
+ DEFAULT_APP_FILES.each{ |path| assert_file path }
end
def test_application_controller_and_layout_files
@@ -58,6 +64,11 @@ class AppGeneratorTest < Rails::Generators::TestCase
assert_no_file "public/stylesheets/application.css"
end
+ def test_options_before_application_name_raises_an_error
+ content = capture(:stderr){ run_generator(["--skip-activerecord", destination_root]) }
+ assert_equal "Options should be given after the application name. For details run: rails --help\n", content
+ end
+
def test_name_collision_raises_an_error
content = capture(:stderr){ run_generator [File.join(destination_root, "generate")] }
assert_equal "Invalid application name generate. Please give a name which does not match one of the reserved rails words.\n", content
@@ -152,7 +163,7 @@ class AppGeneratorTest < Rails::Generators::TestCase
template = %{ say "It works!" }
template.instance_eval "def read; self; end" # Make the string respond to read
- generator([destination_root], :template => path).expects(:open).with(path).returns(template)
+ generator([destination_root], :template => path).expects(:open).with(path, 'Accept' => 'application/x-thor-template').returns(template)
assert_match /It works!/, silence(:stdout){ generator.invoke }
end
@@ -188,10 +199,66 @@ class AppGeneratorTest < Rails::Generators::TestCase
assert_file 'Gemfile', /^gem\s+["']rails["'],\s+:git\s+=>\s+["']#{Regexp.escape("git://github.com/rails/rails.git")}["']$/
end
- protected
+protected
- def action(*args, &block)
- silence(:stdout){ generator.send(*args, &block) }
- end
+ def action(*args, &block)
+ silence(:stdout){ generator.send(*args, &block) }
+ end
end
+
+class CustomAppGeneratorTest < Rails::Generators::TestCase
+ include GeneratorsTestHelper
+ tests Rails::Generators::AppGenerator
+
+ arguments [destination_root]
+
+ def setup
+ super
+ Rails::Generators::AppGenerator.instance_variable_set('@desc', nil)
+ @bundle_command = File.basename(Thor::Util.ruby_command).sub(/ruby/, 'bundle')
+ end
+
+ def teardown
+ super
+ Rails::Generators::AppGenerator.instance_variable_set('@desc', nil)
+ Object.class_eval { remove_const :AppBuilder if const_defined?(:AppBuilder) }
+ end
+
+ def test_builder_option_with_empty_app_builder
+ FileUtils.cd(Rails.root)
+ run_generator([destination_root, "-b", "#{Rails.root}/lib/empty_builder.rb"])
+ DEFAULT_APP_FILES.each{ |path| assert_no_file path }
+ end
+
+ def test_builder_option_with_simple_app_builder
+ FileUtils.cd(Rails.root)
+ run_generator([destination_root, "-b", "#{Rails.root}/lib/simple_builder.rb"])
+ (DEFAULT_APP_FILES - ['config.ru']).each{ |path| assert_no_file path }
+ assert_file "config.ru", %[run proc { |env| [200, { "Content-Type" => "text/html" }, ["Hello World"]] }]
+ end
+
+ def test_builder_option_with_tweak_app_builder
+ FileUtils.cd(Rails.root)
+ run_generator([destination_root, "-b", "#{Rails.root}/lib/tweak_builder.rb"])
+ DEFAULT_APP_FILES.each{ |path| assert_file path }
+ assert_file "config.ru", %[run proc { |env| [200, { "Content-Type" => "text/html" }, ["Hello World"]] }]
+ end
+
+ def test_builder_option_with_http
+ path = "http://gist.github.com/103208.txt"
+ template = "class AppBuilder; end"
+ template.instance_eval "def read; self; end" # Make the string respond to read
+
+ generator([destination_root], :builder => path).expects(:open).with(path, 'Accept' => 'application/x-thor-template').returns(template)
+ capture(:stdout) { generator.invoke }
+
+ DEFAULT_APP_FILES.each{ |path| assert_no_file path }
+ end
+
+protected
+
+ def action(*args, &block)
+ silence(:stdout){ generator.send(*args, &block) }
+ end
+end \ No newline at end of file
diff --git a/railties/test/generators/mailer_generator_test.rb b/railties/test/generators/mailer_generator_test.rb
index 81d6afa221..850b45ff74 100644
--- a/railties/test/generators/mailer_generator_test.rb
+++ b/railties/test/generators/mailer_generator_test.rb
@@ -1,5 +1,6 @@
require 'generators/generators_test_helper'
-require 'rails/generators/rails/mailer/mailer_generator'
+require 'rails/generators/mailer/mailer_generator'
+
class MailerGeneratorTest < Rails::Generators::TestCase
include GeneratorsTestHelper