diff options
Diffstat (limited to 'railties/lib/rails')
54 files changed, 394 insertions, 331 deletions
diff --git a/railties/lib/rails/app_loader.rb b/railties/lib/rails/app_loader.rb index a9fe21824e..af004d85bf 100644 --- a/railties/lib/rails/app_loader.rb +++ b/railties/lib/rails/app_loader.rb @@ -16,7 +16,7 @@ like any other source code, rather than stubs that are generated on demand. Here's how to upgrade: bundle config --delete bin # Turn off Bundler's stub generator - rake rails:update:bin # Use the new Rails 4 executables + rails app:update:bin # Use the new Rails 5 executables git add bin # Add bin/ to source control You may need to remove bin/ from your .gitignore as well. diff --git a/railties/lib/rails/application.rb b/railties/lib/rails/application.rb index cac31e1eed..ed106c9918 100644 --- a/railties/lib/rails/application.rb +++ b/railties/lib/rails/application.rb @@ -1,4 +1,3 @@ -require 'fileutils' require 'yaml' require 'active_support/core_ext/hash/keys' require 'active_support/core_ext/object/blank' @@ -74,8 +73,7 @@ module Rails # the configuration. # # If you decide to define rake tasks, runners, or initializers in an - # application other than +Rails.application+, then you must run those - # these manually. + # application other than +Rails.application+, then you must run them manually. class Application < Engine autoload :Bootstrap, 'rails/application/bootstrap' autoload :Configuration, 'rails/application/configuration' @@ -113,7 +111,7 @@ module Rails attr_accessor :assets, :sandbox alias_method :sandbox?, :sandbox - attr_reader :reloaders + attr_reader :reloaders, :reloader, :executor delegate :default_url_options, :default_url_options=, to: :routes @@ -131,6 +129,10 @@ module Rails @message_verifiers = {} @ran_load_hooks = false + @executor = Class.new(ActiveSupport::Executor) + @reloader = Class.new(ActiveSupport::Reloader) + @reloader.executor = @executor + # are these actually used? @initial_variable_values = initial_variable_values @block = block @@ -214,7 +216,7 @@ module Rails # url: http://localhost:3001 # namespace: my_app_development # - # # config/production.rb + # # config/environments/production.rb # Rails.application.configure do # config.middleware.use ExceptionNotifier, config_for(:exception_notification) # end @@ -243,7 +245,7 @@ module Rails @app_env_config ||= begin validate_secret_key_config! - super.merge({ + super.merge( "action_dispatch.parameter_filter" => config.filter_parameters, "action_dispatch.redirect_filter" => config.filter_redirect, "action_dispatch.secret_token" => secrets.secret_token, @@ -259,7 +261,7 @@ module Rails "action_dispatch.encrypted_signed_cookie_salt" => config.action_dispatch.encrypted_signed_cookie_salt, "action_dispatch.cookies_serializer" => config.action_dispatch.cookies_serializer, "action_dispatch.cookies_digest" => config.action_dispatch.cookies_digest - }) + ) end end diff --git a/railties/lib/rails/application/bootstrap.rb b/railties/lib/rails/application/bootstrap.rb index 9baf8aa742..f615f22b26 100644 --- a/railties/lib/rails/application/bootstrap.rb +++ b/railties/lib/rails/application/bootstrap.rb @@ -1,6 +1,7 @@ -require "active_support/notifications" -require "active_support/dependencies" -require "active_support/descendants_tracker" +require 'fileutils' +require 'active_support/notifications' +require 'active_support/dependencies' +require 'active_support/descendants_tracker' module Rails class Application diff --git a/railties/lib/rails/application/configuration.rb b/railties/lib/rails/application/configuration.rb index 65cff1561a..f415a20833 100644 --- a/railties/lib/rails/application/configuration.rb +++ b/railties/lib/rails/application/configuration.rb @@ -58,7 +58,7 @@ module Rails def static_cache_control=(value) ActiveSupport::Deprecation.warn <<-eow.strip_heredoc - `static_cache_control` is deprecated and will be removed in Rails 5.1. + `config.static_cache_control` is deprecated and will be removed in Rails 5.1. Please use `config.public_file_server.headers = { 'Cache-Control' => '#{value}' }` instead. @@ -69,8 +69,8 @@ module Rails def serve_static_files ActiveSupport::Deprecation.warn <<-eow.strip_heredoc - `serve_static_files` is deprecated and will be removed in Rails 5.1. - Please use `public_file_server.enabled` instead. + `config.serve_static_files` is deprecated and will be removed in Rails 5.1. + Please use `config.public_file_server.enabled` instead. eow @public_file_server.enabled @@ -78,8 +78,8 @@ module Rails def serve_static_files=(value) ActiveSupport::Deprecation.warn <<-eow.strip_heredoc - `serve_static_files` is deprecated and will be removed in Rails 5.1. - Please use `public_file_server.enabled = #{value}` instead. + `config.serve_static_files` is deprecated and will be removed in Rails 5.1. + Please use `config.public_file_server.enabled = #{value}` instead. eow @public_file_server.enabled = value diff --git a/railties/lib/rails/application/default_middleware_stack.rb b/railties/lib/rails/application/default_middleware_stack.rb index 4f1cc0703d..381e548730 100644 --- a/railties/lib/rails/application/default_middleware_stack.rb +++ b/railties/lib/rails/application/default_middleware_stack.rb @@ -34,22 +34,10 @@ module Rails # handling: presumably their code is not threadsafe middleware.use ::Rack::Lock - - elsif config.allow_concurrency == :unsafe - # Do nothing, even if we know this is dangerous. This is the - # historical behaviour for true. - - else - # Default concurrency setting: enabled, but safe - - unless config.cache_classes && config.eager_load - # Without cache_classes + eager_load, the load interlock - # is required for proper operation - - middleware.use ::ActionDispatch::LoadInterlock - end end + middleware.use ::ActionDispatch::Executor, app.executor + middleware.use ::Rack::Runtime middleware.use ::Rack::MethodOverride unless config.api_only middleware.use ::ActionDispatch::RequestId @@ -61,7 +49,7 @@ module Rails middleware.use ::ActionDispatch::RemoteIp, config.action_dispatch.ip_spoofing_check, config.action_dispatch.trusted_proxies unless config.cache_classes - middleware.use ::ActionDispatch::Reloader, lambda { reload_dependencies? } + middleware.use ::ActionDispatch::Reloader, app.reloader end middleware.use ::ActionDispatch::Callbacks @@ -83,10 +71,6 @@ module Rails private - def reload_dependencies? - config.reload_classes_only_on_change != true || app.reloaders.map(&:updated?).any? - end - def load_rack_cache rack_cache = config.action_dispatch.rack_cache return unless rack_cache diff --git a/railties/lib/rails/application/finisher.rb b/railties/lib/rails/application/finisher.rb index 411cdbad19..0aed6c1351 100644 --- a/railties/lib/rails/application/finisher.rb +++ b/railties/lib/rails/application/finisher.rb @@ -22,10 +22,10 @@ module Rails initializer :add_builtin_route do |app| if Rails.env.development? app.routes.append do - get '/rails/info/properties' => "rails/info#properties" - get '/rails/info/routes' => "rails/info#routes" - get '/rails/info' => "rails/info#index" - get '/' => "rails/welcome#index" + get '/rails/info/properties' => "rails/info#properties", internal: true + get '/rails/info/routes' => "rails/info#routes", internal: true + get '/rails/info' => "rails/info#index", internal: true + get '/' => "rails/welcome#index", internal: true end end end @@ -38,16 +38,16 @@ module Rails app.routes.define_mounted_helper(:main_app) end - initializer :add_to_prepare_blocks do + initializer :add_to_prepare_blocks do |app| config.to_prepare_blocks.each do |block| - ActionDispatch::Reloader.to_prepare(&block) + app.reloader.to_prepare(&block) end end # This needs to happen before eager load so it happens # in exactly the same point regardless of config.cache_classes - initializer :run_prepare_callbacks do - ActionDispatch::Reloader.prepare! + initializer :run_prepare_callbacks do |app| + app.reloader.prepare! end initializer :eager_load! do @@ -62,13 +62,60 @@ module Rails ActiveSupport.run_load_hooks(:after_initialize, self) end + class MutexHook + def initialize(mutex = Mutex.new) + @mutex = mutex + end + + def run + @mutex.lock + end + + def complete(_state) + @mutex.unlock + end + end + + module InterlockHook + def self.run + ActiveSupport::Dependencies.interlock.start_running + end + + def self.complete(_state) + ActiveSupport::Dependencies.interlock.done_running + end + end + + initializer :configure_executor_for_concurrency do |app| + if config.allow_concurrency == false + # User has explicitly opted out of concurrent request + # handling: presumably their code is not threadsafe + + app.executor.register_hook(MutexHook.new, outer: true) + + elsif config.allow_concurrency == :unsafe + # Do nothing, even if we know this is dangerous. This is the + # historical behaviour for true. + + else + # Default concurrency setting: enabled, but safe + + unless config.cache_classes && config.eager_load + # Without cache_classes + eager_load, the load interlock + # is required for proper operation + + app.executor.register_hook(InterlockHook, outer: true) + end + end + end + # Set routes reload after the finisher hook to ensure routes added in # the hook are taken into account. - initializer :set_routes_reloader_hook do + initializer :set_routes_reloader_hook do |app| reloader = routes_reloader reloader.execute_if_updated self.reloaders << reloader - ActionDispatch::Reloader.to_prepare do + app.reloader.to_run do # We configure #execute rather than #execute_if_updated because if # autoloaded constants are cleared we need to reload routes also in # case any was used there, as in @@ -78,18 +125,27 @@ module Rails # This means routes are also reloaded if i18n is updated, which # might not be necessary, but in order to be more precise we need # some sort of reloaders dependency support, to be added. + require_unload_lock! reloader.execute end end # Set clearing dependencies after the finisher hook to ensure paths # added in the hook are taken into account. - initializer :set_clear_dependencies_hook, group: :all do + initializer :set_clear_dependencies_hook, group: :all do |app| callback = lambda do - ActiveSupport::Dependencies.interlock.unloading do - ActiveSupport::DescendantsTracker.clear - ActiveSupport::Dependencies.clear + ActiveSupport::DescendantsTracker.clear + ActiveSupport::Dependencies.clear + end + + if config.cache_classes + app.reloader.check = lambda { false } + elsif config.reload_classes_only_on_change + app.reloader.check = lambda do + app.reloaders.map(&:updated?).any? end + else + app.reloader.check = lambda { true } end if config.reload_classes_only_on_change @@ -99,15 +155,19 @@ module Rails # Prepend this callback to have autoloaded constants cleared before # any other possible reloading, in case they need to autoload fresh # constants. - ActionDispatch::Reloader.to_prepare(prepend: true) do + app.reloader.to_run(prepend: true) do # In addition to changes detected by the file watcher, if routes # or i18n have been updated we also need to clear constants, # that's why we run #execute rather than #execute_if_updated, this # callback has to clear autoloaded constants after any update. - reloader.execute + class_unload! do + reloader.execute + end end else - ActionDispatch::Reloader.to_cleanup(&callback) + app.reloader.to_complete do + class_unload!(&callback) + end end end diff --git a/railties/lib/rails/code_statistics.rb b/railties/lib/rails/code_statistics.rb index fc8717c752..7a8f42fe94 100644 --- a/railties/lib/rails/code_statistics.rb +++ b/railties/lib/rails/code_statistics.rb @@ -1,4 +1,5 @@ require 'rails/code_statistics_calculator' +require 'active_support/core_ext/enumerable' class CodeStatistics #:nodoc: diff --git a/railties/lib/rails/command.rb b/railties/lib/rails/command.rb deleted file mode 100644 index f7753cbb83..0000000000 --- a/railties/lib/rails/command.rb +++ /dev/null @@ -1,70 +0,0 @@ -require 'rails/commands/commands_tasks' - -module Rails - class Command #:nodoc: - attr_reader :argv - - def initialize(argv = []) - @argv = argv - - @option_parser = build_option_parser - @options = {} - end - - def self.run(task_name, argv) - command_name = command_name_for(task_name) - - if command = command_for(command_name) - command.new(argv).run(command_name) - else - Rails::CommandsTasks.new(argv).run_command!(task_name) - end - end - - def run(command_name) - parse_options_for(command_name) - @option_parser.parse! @argv - - public_send(command_name) - end - - def self.options_for(command_name, &options_to_parse) - @@command_options[command_name] = options_to_parse - end - - def self.set_banner(command_name, banner) - options_for(command_name) { |opts, _| opts.banner = banner } - end - - private - @@commands = [] - @@command_options = {} - - def parse_options_for(command_name) - @@command_options.fetch(command_name, proc {}).call(@option_parser, @options) - end - - def build_option_parser - OptionParser.new do |opts| - opts.on('-h', '--help', 'Show this help.') do - puts opts - exit - end - end - end - - def self.inherited(command) - @@commands << command - end - - def self.command_name_for(task_name) - task_name.gsub(':', '_').to_sym - end - - def self.command_for(command_name) - @@commands.find do |command| - command.public_instance_methods.include?(command_name) - end - end - end -end diff --git a/railties/lib/rails/commands.rb b/railties/lib/rails/commands.rb index fa47c52b96..5a66b78a92 100644 --- a/railties/lib/rails/commands.rb +++ b/railties/lib/rails/commands.rb @@ -13,6 +13,6 @@ aliases = { command = ARGV.shift command = aliases[command] || command -require 'rails/command' +require 'rails/commands/commands_tasks' -Rails::Command.run(command, ARGV) +Rails::CommandsTasks.new(ARGV).run_command!(command) diff --git a/railties/lib/rails/commands/runner.rb b/railties/lib/rails/commands/runner.rb index 5844e9037c..f9c183ac86 100644 --- a/railties/lib/rails/commands/runner.rb +++ b/railties/lib/rails/commands/runner.rb @@ -2,6 +2,7 @@ require 'optparse' options = { environment: (ENV['RAILS_ENV'] || ENV['RACK_ENV'] || "development").dup } code_or_file = nil +command = 'bin/rails runner' if ARGV.first.nil? ARGV.push "-h" @@ -34,7 +35,7 @@ ARGV.clone.options do |opts| opts.separator "" opts.separator "You can also use runner as a shebang line for your executables:" opts.separator " -------------------------------------------------------------" - opts.separator " #!/usr/bin/env #{File.expand_path($0)} runner" + opts.separator " #!/usr/bin/env #{File.expand_path(command)}" opts.separator "" opts.separator " Product.all.each { |p| p.price *= 2 ; p.save! }" opts.separator " -------------------------------------------------------------" @@ -52,7 +53,7 @@ Rails.application.require_environment! Rails.application.load_runner if code_or_file.nil? - $stderr.puts "Run '#{$0} -h' for help." + $stderr.puts "Run '#{command} -h' for help." exit 1 elsif File.exist?(code_or_file) $0 = code_or_file @@ -62,7 +63,7 @@ else eval(code_or_file, binding, __FILE__, __LINE__) rescue SyntaxError, NameError $stderr.puts "Please specify a valid ruby command or the path of a script to run." - $stderr.puts "Run '#{$0} -h' for help." + $stderr.puts "Run '#{command} -h' for help." exit 1 end end diff --git a/railties/lib/rails/commands/server.rb b/railties/lib/rails/commands/server.rb index 27cbaf360a..7418dff18b 100644 --- a/railties/lib/rails/commands/server.rb +++ b/railties/lib/rails/commands/server.rb @@ -2,6 +2,7 @@ require 'fileutils' require 'optparse' require 'action_dispatch' require 'rails' +require 'rails/dev_caching' module Rails class Server < ::Rack::Server @@ -92,20 +93,17 @@ module Rails DoNotReverseLookup: true, environment: (ENV['RAILS_ENV'] || ENV['RACK_ENV'] || "development").dup, daemonize: false, - caching: false, - pid: Options::DEFAULT_PID_PATH + caching: nil, + pid: Options::DEFAULT_PID_PATH, + restart_cmd: restart_command }) end private def setup_dev_caching - return unless options[:environment] == "development" - - if options[:caching] == false - delete_cache_file - elsif options[:caching] - create_cache_file + if options[:environment] == "development" + Rails::DevCaching.enable_by_argument(options[:caching]) end end @@ -114,16 +112,6 @@ module Rails puts "=> Booting #{ActiveSupport::Inflector.demodulize(server)}" puts "=> Rails #{Rails.version} application starting in #{Rails.env} on #{url}" puts "=> Run `rails server -h` for more startup options" - - puts "=> Ctrl-C to shutdown server" unless options[:daemonize] - end - - def create_cache_file - FileUtils.touch("tmp/caching-dev.txt") - end - - def delete_cache_file - FileUtils.rm("tmp/caching-dev.txt") if File.exist?("tmp/caching-dev.txt") end def create_tmp_directories @@ -143,5 +131,9 @@ module Rails Rails.logger.extend(ActiveSupport::Logger.broadcast(console)) end end + + def restart_command + "bin/rails server #{ARGV.join(' ')}" + end end end diff --git a/railties/lib/rails/console/app.rb b/railties/lib/rails/console/app.rb index ac5836a588..9ad77e0a80 100644 --- a/railties/lib/rails/console/app.rb +++ b/railties/lib/rails/console/app.rb @@ -29,8 +29,7 @@ module Rails # reloads the environment def reload!(print=true) puts "Reloading..." if print - ActionDispatch::Reloader.cleanup! - ActionDispatch::Reloader.prepare! + Rails.application.reloader.reload! true end end diff --git a/railties/lib/rails/dev_caching.rb b/railties/lib/rails/dev_caching.rb new file mode 100644 index 0000000000..f2a53d6417 --- /dev/null +++ b/railties/lib/rails/dev_caching.rb @@ -0,0 +1,43 @@ +require 'fileutils' + +module Rails + module DevCaching # :nodoc: + class << self + FILE = 'tmp/caching-dev.txt' + + def enable_by_file + FileUtils.mkdir_p('tmp') + + if File.exist?(FILE) + delete_cache_file + puts 'Development mode is no longer being cached.' + else + create_cache_file + puts 'Development mode is now being cached.' + end + + FileUtils.touch 'tmp/restart.txt' + FileUtils.rm_f('tmp/pids/server.pid') + end + + def enable_by_argument(caching) + FileUtils.mkdir_p('tmp') + + if caching + create_cache_file + elsif caching == false && File.exist?(FILE) + delete_cache_file + end + end + + private + def create_cache_file + FileUtils.touch FILE + end + + def delete_cache_file + File.delete FILE + end + end + end +end diff --git a/railties/lib/rails/engine/configuration.rb b/railties/lib/rails/engine/configuration.rb index 8cadbc3ddd..294d07446f 100644 --- a/railties/lib/rails/engine/configuration.rb +++ b/railties/lib/rails/engine/configuration.rb @@ -39,6 +39,7 @@ module Rails paths.add "app", eager_load: true, glob: "{*,*/concerns}" paths.add "app/assets", glob: "*" paths.add "app/controllers", eager_load: true + paths.add "app/channels", eager_load: true, glob: "**/*_channel.rb" paths.add "app/helpers", eager_load: true paths.add "app/models", eager_load: true paths.add "app/mailers", eager_load: true diff --git a/railties/lib/rails/gem_version.rb b/railties/lib/rails/gem_version.rb index 93e0151602..081222425c 100644 --- a/railties/lib/rails/gem_version.rb +++ b/railties/lib/rails/gem_version.rb @@ -8,7 +8,7 @@ module Rails MAJOR = 5 MINOR = 0 TINY = 0 - PRE = "beta2" + PRE = "beta3" STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".") end diff --git a/railties/lib/rails/generators.rb b/railties/lib/rails/generators.rb index e3d79521e7..330bd7ec5d 100644 --- a/railties/lib/rails/generators.rb +++ b/railties/lib/rails/generators.rb @@ -105,7 +105,7 @@ module Rails # Configure generators for API only applications. It basically hides # everything that is usually browser related, such as assets and session - # migration generators, and completely disable views, helpers and assets + # migration generators, and completely disable helpers and assets # so generators such as scaffold won't create them. def self.api_only! hide_namespaces "assets", "helper", "css", "js" @@ -116,6 +116,10 @@ module Rails helper: false, template_engine: nil ) + + if ARGV.first == 'mailer' + options[:rails].merge!(template_engine: :erb) + end end # Remove the color from output. diff --git a/railties/lib/rails/generators/actions.rb b/railties/lib/rails/generators/actions.rb index 9ca731347a..c947c062fa 100644 --- a/railties/lib/rails/generators/actions.rb +++ b/railties/lib/rails/generators/actions.rb @@ -1,5 +1,3 @@ -require 'open-uri' - module Rails module Generators module Actions @@ -207,16 +205,22 @@ module Rails in_root { run_ruby_script("bin/rails generate #{what} #{argument}", verbose: false) } end - # Runs the supplied rake task + # Runs the supplied rake task (invoked with 'rake ...') # # rake("db:migrate") # rake("db:migrate", env: "production") # rake("gems:install", sudo: true) def rake(command, options={}) - log :rake, command - env = options[:env] || ENV["RAILS_ENV"] || 'development' - sudo = options[:sudo] && RbConfig::CONFIG['host_os'] !~ /mswin|mingw/ ? 'sudo ' : '' - in_root { run("#{sudo}#{extify(:rake)} #{command} RAILS_ENV=#{env}", verbose: false) } + execute_command :rake, command, options + end + + # Runs the supplied rake task (invoked with 'rails ...') + # + # rails("db:migrate") + # rails("db:migrate", env: "production") + # rails("gems:install", sudo: true) + def rails_command(command, options={}) + execute_command :rails, command, options end # Just run the capify command in root @@ -270,6 +274,16 @@ module Rails end end + + # Runs the supplied command using either "rake ..." or "rails ..." + # based on the executor parameter provided. + def execute_command(executor, command, options={}) + log executor, command + env = options[:env] || ENV["RAILS_ENV"] || 'development' + sudo = options[:sudo] && RbConfig::CONFIG['host_os'] !~ /mswin|mingw/ ? 'sudo ' : '' + in_root { run("#{sudo}#{extify(executor)} #{command} RAILS_ENV=#{env}", verbose: false) } + end + # Add an extension to the given name based on the platform. def extify(name) if RbConfig::CONFIG['host_os'] =~ /mswin|mingw/ diff --git a/railties/lib/rails/generators/actions/create_migration.rb b/railties/lib/rails/generators/actions/create_migration.rb index d664b07652..6c5b55466d 100644 --- a/railties/lib/rails/generators/actions/create_migration.rb +++ b/railties/lib/rails/generators/actions/create_migration.rb @@ -1,3 +1,4 @@ +require 'fileutils' require 'thor/actions' module Rails diff --git a/railties/lib/rails/generators/app_base.rb b/railties/lib/rails/generators/app_base.rb index 8f8c2ec9e1..151bf9a879 100644 --- a/railties/lib/rails/generators/app_base.rb +++ b/railties/lib/rails/generators/app_base.rb @@ -1,3 +1,4 @@ +require 'fileutils' require 'digest/md5' require 'active_support/core_ext/string/strip' require 'rails/version' unless defined?(Rails::VERSION) @@ -63,6 +64,9 @@ module Rails class_option :skip_spring, type: :boolean, default: false, desc: "Don't install Spring application preloader" + class_option :skip_listen, type: :boolean, default: false, + desc: "Don't generate configuration that depends on the listen gem" + class_option :skip_javascript, type: :boolean, aliases: '-J', default: false, desc: 'Skip JavaScript files' @@ -178,7 +182,7 @@ module Rails def webserver_gemfile_entry return [] if options[:skip_puma] comment = 'Use Puma as the app server' - GemfileEntry.new('puma', nil, comment) + GemfileEntry.new('puma', '~> 3.0', comment) end def include_all_railties? @@ -308,12 +312,7 @@ module Rails end def coffee_gemfile_entry - comment = 'Use CoffeeScript for .coffee assets and views' - if options.dev? || options.edge? - GemfileEntry.github 'coffee-rails', 'rails/coffee-rails', nil, comment - else - GemfileEntry.version 'coffee-rails', '~> 4.1.0', comment - end + GemfileEntry.version 'coffee-rails', '~> 4.1.0', 'Use CoffeeScript for .coffee assets and views' end def javascript_gemfile_entry @@ -325,8 +324,8 @@ module Rails "Use #{options[:javascript]} as the JavaScript library") unless options[:skip_turbolinks] - gems << GemfileEntry.version("turbolinks", nil, - "Turbolinks makes following links in your web application faster. Read more: https://github.com/turbolinks/turbolinks") + gems << GemfileEntry.version("turbolinks", "~> 5.x", + "Turbolinks makes navigating your web application faster. Read more: https://github.com/turbolinks/turbolinks") end gems @@ -390,6 +389,10 @@ module Rails !options[:skip_spring] && !options.dev? && Process.respond_to?(:fork) && !RUBY_PLATFORM.include?("cygwin") end + def depend_on_listen? + !options[:skip_listen] && os_supports_listen_out_of_the_box? + end + def os_supports_listen_out_of_the_box? RbConfig::CONFIG['host_os'] =~ /darwin|linux/ end diff --git a/railties/lib/rails/generators/erb/mailer/mailer_generator.rb b/railties/lib/rails/generators/erb/mailer/mailer_generator.rb index bc249aa5e5..7f00943d80 100644 --- a/railties/lib/rails/generators/erb/mailer/mailer_generator.rb +++ b/railties/lib/rails/generators/erb/mailer/mailer_generator.rb @@ -26,7 +26,7 @@ module Erb # :nodoc: end def file_name - @_file_name ||= super.gsub(/\_mailer/i, '') + @_file_name ||= super.gsub(/_mailer/i, '') end end end diff --git a/railties/lib/rails/generators/rails/app/app_generator.rb b/railties/lib/rails/generators/rails/app/app_generator.rb index 248ad20019..f58e6ba653 100644 --- a/railties/lib/rails/generators/rails/app/app_generator.rb +++ b/railties/lib/rails/generators/rails/app/app_generator.rb @@ -80,6 +80,7 @@ module Rails template "secrets.yml" template "cable.yml" unless options[:skip_action_cable] template "puma.rb" unless options[:skip_puma] + template "spring.rb" if spring_install? directory "environments" directory "initializers" @@ -91,20 +92,37 @@ module Rails cookie_serializer_config_exist = File.exist?('config/initializers/cookies_serializer.rb') callback_terminator_config_exist = File.exist?('config/initializers/callback_terminator.rb') active_record_belongs_to_required_by_default_config_exist = File.exist?('config/initializers/active_record_belongs_to_required_by_default.rb') + action_cable_config_exist = File.exist?('config/cable.yml') + ssl_options_exist = File.exist?('config/initializers/ssl_options.rb') + rack_cors_config_exist = File.exist?('config/initializers/cors.rb') config + gsub_file 'config/environments/development.rb', /^(\s+)config\.file_watcher/, '\1# config.file_watcher' + unless callback_terminator_config_exist remove_file 'config/initializers/callback_terminator.rb' end unless cookie_serializer_config_exist - gsub_file 'config/initializers/cookies_serializer.rb', /json/, 'marshal' + gsub_file 'config/initializers/cookies_serializer.rb', /json(?!,)/, 'marshal' end unless active_record_belongs_to_required_by_default_config_exist remove_file 'config/initializers/active_record_belongs_to_required_by_default.rb' end + + unless action_cable_config_exist + template 'config/cable.yml' + end + + unless ssl_options_exist + remove_file 'config/initializers/ssl_options.rb' + end + + unless rack_cors_config_exist + remove_file 'config/initializers/cors.rb' + end end def database_yml @@ -276,9 +294,9 @@ module Rails end end - def delete_app_views_if_api_option + def delete_application_layout_file_if_api_option if options[:api] - remove_dir 'app/views' + remove_file 'app/views/layouts/application.html.erb' end end @@ -317,7 +335,7 @@ module Rails def delete_action_cable_files_skipping_action_cable if options[:skip_action_cable] remove_file 'config/cable.yml' - remove_file 'app/assets/javascripts/cable.coffee' + remove_file 'app/assets/javascripts/cable.js' remove_dir 'app/channels' end end diff --git a/railties/lib/rails/generators/rails/app/templates/Gemfile b/railties/lib/rails/generators/rails/app/templates/Gemfile index c3fad31f23..86143ca1f1 100644 --- a/railties/lib/rails/generators/rails/app/templates/Gemfile +++ b/railties/lib/rails/generators/rails/app/templates/Gemfile @@ -26,25 +26,25 @@ source 'https://rubygems.org' <% if RUBY_ENGINE == 'ruby' -%> group :development, :test do # Call 'byebug' anywhere in the code to stop execution and get a debugger console - gem 'byebug' + gem 'byebug', platform: :mri end group :development do <%- unless options.api? -%> - # Access an IRB console on exception pages or by using <%%= console %> in views + # Access an IRB console on exception pages or by using <%%= console %> anywhere in the code. <%- if options.dev? || options.edge? -%> gem 'web-console', github: 'rails/web-console' <%- else -%> - gem 'web-console', '~> 3.0' + gem 'web-console' <%- end -%> <%- end -%> -<% if os_supports_listen_out_of_the_box? -%> +<% if depend_on_listen? -%> gem 'listen', '~> 3.0.5' <% end -%> <% if spring_install? -%> # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring gem 'spring' -<% if os_supports_listen_out_of_the_box? -%> +<% if depend_on_listen? -%> gem 'spring-watcher-listen', '~> 2.0.0' <% end -%> <% end -%> diff --git a/railties/lib/rails/generators/rails/app/templates/README.md b/railties/lib/rails/generators/rails/app/templates/README.md index 55e144da18..7db80e4ca1 100644 --- a/railties/lib/rails/generators/rails/app/templates/README.md +++ b/railties/lib/rails/generators/rails/app/templates/README.md @@ -1,4 +1,4 @@ -## README +# README This README would normally document whatever steps are necessary to get the application up and running. diff --git a/railties/lib/rails/generators/rails/app/templates/Rakefile b/railties/lib/rails/generators/rails/app/templates/Rakefile index ba6b733dd2..e85f913914 100644 --- a/railties/lib/rails/generators/rails/app/templates/Rakefile +++ b/railties/lib/rails/generators/rails/app/templates/Rakefile @@ -1,6 +1,6 @@ # Add your own tasks in files placed in lib/tasks ending in .rake, # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. -require File.expand_path('../config/application', __FILE__) +require_relative 'config/application' Rails.application.load_tasks diff --git a/railties/lib/rails/generators/rails/app/templates/app/assets/javascripts/cable.coffee b/railties/lib/rails/generators/rails/app/templates/app/assets/javascripts/cable.coffee deleted file mode 100644 index 07934d026f..0000000000 --- a/railties/lib/rails/generators/rails/app/templates/app/assets/javascripts/cable.coffee +++ /dev/null @@ -1,11 +0,0 @@ -# Action Cable provides the framework to deal with WebSockets in Rails. -# You can generate new channels where WebSocket features live using the rails generate channel command. -# -# Turn on the cable connection by removing the comments after the require statements (and ensure it's also on in config/routes.rb). -# -#= require action_cable -#= require_self -#= require_tree ./channels -# -# @App ||= {} -# App.cable = ActionCable.createConsumer() diff --git a/railties/lib/rails/generators/rails/app/templates/app/assets/javascripts/cable.js b/railties/lib/rails/generators/rails/app/templates/app/assets/javascripts/cable.js new file mode 100644 index 0000000000..71ee1e66de --- /dev/null +++ b/railties/lib/rails/generators/rails/app/templates/app/assets/javascripts/cable.js @@ -0,0 +1,13 @@ +// Action Cable provides the framework to deal with WebSockets in Rails. +// You can generate new channels where WebSocket features live using the rails generate channel command. +// +//= require action_cable +//= require_self +//= require_tree ./channels + +(function() { + this.App || (this.App = {}); + + App.cable = ActionCable.createConsumer(); + +}).call(this); diff --git a/railties/lib/rails/generators/rails/app/templates/app/views/layouts/application.html.erb.tt b/railties/lib/rails/generators/rails/app/templates/app/views/layouts/application.html.erb.tt index 68b5c051b2..d51f79bd49 100644 --- a/railties/lib/rails/generators/rails/app/templates/app/views/layouts/application.html.erb.tt +++ b/railties/lib/rails/generators/rails/app/templates/app/views/layouts/application.html.erb.tt @@ -3,16 +3,13 @@ <head> <title><%= camelized %></title> <%%= csrf_meta_tags %> - <%- unless options[:skip_action_cable] -%> - <%%= action_cable_meta_tag %> - <%- end -%> <%- if options[:skip_javascript] -%> <%%= stylesheet_link_tag 'application', media: 'all' %> <%- else -%> <%- if gemfile_entries.any? { |m| m.name == 'turbolinks' } -%> - <%%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track' => true %> - <%%= javascript_include_tag 'application', 'data-turbolinks-track' => true %> + <%%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %> + <%%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %> <%- else -%> <%%= stylesheet_link_tag 'application', media: 'all' %> <%%= javascript_include_tag 'application' %> diff --git a/railties/lib/rails/generators/rails/app/templates/bin/rails b/railties/lib/rails/generators/rails/app/templates/bin/rails index 80ec8080ab..513a2e0183 100644 --- a/railties/lib/rails/generators/rails/app/templates/bin/rails +++ b/railties/lib/rails/generators/rails/app/templates/bin/rails @@ -1,3 +1,3 @@ -APP_PATH = File.expand_path('../../config/application', __FILE__) +APP_PATH = File.expand_path('../config/application', __dir__) require_relative '../config/boot' require 'rails/commands' diff --git a/railties/lib/rails/generators/rails/app/templates/bin/setup b/railties/lib/rails/generators/rails/app/templates/bin/setup index df88bfd3bc..acae810c1a 100644 --- a/railties/lib/rails/generators/rails/app/templates/bin/setup +++ b/railties/lib/rails/generators/rails/app/templates/bin/setup @@ -15,7 +15,7 @@ chdir APP_ROOT do puts '== Installing dependencies ==' system! 'gem install bundler --conservative' - system('bundle check') or system!('bundle install') + system('bundle check') || system!('bundle install') # puts "\n== Copying sample files ==" # unless File.exist?('config/database.yml') diff --git a/railties/lib/rails/generators/rails/app/templates/bin/update b/railties/lib/rails/generators/rails/app/templates/bin/update index c6ed3ae64b..770a605fed 100644 --- a/railties/lib/rails/generators/rails/app/templates/bin/update +++ b/railties/lib/rails/generators/rails/app/templates/bin/update @@ -15,7 +15,7 @@ chdir APP_ROOT do puts '== Installing dependencies ==' system! 'gem install bundler --conservative' - system 'bundle check' or system! 'bundle install' + system('bundle check') || system!('bundle install') puts "\n== Updating database ==" system! 'bin/rails db:migrate' diff --git a/railties/lib/rails/generators/rails/app/templates/config.ru b/railties/lib/rails/generators/rails/app/templates/config.ru new file mode 100644 index 0000000000..f7ba0b527b --- /dev/null +++ b/railties/lib/rails/generators/rails/app/templates/config.ru @@ -0,0 +1,5 @@ +# This file is used by Rack-based servers to start the application. + +require_relative 'config/environment' + +run Rails.application diff --git a/railties/lib/rails/generators/rails/app/templates/config.ru.tt b/railties/lib/rails/generators/rails/app/templates/config.ru.tt deleted file mode 100644 index 343c0833d7..0000000000 --- a/railties/lib/rails/generators/rails/app/templates/config.ru.tt +++ /dev/null @@ -1,10 +0,0 @@ -# This file is used by Rack-based servers to start the application. - -require ::File.expand_path('../config/environment', __FILE__) -<%- unless options[:skip_action_cable] -%> - -# Action Cable requires that all classes are loaded in advance -Rails.application.eager_load! -<%- end -%> - -run Rails.application diff --git a/railties/lib/rails/generators/rails/app/templates/config/application.rb b/railties/lib/rails/generators/rails/app/templates/config/application.rb index cb83364360..c0a0bd0a3e 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/application.rb +++ b/railties/lib/rails/generators/rails/app/templates/config/application.rb @@ -1,4 +1,4 @@ -require File.expand_path('../boot', __FILE__) +require_relative 'boot' <% if include_all_railties? -%> require 'rails/all' diff --git a/railties/lib/rails/generators/rails/app/templates/config/boot.rb b/railties/lib/rails/generators/rails/app/templates/config/boot.rb index 6b750f00b1..30f5120df6 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/boot.rb +++ b/railties/lib/rails/generators/rails/app/templates/config/boot.rb @@ -1,3 +1,3 @@ -ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__) +ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__) require 'bundler/setup' # Set up gems listed in the Gemfile. diff --git a/railties/lib/rails/generators/rails/app/templates/config/environment.rb b/railties/lib/rails/generators/rails/app/templates/config/environment.rb index ee8d90dc65..426333bb46 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/environment.rb +++ b/railties/lib/rails/generators/rails/app/templates/config/environment.rb @@ -1,5 +1,5 @@ # Load the Rails application. -require File.expand_path('../application', __FILE__) +require_relative 'application' # Initialize the Rails application. Rails.application.initialize! diff --git a/railties/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt index 3451ade158..7a537610e9 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt +++ b/railties/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt @@ -15,18 +15,22 @@ Rails.application.configure do # Enable/disable caching. By default caching is disabled. if Rails.root.join('tmp/caching-dev.txt').exist? config.action_controller.perform_caching = true + config.cache_store = :memory_store config.public_file_server.headers = { 'Cache-Control' => 'public, max-age=172800' } else config.action_controller.perform_caching = false + config.cache_store = :null_store end <%- unless options.skip_action_mailer? -%> # Don't care if the mailer can't send. config.action_mailer.raise_delivery_errors = false + + config.action_mailer.perform_caching = false <%- end -%> # Print deprecation notices to the Rails logger. @@ -42,15 +46,6 @@ Rails.application.configure do # This option may cause significant delays in view rendering with a large # number of complex assets. config.assets.debug = true - - # Asset digests allow you to set far-future HTTP expiration dates on all assets, - # yet still be able to expire them through the digest params. - config.assets.digest = true - - # Adds additional error checking when serving assets at runtime. - # Checks for improperly declared sprockets dependencies. - # Raises helpful error messages. - config.assets.raise_runtime_errors = true <%- end -%> # Raises error for missing translations @@ -58,5 +53,5 @@ Rails.application.configure do # Use an evented file watcher to asynchronously detect changes in source code, # routes, locales, etc. This feature depends on the listen gem. - <%= '# ' unless os_supports_listen_out_of_the_box? %>config.file_watcher = ActiveSupport::EventedFileUpdateChecker + <%= '# ' unless depend_on_listen? %>config.file_watcher = ActiveSupport::EventedFileUpdateChecker end diff --git a/railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt index 82509f5ef5..6bd5e42251 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt +++ b/railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt @@ -26,10 +26,6 @@ Rails.application.configure do # Do not fallback to assets pipeline if a precompiled asset is missed. config.assets.compile = false - # Asset digests allow you to set far-future HTTP expiration dates on all assets, - # yet still be able to expire them through the digest params. - config.assets.digest = true - # `config.assets.precompile` and `config.assets.version` have moved to config/initializers/assets.rb <%- end -%> @@ -44,6 +40,9 @@ Rails.application.configure do # Action Cable endpoint configuration # config.action_cable.url = 'wss://example.com/cable' # config.action_cable.allowed_request_origins = [ 'http://example.com', /http:\/\/example.*/ ] + + # Don't mount Action Cable in the main server process. + # config.action_cable.mount_path = nil <%- end -%> # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. @@ -56,10 +55,6 @@ Rails.application.configure do # Prepend all log lines with the following tags. config.log_tags = [ :request_id ] - # Use a different logger for distributed setups. - # require 'syslog/logger' - # config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new 'app-name') - # Use a different cache store in production. # config.cache_store = :mem_cache_store @@ -67,6 +62,7 @@ Rails.application.configure do # config.active_job.queue_adapter = :resque # config.active_job.queue_name_prefix = "<%= app_name %>_#{Rails.env}" <%- unless options.skip_action_mailer? -%> + config.action_mailer.perform_caching = false # Ignore bad email addresses and do not raise email delivery errors. # Set this to true and configure the email server for immediate delivery to raise delivery errors. @@ -82,6 +78,16 @@ Rails.application.configure do # Use default logging formatter so that PID and timestamp are not suppressed. config.log_formatter = ::Logger::Formatter.new + + # Use a different logger for distributed setups. + # require 'syslog/logger' + # config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new 'app-name') + + if ENV["RAILS_LOG_TO_STDOUT"].present? + logger = ActiveSupport::Logger.new(STDOUT) + logger.formatter = config.log_formatter + config.logger = ActiveSupport::TaggedLogging.new(logger) + end <%- unless options.skip_active_record? -%> # Do not dump schema after migrations. diff --git a/railties/lib/rails/generators/rails/app/templates/config/environments/test.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/environments/test.rb.tt index 8133917591..42fee3b036 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/environments/test.rb.tt +++ b/railties/lib/rails/generators/rails/app/templates/config/environments/test.rb.tt @@ -28,6 +28,7 @@ Rails.application.configure do # Disable request forgery protection in test environment. config.action_controller.allow_forgery_protection = false <%- unless options.skip_action_mailer? -%> + config.action_mailer.perform_caching = false # Tell Action Mailer not to deliver emails to the real world. # The :test delivery method accumulates sent emails in the @@ -35,9 +36,6 @@ Rails.application.configure do config.action_mailer.delivery_method = :test <%- end -%> - # Randomize the order test cases are executed. - config.active_support.test_order = :random - # Print deprecation notices to the stderr. config.active_support.deprecation = :stderr diff --git a/railties/lib/rails/generators/rails/app/templates/config/initializers/ssl_options.rb b/railties/lib/rails/generators/rails/app/templates/config/initializers/ssl_options.rb new file mode 100644 index 0000000000..1775dea1e7 --- /dev/null +++ b/railties/lib/rails/generators/rails/app/templates/config/initializers/ssl_options.rb @@ -0,0 +1,4 @@ +# Be sure to restart your server when you modify this file. + +# Configure SSL options to enable HSTS with subdomains. +Rails.application.config.ssl_options = { hsts: { subdomains: true } } diff --git a/railties/lib/rails/generators/rails/app/templates/config/puma.rb b/railties/lib/rails/generators/rails/app/templates/config/puma.rb index 1bf274bc66..c7f311f811 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/puma.rb +++ b/railties/lib/rails/generators/rails/app/templates/config/puma.rb @@ -42,3 +42,6 @@ environment ENV.fetch("RAILS_ENV") { "development" } # on_worker_boot do # ActiveRecord::Base.establish_connection if defined?(ActiveRecord) # end + +# Allow puma to be restarted by `rails restart` command. +plugin :tmp_restart diff --git a/railties/lib/rails/generators/rails/app/templates/config/routes.rb b/railties/lib/rails/generators/rails/app/templates/config/routes.rb index 8293c8a483..787824f888 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/routes.rb +++ b/railties/lib/rails/generators/rails/app/templates/config/routes.rb @@ -1,6 +1,3 @@ Rails.application.routes.draw do # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html - - # Serve websocket cable requests in-process - # mount ActionCable.server => '/cable' end diff --git a/railties/lib/rails/generators/rails/app/templates/config/spring.rb b/railties/lib/rails/generators/rails/app/templates/config/spring.rb new file mode 100644 index 0000000000..c9119b40c0 --- /dev/null +++ b/railties/lib/rails/generators/rails/app/templates/config/spring.rb @@ -0,0 +1,6 @@ +%w( + .ruby-version + .rbenv-vars + tmp/restart.txt + tmp/caching-dev.txt +).each { |path| Spring.watch(path) } diff --git a/railties/lib/rails/generators/rails/plugin/plugin_generator.rb b/railties/lib/rails/generators/rails/plugin/plugin_generator.rb index b5e836b584..56efd35a95 100644 --- a/railties/lib/rails/generators/rails/plugin/plugin_generator.rb +++ b/railties/lib/rails/generators/rails/plugin/plugin_generator.rb @@ -90,6 +90,7 @@ task default: :test opts[:force] = force opts[:skip_bundle] = true opts[:api] = options.api? + opts[:skip_listen] = true invoke Rails::Generators::AppGenerator, [ File.expand_path(dummy_path, destination_root) ], opts @@ -287,10 +288,6 @@ task default: :test protected - def app_templates_dir - "../../app/templates" - end - def create_dummy_app(path = nil) dummy_path(path) if path diff --git a/railties/lib/rails/generators/rails/plugin/templates/app/controllers/%namespaced_name%/application_controller.rb.tt b/railties/lib/rails/generators/rails/plugin/templates/app/controllers/%namespaced_name%/application_controller.rb.tt index 83807f14b4..abbacd9bec 100644 --- a/railties/lib/rails/generators/rails/plugin/templates/app/controllers/%namespaced_name%/application_controller.rb.tt +++ b/railties/lib/rails/generators/rails/plugin/templates/app/controllers/%namespaced_name%/application_controller.rb.tt @@ -1,6 +1,6 @@ <%= wrap_in_modules <<-rb.strip_heredoc class ApplicationController < ActionController::#{api? ? "API" : "Base"} - #{ api? ? '# ' : '' }protect_from_forgery :with => :exception + #{ api? ? '# ' : '' }protect_from_forgery with: :exception end rb %> diff --git a/railties/lib/rails/generators/rails/plugin/templates/rails/application.rb b/railties/lib/rails/generators/rails/plugin/templates/rails/application.rb index b1038c839e..d03b1be878 100644 --- a/railties/lib/rails/generators/rails/plugin/templates/rails/application.rb +++ b/railties/lib/rails/generators/rails/plugin/templates/rails/application.rb @@ -1,4 +1,4 @@ -require File.expand_path('../boot', __FILE__) +require_relative 'boot' <% if include_all_railties? -%> require 'rails/all' @@ -6,10 +6,12 @@ require 'rails/all' # Pick the frameworks you want: <%= comment_if :skip_active_record %>require "active_record/railtie" require "action_controller/railtie" -<%= comment_if :skip_action_mailer %>require "action_mailer/railtie" require "action_view/railtie" -<%= comment_if :skip_sprockets %>require "sprockets/railtie" +<%= comment_if :skip_action_mailer %>require "action_mailer/railtie" +require "active_job/railtie" +<%= comment_if :skip_action_cable %>require "action_cable/engine" <%= comment_if :skip_test %>require "rails/test_unit/railtie" +<%= comment_if :skip_sprockets %>require "sprockets/railtie" <% end -%> Bundler.require(*Rails.groups) diff --git a/railties/lib/rails/generators/rails/plugin/templates/rails/boot.rb b/railties/lib/rails/generators/rails/plugin/templates/rails/boot.rb index 6266cfc509..c9aef85d40 100644 --- a/railties/lib/rails/generators/rails/plugin/templates/rails/boot.rb +++ b/railties/lib/rails/generators/rails/plugin/templates/rails/boot.rb @@ -1,5 +1,5 @@ # Set up gems listed in the Gemfile. -ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../../../Gemfile', __FILE__) +ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../../Gemfile', __dir__) require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE']) -$LOAD_PATH.unshift File.expand_path('../../../../lib', __FILE__) +$LOAD_PATH.unshift File.expand_path('../../../lib', __dir__) diff --git a/railties/lib/rails/generators/test_unit/mailer/mailer_generator.rb b/railties/lib/rails/generators/test_unit/mailer/mailer_generator.rb index 343c8a3949..76a0b79654 100644 --- a/railties/lib/rails/generators/test_unit/mailer/mailer_generator.rb +++ b/railties/lib/rails/generators/test_unit/mailer/mailer_generator.rb @@ -19,7 +19,7 @@ module TestUnit # :nodoc: protected def file_name - @_file_name ||= super.gsub(/\_mailer/i, '') + @_file_name ||= super.gsub(/_mailer/i, '') end end end diff --git a/railties/lib/rails/railtie.rb b/railties/lib/rails/railtie.rb index 8c24d1d56d..492c519222 100644 --- a/railties/lib/rails/railtie.rb +++ b/railties/lib/rails/railtie.rb @@ -1,38 +1,37 @@ require 'rails/initializable' -require 'rails/configuration' require 'active_support/inflector' require 'active_support/core_ext/module/introspection' require 'active_support/core_ext/module/delegation' module Rails - # Railtie is the core of the Rails framework and provides several hooks to extend - # Rails and/or modify the initialization process. + # <tt>Rails::Railtie</tt> is the core of the Rails framework and provides + # several hooks to extend Rails and/or modify the initialization process. # - # Every major component of Rails (Action Mailer, Action Controller, - # Action View and Active Record) is a Railtie. Each of - # them is responsible for their own initialization. This makes Rails itself - # absent of any component hooks, allowing other components to be used in - # place of any of the Rails defaults. + # Every major component of Rails (Action Mailer, Action Controller, Active + # Record, etc.) implements a railtie. Each of them is responsible for their + # own initialization. This makes Rails itself absent of any component hooks, + # allowing other components to be used in place of any of the Rails defaults. # - # Developing a Rails extension does _not_ require any implementation of - # Railtie, but if you need to interact with the Rails framework during - # or after boot, then Railtie is needed. + # Developing a Rails extension does _not_ require implementing a railtie, but + # if you need to interact with the Rails framework during or after boot, then + # a railtie is needed. # - # For example, an extension doing any of the following would require Railtie: + # For example, an extension doing any of the following would need a railtie: # # * creating initializers # * configuring a Rails framework for the application, like setting a generator # * adding <tt>config.*</tt> keys to the environment - # * setting up a subscriber with ActiveSupport::Notifications - # * adding rake tasks + # * setting up a subscriber with <tt>ActiveSupport::Notifications</tt> + # * adding Rake tasks # - # == Creating your Railtie + # == Creating a Railtie # - # To extend Rails using Railtie, create a Railtie class which inherits - # from Rails::Railtie within your extension's namespace. This class must be - # loaded during the Rails boot process. + # To extend Rails using a railtie, create a subclass of <tt>Rails::Railtie</tt>. + # This class must be loaded during the Rails boot process, and is conventionally + # called <tt>MyNamespace::Railtie</tt>. # - # The following example demonstrates an extension which can be used with or without Rails. + # The following example demonstrates an extension which can be used with or + # without Rails. # # # lib/my_gem/railtie.rb # module MyGem @@ -45,8 +44,8 @@ module Rails # # == Initializers # - # To add an initialization step from your Railtie to Rails boot process, you just need - # to create an initializer block: + # To add an initialization step to the Rails boot process from your railtie, just + # define the initialization code with the +initializer+ macro: # # class MyRailtie < Rails::Railtie # initializer "my_railtie.configure_rails_initialization" do @@ -55,7 +54,7 @@ module Rails # end # # If specified, the block can also receive the application object, in case you - # need to access some application specific configuration, like middleware: + # need to access some application-specific configuration, like middleware: # # class MyRailtie < Rails::Railtie # initializer "my_railtie.configure_rails_initialization" do |app| @@ -63,56 +62,56 @@ module Rails # end # end # - # Finally, you can also pass <tt>:before</tt> and <tt>:after</tt> as option to initializer, - # in case you want to couple it with a specific step in the initialization process. + # Finally, you can also pass <tt>:before</tt> and <tt>:after</tt> as options to + # +initializer+, in case you want to couple it with a specific step in the + # initialization process. # # == Configuration # - # Inside the Railtie class, you can access a config object which contains configuration - # shared by all railties and the application: + # Railties can access a config object which contains configuration shared by all + # railties and the application: # # class MyRailtie < Rails::Railtie # # Customize the ORM # config.app_generators.orm :my_railtie_orm # # # Add a to_prepare block which is executed once in production - # # and before each request in development + # # and before each request in development. # config.to_prepare do # MyRailtie.setup! # end # end # - # == Loading rake tasks and generators + # == Loading Rake Tasks and Generators # - # If your railtie has rake tasks, you can tell Rails to load them through the method - # rake_tasks: + # If your railtie has Rake tasks, you can tell Rails to load them through the method + # +rake_tasks+: # # class MyRailtie < Rails::Railtie # rake_tasks do - # load "path/to/my_railtie.tasks" + # load 'path/to/my_railtie.tasks' # end # end # # By default, Rails loads generators from your load path. However, if you want to place - # your generators at a different location, you can specify in your Railtie a block which + # your generators at a different location, you can specify in your railtie a block which # will load them during normal generators lookup: # # class MyRailtie < Rails::Railtie # generators do - # require "path/to/my_railtie_generator" + # require 'path/to/my_railtie_generator' # end # end # # == Application and Engine # - # A Rails::Engine is nothing more than a Railtie with some initializers already set. - # And since Rails::Application is an engine, the same configuration described here - # can be used in both. + # An engine is nothing more than a railtie with some initializers already set. And since + # <tt>Rails::Application</tt> is an engine, the same configuration described here can be + # used in both. # # Be sure to look at the documentation of those specific classes for more information. - # class Railtie - autoload :Configuration, "rails/railtie/configuration" + autoload :Configuration, 'rails/railtie/configuration' include Initializable @@ -183,7 +182,7 @@ module Rails end protected - def generate_railtie_name(string) + def generate_railtie_name(string) #:nodoc: ActiveSupport::Inflector.underscore(string).tr("/", "_") end @@ -200,21 +199,24 @@ module Rails delegate :railtie_name, to: :class - def initialize + def initialize #:nodoc: if self.class.abstract_railtie? raise "#{self.class.name} is abstract, you cannot instantiate it directly." end end - def configure(&block) + def configure(&block) #:nodoc: instance_eval(&block) end + # This is used to create the <tt>config</tt> object on Railties, an instance of + # Railtie::Configuration, that is used by Railties and Application to store + # related configuration. def config @config ||= Railtie::Configuration.new end - def railtie_namespace + def railtie_namespace #:nodoc: @railtie_namespace ||= self.class.parents.detect { |n| n.respond_to?(:railtie_namespace) } end diff --git a/railties/lib/rails/tasks/dev.rake b/railties/lib/rails/tasks/dev.rake index 4593100465..d2ceaacc0c 100644 --- a/railties/lib/rails/tasks/dev.rake +++ b/railties/lib/rails/tasks/dev.rake @@ -1,14 +1,8 @@ +require 'rails/dev_caching' + namespace :dev do desc 'Toggle development mode caching on/off' task :cache do - if File.exist? 'tmp/caching-dev.txt' - File.delete 'tmp/caching-dev.txt' - puts 'Development mode is no longer being cached.' - else - FileUtils.touch 'tmp/caching-dev.txt' - puts 'Development mode is now being cached.' - end - - FileUtils.touch 'tmp/restart.txt' + Rails::DevCaching.enable_by_file end end diff --git a/railties/lib/rails/tasks/framework.rake b/railties/lib/rails/tasks/framework.rake index 7601836809..3e771167ee 100644 --- a/railties/lib/rails/tasks/framework.rake +++ b/railties/lib/rails/tasks/framework.rake @@ -1,4 +1,6 @@ -namespace :rails do +require 'active_support/deprecation' + +namespace :app do desc "Update configs and some other initially generated files (or use just update:configs or update:bin)" task update: [ "update:configs", "update:bin" ] @@ -24,12 +26,12 @@ namespace :rails do default_templates.each do |type, names| local_template_type_dir = File.join(project_templates, type) - FileUtils.mkdir_p local_template_type_dir + mkdir_p local_template_type_dir, verbose: false names.each do |name| dst_name = File.join(local_template_type_dir, name) src_name = File.join(generators_lib, type, name, "templates") - FileUtils.cp_r src_name, dst_name + cp_r src_name, dst_name, verbose: false end end end @@ -45,8 +47,9 @@ namespace :rails do @app_generator ||= begin require 'rails/generators' require 'rails/generators/rails/app/app_generator' - gen = Rails::Generators::AppGenerator.new ["rails"], { with_dispatchers: true, api: !!Rails.application.config.api_only }, - destination_root: Rails.root + gen = Rails::Generators::AppGenerator.new ["rails"], + { api: !!Rails.application.config.api_only }, + destination_root: Rails.root File.exist?(Rails.root.join("config", "application.rb")) ? gen.send(:app_const) : gen.send(:valid_const?) gen @@ -66,3 +69,15 @@ namespace :rails do end end end + +namespace :rails do + %i(update template templates:copy update:configs update:bin).each do |task_name| + task "#{task_name}" do + ActiveSupport::Deprecation.warn(<<-MSG.squish) + Running #{task_name} with the rails: namespace is deprecated in favor of app: namespace. + Run bin/rails app:#{task_name} instead. + MSG + Rake.application.invoke_task("app:#{task_name}") + end + end +end diff --git a/railties/lib/rails/tasks/restart.rake b/railties/lib/rails/tasks/restart.rake index f36c86d81b..3f98cbe51f 100644 --- a/railties/lib/rails/tasks/restart.rake +++ b/railties/lib/rails/tasks/restart.rake @@ -1,5 +1,8 @@ -desc "Restart app by touching tmp/restart.txt" +desc 'Restart app by touching tmp/restart.txt' task :restart do - FileUtils.mkdir_p('tmp') - FileUtils.touch('tmp/restart.txt') + verbose(false) do + mkdir_p 'tmp' + touch 'tmp/restart.txt' + rm_f 'tmp/pids/server.pid' + end end diff --git a/railties/lib/rails/tasks/tmp.rake b/railties/lib/rails/tasks/tmp.rake index 9162ef234a..c74a17a0ca 100644 --- a/railties/lib/rails/tasks/tmp.rake +++ b/railties/lib/rails/tasks/tmp.rake @@ -5,9 +5,7 @@ namespace :tmp do tmp_dirs = [ 'tmp/cache', 'tmp/sockets', 'tmp/pids', - 'tmp/cache/assets/development', - 'tmp/cache/assets/test', - 'tmp/cache/assets/production' ] + 'tmp/cache/assets' ] tmp_dirs.each { |d| directory d } @@ -17,21 +15,21 @@ namespace :tmp do namespace :cache do # desc "Clears all files and directories in tmp/cache" task :clear do - FileUtils.rm_rf(Dir['tmp/cache/[^.]*']) + rm_rf Dir['tmp/cache/[^.]*'], verbose: false end end namespace :sockets do # desc "Clears all files in tmp/sockets" task :clear do - FileUtils.rm(Dir['tmp/sockets/[^.]*']) + rm Dir['tmp/sockets/[^.]*'], verbose: false end end namespace :pids do # desc "Clears all files in tmp/pids" task :clear do - FileUtils.rm(Dir['tmp/pids/[^.]*']) + rm Dir['tmp/pids/[^.]*'], verbose: false end end end diff --git a/railties/lib/rails/test_unit/minitest_plugin.rb b/railties/lib/rails/test_unit/minitest_plugin.rb index 29a3d991b8..e9195d5b4e 100644 --- a/railties/lib/rails/test_unit/minitest_plugin.rb +++ b/railties/lib/rails/test_unit/minitest_plugin.rb @@ -1,6 +1,7 @@ require "active_support/core_ext/module/attribute_accessors" require "rails/test_unit/reporter" require "rails/test_unit/test_requirer" +require 'shellwords' module Minitest class SuppressedSummaryReporter < SummaryReporter @@ -42,7 +43,7 @@ module Minitest end opts.on("-f", "--fail-fast", - "Abort test run on first failure") do + "Abort test run on first failure or error") do options[:fail_fast] = true end @@ -60,11 +61,13 @@ module Minitest # as the patterns would also contain the other Rake tasks. def self.rake_run(patterns) # :nodoc: @rake_patterns = patterns - passed = run + passed = run(Shellwords.split(ENV['TESTOPTS'] || '')) exit passed unless passed passed end + # Owes great inspiration to test runner trailblazers like RSpec, + # minitest-reporters, maxitest and others. def self.plugin_rails_init(options) self.run_with_rails_extension = true @@ -81,14 +84,18 @@ module Minitest end # Replace progress reporter for colors. - self.reporter.reporters.delete_if { |reporter| reporter.kind_of?(SummaryReporter) || reporter.kind_of?(ProgressReporter) } - self.reporter << SuppressedSummaryReporter.new(options[:io], options) - self.reporter << ::Rails::TestUnitReporter.new(options[:io], options) + reporter.reporters.delete_if { |reporter| reporter.kind_of?(SummaryReporter) || reporter.kind_of?(ProgressReporter) } + reporter << SuppressedSummaryReporter.new(options[:io], options) + reporter << ::Rails::TestUnitReporter.new(options[:io], options) end mattr_accessor(:run_with_autorun) { false } mattr_accessor(:run_with_rails_extension) { false } end +# Put Rails as the first plugin minitest initializes so other plugins +# can override or replace our default reporter setup. +# Since minitest only loads plugins if its extensions are empty we have +# to call `load_plugins` first. Minitest.load_plugins -Minitest.extensions << 'rails' +Minitest.extensions.unshift 'rails' diff --git a/railties/lib/rails/test_unit/reporter.rb b/railties/lib/rails/test_unit/reporter.rb index 73b8d7d27b..4086d5b731 100644 --- a/railties/lib/rails/test_unit/reporter.rb +++ b/railties/lib/rails/test_unit/reporter.rb @@ -18,13 +18,13 @@ module Rails if output_inline? && result.failure && (!result.skipped? || options[:verbose]) io.puts io.puts - io.puts format_failures(result).map { |line| color_output(line, by: result) } + io.puts color_output(result, by: result) io.puts io.puts format_rerun_snippet(result) io.puts end - if fail_fast? && result.failure && !result.error? && !result.skipped? + if fail_fast? && result.failure && !result.skipped? raise Interrupt end end @@ -66,21 +66,9 @@ module Rails "%s#%s = %.2f s = %s" % [result.class, result.name, result.time, result.result_code] end - def format_failures(result) - result.failures.map do |failure| - "#{failure.result_label}:\n#{result.class}##{result.name}:\n#{failure.message}\n" - end - end - def format_rerun_snippet(result) - # Try to extract path to assertion from backtrace. - if result.location =~ /\[(.*)\]\z/ - assertion_path = $1 - else - assertion_path = result.method(result.name).source_location.join(':') - end - - "#{self.executable} #{relative_path_for(assertion_path)}" + location, line = result.method(result.name).source_location + "#{self.executable} #{relative_path_for(location)}:#{line}" end def app_root |