diff options
Diffstat (limited to 'railties')
148 files changed, 2253 insertions, 1700 deletions
diff --git a/railties/CHANGELOG.md b/railties/CHANGELOG.md index 594d239290..487f02d23f 100644 --- a/railties/CHANGELOG.md +++ b/railties/CHANGELOG.md @@ -1,3 +1,71 @@ +* Make `Rails.env` fall back to `development` when `RAILS_ENV` and `RACK_ENV` is an empty string. + + *Daniel Deng* + +* Remove deprecated `CONTROLLER` environment variable for `routes` task. + + *Rafael Mendonça França* + +* Remove deprecated tasks: `rails:update`, `rails:template`, `rails:template:copy`, + `rails:update:configs` and `rails:update:bin`. + + *Rafael Mendonça França* + +* Remove deprecated file `rails/rack/debugger`. + + *Rafael Mendonça França* + +* Remove deprecated `config.serve_static_files`. + + *Rafael Mendonça França* + +* Remove deprecated `config.static_cache_control`. + + *Rafael Mendonça França* + +* The `log:clear` task clear all environments log files by default. + + *Yuji Yaginuma* + +* Add Webpack support in new apps via the --webpack option, which will delegate to the rails/webpacker gem. + + To generate a new app that has Webpack dependencies configured and binstubs for webpack and webpack-watcher: + + `rails new myapp --webpack` + + To generate a new app that has Webpack + React configured and an example intalled: + + `rails new myapp --webpack=react` + + *DHH* + +* Add Yarn support in new apps with a yarn binstub and vendor/package.json. Skippable via --skip-yarn option. + + *Liceth Ovalles*, *Guillermo Iguaran*, *DHH* + +* Removed jquery-rails from default stack, instead rails-ujs that is shipped + with Action View is included as default UJS adapter. + + *Guillermo Iguaran* + +* The config file `secrets.yml` is now loaded in with all keys as symbols. + This allows secrets files to contain more complex information without all + child keys being strings while parent keys are symbols. + + *Isaac Sloan* + +* Add `:skip_sprockets` to `Rails::PluginBuilder::PASSTHROUGH_OPTIONS` + + *Tsukuru Tanimichi* + +* Allow the use of listen's 3.1.x branch + + *Esteban Santana Santana* + +* Run `Minitest.after_run` hooks when running `rails test`. + + *Michael Grosser* + * Run `before_configuration` callbacks as soon as application constant inherits from `Rails::Application`. diff --git a/railties/MIT-LICENSE b/railties/MIT-LICENSE index 1f496cf280..f9e4444f07 100644 --- a/railties/MIT-LICENSE +++ b/railties/MIT-LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2004-2016 David Heinemeier Hansson +Copyright (c) 2004-2017 David Heinemeier Hansson Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the diff --git a/railties/Rakefile b/railties/Rakefile index 202644fb26..680ed03f75 100644 --- a/railties/Rakefile +++ b/railties/Rakefile @@ -18,6 +18,7 @@ namespace :test do "lib", "#{File.dirname(__FILE__)}/../activesupport/lib", "#{File.dirname(__FILE__)}/../actionpack/lib", + "#{File.dirname(__FILE__)}/../actionview/lib", "#{File.dirname(__FILE__)}/../activemodel/lib" ] ruby "-w", "-I#{dash_i.join ':'}", file diff --git a/railties/bin/test b/railties/bin/test new file mode 100755 index 0000000000..a7beb14b27 --- /dev/null +++ b/railties/bin/test @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby + +COMPONENT_ROOT = File.expand_path("..", __dir__) +require File.expand_path("../tools/test", COMPONENT_ROOT) diff --git a/railties/lib/rails.rb b/railties/lib/rails.rb index e9c96c7b43..00add5829d 100644 --- a/railties/lib/rails.rb +++ b/railties/lib/rails.rb @@ -7,6 +7,7 @@ require "active_support/dependencies/autoload" require "active_support/core_ext/kernel/reporting" require "active_support/core_ext/module/delegation" require "active_support/core_ext/array/extract_options" +require "active_support/core_ext/object/blank" require "rails/application" require "rails/version" @@ -46,14 +47,14 @@ module Rails def backtrace_cleaner @backtrace_cleaner ||= begin - # Relies on Active Support, so we have to lazy load to postpone definition until AS has been loaded + # Relies on Active Support, so we have to lazy load to postpone definition until Active Support has been loaded require "rails/backtrace_cleaner" Rails::BacktraceCleaner.new end end # Returns a Pathname object of the current Rails project, - # otherwise it returns nil if there is no project: + # otherwise it returns +nil+ if there is no project: # # Rails.root # # => #<Pathname:/Users/someuser/some/path/project> @@ -67,7 +68,7 @@ module Rails # Rails.env.development? # => true # Rails.env.production? # => false def env - @_env ||= ActiveSupport::StringInquirer.new(ENV["RAILS_ENV"] || ENV["RACK_ENV"] || "development") + @_env ||= ActiveSupport::StringInquirer.new(ENV["RAILS_ENV"].presence || ENV["RACK_ENV"].presence || "development") end # Sets the Rails environment. @@ -100,7 +101,7 @@ module Rails end # Returns a Pathname object of the public folder of the current - # Rails project, otherwise it returns nil if there is no project: + # Rails project, otherwise it returns +nil+ if there is no project: # # Rails.public_path # # => #<Pathname:/Users/someuser/some/path/project/public> diff --git a/railties/lib/rails/application.rb b/railties/lib/rails/application.rb index b01196e3ed..f96432c89f 100644 --- a/railties/lib/rails/application.rb +++ b/railties/lib/rails/application.rb @@ -274,7 +274,7 @@ module Rails # Sends the initializers to the +initializer+ method defined in the # Rails::Initializable module. Each Rails::Application class has its own # set of initializers, as defined by the Initializable module. - def initializer(name, opts={}, &block) + def initializer(name, opts = {}, &block) self.class.initializer(name, opts, &block) end @@ -347,7 +347,7 @@ module Rails # Initialize the application passing the given group. By default, the # group is :default - def initialize!(group=:default) #:nodoc: + def initialize!(group = :default) #:nodoc: raise "Application has been already initialized." if @initialized run_initializers(group, self) @initialized = true @@ -394,8 +394,8 @@ module Rails shared_secrets = all_secrets["shared"] env_secrets = all_secrets[Rails.env] - secrets.merge!(shared_secrets.symbolize_keys) if shared_secrets - secrets.merge!(env_secrets.symbolize_keys) if env_secrets + secrets.merge!(shared_secrets.deep_symbolize_keys) if shared_secrets + secrets.merge!(env_secrets.deep_symbolize_keys) if env_secrets end # Fallback to config.secret_key_base if secrets.secret_key_base isn't set diff --git a/railties/lib/rails/application/configuration.rb b/railties/lib/rails/application/configuration.rb index 810750ed35..59020333ba 100644 --- a/railties/lib/rails/application/configuration.rb +++ b/railties/lib/rails/application/configuration.rb @@ -4,7 +4,6 @@ require "rails/engine/configuration" require "rails/source_annotation_extractor" require "active_support/deprecation" -require "active_support/core_ext/string/strip" # for strip_heredoc module Rails class Application @@ -19,7 +18,7 @@ module Rails :beginning_of_week, :filter_redirect, :x, :enable_dependency_loading attr_writer :log_level - attr_reader :encoding, :api_only, :static_cache_control + attr_reader :encoding, :api_only def initialize(*) super @@ -56,35 +55,6 @@ module Rails @enable_dependency_loading = false end - def static_cache_control=(value) - ActiveSupport::Deprecation.warn <<-eow.strip_heredoc - `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. - eow - - @static_cache_control = value - end - - def serve_static_files - ActiveSupport::Deprecation.warn <<-eow.strip_heredoc - `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 - end - - def serve_static_files=(value) - ActiveSupport::Deprecation.warn <<-eow.strip_heredoc - `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 - end - def encoding=(value) @encoding = value silence_warnings do diff --git a/railties/lib/rails/application/default_middleware_stack.rb b/railties/lib/rails/application/default_middleware_stack.rb index 14c0a8cbe4..8fe48feefb 100644 --- a/railties/lib/rails/application/default_middleware_stack.rb +++ b/railties/lib/rails/application/default_middleware_stack.rb @@ -19,7 +19,6 @@ module Rails if config.public_file_server.enabled headers = config.public_file_server.headers || {} - headers["Cache-Control".freeze] = config.static_cache_control if config.static_cache_control middleware.use ::ActionDispatch::Static, paths["public"].first, index: config.public_file_server.index_name, headers: headers end @@ -41,12 +40,11 @@ module Rails middleware.use ::Rack::Runtime middleware.use ::Rack::MethodOverride unless config.api_only middleware.use ::ActionDispatch::RequestId + middleware.use ::ActionDispatch::RemoteIp, config.action_dispatch.ip_spoofing_check, config.action_dispatch.trusted_proxies - # Must come after Rack::MethodOverride to properly log overridden methods middleware.use ::Rails::Rack::Logger, config.log_tags middleware.use ::ActionDispatch::ShowExceptions, show_exceptions_app middleware.use ::ActionDispatch::DebugExceptions, app, config.debug_exception_response_format - middleware.use ::ActionDispatch::RemoteIp, config.action_dispatch.ip_spoofing_check, config.action_dispatch.trusted_proxies unless config.cache_classes middleware.use ::ActionDispatch::Reloader, app.reloader diff --git a/railties/lib/rails/application_controller.rb b/railties/lib/rails/application_controller.rb index f8394b8e0a..a98e51fd28 100644 --- a/railties/lib/rails/application_controller.rb +++ b/railties/lib/rails/application_controller.rb @@ -2,7 +2,7 @@ class Rails::ApplicationController < ActionController::Base # :nodoc: self.view_paths = File.expand_path("../templates", __FILE__) layout "application" - protected + private def require_local! unless local_request? diff --git a/railties/lib/rails/cli.rb b/railties/lib/rails/cli.rb index 26ef3822ba..973b746068 100644 --- a/railties/lib/rails/cli.rb +++ b/railties/lib/rails/cli.rb @@ -7,9 +7,11 @@ Rails::AppLoader.exec_app require "rails/ruby_version_check" Signal.trap("INT") { puts; exit(1) } +require "rails/command" + if ARGV.first == "plugin" ARGV.shift - require "rails/commands/plugin" + Rails::Command.invoke :plugin, ARGV else - require "rails/commands/application" + Rails::Command.invoke :application, ARGV end diff --git a/railties/lib/rails/code_statistics.rb b/railties/lib/rails/code_statistics.rb index b3d88147a5..9c4bd16aad 100644 --- a/railties/lib/rails/code_statistics.rb +++ b/railties/lib/rails/code_statistics.rb @@ -106,7 +106,7 @@ class CodeStatistics #:nodoc: code = calculate_code tests = calculate_tests - puts " Code LOC: #{code} Test LOC: #{tests} Code to Test Ratio: 1:#{sprintf("%.1f", tests.to_f/code)}" + puts " Code LOC: #{code} Test LOC: #{tests} Code to Test Ratio: 1:#{sprintf("%.1f", tests.to_f / code)}" puts "" end end diff --git a/railties/lib/rails/command.rb b/railties/lib/rails/command.rb new file mode 100644 index 0000000000..ddb953543f --- /dev/null +++ b/railties/lib/rails/command.rb @@ -0,0 +1,99 @@ +require "active_support" +require "active_support/dependencies/autoload" +require "active_support/core_ext/enumerable" +require "active_support/core_ext/object/blank" +require "active_support/core_ext/hash/transform_values" + +require "thor" + +module Rails + module Command + extend ActiveSupport::Autoload + + autoload :Behavior + autoload :Base + + include Behavior + + class << self + def hidden_commands # :nodoc: + @hidden_commands ||= [] + end + + def environment # :nodoc: + ENV["RAILS_ENV"] || ENV["RACK_ENV"] || "development" + end + + # Receives a namespace, arguments and the behavior to invoke the command. + def invoke(namespace, args = [], **config) + namespace = namespace.to_s + namespace = "help" if namespace.blank? || Thor::HELP_MAPPINGS.include?(namespace) + namespace = "version" if %w( -v --version ).include? namespace + + if command = find_by_namespace(namespace) + command.perform(namespace, args, config) + else + find_by_namespace("rake").perform(namespace, args, config) + end + end + + # Rails finds namespaces similar to thor, it only adds one rule: + # + # Command names must end with "_command.rb". This is required because Rails + # looks in load paths and loads the command just before it's going to be used. + # + # find_by_namespace :webrat, :rails, :integration + # + # Will search for the following commands: + # + # "rails:webrat", "webrat:integration", "webrat" + # + # Notice that "rails:commands:webrat" could be loaded as well, what + # Rails looks for is the first and last parts of the namespace. + def find_by_namespace(name) # :nodoc: + lookups = [ name, "rails:#{name}" ] + + lookup(lookups) + + namespaces = subclasses.index_by(&:namespace) + namespaces[(lookups & namespaces.keys).first] + end + + # Returns the root of the Rails engine or app running the command. + def root + if defined?(ENGINE_ROOT) + Pathname.new(ENGINE_ROOT) + elsif defined?(APP_PATH) + Pathname.new(File.expand_path("../..", APP_PATH)) + end + end + + def print_commands # :nodoc: + sorted_groups.each { |b, n| print_list(b, n) } + end + + def sorted_groups # :nodoc: + lookup! + + groups = (subclasses - hidden_commands).group_by { |c| c.namespace.split(":").first } + groups.transform_values! { |commands| commands.flat_map(&:printing_commands).sort } + + rails = groups.delete("rails") + [[ "rails", rails ]] + groups.sort.to_a + end + + private + def command_type # :doc: + @command_type ||= "command" + end + + def lookup_paths # :doc: + @lookup_paths ||= %w( rails/commands commands ) + end + + def file_lookup_paths # :doc: + @file_lookup_paths ||= [ "{#{lookup_paths.join(',')}}", "**", "*_command.rb" ] + end + end + end +end diff --git a/railties/lib/rails/command/actions.rb b/railties/lib/rails/command/actions.rb new file mode 100644 index 0000000000..31b656ec31 --- /dev/null +++ b/railties/lib/rails/command/actions.rb @@ -0,0 +1,42 @@ +module Rails + module Command + module Actions + # Change to the application's path if there is no config.ru file in current directory. + # This allows us to run `rails server` from other directories, but still get + # the main config.ru and properly set the tmp directory. + def set_application_directory! + Dir.chdir(File.expand_path("../../", APP_PATH)) unless File.exist?(File.expand_path("config.ru")) + end + + if defined?(ENGINE_PATH) + def require_application_and_environment! + require ENGINE_PATH + end + + def load_tasks + Rake.application.init("rails") + Rake.application.load_rakefile + end + + def load_generators + engine = ::Rails::Engine.find(ENGINE_ROOT) + Rails::Generators.namespace = engine.railtie_namespace + engine.load_generators + end + else + def require_application_and_environment! + require APP_PATH + Rails.application.require_environment! + end + + def load_tasks + Rails.application.load_tasks + end + + def load_generators + Rails.application.load_generators + end + end + end + end +end diff --git a/railties/lib/rails/command/base.rb b/railties/lib/rails/command/base.rb new file mode 100644 index 0000000000..7ae190433a --- /dev/null +++ b/railties/lib/rails/command/base.rb @@ -0,0 +1,143 @@ +require "thor" +require "erb" + +require "active_support/core_ext/string/filters" +require "active_support/core_ext/string/inflections" + +require "rails/command/actions" + +module Rails + module Command + class Base < Thor + class Error < Thor::Error # :nodoc: + end + + include Actions + + class << self + # Returns true when the app is a Rails engine. + def engine? + defined?(ENGINE_ROOT) + end + + # Tries to get the description from a USAGE file one folder above the command + # root. + def desc(usage = nil, description = nil, options = {}) + if usage + super + else + @desc ||= ERB.new(File.read(usage_path)).result(binding) if usage_path + end + end + + # Convenience method to get the namespace from the class name. It's the + # same as Thor default except that the Command at the end of the class + # is removed. + def namespace(name = nil) + if name + super + else + @namespace ||= super.chomp("_command").sub(/:command:/, ":") + end + end + + # Convenience method to hide this command from the available ones when + # running rails command. + def hide_command! + Rails::Command.hidden_commands << self + end + + def inherited(base) #:nodoc: + super + + if base.name && base.name !~ /Base$/ + Rails::Command.subclasses << base + end + end + + def perform(command, args, config) # :nodoc: + command = nil if Thor::HELP_MAPPINGS.include?(args.first) + + dispatch(command, args.dup, nil, config) + end + + def printing_commands + namespace.sub(/^rails:/, "") + end + + def executable + "bin/rails #{command_name}" + end + + # Use Rails' default banner. + def banner(*) + "#{executable} #{arguments.map(&:usage).join(' ')} [options]".squish! + end + + # Sets the base_name taking into account the current class namespace. + # + # Rails::Command::TestCommand.base_name # => 'rails' + def base_name + @base_name ||= begin + if base = name.to_s.split("::").first + base.underscore + end + end + end + + # Return command name without namespaces. + # + # Rails::Command::TestCommand.command_name # => 'test' + def command_name + @command_name ||= begin + if command = name.to_s.split("::").last + command.chomp!("Command") + command.underscore + end + end + end + + # Path to lookup a USAGE description in a file. + def usage_path + if default_command_root + path = File.join(default_command_root, "USAGE") + path if File.exist?(path) + end + end + + # Default file root to place extra files a command might need, placed + # one folder above the command file. + # + # For a `Rails::Command::TestCommand` placed in `rails/command/test_command.rb` + # would return `rails/test`. + def default_command_root + path = File.expand_path(File.join("../commands", command_name), __dir__) + path if File.exist?(path) + end + + private + # Allow the command method to be called perform. + def create_command(meth) + if meth == "perform" + alias_method command_name, meth + else + # Prevent exception about command without usage. + # Some commands define their documentation differently. + @usage ||= "" + @desc ||= "" + + super + end + end + end + + def help + if command_name = self.class.command_name + self.class.command_help(shell, command_name) + else + super + end + end + end + end +end diff --git a/railties/lib/rails/command/behavior.rb b/railties/lib/rails/command/behavior.rb new file mode 100644 index 0000000000..4a92f72f16 --- /dev/null +++ b/railties/lib/rails/command/behavior.rb @@ -0,0 +1,123 @@ +require "active_support" + +module Rails + module Command + module Behavior #:nodoc: + extend ActiveSupport::Concern + + class_methods do + # Remove the color from output. + def no_color! + Thor::Base.shell = Thor::Shell::Basic + end + + # Track all command subclasses. + def subclasses + @subclasses ||= [] + end + + private + + # This code is based directly on the Text gem implementation. + # Copyright (c) 2006-2013 Paul Battley, Michael Neumann, Tim Fletcher. + # + # Returns a value representing the "cost" of transforming str1 into str2. + def levenshtein_distance(str1, str2) # :doc: + s = str1 + t = str2 + n = s.length + m = t.length + + return m if (0 == n) + return n if (0 == m) + + d = (0..m).to_a + x = nil + + # avoid duplicating an enumerable object in the loop + str2_codepoint_enumerable = str2.each_codepoint + + str1.each_codepoint.with_index do |char1, i| + e = i + 1 + + str2_codepoint_enumerable.with_index do |char2, j| + cost = (char1 == char2) ? 0 : 1 + x = [ + d[j + 1] + 1, # insertion + e + 1, # deletion + d[j] + cost # substitution + ].min + d[j] = e + e = x + end + + d[m] = x + end + + x + end + + # Prints a list of generators. + def print_list(base, namespaces) + return if namespaces.empty? + puts "#{base.camelize}:" + + namespaces.each do |namespace| + puts(" #{namespace}") + end + + puts + end + + # Receives namespaces in an array and tries to find matching generators + # in the load path. + def lookup(namespaces) + paths = namespaces_to_paths(namespaces) + + paths.each do |raw_path| + lookup_paths.each do |base| + path = "#{base}/#{raw_path}_#{command_type}" + + begin + require path + return + rescue LoadError => e + raise unless e.message =~ /#{Regexp.escape(path)}$/ + rescue Exception => e + warn "[WARNING] Could not load #{command_type} #{path.inspect}. Error: #{e.message}.\n#{e.backtrace.join("\n")}" + end + end + end + end + + # This will try to load any command in the load path to show in help. + def lookup! + $LOAD_PATH.each do |base| + Dir[File.join(base, *file_lookup_paths)].each do |path| + begin + path = path.sub("#{base}/", "") + require path + rescue Exception + # No problem + end + end + end + end + + # Convert namespaces to paths by replacing ":" for "/" and adding + # an extra lookup. For example, "rails:model" should be searched + # in both: "rails/model/model_generator" and "rails/model_generator". + def namespaces_to_paths(namespaces) + paths = [] + namespaces.each do |namespace| + pieces = namespace.split(":") + paths << pieces.dup.push(pieces.last).join("/") + paths << pieces.join("/") + end + paths.uniq! + paths + end + end + end + end +end diff --git a/railties/lib/rails/command/environment_argument.rb b/railties/lib/rails/command/environment_argument.rb new file mode 100644 index 0000000000..05eac34155 --- /dev/null +++ b/railties/lib/rails/command/environment_argument.rb @@ -0,0 +1,34 @@ +require "active_support" + +module Rails + module Command + module EnvironmentArgument #:nodoc: + extend ActiveSupport::Concern + + included do + argument :environment, optional: true, banner: "environment" + end + + private + def extract_environment_option_from_argument + if environment + self.options = options.merge(environment: acceptable_environment(environment)) + elsif !options[:environment] + self.options = options.merge(environment: Rails::Command.environment) + end + end + + def acceptable_environment(env = nil) + if available_environments.include? env + env + else + %w( production development test ).detect { |e| e =~ /^#{env}/ } || env + end + end + + def available_environments + Dir["config/environments/*.rb"].map { |fname| File.basename(fname, ".*") } + end + end + end +end diff --git a/railties/lib/rails/commands.rb b/railties/lib/rails/commands.rb index d64b355aec..fff0119c65 100644 --- a/railties/lib/rails/commands.rb +++ b/railties/lib/rails/commands.rb @@ -1,4 +1,4 @@ -ARGV << "--help" if ARGV.empty? +require "rails/command" aliases = { "g" => "generate", @@ -13,6 +13,4 @@ aliases = { command = ARGV.shift command = aliases[command] || command -require "rails/commands/commands_tasks" - -Rails::CommandsTasks.new(ARGV).run_command!(command) +Rails::Command.invoke command, ARGV diff --git a/railties/lib/rails/commands/application.rb b/railties/lib/rails/commands/application/application_command.rb index f6e7771cf3..7675d3b3d1 100644 --- a/railties/lib/rails/commands/application.rb +++ b/railties/lib/rails/commands/application/application_command.rb @@ -11,7 +11,19 @@ module Rails end end end -end -args = Rails::Generators::ARGVScrubber.new(ARGV).prepare! -Rails::Generators::AppGenerator.start args + module Command + class ApplicationCommand < Base # :nodoc: + hide_command! + + def help + perform # Punt help output to the generator. + end + + def perform(*args) + Rails::Generators::AppGenerator.start \ + Rails::Generators::ARGVScrubber.new(args).prepare! + end + end + end +end diff --git a/railties/lib/rails/commands/commands_tasks.rb b/railties/lib/rails/commands/commands_tasks.rb deleted file mode 100644 index 43f9dd38f3..0000000000 --- a/railties/lib/rails/commands/commands_tasks.rb +++ /dev/null @@ -1,136 +0,0 @@ -require "rails/commands/rake_proxy" -require "rails/commands/common_commands_tasks" -require "active_support/core_ext/string/strip" - -module Rails - # This is a class which takes in a rails command and initiates the appropriate - # initiation sequence. - # - # Warning: This class mutates ARGV because some commands require manipulating - # it before they are run. - class CommandsTasks # :nodoc: - include Rails::RakeProxy - include Rails::CommonCommandsTasks - - attr_reader :argv - - ADDITIONAL_COMMANDS = [ - [ "destroy", 'Undo code generated with "generate" (short-cut alias: "d")' ], - [ "plugin new", "Generates skeleton for developing a Rails plugin" ], - [ "runner", - 'Run a piece of code in the application environment (short-cut alias: "r")' ] - ] - - def initialize(argv) - @argv = argv - end - - def plugin - require_command!("plugin") - end - - def console - require_command!("console") - options = Rails::Console.parse_arguments(argv) - - # RAILS_ENV needs to be set before config/application is required - ENV["RAILS_ENV"] = options[:environment] if options[:environment] - - # shift ARGV so IRB doesn't freak - shift_argv! - - require_application_and_environment! - Rails::Console.start(Rails.application, options) - end - - def server - set_application_directory! - require_command!("server") - - Rails::Server.new.tap do |server| - # We need to require application after the server sets environment, - # otherwise the --environment option given to the server won't propagate. - require APP_PATH - Dir.chdir(Rails.application.root) - server.start - end - end - - def dbconsole - require_command!("dbconsole") - Rails::DBConsole.start - end - - def runner - require_command!("runner") - end - - def new - if %w(-h --help).include?(argv.first) - require_command!("application") - else - exit_with_initialization_warning! - end - end - - private - - def exit_with_initialization_warning! - puts "Can't initialize a new Rails application within the directory of another, please change to a non-Rails directory first.\n" - puts "Type 'rails' for help." - exit(1) - end - - def shift_argv! - argv.shift if argv.first && argv.first[0] != "-" - end - - # Change to the application's path if there is no config.ru file in current directory. - # This allows us to run `rails server` from other directories, but still get - # the main config.ru and properly set the tmp directory. - def set_application_directory! - Dir.chdir(File.expand_path("../../", APP_PATH)) unless File.exist?(File.expand_path("config.ru")) - end - - def commands - ADDITIONAL_COMMANDS + formatted_rake_tasks - end - - def command_whitelist - %w(plugin generate destroy console server dbconsole runner new version help test) - end - - def help_message - <<-EOT.strip_heredoc - Usage: rails COMMAND [ARGS] - - The most common rails commands are: - generate Generate new code (short-cut alias: "g") - console Start the Rails console (short-cut alias: "c") - server Start the Rails server (short-cut alias: "s") - test Run tests (short-cut alias: "t") - dbconsole Start a console for the database specified in config/database.yml - (short-cut alias: "db") - new Create a new Rails application. "rails new my_app" creates a - new application called MyApp in "./my_app" - - All commands can be run with -h (or --help) for more information. - - In addition to those commands, there are: - EOT - end - - def require_application_and_environment! - require APP_PATH - Rails.application.require_environment! - end - - def load_tasks - Rails.application.load_tasks - end - - def load_generators - Rails.application.load_generators - end - end -end diff --git a/railties/lib/rails/commands/common_commands_tasks.rb b/railties/lib/rails/commands/common_commands_tasks.rb deleted file mode 100644 index c1484d7ae2..0000000000 --- a/railties/lib/rails/commands/common_commands_tasks.rb +++ /dev/null @@ -1,68 +0,0 @@ -module Rails - module CommonCommandsTasks # :nodoc: - def run_command!(command) - command = parse_command(command) - - if command_whitelist.include?(command) - send(command) - else - run_rake_task(command) - end - end - - def generate - generate_or_destroy(:generate) - end - - def destroy - generate_or_destroy(:destroy) - end - - def test - require_command!("test") - end - - def version - argv.unshift "--version" - require_command!("application") - end - - def help - write_help_message - write_commands(commands) - end - - private - - def generate_or_destroy(command) - require "rails/generators" - require_application_and_environment! - load_generators - require_command!(command) - end - - def require_command!(command) - require "rails/commands/#{command}" - end - - def write_help_message - puts help_message - end - - def write_commands(commands) - width = commands.map { |name, _| name.size }.max || 10 - commands.each { |command| printf(" %-#{width}s %s\n", *command) } - end - - def parse_command(command) - case command - when "--version", "-v" - "version" - when "--help", "-h" - "help" - else - command - end - end - end -end diff --git a/railties/lib/rails/commands/console.rb b/railties/lib/rails/commands/console/console_command.rb index e00887323e..62e3aa19df 100644 --- a/railties/lib/rails/commands/console.rb +++ b/railties/lib/rails/commands/console/console_command.rb @@ -1,12 +1,10 @@ -require "optparse" require "irb" require "irb/completion" -require "rails/commands/console_helper" + +require "rails/command/environment_argument" module Rails class Console - include ConsoleHelper - module BacktraceCleaner def filter_backtrace(bt) if result = super @@ -15,26 +13,13 @@ module Rails end end - class << self - def parse_arguments(arguments) - options = {} - - OptionParser.new do |opt| - opt.banner = "Usage: rails console [environment] [options]" - opt.on("-s", "--sandbox", "Rollback database modifications on exit.") { |v| options[:sandbox] = v } - opt.on("-e", "--environment=name", String, - "Specifies the environment to run this console under (test/development/production).", - "Default: development") { |v| options[:environment] = v.strip } - opt.parse!(arguments) - end - - set_options_env(arguments, options) - end + def self.start(*args) + new(*args).start end attr_reader :options, :app, :console - def initialize(app, options={}) + def initialize(app, options = {}) @app = app @options = options @@ -53,7 +38,7 @@ module Rails end def environment - options[:environment] ||= super + options[:environment] end alias_method :environment?, :environment @@ -77,4 +62,28 @@ module Rails console.start end end + + module Command + class ConsoleCommand < Base # :nodoc: + include EnvironmentArgument + + class_option :sandbox, aliases: "-s", type: :boolean, default: false, + desc: "Rollback database modifications on exit." + + class_option :environment, aliases: "-e", type: :string, + desc: "Specifies the environment to run this console under (test/development/production)." + + def perform + extract_environment_option_from_argument + + # RAILS_ENV needs to be set before config/application is required. + ENV["RAILS_ENV"] = options[:environment] + + ARGV.clear # Clear ARGV so IRB doesn't freak. + + require_application_and_environment! + Rails::Console.start(Rails.application, options) + end + end + end end diff --git a/railties/lib/rails/commands/console_helper.rb b/railties/lib/rails/commands/console_helper.rb deleted file mode 100644 index 0b7f1c4249..0000000000 --- a/railties/lib/rails/commands/console_helper.rb +++ /dev/null @@ -1,34 +0,0 @@ -require "active_support/concern" - -module Rails - module ConsoleHelper # :nodoc: - extend ActiveSupport::Concern - - module ClassMethods - def start(*args) - new(*args).start - end - - private - def set_options_env(arguments, options) - if arguments.first && arguments.first[0] != "-" - env = arguments.first - if available_environments.include? env - options[:environment] = env - else - options[:environment] = %w(production development test).detect { |e| e =~ /^#{env}/ } || env - end - end - options - end - - def available_environments - Dir["config/environments/*.rb"].map { |fname| File.basename(fname, ".*") } - end - end - - def environment - ENV["RAILS_ENV"] || ENV["RACK_ENV"] || "development" - end - end -end diff --git a/railties/lib/rails/commands/dbconsole.rb b/railties/lib/rails/commands/dbconsole/dbconsole_command.rb index 66b7a14f16..588fb06b15 100644 --- a/railties/lib/rails/commands/dbconsole.rb +++ b/railties/lib/rails/commands/dbconsole/dbconsole_command.rb @@ -1,58 +1,17 @@ -require "erb" -require "yaml" -require "optparse" -require "rails/commands/console_helper" +require "rails/command/environment_argument" module Rails class DBConsole - include ConsoleHelper - - attr_reader :arguments - - class << self - def parse_arguments(arguments) - options = {} - - OptionParser.new do |opt| - opt.banner = "Usage: rails dbconsole [environment] [options]" - opt.on("-p", "--include-password", "Automatically provide the password from database.yml") do |v| - options["include_password"] = true - end - - opt.on("--mode [MODE]", ["html", "list", "line", "column"], - "Automatically put the sqlite3 database in the specified mode (html, list, line, column).") do |mode| - options["mode"] = mode - end - - opt.on("--header") do |h| - options["header"] = h - end - - opt.on("-h", "--help", "Show this help message.") do - puts opt - exit - end - - opt.on("-e", "--environment=name", String, - "Specifies the environment to run this console under (test/development/production).", - "Default: development" - ) { |v| options[:environment] = v.strip } - - opt.parse!(arguments) - abort opt.to_s unless (0..1).include?(arguments.size) - end - - set_options_env(arguments, options) - end + def self.start(*args) + new(*args).start end - def initialize(arguments = ARGV) - @arguments = arguments + def initialize(options = {}) + @options = options end def start - options = self.class.parse_arguments(arguments) - ENV["RAILS_ENV"] = options[:environment] || environment + ENV["RAILS_ENV"] = @options[:environment] || environment case config["adapter"] when /^(jdbc)?mysql/ @@ -69,7 +28,7 @@ module Rails "sslkey" => "--ssl-key" }.map { |opt, arg| "#{arg}=#{config[opt]}" if config[opt] }.compact - if config["password"] && options["include_password"] + if config["password"] && @options["include_password"] args << "--password=#{config['password']}" elsif config["password"] && !config["password"].to_s.empty? args << "-p" @@ -83,14 +42,14 @@ module Rails ENV["PGUSER"] = config["username"] if config["username"] ENV["PGHOST"] = config["host"] if config["host"] ENV["PGPORT"] = config["port"].to_s if config["port"] - ENV["PGPASSWORD"] = config["password"].to_s if config["password"] && options["include_password"] + ENV["PGPASSWORD"] = config["password"].to_s if config["password"] && @options["include_password"] find_cmd_and_exec("psql", config["database"]) when "sqlite3" args = [] - args << "-#{options['mode']}" if options["mode"] - args << "-header" if options["header"] + args << "-#{@options['mode']}" if @options["mode"] + args << "-header" if @options["header"] args << File.expand_path(config["database"], Rails.respond_to?(:root) ? Rails.root : nil) find_cmd_and_exec("sqlite3", *args) @@ -100,7 +59,7 @@ module Rails if config["username"] logon = config["username"] - logon << "/#{config['password']}" if config["password"] && options["include_password"] + logon << "/#{config['password']}" if config["password"] && @options["include_password"] logon << "@#{config['database']}" if config["database"] end @@ -137,17 +96,17 @@ module Rails end def environment - Rails.respond_to?(:env) ? Rails.env : super + Rails.respond_to?(:env) ? Rails.env : Rails::Command.environment end - protected - def configurations + private + def configurations # :doc: require APP_PATH ActiveRecord::Base.configurations = Rails.application.config.database_configuration ActiveRecord::Base.configurations end - def find_cmd_and_exec(commands, *args) + def find_cmd_and_exec(commands, *args) # :doc: commands = Array(commands) dirs_on_path = ENV["PATH"].to_s.split(File::PATH_SEPARATOR) @@ -170,4 +129,27 @@ module Rails end end end + + module Command + class DbconsoleCommand < Base # :nodoc: + include EnvironmentArgument + + class_option :include_password, aliases: "-p", type: :boolean, + desc: "Automatically provide the password from database.yml" + + class_option :mode, enum: %w( html list line column ), type: :string, + desc: "Automatically put the sqlite3 database in the specified mode (html, list, line, column)." + + class_option :header, type: :string + + class_option :environment, aliases: "-e", type: :string, + desc: "Specifies the environment to run this console under (test/development/production)." + + def perform + extract_environment_option_from_argument + + Rails::DBConsole.start(options) + end + end + end end diff --git a/railties/lib/rails/commands/destroy.rb b/railties/lib/rails/commands/destroy.rb deleted file mode 100644 index 71c8c5e526..0000000000 --- a/railties/lib/rails/commands/destroy.rb +++ /dev/null @@ -1,11 +0,0 @@ -require "rails/generators" - -#if no argument/-h/--help is passed to rails destroy command, then -#it generates the help associated. -if [nil, "-h", "--help"].include?(ARGV.first) - Rails::Generators.help "destroy" - exit -end - -name = ARGV.shift -Rails::Generators.invoke name, ARGV, behavior: :revoke, destination_root: Rails.root diff --git a/railties/lib/rails/commands/destroy/destroy_command.rb b/railties/lib/rails/commands/destroy/destroy_command.rb new file mode 100644 index 0000000000..5b552b2070 --- /dev/null +++ b/railties/lib/rails/commands/destroy/destroy_command.rb @@ -0,0 +1,21 @@ +require "rails/generators" + +module Rails + module Command + class DestroyCommand < Base # :nodoc: + def help + Rails::Generators.help self.class.command_name + end + + def perform(*) + generator = args.shift + return help unless generator + + require_application_and_environment! + Rails.application.load_generators + + Rails::Generators.invoke generator, args, behavior: :revoke, destination_root: Rails.root + end + end + end +end diff --git a/railties/lib/rails/commands/generate.rb b/railties/lib/rails/commands/generate.rb deleted file mode 100644 index ba6f14073e..0000000000 --- a/railties/lib/rails/commands/generate.rb +++ /dev/null @@ -1,13 +0,0 @@ -require "rails/generators" - -#if no argument/-h/--help is passed to rails generate command, then -#it generates the help associated. -if [nil, "-h", "--help"].include?(ARGV.first) - Rails::Generators.help "generate" - exit -end - -name = ARGV.shift - -root = defined?(ENGINE_ROOT) ? ENGINE_ROOT : Rails.root -Rails::Generators.invoke name, ARGV, behavior: :invoke, destination_root: root diff --git a/railties/lib/rails/commands/generate/generate_command.rb b/railties/lib/rails/commands/generate/generate_command.rb new file mode 100644 index 0000000000..aa8dab71b0 --- /dev/null +++ b/railties/lib/rails/commands/generate/generate_command.rb @@ -0,0 +1,23 @@ +require "rails/generators" + +module Rails + module Command + class GenerateCommand < Base # :nodoc: + def help + Rails::Generators.help self.class.command_name + end + + def perform(*) + generator = args.shift + return help unless generator + + require_application_and_environment! + load_generators + + ARGV.shift + + Rails::Generators.invoke generator, args, behavior: :invoke, destination_root: Rails::Command.root + end + end + end +end diff --git a/railties/lib/rails/commands/help/USAGE b/railties/lib/rails/commands/help/USAGE new file mode 100644 index 0000000000..348f41861f --- /dev/null +++ b/railties/lib/rails/commands/help/USAGE @@ -0,0 +1,27 @@ +Usage: bin/rails COMMAND [args] [options] +<% if engine? %> +The common Rails commands available for engines are: + generate Generate new code (short-cut alias: "g") + destroy Undo code generated with "generate" (short-cut alias: "d") + test Run tests (short-cut alias: "t") + +All commands can be run with -h for more information. + +If you want to run any commands that need to be run in context +of the application, like `bin/rails server` or `bin/rails console`, +you should do it from the application's directory (typically test/dummy). +<% else %> +The most common rails commands are: + generate Generate new code (short-cut alias: "g") + console Start the Rails console (short-cut alias: "c") + server Start the Rails server (short-cut alias: "s") + test Run tests (short-cut alias: "t") + dbconsole Start a console for the database specified in config/database.yml + (short-cut alias: "db") + new Create a new Rails application. "rails new my_app" creates a + new application called MyApp in "./my_app" + +All commands can be run with -h (or --help) for more information. +<% end %> +In addition to those commands, there are: + diff --git a/railties/lib/rails/commands/help/help_command.rb b/railties/lib/rails/commands/help/help_command.rb new file mode 100644 index 0000000000..90d37217fc --- /dev/null +++ b/railties/lib/rails/commands/help/help_command.rb @@ -0,0 +1,13 @@ +module Rails + module Command + class HelpCommand < Base # :nodoc: + hide_command! + + def help(*) + puts self.class.desc + + Rails::Command.print_commands + end + end + end +end diff --git a/railties/lib/rails/commands/new/new_command.rb b/railties/lib/rails/commands/new/new_command.rb new file mode 100644 index 0000000000..74d1fa5021 --- /dev/null +++ b/railties/lib/rails/commands/new/new_command.rb @@ -0,0 +1,15 @@ +module Rails + module Command + class NewCommand < Base # :nodoc: + def help + Rails::Command.invoke :application, [ "--help" ] + end + + def perform(*) + puts "Can't initialize a new Rails application within the directory of another, please change to a non-Rails directory first.\n" + puts "Type 'rails' for help." + exit 1 + end + end + end +end diff --git a/railties/lib/rails/commands/plugin.rb b/railties/lib/rails/commands/plugin.rb deleted file mode 100644 index 60653a2cee..0000000000 --- a/railties/lib/rails/commands/plugin.rb +++ /dev/null @@ -1,24 +0,0 @@ -if ARGV.first != "new" - ARGV[0] = "--help" -else - ARGV.shift - unless ARGV.delete("--no-rc") - customrc = ARGV.index { |x| x.include?("--rc=") } - railsrc = if customrc - File.expand_path(ARGV.delete_at(customrc).gsub(/--rc=/, "")) - else - File.join(File.expand_path("~"), ".railsrc") - end - - if File.exist?(railsrc) - extra_args_string = File.read(railsrc) - extra_args = extra_args_string.split(/\n+/).flat_map(&:split) - puts "Using #{extra_args.join(" ")} from #{railsrc}" - ARGV.insert(1, *extra_args) - end - end -end - -require "rails/generators" -require "rails/generators/rails/plugin/plugin_generator" -Rails::Generators::PluginGenerator.start diff --git a/railties/lib/rails/commands/plugin/plugin_command.rb b/railties/lib/rails/commands/plugin/plugin_command.rb new file mode 100644 index 0000000000..b40ab006af --- /dev/null +++ b/railties/lib/rails/commands/plugin/plugin_command.rb @@ -0,0 +1,43 @@ +module Rails + module Command + class PluginCommand < Base # :nodoc: + hide_command! + + def help + run_plugin_generator %w( --help ) + end + + def self.banner(*) # :nodoc: + "#{executable} new [options]" + end + + class_option :rc, type: :string, default: File.join("~", ".railsrc"), + desc: "Initialize the plugin command with previous defaults. Uses .railsrc in your home directory by default." + + class_option :no_rc, desc: "Skip evaluating .railsrc." + + def perform(type = nil, *plugin_args) + plugin_args << "--help" unless type == "new" + + unless options.key?("no_rc") # Thor's not so indifferent access hash. + railsrc = File.expand_path(options[:rc]) + + if File.exist?(railsrc) + extra_args = File.read(railsrc).split(/\n+/).flat_map(&:split) + puts "Using #{extra_args.join(" ")} from #{railsrc}" + plugin_args.insert(1, *extra_args) + end + end + + run_plugin_generator plugin_args + end + + private + def run_plugin_generator(plugin_args) + require "rails/generators" + require "rails/generators/rails/plugin/plugin_generator" + Rails::Generators::PluginGenerator.start plugin_args + end + end + end +end diff --git a/railties/lib/rails/commands/rake/rake_command.rb b/railties/lib/rails/commands/rake/rake_command.rb new file mode 100644 index 0000000000..075b1fd23d --- /dev/null +++ b/railties/lib/rails/commands/rake/rake_command.rb @@ -0,0 +1,49 @@ +module Rails + module Command + class RakeCommand < Base # :nodoc: + extend Rails::Command::Actions + + namespace "rake" + + class << self + def printing_commands + formatted_rake_tasks.map(&:first) + end + + def perform(task, *) + require_rake + + ARGV.unshift(task) # Prepend the task, so Rake knows how to run it. + + Rake.application.standard_exception_handling do + Rake.application.init("rails") + Rake.application.load_rakefile + Rake.application.top_level + end + end + + private + def rake_tasks + require_rake + + return @rake_tasks if defined?(@rake_tasks) + + require_application_and_environment! + + Rake::TaskManager.record_task_metadata = true + Rake.application.instance_variable_set(:@name, "rails") + load_tasks + @rake_tasks = Rake.application.tasks.select(&:comment) + end + + def formatted_rake_tasks + rake_tasks.map { |t| [ t.name_with_args, t.comment ] } + end + + def require_rake + require "rake" # Defer booting Rake until we know it's needed. + end + end + end + end +end diff --git a/railties/lib/rails/commands/rake_proxy.rb b/railties/lib/rails/commands/rake_proxy.rb deleted file mode 100644 index f8da71831a..0000000000 --- a/railties/lib/rails/commands/rake_proxy.rb +++ /dev/null @@ -1,41 +0,0 @@ -require "active_support" - -module Rails - module RakeProxy #:nodoc: - private - def run_rake_task(command) - require_rake - - ARGV.unshift(command) # Prepend the command, so Rake knows how to run it. - - Rake.application.standard_exception_handling do - Rake.application.init("rails") - Rake.application.load_rakefile - Rake.application.top_level - end - end - - def rake_tasks - require_rake - - return @rake_tasks if defined?(@rake_tasks) - - ActiveSupport::Deprecation.silence do - require_application_and_environment! - end - - Rake::TaskManager.record_task_metadata = true - Rake.application.instance_variable_set(:@name, "rails") - load_tasks - @rake_tasks = Rake.application.tasks.select(&:comment) - end - - def formatted_rake_tasks - rake_tasks.map { |t| [ t.name_with_args, t.comment ] } - end - - def require_rake - require "rake" # Defer booting Rake until we know it's needed. - end - end -end diff --git a/railties/lib/rails/commands/runner.rb b/railties/lib/rails/commands/runner.rb deleted file mode 100644 index b74addf587..0000000000 --- a/railties/lib/rails/commands/runner.rb +++ /dev/null @@ -1,71 +0,0 @@ -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" -end - -ARGV.clone.options do |opts| - opts.banner = "Usage: rails runner [options] [<'Some.ruby(code)'> | <filename.rb>]" - - opts.separator "" - - opts.on("-e", "--environment=name", String, - "Specifies the environment for the runner to operate under (test/development/production).", - "Default: development") { |v| options[:environment] = v } - - opts.separator "" - - opts.on("-h", "--help", - "Show this help message.") { $stdout.puts opts; exit } - - opts.separator "" - opts.separator "Examples: " - - opts.separator " rails runner 'puts Rails.env'" - opts.separator " This runs the code `puts Rails.env` after loading the app" - opts.separator "" - opts.separator " rails runner path/to/filename.rb" - opts.separator " This runs the Ruby file located at `path/to/filename.rb` after loading the app" - - if RbConfig::CONFIG["host_os"] !~ /mswin|mingw/ - 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(command)}" - opts.separator "" - opts.separator " Product.all.each { |p| p.price *= 2 ; p.save! }" - opts.separator " -------------------------------------------------------------" - end - - opts.order! { |o| code_or_file ||= o } rescue retry -end - -ARGV.delete(code_or_file) - -ENV["RAILS_ENV"] = options[:environment] - -require APP_PATH -Rails.application.require_environment! -Rails.application.load_runner - -if code_or_file.nil? - $stderr.puts "Run '#{command} -h' for help." - exit 1 -elsif File.exist?(code_or_file) - $0 = code_or_file - Kernel.load code_or_file -else - begin - eval(code_or_file, binding, __FILE__, __LINE__) - rescue SyntaxError, NameError => e - $stderr.puts "Please specify a valid ruby command or the path of a script to run." - $stderr.puts "Run '#{command} -h' for help." - $stderr.puts - $stderr.puts e - exit 1 - end -end diff --git a/railties/lib/rails/commands/runner/USAGE b/railties/lib/rails/commands/runner/USAGE new file mode 100644 index 0000000000..b2a6e8493d --- /dev/null +++ b/railties/lib/rails/commands/runner/USAGE @@ -0,0 +1,17 @@ +Examples: + +Run `puts Rails.env` after loading the app: + + <%= executable %> 'puts Rails.env' + +Run the Ruby file located at `path/to/filename.rb` after loading the app: + + <%= executable %> path/to/filename.rb + +<% unless Gem.win_platform? %> +You can also use the runner command as a shebang line for your executables: + + #!/usr/bin/env <%= File.expand_path(executable) %> + + Product.all.each { |p| p.price *= 2 ; p.save! } +<% end %> diff --git a/railties/lib/rails/commands/runner/runner_command.rb b/railties/lib/rails/commands/runner/runner_command.rb new file mode 100644 index 0000000000..4989a7837d --- /dev/null +++ b/railties/lib/rails/commands/runner/runner_command.rb @@ -0,0 +1,46 @@ +module Rails + module Command + class RunnerCommand < Base # :nodoc: + class_option :environment, aliases: "-e", type: :string, + default: Rails::Command.environment.dup, + desc: "The environment for the runner to operate under (test/development/production)" + + def help + super + puts self.class.desc + end + + def self.banner(*) + "#{super} [<'Some.ruby(code)'> | <filename.rb>]" + end + + def perform(code_or_file = nil, *file_argv) + unless code_or_file + help + exit 1 + end + + ENV["RAILS_ENV"] = options[:environment] + + require_application_and_environment! + Rails.application.load_runner + + if File.exist?(code_or_file) + $0 = code_or_file + ARGV.replace(file_argv) + Kernel.load code_or_file + else + begin + eval(code_or_file, binding, __FILE__, __LINE__) + rescue SyntaxError, NameError => error + $stderr.puts "Please specify a valid ruby command or the path of a script to run." + $stderr.puts "Run '#{self.class.executable} -h' for help." + $stderr.puts + $stderr.puts error + exit 1 + end + end + end + end + end +end diff --git a/railties/lib/rails/commands/server.rb b/railties/lib/rails/commands/server.rb deleted file mode 100644 index 1eabf3fef3..0000000000 --- a/railties/lib/rails/commands/server.rb +++ /dev/null @@ -1,139 +0,0 @@ -require "fileutils" -require "optparse" -require "action_dispatch" -require "rails" -require "rails/dev_caching" - -module Rails - class Server < ::Rack::Server - class Options - DEFAULT_PID_PATH = File.expand_path("tmp/pids/server.pid").freeze - - def parse!(args) - args, options = args.dup, {} - - option_parser(options).parse! args - - options[:log_stdout] = options[:daemonize].blank? && (options[:environment] || Rails.env) == "development" - options[:server] = args.shift - options - end - - private - - def option_parser(options) - OptionParser.new do |opts| - opts.banner = "Usage: rails server [puma, thin etc] [options]" - opts.on("-p", "--port=port", Integer, - "Runs Rails on the specified port.", "Default: 3000") { |v| options[:Port] = v } - opts.on("-b", "--binding=IP", String, - "Binds Rails to the specified IP.", "Default: localhost") { |v| options[:Host] = v } - opts.on("-c", "--config=file", String, - "Uses a custom rackup configuration.") { |v| options[:config] = v } - opts.on("-d", "--daemon", "Runs server as a Daemon.") { options[:daemonize] = true } - opts.on("-e", "--environment=name", String, - "Specifies the environment to run this server under (test/development/production).", - "Default: development") { |v| options[:environment] = v } - opts.on("-P", "--pid=pid", String, - "Specifies the PID file.", - "Default: tmp/pids/server.pid") { |v| options[:pid] = v } - opts.on("-C", "--[no-]dev-caching", - "Specifies whether to perform caching in development.", - "true or false") { |v| options[:caching] = v } - - opts.separator "" - - opts.on("-h", "--help", "Shows this help message.") { puts opts; exit } - end - end - end - - def initialize(*) - super - set_environment - end - - # TODO: this is no longer required but we keep it for the moment to support older config.ru files. - def app - @app ||= begin - app = super - app.respond_to?(:to_app) ? app.to_app : app - end - end - - def opt_parser - Options.new - end - - def set_environment - ENV["RAILS_ENV"] ||= options[:environment] - end - - def start - print_boot_information - trap(:INT) { exit } - create_tmp_directories - setup_dev_caching - log_to_stdout if options[:log_stdout] - - super - ensure - # The '-h' option calls exit before @options is set. - # If we call 'options' with it unset, we get double help banners. - puts "Exiting" unless @options && options[:daemonize] - end - - def middleware - Hash.new([]) - end - - def default_options - super.merge( - Port: ENV.fetch("PORT", 3000).to_i, - Host: ENV.fetch("HOST", "localhost").dup, - DoNotReverseLookup: true, - environment: (ENV["RAILS_ENV"] || ENV["RACK_ENV"] || "development").dup, - daemonize: false, - caching: nil, - pid: Options::DEFAULT_PID_PATH, - restart_cmd: restart_command) - end - - private - - def setup_dev_caching - if options[:environment] == "development" - Rails::DevCaching.enable_by_argument(options[:caching]) - end - end - - def print_boot_information - url = "#{options[:SSLEnable] ? 'https' : 'http'}://#{options[:Host]}:#{options[:Port]}" - 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" - end - - def create_tmp_directories - %w(cache pids sockets).each do |dir_to_make| - FileUtils.mkdir_p(File.join(Rails.root, "tmp", dir_to_make)) - end - end - - def log_to_stdout - wrapped_app # touch the app so the logger is set up - - console = ActiveSupport::Logger.new(STDOUT) - console.formatter = Rails.logger.formatter - console.level = Rails.logger.level - - unless ActiveSupport::Logger.logger_outputs_to?(Rails.logger, STDOUT) - 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/commands/server/server_command.rb b/railties/lib/rails/commands/server/server_command.rb new file mode 100644 index 0000000000..15c636103b --- /dev/null +++ b/railties/lib/rails/commands/server/server_command.rb @@ -0,0 +1,173 @@ +require "fileutils" +require "optparse" +require "action_dispatch" +require "rails" +require "rails/dev_caching" + +module Rails + class Server < ::Rack::Server + class Options + def parse!(args) + Rails::Command::ServerCommand.new([], args).server_options + end + end + + def initialize(options = nil) + @default_options = options || {} + super(@default_options) + set_environment + end + + # TODO: this is no longer required but we keep it for the moment to support older config.ru files. + def app + @app ||= begin + app = super + app.respond_to?(:to_app) ? app.to_app : app + end + end + + def opt_parser + Options.new + end + + def set_environment + ENV["RAILS_ENV"] ||= options[:environment] + end + + def start + print_boot_information + trap(:INT) { exit } + create_tmp_directories + setup_dev_caching + log_to_stdout if options[:log_stdout] + + super + ensure + # The '-h' option calls exit before @options is set. + # If we call 'options' with it unset, we get double help banners. + puts "Exiting" unless @options && options[:daemonize] + end + + def middleware + Hash.new([]) + end + + def default_options + super.merge(@default_options) + end + + private + def setup_dev_caching + if options[:environment] == "development" + Rails::DevCaching.enable_by_argument(options[:caching]) + end + end + + def print_boot_information + url = "#{options[:SSLEnable] ? 'https' : 'http'}://#{options[:Host]}:#{options[:Port]}" + 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" + end + + def create_tmp_directories + %w(cache pids sockets).each do |dir_to_make| + FileUtils.mkdir_p(File.join(Rails.root, "tmp", dir_to_make)) + end + end + + def log_to_stdout + wrapped_app # touch the app so the logger is set up + + console = ActiveSupport::Logger.new(STDOUT) + console.formatter = Rails.logger.formatter + console.level = Rails.logger.level + + unless ActiveSupport::Logger.logger_outputs_to?(Rails.logger, STDOUT) + Rails.logger.extend(ActiveSupport::Logger.broadcast(console)) + end + end + + def restart_command + "bin/rails server #{ARGV.join(' ')}" + end + end + + module Command + class ServerCommand < Base # :nodoc: + DEFAULT_PID_PATH = File.expand_path("tmp/pids/server.pid").freeze + + class_option :port, aliases: "-p", type: :numeric, + desc: "Runs Rails on the specified port.", banner: :port, default: 3000 + class_option :binding, aliases: "-b", type: :string, default: "localhost", + desc: "Binds Rails to the specified IP.", banner: :IP + class_option :config, aliases: "-c", type: :string, default: "config.ru", + desc: "Uses a custom rackup configuration.", banner: :file + class_option :daemon, aliases: "-d", type: :boolean, default: false, + desc: "Runs server as a Daemon." + class_option :environment, aliases: "-e", type: :string, + desc: "Specifies the environment to run this server under (development/test/production).", banner: :name + class_option :pid, aliases: "-P", type: :string, default: DEFAULT_PID_PATH, + desc: "Specifies the PID file." + class_option "dev-caching", aliases: "-C", type: :boolean, default: nil, + desc: "Specifies whether to perform caching in development." + + def initialize(args = [], local_options = {}, config = {}) + @original_options = local_options + super + @server = self.args.shift + @log_stdout = options[:daemon].blank? && (options[:environment] || Rails.env) == "development" + end + + def perform + set_application_directory! + Rails::Server.new(server_options).tap do |server| + # Require application after server sets environment to propagate + # the --environment option. + require APP_PATH + Dir.chdir(Rails.application.root) + server.start + end + end + + no_commands do + def server_options + { + server: @server, + log_stdout: @log_stdout, + Port: port, + Host: host, + DoNotReverseLookup: true, + config: options[:config], + environment: environment, + daemonize: options[:daemon], + pid: options[:pid], + caching: options["dev-caching"], + restart_cmd: restart_command + } + end + end + + private + def port + ENV.fetch("PORT", options[:port]).to_i + end + + def host + ENV.fetch("HOST", options[:binding]) + end + + def environment + options[:environment] || Rails::Command.environment + end + + def restart_command + "bin/rails server #{@server} #{@original_options.join(" ")}" + end + + def self.banner(*) + "rails server [puma, thin etc] [options]" + end + end + end +end diff --git a/railties/lib/rails/commands/test.rb b/railties/lib/rails/commands/test.rb deleted file mode 100644 index 219c2fa4e0..0000000000 --- a/railties/lib/rails/commands/test.rb +++ /dev/null @@ -1,9 +0,0 @@ -require "rails/test_unit/minitest_plugin" - -if defined?(ENGINE_ROOT) - $: << File.expand_path("test", ENGINE_ROOT) -else - $: << File.expand_path("../../test", APP_PATH) -end - -exit Minitest.run(ARGV) diff --git a/railties/lib/rails/commands/test/test_command.rb b/railties/lib/rails/commands/test/test_command.rb new file mode 100644 index 0000000000..7bf8f61137 --- /dev/null +++ b/railties/lib/rails/commands/test/test_command.rb @@ -0,0 +1,20 @@ +require "rails/command" +require "rails/test_unit/minitest_plugin" + +module Rails + module Command + class TestCommand < Base # :nodoc: + def help + perform # Hand over help printing to minitest. + end + + def perform(*) + $LOAD_PATH << Rails::Command.root.join("test") + + Minitest.run_via[:rails] = true + + require "active_support/testing/autorun" + end + end + end +end diff --git a/railties/lib/rails/commands/version/version_command.rb b/railties/lib/rails/commands/version/version_command.rb new file mode 100644 index 0000000000..ac745594ee --- /dev/null +++ b/railties/lib/rails/commands/version/version_command.rb @@ -0,0 +1,9 @@ +module Rails + module Command + class VersionCommand < Base # :nodoc: + def perform + Rails::Command.invoke :application, [ "--version" ] + end + end + end +end diff --git a/railties/lib/rails/configuration.rb b/railties/lib/rails/configuration.rb index 7dfab969e8..fc7d4909f6 100644 --- a/railties/lib/rails/configuration.rb +++ b/railties/lib/rails/configuration.rb @@ -91,8 +91,8 @@ module Rails attr_reader :hidden_namespaces def initialize - @aliases = Hash.new { |h,k| h[k] = {} } - @options = Hash.new { |h,k| h[k] = {} } + @aliases = Hash.new { |h, k| h[k] = {} } + @options = Hash.new { |h, k| h[k] = {} } @fallbacks = {} @templates = [] @colorize_logging = true diff --git a/railties/lib/rails/console/app.rb b/railties/lib/rails/console/app.rb index 541d5e3dad..affadc8e09 100644 --- a/railties/lib/rails/console/app.rb +++ b/railties/lib/rails/console/app.rb @@ -5,7 +5,7 @@ module Rails module ConsoleMethods # reference the global "app" instance, created on demand. To recreate the # instance, pass a non-false value as the parameter. - def app(create=false) + def app(create = false) @app_integration_instance = nil if create @app_integration_instance ||= new_session do |sess| sess.host! "www.example.com" @@ -27,7 +27,7 @@ module Rails end # reloads the environment - def reload!(print=true) + def reload!(print = true) puts "Reloading..." if print Rails.application.reloader.reload! true diff --git a/railties/lib/rails/engine.rb b/railties/lib/rails/engine.rb index 86d66afddb..2dd1fb3273 100644 --- a/railties/lib/rails/engine.rb +++ b/railties/lib/rails/engine.rb @@ -337,7 +337,7 @@ module Rails # == Loading priority # # In order to change engine's priority you can use +config.railties_order+ in the main application. - # It will affect the priority of loading views, helpers, assets and all the other files + # It will affect the priority of loading views, helpers, assets, and all the other files # related to engine or application. # # # load Blog::Engine with highest priority, followed by application and other railties @@ -436,7 +436,7 @@ module Rails # Load console and invoke the registered hooks. # Check <tt>Rails::Railtie.console</tt> for more info. - def load_console(app=self) + def load_console(app = self) require "rails/console/app" require "rails/console/helpers" run_console_blocks(app) @@ -445,14 +445,14 @@ module Rails # Load Rails runner and invoke the registered hooks. # Check <tt>Rails::Railtie.runner</tt> for more info. - def load_runner(app=self) + def load_runner(app = self) run_runner_blocks(app) self end # Load Rake, railties tasks and invoke the registered hooks. # Check <tt>Rails::Railtie.rake_tasks</tt> for more info. - def load_tasks(app=self) + def load_tasks(app = self) require "rake" run_tasks_blocks(app) self @@ -460,7 +460,7 @@ module Rails # Load Rails generators and invoke the registered hooks. # Check <tt>Rails::Railtie.generators</tt> for more info. - def load_generators(app=self) + def load_generators(app = self) require "rails/generators" run_generators_blocks(app) Rails::Generators.configure!(app.config.generators) @@ -643,22 +643,24 @@ module Rails protected - def load_config_initializer(initializer) - ActiveSupport::Notifications.instrument("load_config_initializer.railties", initializer: initializer) do - load(initializer) - end - end - def run_tasks_blocks(*) #:nodoc: super paths["lib/tasks"].existent.sort.each { |ext| load(ext) } end - def has_migrations? #:nodoc: + private + + def load_config_initializer(initializer) # :doc: + ActiveSupport::Notifications.instrument("load_config_initializer.railties", initializer: initializer) do + load(initializer) + end + end + + def has_migrations? paths["db/migrate"].existent.any? end - def self.find_root_with_flag(flag, root_path, default=nil) #:nodoc: + def self.find_root_with_flag(flag, root_path, default = nil) #:nodoc: while root_path && File.directory?(root_path) && !File.exist?("#{root_path}/#{flag}") parent = File.dirname(root_path) @@ -671,24 +673,22 @@ module Rails Pathname.new File.realpath root end - def default_middleware_stack #:nodoc: + def default_middleware_stack ActionDispatch::MiddlewareStack.new end - def _all_autoload_once_paths #:nodoc: + def _all_autoload_once_paths config.autoload_once_paths end - def _all_autoload_paths #:nodoc: + def _all_autoload_paths @_all_autoload_paths ||= (config.autoload_paths + config.eager_load_paths + config.autoload_once_paths).uniq end - def _all_load_paths #:nodoc: + def _all_load_paths @_all_load_paths ||= (config.paths.load_paths + _all_autoload_paths).uniq end - private - def build_request(env) env.merge!(env_config) req = ActionDispatch::Request.new env diff --git a/railties/lib/rails/engine/commands.rb b/railties/lib/rails/engine/commands.rb index dfbeea36b8..a23ae44b0b 100644 --- a/railties/lib/rails/engine/commands.rb +++ b/railties/lib/rails/engine/commands.rb @@ -1,6 +1,4 @@ -require "rails/engine/commands_tasks" - -ARGV << "--help" if ARGV.empty? +require "rails/command" aliases = { "g" => "generate", @@ -11,4 +9,4 @@ aliases = { command = ARGV.shift command = aliases[command] || command -Rails::Engine::CommandsTasks.new(ARGV).run_command!(command) +Rails::Command.invoke command, ARGV diff --git a/railties/lib/rails/engine/commands_tasks.rb b/railties/lib/rails/engine/commands_tasks.rb deleted file mode 100644 index d6effdb732..0000000000 --- a/railties/lib/rails/engine/commands_tasks.rb +++ /dev/null @@ -1,62 +0,0 @@ -require "rails/commands/rake_proxy" -require "rails/commands/common_commands_tasks" -require "active_support/core_ext/string/strip" - -module Rails - class Engine - class CommandsTasks # :nodoc: - include Rails::RakeProxy - include Rails::CommonCommandsTasks - - attr_reader :argv - - def initialize(argv) - @argv = argv - end - - private - - def commands - formatted_rake_tasks - end - - def command_whitelist - %w(generate destroy version help test) - end - - def help_message - <<-EOT.strip_heredoc - Usage: rails COMMAND [ARGS] - - The common Rails commands available for engines are: - generate Generate new code (short-cut alias: "g") - destroy Undo code generated with "generate" (short-cut alias: "d") - test Run tests (short-cut alias: "t") - - All commands can be run with -h for more information. - - If you want to run any commands that need to be run in context - of the application, like `rails server` or `rails console`, - you should do it from application's directory (typically test/dummy). - - In addition to those commands, there are: - EOT - end - - def require_application_and_environment! - require ENGINE_PATH - end - - def load_tasks - Rake.application.init("rails") - Rake.application.load_rakefile - end - - def load_generators - engine = ::Rails::Engine.find(ENGINE_ROOT) - Rails::Generators.namespace = engine.railtie_namespace - engine.load_generators - end - end - end -end diff --git a/railties/lib/rails/engine/configuration.rb b/railties/lib/rails/engine/configuration.rb index 147b904679..0c40173c38 100644 --- a/railties/lib/rails/engine/configuration.rb +++ b/railties/lib/rails/engine/configuration.rb @@ -7,7 +7,7 @@ module Rails attr_accessor :middleware attr_writer :eager_load_paths, :autoload_once_paths, :autoload_paths - def initialize(root=nil) + def initialize(root = nil) super() @root = root @generators = app_generators.dup diff --git a/railties/lib/rails/generators.rb b/railties/lib/rails/generators.rb index fd35dfd1a2..e1980a42ad 100644 --- a/railties/lib/rails/generators.rb +++ b/railties/lib/rails/generators.rb @@ -2,6 +2,7 @@ activesupport_path = File.expand_path("../../../../activesupport/lib", __FILE__) $:.unshift(activesupport_path) if File.directory?(activesupport_path) && !$:.include?(activesupport_path) require "thor/group" +require "rails/command" require "active_support" require "active_support/core_ext/object/blank" @@ -13,6 +14,8 @@ require "active_support/core_ext/string/inflections" module Rails module Generators + include Rails::Command::Behavior + autoload :Actions, "rails/generators/actions" autoload :ActiveModel, "rails/generators/active_model" autoload :Base, "rails/generators/base" @@ -64,337 +67,247 @@ module Rails } } - def self.configure!(config) #:nodoc: - api_only! if config.api_only - no_color! unless config.colorize_logging - aliases.deep_merge! config.aliases - options.deep_merge! config.options - fallbacks.merge! config.fallbacks - templates_path.concat config.templates - templates_path.uniq! - hide_namespaces(*config.hidden_namespaces) - end - - def self.templates_path #:nodoc: - @templates_path ||= [] - end - - def self.aliases #:nodoc: - @aliases ||= DEFAULT_ALIASES.dup - end - - def self.options #:nodoc: - @options ||= DEFAULT_OPTIONS.dup - end - - # Hold configured generators fallbacks. If a plugin developer wants a - # generator group to fallback to another group in case of missing generators, - # they can add a fallback. - # - # For example, shoulda is considered a test_framework and is an extension - # of test_unit. However, most part of shoulda generators are similar to - # test_unit ones. - # - # Shoulda then can tell generators to search for test_unit generators when - # some of them are not available by adding a fallback: - # - # Rails::Generators.fallbacks[:shoulda] = :test_unit - def self.fallbacks - @fallbacks ||= {} - end - - # 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 helpers and assets - # so generators such as scaffold won't create them. - def self.api_only! - hide_namespaces "assets", "helper", "css", "js" - - options[:rails].merge!( - api: true, - assets: false, - helper: false, - template_engine: nil - ) - - if ARGV.first == "mailer" - options[:rails].merge!(template_engine: :erb) + class << self + def configure!(config) #:nodoc: + api_only! if config.api_only + no_color! unless config.colorize_logging + aliases.deep_merge! config.aliases + options.deep_merge! config.options + fallbacks.merge! config.fallbacks + templates_path.concat config.templates + templates_path.uniq! + hide_namespaces(*config.hidden_namespaces) end - end - - # Remove the color from output. - def self.no_color! - Thor::Base.shell = Thor::Shell::Basic - end - - # Track all generators subclasses. - def self.subclasses - @subclasses ||= [] - end - # Rails finds namespaces similar to thor, it only adds one rule: - # - # Generators names must end with "_generator.rb". This is required because Rails - # looks in load paths and loads the generator just before it's going to be used. - # - # find_by_namespace :webrat, :rails, :integration - # - # Will search for the following generators: - # - # "rails:webrat", "webrat:integration", "webrat" - # - # Notice that "rails:generators:webrat" could be loaded as well, what - # Rails looks for is the first and last parts of the namespace. - def self.find_by_namespace(name, base=nil, context=nil) #:nodoc: - lookups = [] - lookups << "#{base}:#{name}" if base - lookups << "#{name}:#{context}" if context - - unless base || context - unless name.to_s.include?(?:) - lookups << "#{name}:#{name}" - lookups << "rails:#{name}" - end - lookups << "#{name}" + def templates_path #:nodoc: + @templates_path ||= [] end - lookup(lookups) + def aliases #:nodoc: + @aliases ||= DEFAULT_ALIASES.dup + end - namespaces = Hash[subclasses.map { |klass| [klass.namespace, klass] }] + def options #:nodoc: + @options ||= DEFAULT_OPTIONS.dup + end - lookups.each do |namespace| - klass = namespaces[namespace] - return klass if klass + # Hold configured generators fallbacks. If a plugin developer wants a + # generator group to fallback to another group in case of missing generators, + # they can add a fallback. + # + # For example, shoulda is considered a test_framework and is an extension + # of test_unit. However, most part of shoulda generators are similar to + # test_unit ones. + # + # Shoulda then can tell generators to search for test_unit generators when + # some of them are not available by adding a fallback: + # + # Rails::Generators.fallbacks[:shoulda] = :test_unit + def fallbacks + @fallbacks ||= {} end - invoke_fallbacks_for(name, base) || invoke_fallbacks_for(context, name) - end + # 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 helpers and assets + # so generators such as scaffold won't create them. + def api_only! + hide_namespaces "assets", "helper", "css", "js" + + options[:rails].merge!( + api: true, + assets: false, + helper: false, + template_engine: nil + ) + + if ARGV.first == "mailer" + options[:rails].merge!(template_engine: :erb) + end + end - # Receives a namespace, arguments and the behavior to invoke the generator. - # It's used as the default entry point for generate, destroy and update - # commands. - def self.invoke(namespace, args=ARGV, config={}) - names = namespace.to_s.split(":") - if klass = find_by_namespace(names.pop, names.any? && names.join(":")) - args << "--help" if args.empty? && klass.arguments.any?(&:required?) - klass.start(args, config) - else - options = sorted_groups.flat_map(&:last) - suggestions = options.sort_by { |suggested| levenshtein_distance(namespace.to_s, suggested) }.first(3) - msg = "Could not find generator '#{namespace}'. " - msg << "Maybe you meant #{ suggestions.map { |s| "'#{s}'" }.to_sentence(last_word_connector: " or ", locale: :en) }\n" - msg << "Run `rails generate --help` for more options." - puts msg + # Remove the color from output. + def no_color! + Thor::Base.shell = Thor::Shell::Basic end - end - # Returns an array of generator namespaces that are hidden. - # Generator namespaces may be hidden for a variety of reasons. - # Some are aliased such as "rails:migration" and can be - # invoked with the shorter "migration", others are private to other generators - # such as "css:scaffold". - def self.hidden_namespaces - @hidden_namespaces ||= begin - orm = options[:rails][:orm] - test = options[:rails][:test_framework] - template = options[:rails][:template_engine] - css = options[:rails][:stylesheet_engine] - - [ - "rails", - "resource_route", - "#{orm}:migration", - "#{orm}:model", - "#{test}:controller", - "#{test}:helper", - "#{test}:integration", - "#{test}:mailer", - "#{test}:model", - "#{test}:scaffold", - "#{test}:view", - "#{test}:job", - "#{template}:controller", - "#{template}:scaffold", - "#{template}:mailer", - "#{css}:scaffold", - "#{css}:assets", - "css:assets", - "css:scaffold" - ] + # Returns an array of generator namespaces that are hidden. + # Generator namespaces may be hidden for a variety of reasons. + # Some are aliased such as "rails:migration" and can be + # invoked with the shorter "migration", others are private to other generators + # such as "css:scaffold". + def hidden_namespaces + @hidden_namespaces ||= begin + orm = options[:rails][:orm] + test = options[:rails][:test_framework] + template = options[:rails][:template_engine] + css = options[:rails][:stylesheet_engine] + + [ + "rails", + "resource_route", + "#{orm}:migration", + "#{orm}:model", + "#{test}:controller", + "#{test}:helper", + "#{test}:integration", + "#{test}:mailer", + "#{test}:model", + "#{test}:scaffold", + "#{test}:view", + "#{test}:job", + "#{template}:controller", + "#{template}:scaffold", + "#{template}:mailer", + "#{css}:scaffold", + "#{css}:assets", + "css:assets", + "css:scaffold" + ] + end end - end - class << self def hide_namespaces(*namespaces) hidden_namespaces.concat(namespaces) end alias hide_namespace hide_namespaces - end - # Show help message with available generators. - def self.help(command = "generate") - puts "Usage: rails #{command} GENERATOR [args] [options]" - puts - puts "General options:" - puts " -h, [--help] # Print generator's options and usage" - puts " -p, [--pretend] # Run but do not make any changes" - puts " -f, [--force] # Overwrite files that already exist" - puts " -s, [--skip] # Skip files that already exist" - puts " -q, [--quiet] # Suppress status output" - puts - puts "Please choose a generator below." - puts - - print_generators - end + # Show help message with available generators. + def help(command = "generate") + puts "Usage: rails #{command} GENERATOR [args] [options]" + puts + puts "General options:" + puts " -h, [--help] # Print generator's options and usage" + puts " -p, [--pretend] # Run but do not make any changes" + puts " -f, [--force] # Overwrite files that already exist" + puts " -s, [--skip] # Skip files that already exist" + puts " -q, [--quiet] # Suppress status output" + puts + puts "Please choose a generator below." + puts - def self.public_namespaces - lookup! - subclasses.map(&:namespace) - end + print_generators + end - def self.print_generators - sorted_groups.each { |b, n| print_list(b, n) } - end + def public_namespaces + lookup! + subclasses.map(&:namespace) + end - def self.sorted_groups - namespaces = public_namespaces - namespaces.sort! - groups = Hash.new { |h,k| h[k] = [] } - namespaces.each do |namespace| - base = namespace.split(":").first - groups[base] << namespace + def print_generators + sorted_groups.each { |b, n| print_list(b, n) } end - rails = groups.delete("rails") - rails.map! { |n| n.sub(/^rails:/, "") } - rails.delete("app") - rails.delete("plugin") - hidden_namespaces.each { |n| groups.delete(n.to_s) } + def sorted_groups + namespaces = public_namespaces + namespaces.sort! - [["rails", rails]] + groups.sort.to_a - end + groups = Hash.new { |h, k| h[k] = [] } + namespaces.each do |namespace| + base = namespace.split(":").first + groups[base] << namespace + end + + rails = groups.delete("rails") + rails.map! { |n| n.sub(/^rails:/, "") } + rails.delete("app") + rails.delete("plugin") - protected + hidden_namespaces.each { |n| groups.delete(n.to_s) } - # This code is based directly on the Text gem implementation. - # Copyright (c) 2006-2013 Paul Battley, Michael Neumann, Tim Fletcher. + [[ "rails", rails ]] + groups.sort.to_a + end + + # Rails finds namespaces similar to thor, it only adds one rule: + # + # Generators names must end with "_generator.rb". This is required because Rails + # looks in load paths and loads the generator just before it's going to be used. + # + # find_by_namespace :webrat, :rails, :integration # - # Returns a value representing the "cost" of transforming str1 into str2 - def self.levenshtein_distance(str1, str2) - s = str1 - t = str2 - n = s.length - m = t.length - - return m if (0 == n) - return n if (0 == m) - - d = (0..m).to_a - x = nil - - # avoid duplicating an enumerable object in the loop - str2_codepoint_enumerable = str2.each_codepoint - - str1.each_codepoint.with_index do |char1, i| - e = i+1 - - str2_codepoint_enumerable.with_index do |char2, j| - cost = (char1 == char2) ? 0 : 1 - x = [ - d[j+1] + 1, # insertion - e + 1, # deletion - d[j] + cost # substitution - ].min - d[j] = e - e = x + # Will search for the following generators: + # + # "rails:webrat", "webrat:integration", "webrat" + # + # Notice that "rails:generators:webrat" could be loaded as well, what + # Rails looks for is the first and last parts of the namespace. + def find_by_namespace(name, base = nil, context = nil) #:nodoc: + lookups = [] + lookups << "#{base}:#{name}" if base + lookups << "#{name}:#{context}" if context + + unless base || context + unless name.to_s.include?(?:) + lookups << "#{name}:#{name}" + lookups << "rails:#{name}" end + lookups << "#{name}" + end + + lookup(lookups) - d[m] = x + namespaces = Hash[subclasses.map { |klass| [klass.namespace, klass] }] + lookups.each do |namespace| + + klass = namespaces[namespace] + return klass if klass end - x + invoke_fallbacks_for(name, base) || invoke_fallbacks_for(context, name) end - # Prints a list of generators. - def self.print_list(base, namespaces) #:nodoc: - namespaces = namespaces.reject do |n| - hidden_namespaces.include?(n) + # Receives a namespace, arguments and the behavior to invoke the generator. + # It's used as the default entry point for generate, destroy and update + # commands. + def invoke(namespace, args = ARGV, config = {}) + names = namespace.to_s.split(":") + if klass = find_by_namespace(names.pop, names.any? && names.join(":")) + args << "--help" if args.empty? && klass.arguments.any?(&:required?) + klass.start(args, config) + else + options = sorted_groups.flat_map(&:last) + suggestions = options.sort_by { |suggested| levenshtein_distance(namespace.to_s, suggested) }.first(3) + msg = "Could not find generator '#{namespace}'. " + msg << "Maybe you meant #{ suggestions.map { |s| "'#{s}'" }.to_sentence(last_word_connector: " or ", locale: :en) }\n" + msg << "Run `rails generate --help` for more options." + puts msg end + end - return if namespaces.empty? - puts "#{base.camelize}:" + private - namespaces.each do |namespace| - puts(" #{namespace}") + def print_list(base, namespaces) # :doc: + namespaces = namespaces.reject { |n| hidden_namespaces.include?(n) } + super end - puts - end + # Try fallbacks for the given base. + def invoke_fallbacks_for(name, base) + return nil unless base && fallbacks[base.to_sym] + invoked_fallbacks = [] - # Try fallbacks for the given base. - def self.invoke_fallbacks_for(name, base) #:nodoc: - return nil unless base && fallbacks[base.to_sym] - invoked_fallbacks = [] + Array(fallbacks[base.to_sym]).each do |fallback| + next if invoked_fallbacks.include?(fallback) + invoked_fallbacks << fallback - Array(fallbacks[base.to_sym]).each do |fallback| - next if invoked_fallbacks.include?(fallback) - invoked_fallbacks << fallback + klass = find_by_namespace(name, fallback) + return klass if klass + end - klass = find_by_namespace(name, fallback) - return klass if klass + nil end - nil - end - - # Receives namespaces in an array and tries to find matching generators - # in the load path. - def self.lookup(namespaces) #:nodoc: - paths = namespaces_to_paths(namespaces) - - paths.each do |raw_path| - ["rails/generators", "generators"].each do |base| - path = "#{base}/#{raw_path}_generator" - - begin - require path - return - rescue LoadError => e - raise unless e.message =~ /#{Regexp.escape(path)}$/ - rescue Exception => e - warn "[WARNING] Could not load generator #{path.inspect}. Error: #{e.message}.\n#{e.backtrace.join("\n")}" - end - end + def command_type # :doc: + @command_type ||= "generator" end - end - # This will try to load any generator in the load path to show in help. - def self.lookup! #:nodoc: - $LOAD_PATH.each do |base| - Dir[File.join(base, "{rails/generators,generators}", "**", "*_generator.rb")].each do |path| - begin - path = path.sub("#{base}/", "") - require path - rescue Exception - # No problem - end - end + def lookup_paths # :doc: + @lookup_paths ||= %w( rails/generators generators ) end - end - # Convert namespaces to paths by replacing ":" for "/" and adding - # an extra lookup. For example, "rails:model" should be searched - # in both: "rails/model/model_generator" and "rails/model_generator". - def self.namespaces_to_paths(namespaces) #:nodoc: - paths = [] - namespaces.each do |namespace| - pieces = namespace.split(":") - paths << pieces.dup.push(pieces.last).join("/") - paths << pieces.join("/") + def file_lookup_paths # :doc: + @file_lookup_paths ||= [ "{#{lookup_paths.join(',')}}", "**", "*_generator.rb" ] end - paths.uniq! - paths - end + end end end diff --git a/railties/lib/rails/generators/actions.rb b/railties/lib/rails/generators/actions.rb index ab9dc019e2..d058d82cea 100644 --- a/railties/lib/rails/generators/actions.rb +++ b/railties/lib/rails/generators/actions.rb @@ -68,7 +68,7 @@ module Rails # add_source "http://gems.github.com/" do # gem "rspec-rails" # end - def add_source(source, options={}, &block) + def add_source(source, options = {}, &block) log :source, source in_root do @@ -96,7 +96,7 @@ module Rails # environment(nil, env: "development") do # "config.action_controller.asset_host = 'localhost:3000'" # end - def environment(data=nil, options={}) + def environment(data = nil, options = {}) sentinel = /class [a-z_:]+ < Rails::Application/i env_file_sentinel = /Rails\.application\.configure do/ data = yield if !data && block_given? @@ -118,7 +118,7 @@ module Rails # git :init # git add: "this.file that.rb" # git add: "onefile.rb", rm: "badfile.cxx" - def git(commands={}) + def git(commands = {}) if commands.is_a?(Symbol) run "git #{commands}" else @@ -137,7 +137,7 @@ module Rails # end # # vendor("foreign.rb", "# Foreign code is fun") - def vendor(filename, data=nil, &block) + def vendor(filename, data = nil, &block) log :vendor, filename create_file("vendor/#{filename}", data, verbose: false, &block) end @@ -150,7 +150,7 @@ module Rails # end # # lib("foreign.rb", "# Foreign code is fun") - def lib(filename, data=nil, &block) + def lib(filename, data = nil, &block) log :lib, filename create_file("lib/#{filename}", data, verbose: false, &block) end @@ -170,7 +170,7 @@ module Rails # end # # rakefile('seed.rake', 'puts "Planting seeds"') - def rakefile(filename, data=nil, &block) + def rakefile(filename, data = nil, &block) log :rakefile, filename create_file("lib/tasks/#{filename}", data, verbose: false, &block) end @@ -188,7 +188,7 @@ module Rails # end # # initializer("api.rb", "API_KEY = '123456'") - def initializer(filename, data=nil, &block) + def initializer(filename, data = nil, &block) log :initializer, filename create_file("config/initializers/#{filename}", data, verbose: false, &block) end @@ -210,7 +210,7 @@ module Rails # rake("db:migrate") # rake("db:migrate", env: "production") # rake("gems:install", sudo: true) - def rake(command, options={}) + def rake(command, options = {}) execute_command :rake, command, options end @@ -219,7 +219,7 @@ module Rails # rails("db:migrate") # rails("db:migrate", env: "production") # rails("gems:install", sudo: true) - def rails_command(command, options={}) + def rails_command(command, options = {}) execute_command :rails, command, options end @@ -260,12 +260,12 @@ module Rails @after_bundle_callbacks << block end - protected + private # Define log for backwards compatibility. If just one argument is sent, # invoke say, otherwise invoke say_status. Differently from say and # similarly to say_status, this method respects the quiet? option given. - def log(*args) + def log(*args) # :doc: if args.size == 1 say args.first.to_s unless options.quiet? else @@ -276,16 +276,16 @@ module Rails # Runs the supplied command using either "rake ..." or "rails ..." # based on the executor parameter provided. - def execute_command(executor, command, options={}) + def execute_command(executor, command, options = {}) # :doc: log executor, command env = options[:env] || ENV["RAILS_ENV"] || "development" - sudo = options[:sudo] && RbConfig::CONFIG["host_os"] !~ /mswin|mingw/ ? "sudo " : "" + sudo = options[:sudo] && !Gem.win_platform? ? "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/ + def extify(name) # :doc: + if Gem.win_platform? "#{name}.bat" else name @@ -294,7 +294,7 @@ module Rails # Surround string with single quotes if there is no quotes. # Otherwise fall back to double quotes - def quote(value) + def quote(value) # :doc: return value.inspect unless value.is_a? String if value.include?("'") diff --git a/railties/lib/rails/generators/actions/create_migration.rb b/railties/lib/rails/generators/actions/create_migration.rb index 587c61fd42..f677e545e5 100644 --- a/railties/lib/rails/generators/actions/create_migration.rb +++ b/railties/lib/rails/generators/actions/create_migration.rb @@ -37,9 +37,9 @@ module Rails end alias :exists? :existing_migration - protected + private - def on_conflict_behavior + def on_conflict_behavior # :doc: options = base.options.merge(config) if identical? say_status :identical, :blue, relative_existing_migration @@ -60,7 +60,7 @@ module Rails end end - def say_status(status, color, message = relative_destination) + def say_status(status, color, message = relative_destination) # :doc: base.shell.say_status(status, message, color) if config[:verbose] end end diff --git a/railties/lib/rails/generators/active_model.rb b/railties/lib/rails/generators/active_model.rb index 6183944bb0..2679d06fe4 100644 --- a/railties/lib/rails/generators/active_model.rb +++ b/railties/lib/rails/generators/active_model.rb @@ -39,13 +39,13 @@ module Rails # GET edit # PATCH/PUT update # DELETE destroy - def self.find(klass, params=nil) + def self.find(klass, params = nil) "#{klass}.find(#{params})" end # GET new # POST create - def self.build(klass, params=nil) + def self.build(klass, params = nil) if params "#{klass}.new(#{params})" else @@ -59,7 +59,7 @@ module Rails end # PATCH/PUT update - def update(params=nil) + def update(params = nil) "#{name}.update(#{params})" end diff --git a/railties/lib/rails/generators/app_base.rb b/railties/lib/rails/generators/app_base.rb index d76acbdafc..ea88afe9f4 100644 --- a/railties/lib/rails/generators/app_base.rb +++ b/railties/lib/rails/generators/app_base.rb @@ -30,15 +30,18 @@ module Rails class_option :database, type: :string, aliases: "-d", default: "sqlite3", desc: "Preconfigure for selected database (options: #{DATABASES.join('/')})" - class_option :javascript, type: :string, aliases: "-j", default: "jquery", + class_option :javascript, type: :string, aliases: "-j", desc: "Preconfigure for selected JavaScript library" + class_option :webpack, type: :string, default: nil, + desc: "Preconfigure for app-like JavaScript with Webpack" + + class_option :skip_yarn, type: :boolean, default: false, + desc: "Don't use Yarn for managing JavaScript dependencies" + class_option :skip_gemfile, type: :boolean, default: false, desc: "Don't create a Gemfile" - class_option :skip_bundle, type: :boolean, aliases: "-B", default: false, - desc: "Don't run bundle install" - class_option :skip_git, type: :boolean, aliases: "-G", default: false, desc: "Skip .gitignore file" @@ -67,6 +70,9 @@ module Rails class_option :skip_listen, type: :boolean, default: false, desc: "Don't generate configuration that depends on the listen gem" + class_option :skip_coffee, type: :boolean, default: false, + desc: "Don't use CoffeeScript" + class_option :skip_javascript, type: :boolean, aliases: "-J", default: false, desc: "Skip JavaScript files" @@ -99,9 +105,9 @@ module Rails convert_database_option_for_jruby end - protected + private - def gemfile_entry(name, *args) + def gemfile_entry(name, *args) # :doc: options = args.extract_options! version = args.first github = options[:github] @@ -117,11 +123,12 @@ module Rails self end - def gemfile_entries + def gemfile_entries # :doc: [rails_gemfile_entry, database_gemfile_entry, webserver_gemfile_entry, assets_gemfile_entry, + webpacker_gemfile_entry, javascript_gemfile_entry, jbuilder_gemfile_entry, psych_gemfile_entry, @@ -129,13 +136,13 @@ module Rails @extra_entries].flatten.find_all(&@gem_filter) end - def add_gem_entry_filter + def add_gem_entry_filter # :doc: @gem_filter = lambda { |next_filter, entry| yield(entry) && next_filter.call(entry) }.curry[@gem_filter] end - def builder + def builder # :doc: @builder ||= begin builder_class = get_builder_class builder_class.include(ActionMethods) @@ -143,24 +150,24 @@ module Rails end end - def build(meth, *args) + def build(meth, *args) # :doc: builder.send(meth, *args) if builder.respond_to?(meth) end - def create_root + def create_root # :doc: valid_const? empty_directory "." FileUtils.cd(destination_root) unless options[:pretend] end - def apply_rails_template + def apply_rails_template # :doc: 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 set_default_accessors! + def set_default_accessors! # :doc: self.destination_root = File.expand_path(app_path, destination_root) self.rails_template = \ case options[:template] @@ -173,32 +180,32 @@ module Rails end end - def database_gemfile_entry + def database_gemfile_entry # :doc: return [] if options[:skip_active_record] gem_name, gem_version = gem_for_database GemfileEntry.version gem_name, gem_version, "Use #{options[:database]} as the database for Active Record" end - def webserver_gemfile_entry + def webserver_gemfile_entry # :doc: return [] if options[:skip_puma] comment = "Use Puma as the app server" GemfileEntry.new("puma", "~> 3.0", comment) end - def include_all_railties? + def include_all_railties? # :doc: options.values_at(:skip_active_record, :skip_action_mailer, :skip_test, :skip_sprockets, :skip_action_cable).none? end - def comment_if(value) + def comment_if(value) # :doc: options[value] ? "# " : "" end - def keeps? + def keeps? # :doc: !options[:skip_keeps] end - def sqlite3? + def sqlite3? # :doc: !options[:skip_active_record] && options[:database] == "sqlite3" end @@ -236,6 +243,7 @@ module Rails def rails_gemfile_entry dev_edge_common = [ + GemfileEntry.github("arel", "rails/arel") ] if options.dev? [ @@ -243,7 +251,7 @@ module Rails ] + dev_edge_common elsif options.edge? [ - GemfileEntry.github("rails", "rails/rails", "5-0-stable") + GemfileEntry.github("rails", "rails/rails") ] + dev_edge_common else [GemfileEntry.version("rails", @@ -309,6 +317,13 @@ module Rails gems end + def webpacker_gemfile_entry + return [] unless options[:webpack] + + comment = "Transpile app-like JavaScript. Read more: https://github.com/rails/webpacker" + GemfileEntry.github "webpacker", "rails/webpacker", nil, comment + end + def jbuilder_gemfile_entry comment = "Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder" GemfileEntry.new "jbuilder", "~> 2.5", comment, {}, options[:api] @@ -322,9 +337,13 @@ module Rails if options[:skip_javascript] || options[:skip_sprockets] [] else - gems = [coffee_gemfile_entry, javascript_runtime_gemfile_entry] - gems << GemfileEntry.version("#{options[:javascript]}-rails", nil, - "Use #{options[:javascript]} as the JavaScript library") + gems = [javascript_runtime_gemfile_entry] + gems << coffee_gemfile_entry unless options[:skip_coffee] + + if options[:javascript] + gems << GemfileEntry.version("#{options[:javascript]}-rails", nil, + "Use #{options[:javascript]} as the JavaScript library") + end unless options[:skip_turbolinks] gems << GemfileEntry.version("turbolinks", "~> 5", @@ -404,6 +423,13 @@ module Rails bundle_command("install") if bundle_install? end + def run_webpack + if !(webpack = options[:webpack]).nil? + rails_command "webpacker:install" + rails_command "webpacker:install:#{webpack}" unless webpack == "webpack" + end + end + def generate_spring_binstubs if bundle_install? && spring_install? bundle_command("exec spring binstub --all") diff --git a/railties/lib/rails/generators/base.rb b/railties/lib/rails/generators/base.rb index 1a0420c769..cc6ae3860f 100644 --- a/railties/lib/rails/generators/base.rb +++ b/railties/lib/rails/generators/base.rb @@ -20,14 +20,14 @@ module Rails strict_args_position! # Returns the source root for this generator using default_source_root as default. - def self.source_root(path=nil) + 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) + def self.desc(description = nil) return super if description @desc ||= if usage_path @@ -40,7 +40,7 @@ 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) + def self.namespace(name = nil) return super if name @namespace ||= super.sub(/_generator$/, "").sub(/:generators:/, ":") end @@ -195,7 +195,7 @@ module Rails end # Make class option aware of Rails::Generators.options and Rails::Generators.aliases. - def self.class_option(name, options={}) #:nodoc: + 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) options[:default] = default_value_for_option(name, options) @@ -239,11 +239,11 @@ module Rails end end - protected + private # Check whether the given class names are already taken by user # application or Ruby on Rails. - def class_collisions(*class_names) #:nodoc: + def class_collisions(*class_names) return unless behavior == :invoke class_names.flatten.each do |class_name| @@ -264,7 +264,7 @@ module Rails end # Takes in an array of nested modules and extracts the last module - def extract_last_module(nesting) + def extract_last_module(nesting) # :doc: nesting.inject(Object) do |last_module, nest| break unless last_module.const_defined?(nest, false) last_module.const_get(nest) @@ -272,12 +272,12 @@ module Rails end # Use Rails default banner. - def self.banner - "rails generate #{namespace.sub(/^rails:/,'')} #{arguments.map(&:usage).join(' ')} [options]".gsub(/\s+/, " ") + def self.banner # :doc: + "rails generate #{namespace.sub(/^rails:/, '')} #{arguments.map(&:usage).join(' ')} [options]".gsub(/\s+/, " ") end # Sets the base_name taking into account the current class namespace. - def self.base_name + def self.base_name # :doc: @base_name ||= begin if base = name.to_s.split("::").first base.underscore @@ -287,7 +287,7 @@ module Rails # Removes the namespaces and get the generator name. For example, # Rails::Generators::ModelGenerator will return "model" as generator name. - def self.generator_name + def self.generator_name # :doc: @generator_name ||= begin if generator = name.to_s.split("::").last generator.sub!(/Generator$/, "") @@ -298,18 +298,18 @@ module Rails # Returns the default value for the option name given doing a lookup in # Rails::Generators.options. - def self.default_value_for_option(name, options) + def self.default_value_for_option(name, options) # :doc: default_for_option(Rails::Generators.options, name, options, options[:default]) end # Returns default aliases for the option name given doing a lookup in # Rails::Generators.aliases. - def self.default_aliases_for_option(name, options) + def self.default_aliases_for_option(name, options) # :doc: default_for_option(Rails::Generators.aliases, name, options, options[:aliases]) end # Returns default for the option name given doing a lookup in config. - def self.default_for_option(config, name, options, default) + def self.default_for_option(config, name, options, default) # :doc: if generator_name && (c = config[generator_name.to_sym]) && c.key?(name) c[name] elsif base_name && (c = config[base_name.to_sym]) && c.key?(name) @@ -343,7 +343,7 @@ module Rails # Small macro to add ruby as an option to the generator with proper # default value plus an instance helper method called shebang. - def self.add_shebang_option! + def self.add_shebang_option! # :doc: class_option :ruby, type: :string, aliases: "-r", default: Thor::Util.ruby_command, desc: "Path to the Ruby binary of your choice", banner: "PATH" @@ -361,7 +361,7 @@ module Rails } end - def self.usage_path + def self.usage_path # :doc: paths = [ source_root && File.expand_path("../USAGE", source_root), default_generator_root && File.join(default_generator_root, "USAGE") @@ -369,7 +369,7 @@ module Rails paths.compact.detect { |path| File.exist? path } end - def self.default_generator_root + def self.default_generator_root # :doc: path = File.expand_path(File.join(base_name, generator_name), base_root) path if File.exist?(path) end diff --git a/railties/lib/rails/generators/erb.rb b/railties/lib/rails/generators/erb.rb index d01502002f..d5e326d6ee 100644 --- a/railties/lib/rails/generators/erb.rb +++ b/railties/lib/rails/generators/erb.rb @@ -3,7 +3,7 @@ require "rails/generators/named_base" module Erb # :nodoc: module Generators # :nodoc: class Base < Rails::Generators::NamedBase #:nodoc: - protected + private def formats [format] diff --git a/railties/lib/rails/generators/erb/mailer/mailer_generator.rb b/railties/lib/rails/generators/erb/mailer/mailer_generator.rb index f150240908..677f8041ae 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 end - protected + private def formats [:text, :html] diff --git a/railties/lib/rails/generators/erb/scaffold/scaffold_generator.rb b/railties/lib/rails/generators/erb/scaffold/scaffold_generator.rb index 154d85f381..0d77ef21da 100644 --- a/railties/lib/rails/generators/erb/scaffold/scaffold_generator.rb +++ b/railties/lib/rails/generators/erb/scaffold/scaffold_generator.rb @@ -21,7 +21,7 @@ module Erb # :nodoc: end end - protected + private def available_views %w(index edit show new _form) diff --git a/railties/lib/rails/generators/generated_attribute.rb b/railties/lib/rails/generators/generated_attribute.rb index 61181b7b97..baed7bf1e3 100644 --- a/railties/lib/rails/generators/generated_attribute.rb +++ b/railties/lib/rails/generators/generated_attribute.rb @@ -56,7 +56,7 @@ module Rails end end - def initialize(name, type=nil, index_type=false, attr_options={}) + def initialize(name, type = nil, index_type = false, attr_options = {}) @name = name @type = type || :string @has_index = INDEX_OPTIONS.include?(index_type) @@ -151,7 +151,7 @@ module Rails end def inject_options - "".tap { |s| options_for_migration.each { |k,v| s << ", #{k}: #{v.inspect}" } } + "".tap { |s| options_for_migration.each { |k, v| s << ", #{k}: #{v.inspect}" } } end def inject_index_options diff --git a/railties/lib/rails/generators/migration.rb b/railties/lib/rails/generators/migration.rb index 7290e235a1..0d63b9a5c9 100644 --- a/railties/lib/rails/generators/migration.rb +++ b/railties/lib/rails/generators/migration.rb @@ -52,7 +52,7 @@ module Rails # # migration_template "migration.rb", "db/migrate/add_foo_to_bar.rb" def migration_template(source, destination, config = {}) - source = File.expand_path(find_in_source_paths(source.to_s)) + source = File.expand_path(find_in_source_paths(source.to_s)) set_migration_assigns!(destination) context = instance_eval("binding") diff --git a/railties/lib/rails/generators/named_base.rb b/railties/lib/rails/generators/named_base.rb index c39ea24935..e3660b012a 100644 --- a/railties/lib/rails/generators/named_base.rb +++ b/railties/lib/rails/generators/named_base.rb @@ -32,145 +32,145 @@ module Rails end end + # TODO Change this to private once we've dropped Ruby 2.2 support. + # Workaround for Ruby 2.2 "private attribute?" warning. protected attr_reader :file_name + private + # FIXME: We are avoiding to use alias because a bug on thor that make # this method public and add it to the task list. - def singular_name + def singular_name # :doc: file_name end # Wrap block with namespace of current application # if namespace exists and is not skipped - def module_namespacing(&block) + def module_namespacing(&block) # :doc: content = capture(&block) content = wrap_with_namespace(content) if namespaced? concat(content) end - def indent(content, multiplier = 2) + def indent(content, multiplier = 2) # :doc: spaces = " " * multiplier content.each_line.map { |line| line.blank? ? line : "#{spaces}#{line}" }.join end - def wrap_with_namespace(content) + def wrap_with_namespace(content) # :doc: content = indent(content).chomp "module #{namespace.name}\n#{content}\nend\n" end - def inside_template + def inside_template # :doc: @inside_template = true yield ensure @inside_template = false end - def inside_template? + def inside_template? # :doc: @inside_template end - def namespace + def namespace # :doc: Rails::Generators.namespace end - def namespaced? + def namespaced? # :doc: !options[:skip_namespace] && namespace end - def file_path + def file_path # :doc: @file_path ||= (class_path + [file_name]).join("/") end - def class_path + def class_path # :doc: inside_template? || !namespaced? ? regular_class_path : namespaced_class_path end - def regular_class_path + def regular_class_path # :doc: @class_path end - def namespaced_file_path - @namespaced_file_path ||= namespaced_class_path.join("/") - end - - def namespaced_class_path + def namespaced_class_path # :doc: @namespaced_class_path ||= [namespaced_path] + @class_path end - def namespaced_path + def namespaced_path # :doc: @namespaced_path ||= namespace.name.split("::").first.underscore end - def class_name + def class_name # :doc: (class_path + [file_name]).map!(&:camelize).join("::") end - def human_name + def human_name # :doc: @human_name ||= singular_name.humanize end - def plural_name + def plural_name # :doc: @plural_name ||= singular_name.pluralize end - def i18n_scope + def i18n_scope # :doc: @i18n_scope ||= file_path.tr("/", ".") end - def table_name + def table_name # :doc: @table_name ||= begin base = pluralize_table_names? ? plural_name : singular_name (class_path + [base]).join("_") end end - def uncountable? + def uncountable? # :doc: singular_name == plural_name end - def index_helper + def index_helper # :doc: uncountable? ? "#{plural_table_name}_index" : plural_table_name end - def show_helper + def show_helper # :doc: "#{singular_table_name}_url(@#{singular_table_name})" end - def edit_helper + def edit_helper # :doc: "edit_#{show_helper}" end - def new_helper + def new_helper # :doc: "new_#{singular_table_name}_url" end - def singular_table_name + def singular_table_name # :doc: @singular_table_name ||= (pluralize_table_names? ? table_name.singularize : table_name) end - def plural_table_name + def plural_table_name # :doc: @plural_table_name ||= (pluralize_table_names? ? table_name : table_name.pluralize) end - def plural_file_name + def plural_file_name # :doc: @plural_file_name ||= file_name.pluralize end - def fixture_file_name + def fixture_file_name # :doc: @fixture_file_name ||= (pluralize_table_names? ? plural_file_name : file_name) end - def route_url + def route_url # :doc: @route_url ||= class_path.collect { |dname| "/" + dname }.join + "/" + plural_file_name end - def url_helper_prefix + def url_helper_prefix # :doc: @url_helper_prefix ||= (class_path + [file_name]).join("_") end # Tries to retrieve the application name or simply return application. - def application_name + def application_name # :doc: if defined?(Rails) && Rails.application Rails.application.class.name.split("::").first.underscore else @@ -178,20 +178,20 @@ module Rails end end - def assign_names!(name) #:nodoc: + def assign_names!(name) @class_path = name.include?("/") ? name.split("/") : name.split("::") @class_path.map!(&:underscore) @file_name = @class_path.pop end # Convert attributes array into GeneratedAttribute objects. - def parse_attributes! #:nodoc: + def parse_attributes! self.attributes = (attributes || []).map do |attr| Rails::Generators::GeneratedAttribute.parse(attr) end end - def attributes_names + def attributes_names # :doc: @attributes_names ||= attributes.each_with_object([]) do |a, names| names << a.column_name names << "password_confirmation" if a.password_digest? @@ -199,11 +199,11 @@ module Rails end end - def pluralize_table_names? + def pluralize_table_names? # :doc: !defined?(ActiveRecord::Base) || ActiveRecord::Base.pluralize_table_names end - def mountable_engine? + def mountable_engine? # :doc: defined?(ENGINE_ROOT) && namespaced? end @@ -217,7 +217,7 @@ module Rails # If the generator is invoked with class name Admin, it will check for # the presence of "AdminDecorator". # - def self.check_class_collision(options={}) + def self.check_class_collision(options = {}) # :doc: define_method :check_class_collision do name = if self.respond_to?(:controller_class_name) # for ScaffoldBase controller_class_name diff --git a/railties/lib/rails/generators/rails/app/app_generator.rb b/railties/lib/rails/generators/rails/app/app_generator.rb index 9f9c50ca10..8efdfdcb44 100644 --- a/railties/lib/rails/generators/rails/app/app_generator.rb +++ b/railties/lib/rails/generators/rails/app/app_generator.rb @@ -56,7 +56,7 @@ module Rails def app directory "app" - keep_file "app/assets/images" + keep_file "app/assets/images" empty_directory_with_keep_file "app/assets/javascripts/channels" unless options[:skip_action_cable] keep_file "app/controllers/concerns" @@ -151,19 +151,12 @@ module Rails end def vendor - vendor_javascripts - vendor_stylesheets - end + empty_directory_with_keep_file "vendor" - def vendor_javascripts - unless options[:skip_javascript] - empty_directory_with_keep_file "vendor/assets/javascripts" + unless options[:skip_yarn] + template "package.json", "vendor/package.json" end end - - def vendor_stylesheets - empty_directory_with_keep_file "vendor/assets/stylesheets" - end end module Generators @@ -182,6 +175,9 @@ module Rails class_option :api, type: :boolean, desc: "Preconfigure smaller stack for API only apps" + class_option :skip_bundle, type: :boolean, aliases: "-B", default: false, + desc: "Don't run bundle install" + def initialize(*args) super @@ -193,9 +189,11 @@ module Rails raise Error, "Invalid value for --database option. Supported for preconfiguration are: #{DATABASES.join(", ")}." end - # Force sprockets to be skipped when generating API only apps. + # Force sprockets and yarn to be skipped when generating API only apps. # Can't modify options hash as it's frozen by default. - self.options = options.merge(skip_sprockets: true, skip_javascript: true).freeze if options[:api] + if options[:api] + self.options = options.merge(skip_sprockets: true, skip_javascript: true, skip_yarn: true).freeze + end end public_task :set_default_accessors! @@ -205,8 +203,8 @@ module Rails build(:readme) build(:rakefile) build(:configru) - build(:gitignore) unless options[:skip_git] - build(:gemfile) unless options[:skip_gemfile] + build(:gitignore) unless options[:skip_git] + build(:gemfile) unless options[:skip_gemfile] end def create_app_files @@ -241,6 +239,7 @@ module Rails end def create_db_files + return if options[:skip_active_record] build(:db) end @@ -266,6 +265,10 @@ module Rails def create_vendor_files build(:vendor) + + if options[:skip_yarn] + remove_file "vendor/package.json" + end end def delete_app_assets_if_api_option @@ -273,7 +276,6 @@ module Rails remove_dir "app/assets" remove_dir "lib/assets" remove_dir "tmp/cache/assets" - remove_dir "vendor/assets" end end @@ -321,7 +323,6 @@ module Rails def delete_action_mailer_files_skipping_action_mailer if options[:skip_action_mailer] - remove_file "app/mailers/application_mailer.rb" remove_file "app/views/layouts/mailer.html.erb" remove_file "app/views/layouts/mailer.text.erb" remove_dir "app/mailers" @@ -349,23 +350,27 @@ module Rails end end + def delete_bin_yarn_if_skip_yarn_option + remove_file "bin/yarn" if options[:skip_yarn] + end + def finish_template build(:leftovers) end public_task :apply_rails_template, :run_bundle - public_task :generate_spring_binstubs + public_task :run_webpack, :generate_spring_binstubs def run_after_bundle_callbacks @after_bundle_callbacks.each(&:call) end - protected - def self.banner "rails new #{arguments.map(&:usage).join(' ')} [options]" end + private + # Define file as an alias to create_file for backwards compatibility. def file(*args, &block) create_file(*args, &block) @@ -422,7 +427,7 @@ module Rails "/opt/local/var/run/mysql4/mysqld.sock", # mac + darwinports + mysql4 "/opt/local/var/run/mysql5/mysqld.sock", # mac + darwinports + mysql5 "/opt/lampp/var/mysql/mysql.sock" # xampp for linux - ].find { |f| File.exist?(f) } unless RbConfig::CONFIG["host_os"] =~ /mswin|mingw/ + ].find { |f| File.exist?(f) } unless Gem.win_platform? end def get_builder_class diff --git a/railties/lib/rails/generators/rails/app/templates/Gemfile b/railties/lib/rails/generators/rails/app/templates/Gemfile index 7af5fcd3c1..f1015b16d5 100644 --- a/railties/lib/rails/generators/rails/app/templates/Gemfile +++ b/railties/lib/rails/generators/rails/app/templates/Gemfile @@ -1,5 +1,10 @@ source 'https://rubygems.org' +git_source(:github) do |repo_name| + repo_name = "#{repo_name}/#{repo_name}" unless repo_name.include?("/") + "https://github.com/#{repo_name}.git" +end + <% gemfile_entries.each do |gem| -%> <% if gem.comment -%> @@ -39,7 +44,7 @@ group :development do <%- end -%> <%- end -%> <% if depend_on_listen? -%> - gem 'listen', '~> 3.0.5' + gem 'listen', '>= 3.0.5', '< 3.2' <% end -%> <% if spring_install? -%> # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring diff --git a/railties/lib/rails/generators/rails/app/templates/app/assets/javascripts/application.js.tt b/railties/lib/rails/generators/rails/app/templates/app/assets/javascripts/application.js.tt index c88426ec06..25870f19c8 100644 --- a/railties/lib/rails/generators/rails/app/templates/app/assets/javascripts/application.js.tt +++ b/railties/lib/rails/generators/rails/app/templates/app/assets/javascripts/application.js.tt @@ -1,8 +1,8 @@ // This is a manifest file that'll be compiled into application.js, which will include all the files // listed below. // -// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts, -// or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path. +// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, or any plugin's +// vendor/assets/javascripts directory can be referenced here using a relative path. // // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the // compiled file. JavaScript code in this file should be added after the last require_* statement. @@ -11,9 +11,11 @@ // about supported directives. // <% unless options[:skip_javascript] -%> +<% if options[:javascript] -%> //= require <%= options[:javascript] %> -//= require <%= options[:javascript] %>_ujs -<% if gemfile_entries.any? { |m| m.name == "turbolinks" } -%> +<% end -%> +//= require rails-ujs +<% unless options[:skip_turbolinks] -%> //= require turbolinks <% end -%> <% end -%> diff --git a/railties/lib/rails/generators/rails/app/templates/app/assets/stylesheets/application.css b/railties/lib/rails/generators/rails/app/templates/app/assets/stylesheets/application.css index 0ebd7fe829..865300bef9 100644 --- a/railties/lib/rails/generators/rails/app/templates/app/assets/stylesheets/application.css +++ b/railties/lib/rails/generators/rails/app/templates/app/assets/stylesheets/application.css @@ -2,8 +2,8 @@ * This is a manifest file that'll be compiled into application.css, which will include all the files * listed below. * - * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets, - * or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path. + * Any CSS and SCSS file within this directory, lib/assets/stylesheets, or any plugin's + * vendor/assets/stylesheets directory can be referenced here using a relative path. * * You're free to add application-wide styles to this file and they'll appear at the bottom of the * compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS 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 d51f79bd49..5460155b3e 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 @@ -7,7 +7,7 @@ <%- if options[:skip_javascript] -%> <%%= stylesheet_link_tag 'application', media: 'all' %> <%- else -%> - <%- if gemfile_entries.any? { |m| m.name == 'turbolinks' } -%> + <%- unless options[:skip_turbolinks] -%> <%%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %> <%%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %> <%- else -%> diff --git a/railties/lib/rails/generators/rails/app/templates/bin/setup b/railties/lib/rails/generators/rails/app/templates/bin/setup.tt index acae810c1a..c6607dbb2b 100644 --- a/railties/lib/rails/generators/rails/app/templates/bin/setup +++ b/railties/lib/rails/generators/rails/app/templates/bin/setup.tt @@ -16,7 +16,12 @@ chdir APP_ROOT do puts '== Installing dependencies ==' system! 'gem install bundler --conservative' system('bundle check') || system!('bundle install') +<% unless options[:skip_yarn] %> + # Install JavaScript dependencies if using Yarn + # system('bin/yarn') +<% end %> +<% unless options.skip_active_record -%> # puts "\n== Copying sample files ==" # unless File.exist?('config/database.yml') # cp 'config/database.yml.sample', 'config/database.yml' @@ -24,6 +29,7 @@ chdir APP_ROOT do puts "\n== Preparing database ==" system! 'bin/rails db:setup' +<% end -%> puts "\n== Removing old logs and tempfiles ==" system! 'bin/rails log:clear tmp:clear' diff --git a/railties/lib/rails/generators/rails/app/templates/bin/update b/railties/lib/rails/generators/rails/app/templates/bin/update.tt index 770a605fed..d23af018c7 100644 --- a/railties/lib/rails/generators/rails/app/templates/bin/update +++ b/railties/lib/rails/generators/rails/app/templates/bin/update.tt @@ -16,9 +16,10 @@ chdir APP_ROOT do puts '== Installing dependencies ==' system! 'gem install bundler --conservative' system('bundle check') || system!('bundle install') - +<% unless options.skip_active_record -%> puts "\n== Updating database ==" system! 'bin/rails db:migrate' +<% end -%> puts "\n== Removing old logs and tempfiles ==" system! 'bin/rails log:clear tmp:clear' diff --git a/railties/lib/rails/generators/rails/app/templates/bin/yarn b/railties/lib/rails/generators/rails/app/templates/bin/yarn new file mode 100644 index 0000000000..872438cecb --- /dev/null +++ b/railties/lib/rails/generators/rails/app/templates/bin/yarn @@ -0,0 +1,9 @@ +VENDOR_PATH = File.expand_path('../vendor', __dir__) +Dir.chdir(VENDOR_PATH) do + begin + exec "yarnpkg #{ARGV.join(" ")}" + rescue Errno::ENOENT + puts "Yarn executable was not detected in the system." + puts "Download Yarn at https://yarnpkg.com/en/docs/install" + end +end diff --git a/railties/lib/rails/generators/rails/app/templates/config/databases/jdbcmysql.yml b/railties/lib/rails/generators/rails/app/templates/config/databases/jdbcmysql.yml index a2b2a64ba6..8bc8735a8e 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/databases/jdbcmysql.yml +++ b/railties/lib/rails/generators/rails/app/templates/config/databases/jdbcmysql.yml @@ -1,4 +1,4 @@ -# MySQL. Versions 5.0 and up are supported. +# MySQL. Versions 5.1.10 and up are supported. # # Install the MySQL driver: # gem install activerecord-jdbcmysql-adapter diff --git a/railties/lib/rails/generators/rails/app/templates/config/databases/mysql.yml b/railties/lib/rails/generators/rails/app/templates/config/databases/mysql.yml index d987cf303b..269af1470d 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/databases/mysql.yml +++ b/railties/lib/rails/generators/rails/app/templates/config/databases/mysql.yml @@ -1,4 +1,4 @@ -# MySQL. Versions 5.0 and up are supported. +# MySQL. Versions 5.1.10 and up are supported. # # Install the MySQL driver # gem install mysql2 diff --git a/railties/lib/rails/generators/rails/app/templates/config/initializers/assets.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/initializers/assets.rb.tt index 2318cf59ff..f5d03fb117 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/initializers/assets.rb.tt +++ b/railties/lib/rails/generators/rails/app/templates/config/initializers/assets.rb.tt @@ -3,8 +3,12 @@ # Version of your assets, change this if you want to expire all your assets. Rails.application.config.assets.version = '1.0' -# Add additional assets to the asset load path +# Add additional assets to the asset load path. # Rails.application.config.assets.paths << Emoji.images_path +<%- unless options[:skip_yarn] -%> +# Add Yarn node_modules folder to the asset load path. +Rails.application.config.assets.paths << Rails.root.join('vendor/node_modules') +<%- end -%> # Precompile additional assets. # application.js, application.css, and all non-JS/CSS in the app/assets diff --git a/railties/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults.rb.tt index 5ad18cc5ad..3ad3eba98a 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults.rb.tt +++ b/railties/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults.rb.tt @@ -32,7 +32,9 @@ ActiveSupport.halt_callback_chains_on_return_false = <%= options[:update] ? true # Configure SSL options to enable HSTS with subdomains. Previous versions had false. Rails.application.config.ssl_options = { hsts: { subdomains: true } } <%- end -%> +<%- unless options[:skip_sprockets] -%> # Unknown asset fallback will return the path passed in when the given # asset is not present in the asset pipeline. Rails.application.config.assets.unknown_asset_fallback = <%= options[:update] ? true : false %> +<%- end -%> 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 121ad7080e..1e19380dcb 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/puma.rb +++ b/railties/lib/rails/generators/rails/app/templates/config/puma.rb @@ -1,13 +1,13 @@ # Puma can serve each request in a thread from an internal thread pool. -# The `threads` method setting takes two numbers a minimum and maximum. +# The `threads` method setting takes two numbers: a minimum and maximum. # Any libraries that use thread pools should be configured to match # the maximum value specified for Puma. Default is set to 5 threads for minimum -# and maximum, this matches the default thread size of Active Record. +# and maximum; this matches the default thread size of Active Record. # threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 } threads threads_count, threads_count -# Specifies the `port` that Puma will listen on to receive requests, default is 3000. +# Specifies the `port` that Puma will listen on to receive requests; default is 3000. # port ENV.fetch("PORT") { 3000 } @@ -32,16 +32,25 @@ environment ENV.fetch("RAILS_ENV") { "development" } # # preload_app! +# If you are preloading your application and using Active Record, it's +# recommended that you close any connections to the database before workers +# are forked to prevent connection leakage. +# +# before_fork do +# ActiveRecord::Base.connection_pool.disconnect! if defined?(ActiveRecord) +# end + # The code in the `on_worker_boot` will be called if you are using # clustered mode by specifying a number of `workers`. After each worker -# process is booted this block will be run, if you are using `preload_app!` -# option you will want to use this block to reconnect to any threads -# or connections that may have been created at application boot, Ruby +# process is booted, this block will be run. If you are using the `preload_app!` +# option, you will want to use this block to reconnect to any threads +# or connections that may have been created at application boot, as Ruby # cannot share connections between processes. # # 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/gitignore b/railties/lib/rails/generators/rails/app/templates/gitignore index 0e66cc4237..709b341387 100644 --- a/railties/lib/rails/generators/rails/app/templates/gitignore +++ b/railties/lib/rails/generators/rails/app/templates/gitignore @@ -21,5 +21,8 @@ !/tmp/.keep <% end -%> -# Ignore Byebug command history file. +<% unless options[:skip_yarn] -%> +/vendor/node_modules + +<% end -%> .byebug_history diff --git a/railties/lib/rails/generators/rails/app/templates/package.json b/railties/lib/rails/generators/rails/app/templates/package.json new file mode 100644 index 0000000000..46db57dcbe --- /dev/null +++ b/railties/lib/rails/generators/rails/app/templates/package.json @@ -0,0 +1,5 @@ +{ + "name": "<%= app_name %>", + "private": true, + "dependencies": {} +} diff --git a/railties/lib/rails/generators/rails/app/templates/test/test_helper.rb b/railties/lib/rails/generators/rails/app/templates/test/test_helper.rb index 87b8fe3516..2f92168eef 100644 --- a/railties/lib/rails/generators/rails/app/templates/test/test_helper.rb +++ b/railties/lib/rails/generators/rails/app/templates/test/test_helper.rb @@ -1,4 +1,3 @@ -ENV['RAILS_ENV'] ||= 'test' require File.expand_path('../../config/environment', __FILE__) require 'rails/test_help' diff --git a/railties/lib/rails/generators/rails/assets/assets_generator.rb b/railties/lib/rails/generators/rails/assets/assets_generator.rb index 265dada2ca..95d00c2d39 100644 --- a/railties/lib/rails/generators/rails/assets/assets_generator.rb +++ b/railties/lib/rails/generators/rails/assets/assets_generator.rb @@ -7,7 +7,7 @@ module Rails class_option :javascript_engine, desc: "Engine for JavaScripts" class_option :stylesheet_engine, desc: "Engine for Stylesheets" - protected + private def asset_name file_name diff --git a/railties/lib/rails/generators/rails/controller/controller_generator.rb b/railties/lib/rails/generators/rails/controller/controller_generator.rb index 213de37cce..06bdb8b5ce 100644 --- a/railties/lib/rails/generators/rails/controller/controller_generator.rb +++ b/railties/lib/rails/generators/rails/controller/controller_generator.rb @@ -3,6 +3,8 @@ module Rails class ControllerGenerator < NamedBase # :nodoc: argument :actions, type: :array, default: [], banner: "action action" class_option :skip_routes, type: :boolean, desc: "Don't add routes to config/routes.rb." + class_option :helper, type: :boolean + class_option :assets, type: :boolean check_class_collision suffix: "Controller" @@ -14,7 +16,7 @@ module Rails unless options[:skip_routes] actions.reverse_each do |action| # route prepends two spaces onto the front of the string that is passed, this corrects that. - route generate_routing_code(action)[2..-1] + route indent(generate_routing_code(action), 2)[2..-1] end end end @@ -32,27 +34,30 @@ module Rails # end # end def generate_routing_code(action) - depth = regular_class_path.length + depth = 0 + lines = [] + # Create 'namespace' ladder # namespace :foo do # namespace :bar do - namespace_ladder = regular_class_path.each_with_index.map do |ns, i| - indent(" namespace :#{ns} do\n", i * 2) - end.join + regular_class_path.each do |ns| + lines << indent("namespace :#{ns} do\n", depth * 2) + depth += 1 + end # Create route # get 'baz/index' - route = indent(%{ get '#{file_name}/#{action}'\n}, depth * 2) + lines << indent(%{get '#{file_name}/#{action}'\n}, depth * 2) # Create `end` ladder # end # end - end_ladder = (1..depth).reverse_each.map do |i| - indent("end\n", i * 2) - end.join + until depth.zero? + depth -= 1 + lines << indent("end\n", depth * 2) + end - # Combine the 3 parts to generate complete route entry - namespace_ladder + route + end_ladder + lines.join end end end diff --git a/railties/lib/rails/generators/rails/generator/generator_generator.rb b/railties/lib/rails/generators/rails/generator/generator_generator.rb index 8040ec5e7b..299a7da5f1 100644 --- a/railties/lib/rails/generators/rails/generator/generator_generator.rb +++ b/railties/lib/rails/generators/rails/generator/generator_generator.rb @@ -12,7 +12,7 @@ module Rails hook_for :test_framework - protected + private def generator_dir if options[:namespace] diff --git a/railties/lib/rails/generators/rails/plugin/plugin_generator.rb b/railties/lib/rails/generators/rails/plugin/plugin_generator.rb index 9ffeab4fbe..4cf4f8cd9a 100644 --- a/railties/lib/rails/generators/rails/plugin/plugin_generator.rb +++ b/railties/lib/rails/generators/rails/plugin/plugin_generator.rb @@ -81,7 +81,7 @@ task default: :test end PASSTHROUGH_OPTIONS = [ - :skip_active_record, :skip_action_mailer, :skip_javascript, :database, + :skip_active_record, :skip_action_mailer, :skip_javascript, :skip_sprockets, :database, :javascript, :quiet, :pretend, :force, :skip ] @@ -270,8 +270,8 @@ task default: :test @name ||= begin # same as ActiveSupport::Inflector#underscore except not replacing '-' underscored = original_name.dup - underscored.gsub!(/([A-Z]+)([A-Z][a-z])/,'\1_\2') - underscored.gsub!(/([a-z\d])([A-Z])/,'\1_\2') + underscored.gsub!(/([A-Z]+)([A-Z][a-z])/, '\1_\2') + underscored.gsub!(/([a-z\d])([A-Z])/, '\1_\2') underscored.downcase! underscored @@ -283,10 +283,10 @@ task default: :test end def namespaced_name - @namespaced_name ||= name.gsub("-", "/") + @namespaced_name ||= name.tr("-", "/") end - protected + private def create_dummy_app(path = nil) dummy_path(path) if path diff --git a/railties/lib/rails/generators/rails/plugin/templates/bin/test.tt b/railties/lib/rails/generators/rails/plugin/templates/bin/test.tt index 62b94618fd..c0fbb84a93 100644 --- a/railties/lib/rails/generators/rails/plugin/templates/bin/test.tt +++ b/railties/lib/rails/generators/rails/plugin/templates/bin/test.tt @@ -5,4 +5,6 @@ require 'rails/test_unit/minitest_plugin' Rails::TestUnitReporter.executable = 'bin/test' -exit Minitest.run(ARGV) +Minitest.run_via[:rails] = true + +require "active_support/testing/autorun" diff --git a/railties/lib/rails/generators/rails/plugin/templates/test/test_helper.rb b/railties/lib/rails/generators/rails/plugin/templates/test/test_helper.rb index a5eebcb19f..e84e403018 100644 --- a/railties/lib/rails/generators/rails/plugin/templates/test/test_helper.rb +++ b/railties/lib/rails/generators/rails/plugin/templates/test/test_helper.rb @@ -1,6 +1,3 @@ -# Configure Rails Environment -ENV["RAILS_ENV"] = "test" - require File.expand_path("../../<%= options[:dummy_path] -%>/config/environment.rb", __FILE__) <% unless options[:skip_active_record] -%> ActiveRecord::Migrator.migrations_paths = [File.expand_path("../../<%= options[:dummy_path] -%>/db/migrate", __FILE__)] diff --git a/railties/lib/rails/generators/resource_helpers.rb b/railties/lib/rails/generators/resource_helpers.rb index 6d80003271..978b053308 100644 --- a/railties/lib/rails/generators/resource_helpers.rb +++ b/railties/lib/rails/generators/resource_helpers.rb @@ -23,10 +23,14 @@ module Rails assign_controller_names!(controller_name.pluralize) end + # TODO Change this to private once we've dropped Ruby 2.2 support. + # Workaround for Ruby 2.2 "private attribute?" warning. protected attr_reader :controller_name, :controller_file_name + private + def controller_class_path if options[:model_name] @controller_class_path @@ -73,7 +77,7 @@ module Rails end # Initialize ORM::Generators::ActiveModel to access instance methods. - def orm_instance(name=singular_table_name) + def orm_instance(name = singular_table_name) @orm_instance ||= orm_class.new(name) end end diff --git a/railties/lib/rails/generators/test_unit/generator/generator_generator.rb b/railties/lib/rails/generators/test_unit/generator/generator_generator.rb index 59f8d40343..6b6e094453 100644 --- a/railties/lib/rails/generators/test_unit/generator/generator_generator.rb +++ b/railties/lib/rails/generators/test_unit/generator/generator_generator.rb @@ -12,7 +12,7 @@ module TestUnit # :nodoc: template "generator_test.rb", File.join("test/lib/generators", class_path, "#{file_name}_generator_test.rb") end - protected + private def generator_path if options[:namespace] 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 806279788e..67bff8e4f9 100644 --- a/railties/lib/rails/generators/test_unit/mailer/mailer_generator.rb +++ b/railties/lib/rails/generators/test_unit/mailer/mailer_generator.rb @@ -17,7 +17,7 @@ module TestUnit # :nodoc: template "preview.rb", File.join("test/mailers/previews", class_path, "#{file_name}_mailer_preview.rb") end - protected + private def file_name @_file_name ||= super.gsub(/_mailer/i, "") end diff --git a/railties/lib/rails/generators/testing/behaviour.rb b/railties/lib/rails/generators/testing/behaviour.rb index a1e5a233b9..64d641d096 100644 --- a/railties/lib/rails/generators/testing/behaviour.rb +++ b/railties/lib/rails/generators/testing/behaviour.rb @@ -82,23 +82,23 @@ module Rails Rails::Generators::GeneratedAttribute.parse([name, attribute_type, index].compact.join(":")) end - protected + private - def destination_root_is_set? # :nodoc: + def destination_root_is_set? raise "You need to configure your Rails::Generators::TestCase destination root." unless destination_root end - def ensure_current_path # :nodoc: + def ensure_current_path cd current_path end # Clears all files and directories in destination. - def prepare_destination + def prepare_destination # :doc: rm_rf(destination_root) mkdir_p(destination_root) end - def migration_file_name(relative) # :nodoc: + def migration_file_name(relative) absolute = File.expand_path(relative, destination_root) dirname, file_name = File.dirname(absolute), File.basename(absolute).sub(/\.rb$/, "") Dir.glob("#{dirname}/[0-9]*_*.rb").grep(/\d+_#{file_name}.rb$/).first diff --git a/railties/lib/rails/initializable.rb b/railties/lib/rails/initializable.rb index 81b1cd8110..a2615d5efd 100644 --- a/railties/lib/rails/initializable.rb +++ b/railties/lib/rails/initializable.rb @@ -53,7 +53,7 @@ module Rails end end - def run_initializers(group=:default, *args) + def run_initializers(group = :default, *args) return if instance_variable_defined?(:@ran) initializers.tsort_each do |initializer| initializer.run(*args) if initializer.belongs_to?(group) diff --git a/railties/lib/rails/mailers_controller.rb b/railties/lib/rails/mailers_controller.rb index 95de998208..000ce40fbc 100644 --- a/railties/lib/rails/mailers_controller.rb +++ b/railties/lib/rails/mailers_controller.rb @@ -40,12 +40,12 @@ class Rails::MailersController < Rails::ApplicationController # :nodoc: end end - protected - def show_previews? + private + def show_previews? # :doc: ActionMailer::Base.show_previews end - def find_preview + def find_preview # :doc: candidates = [] params[:path].to_s.scan(%r{/|$}) { candidates << $` } preview = candidates.detect { |candidate| ActionMailer::Preview.exists?(candidate) } @@ -57,7 +57,7 @@ class Rails::MailersController < Rails::ApplicationController # :nodoc: end end - def find_preferred_part(*formats) + def find_preferred_part(*formats) # :doc: formats.each do |format| if part = @email.find_first_mime_type(format) return part @@ -69,7 +69,7 @@ class Rails::MailersController < Rails::ApplicationController # :nodoc: end end - def find_part(format) + def find_part(format) # :doc: if part = @email.find_first_mime_type(format) part elsif @email.mime_type == format diff --git a/railties/lib/rails/paths.rb b/railties/lib/rails/paths.rb index 88ec2ba85b..10925de8b2 100644 --- a/railties/lib/rails/paths.rb +++ b/railties/lib/rails/paths.rb @@ -30,7 +30,7 @@ module Rails # root["config/routes"].inspect # => ["config/routes.rb"] # # The +add+ method accepts the following options as arguments: - # eager_load, autoload, autoload_once and glob. + # eager_load, autoload, autoload_once, and glob. # # Finally, the +Path+ object also provides a few helpers: # @@ -45,7 +45,6 @@ module Rails attr_accessor :path def initialize(path) - @current = nil @path = path @root = {} end diff --git a/railties/lib/rails/rack/debugger.rb b/railties/lib/rails/rack/debugger.rb deleted file mode 100644 index dccfa3e9bb..0000000000 --- a/railties/lib/rails/rack/debugger.rb +++ /dev/null @@ -1,3 +0,0 @@ -require "active_support/deprecation" - -ActiveSupport::Deprecation.warn("This file is deprecated and will be removed in Rails 5.1 with no replacement.") diff --git a/railties/lib/rails/rack/logger.rb b/railties/lib/rails/rack/logger.rb index e3fee75603..853fc26051 100644 --- a/railties/lib/rails/rack/logger.rb +++ b/railties/lib/rails/rack/logger.rb @@ -27,45 +27,43 @@ module Rails end end - protected + private - def call_app(request, env) - instrumenter = ActiveSupport::Notifications.instrumenter - instrumenter.start "request.action_dispatch", request: request - logger.info { started_request_message(request) } - resp = @app.call(env) - resp[2] = ::Rack::BodyProxy.new(resp[2]) { finish(request) } - resp - rescue Exception - finish(request) - raise - ensure - ActiveSupport::LogSubscriber.flush_all! - end + def call_app(request, env) # :doc: + instrumenter = ActiveSupport::Notifications.instrumenter + instrumenter.start "request.action_dispatch", request: request + logger.info { started_request_message(request) } + resp = @app.call(env) + resp[2] = ::Rack::BodyProxy.new(resp[2]) { finish(request) } + resp + rescue Exception + finish(request) + raise + ensure + ActiveSupport::LogSubscriber.flush_all! + end - # Started GET "/session/new" for 127.0.0.1 at 2012-09-26 14:51:42 -0700 - def started_request_message(request) - 'Started %s "%s" for %s at %s' % [ - request.request_method, - request.filtered_path, - request.ip, - Time.now.to_default_s ] - end + # Started GET "/session/new" for 127.0.0.1 at 2012-09-26 14:51:42 -0700 + def started_request_message(request) # :doc: + 'Started %s "%s" for %s at %s' % [ + request.request_method, + request.filtered_path, + request.ip, + Time.now.to_default_s ] + end - def compute_tags(request) - @taggers.collect do |tag| - case tag - when Proc - tag.call(request) - when Symbol - request.send(tag) - else - tag + def compute_tags(request) # :doc: + @taggers.collect do |tag| + case tag + when Proc + tag.call(request) + when Symbol + request.send(tag) + else + tag + end end end - end - - private def finish(request) instrumenter = ActiveSupport::Notifications.instrumenter diff --git a/railties/lib/rails/railtie.rb b/railties/lib/rails/railtie.rb index eb3f5d4ee9..474118c0a9 100644 --- a/railties/lib/rails/railtie.rb +++ b/railties/lib/rails/railtie.rb @@ -132,27 +132,19 @@ module Rails end def rake_tasks(&blk) - @rake_tasks ||= [] - @rake_tasks << blk if blk - @rake_tasks + register_block_for(:rake_tasks, &blk) end def console(&blk) - @load_console ||= [] - @load_console << blk if blk - @load_console + register_block_for(:load_console, &blk) end def runner(&blk) - @load_runner ||= [] - @load_runner << blk if blk - @load_runner + register_block_for(:runner, &blk) end def generators(&blk) - @generators ||= [] - @generators << blk if blk - @generators + register_block_for(:generators, &blk) end def abstract_railtie? @@ -181,8 +173,8 @@ module Rails instance.configure(&block) end - protected - def generate_railtie_name(string) #:nodoc: + private + def generate_railtie_name(string) ActiveSupport::Inflector.underscore(string).tr("/", "_") end @@ -195,6 +187,16 @@ module Rails super end end + + # receives an instance variable identifier, set the variable value if is + # blank and append given block to value, which will be used later in + # `#each_registered_block(type, &block)` + def register_block_for(type, &blk) + var_name = "@#{type}" + blocks = instance_variable_defined?(var_name) ? instance_variable_get(var_name) : instance_variable_set(var_name, []) + blocks << blk if blk + blocks + end end delegate :railtie_name, to: :class @@ -241,6 +243,7 @@ module Rails private + # run `&block` in every registered block in `#register_block_for` def each_registered_block(type, &block) klass = self.class while klass.respond_to?(type) diff --git a/railties/lib/rails/railtie/configurable.rb b/railties/lib/rails/railtie/configurable.rb index 39f1f87575..2a8295426e 100644 --- a/railties/lib/rails/railtie/configurable.rb +++ b/railties/lib/rails/railtie/configurable.rb @@ -24,7 +24,7 @@ module Rails class_eval(&block) end - protected + private def method_missing(*args, &block) instance.send(*args, &block) diff --git a/railties/lib/rails/source_annotation_extractor.rb b/railties/lib/rails/source_annotation_extractor.rb index f0df76d3f3..3a48c4c496 100644 --- a/railties/lib/rails/source_annotation_extractor.rb +++ b/railties/lib/rails/source_annotation_extractor.rb @@ -44,7 +44,7 @@ class SourceAnnotationExtractor # # If +options+ has a flag <tt>:tag</tt> the tag is shown as in the example above. # Otherwise the string contains just line and text. - def to_s(options={}) + def to_s(options = {}) s = "[#{line.to_s.rjust(options[:indent])}] " s << "[#{tag}] " if options[:tag] s << text @@ -66,7 +66,7 @@ class SourceAnnotationExtractor # See <tt>#find_in</tt> for a list of file extensions that will be taken into account. # # This class method is the single entry point for the rake tasks. - def self.enumerate(tag, options={}) + def self.enumerate(tag, options = {}) extractor = new(tag) dirs = options.delete(:dirs) || Annotation.directories extractor.display(extractor.find(dirs), options) @@ -116,7 +116,7 @@ class SourceAnnotationExtractor # Otherwise it returns an empty hash. def extract_annotations_from(file, pattern) lineno = 0 - result = File.readlines(file).inject([]) do |list, line| + result = File.readlines(file, encoding: Encoding::BINARY).inject([]) do |list, line| lineno += 1 next list unless line =~ pattern list << Annotation.new(lineno, $1, $2) @@ -126,7 +126,7 @@ class SourceAnnotationExtractor # Prints the mapping from filenames to annotations in +results+ ordered by filename. # The +options+ hash is passed to each annotation's +to_s+. - def display(results, options={}) + def display(results, options = {}) options[:indent] = results.flat_map { |f, a| a.map(&:line) }.max.to_s.size results.keys.sort.each do |file| puts "#{file}:" diff --git a/railties/lib/rails/tasks/framework.rake b/railties/lib/rails/tasks/framework.rake index a2167796eb..d42d001b1a 100644 --- a/railties/lib/rails/tasks/framework.rake +++ b/railties/lib/rails/tasks/framework.rake @@ -73,15 +73,3 @@ namespace :app 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/log.rake b/railties/lib/rails/tasks/log.rake index c376234fee..ba796845d7 100644 --- a/railties/lib/rails/tasks/log.rake +++ b/railties/lib/rails/tasks/log.rake @@ -3,7 +3,7 @@ namespace :log do ## # Truncates all/specified log files # ENV['LOGS'] - # - defaults to standard environment log files i.e. 'development,test,production' + # - defaults to all environments log files i.e. 'development,test,production' # - ENV['LOGS']=all truncates all files i.e. log/*.log # - ENV['LOGS']='test,development' truncates only specified files desc "Truncates all/specified *.log files in log/ to zero bytes (specify which logs with LOGS=test,development)" @@ -19,7 +19,7 @@ namespace :log do elsif ENV["LOGS"] log_files_to_truncate(ENV["LOGS"]) else - log_files_to_truncate("development,test,production") + log_files_to_truncate(all_environments.join(",")) end end @@ -33,4 +33,8 @@ namespace :log do f = File.open(file, "w") f.close end + + def all_environments + Dir["config/environments/*.rb"].map { |fname| File.basename(fname, ".*") } + end end diff --git a/railties/lib/rails/tasks/routes.rake b/railties/lib/rails/tasks/routes.rake index f5e5b9ae87..04daaf4a83 100644 --- a/railties/lib/rails/tasks/routes.rake +++ b/railties/lib/rails/tasks/routes.rake @@ -7,15 +7,8 @@ task routes: :environment do all_routes = Rails.application.routes.routes require "action_dispatch/routing/inspector" inspector = ActionDispatch::Routing::RoutesInspector.new(all_routes) - if ARGV.any? { |argv| argv.start_with? "CONTROLLER" } - puts <<-eow.strip_heredoc - Passing `CONTROLLER` to `bin/rails routes` is deprecated and will be removed in Rails 5.1. - Please use `bin/rails routes -c controller_name` instead. - eow - end routes_filter = nil - routes_filter = { controller: ENV["CONTROLLER"] } if ENV["CONTROLLER"] OptionParser.new do |opts| opts.banner = "Usage: rails routes [options]" diff --git a/railties/lib/rails/tasks/statistics.rake b/railties/lib/rails/tasks/statistics.rake index a6cdd1e99c..ba1697186e 100644 --- a/railties/lib/rails/tasks/statistics.rake +++ b/railties/lib/rails/tasks/statistics.rake @@ -8,9 +8,8 @@ STATS_DIRECTORIES = [ %w(Models app/models), %w(Mailers app/mailers), %w(Channels app/channels), - %w(Javascripts app/assets/javascripts), + %w(JavaScripts app/assets/javascripts), %w(Libraries lib/), - %w(Tasks lib/tasks), %w(APIs app/apis), %w(Controller\ tests test/controllers), %w(Helper\ tests test/helpers), diff --git a/railties/lib/rails/test_unit/minitest_plugin.rb b/railties/lib/rails/test_unit/minitest_plugin.rb index e15c6b3a38..6e196a32ab 100644 --- a/railties/lib/rails/test_unit/minitest_plugin.rb +++ b/railties/lib/rails/test_unit/minitest_plugin.rb @@ -61,19 +61,30 @@ module Minitest # as the patterns would also contain the other Rake tasks. def self.rake_run(patterns) # :nodoc: @rake_patterns = patterns - passed = run(Shellwords.split(ENV["TESTOPTS"] || "")) - exit passed unless passed - passed + autorun end + module RunRespectingRakeTestopts + def run(args = []) + if defined?(@rake_patterns) + args = Shellwords.split(ENV["TESTOPTS"] || "") + end + + super + end + end + + singleton_class.prepend RunRespectingRakeTestopts + # 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 - ENV["RAILS_ENV"] = options[:environment] || "test" - ::Rails::TestRequirer.require_files(options[:patterns]) unless run_with_autorun + # If run via `ruby` we've been passed the files to run directly. + unless run_via[:ruby] + ::Rails::TestRequirer.require_files(options[:patterns]) + end unless options[:full_backtrace] || ENV["BACKTRACE"] # Plugin can run without Rails loaded, check before filtering. @@ -86,8 +97,7 @@ module Minitest reporter << ::Rails::TestUnitReporter.new(options[:io], options) end - mattr_accessor(:run_with_autorun) { false } - mattr_accessor(:run_with_rails_extension) { false } + mattr_accessor(:run_via) { Hash.new } end # Put Rails as the first plugin minitest initializes so other plugins diff --git a/railties/lib/rails/test_unit/railtie.rb b/railties/lib/rails/test_unit/railtie.rb index d0fc795515..746120e6a1 100644 --- a/railties/lib/rails/test_unit/railtie.rb +++ b/railties/lib/rails/test_unit/railtie.rb @@ -14,7 +14,9 @@ module Rails end initializer "test_unit.line_filtering" do - ActiveSupport::TestCase.extend Rails::LineFiltering + ActiveSupport.on_load(:active_support_test_case) { + ActiveSupport::TestCase.extend Rails::LineFiltering + } end rake_tasks do diff --git a/railties/test/app_loader_test.rb b/railties/test/app_loader_test.rb index 7fd5c72c1c..85f5502b4d 100644 --- a/railties/test/app_loader_test.rb +++ b/railties/test/app_loader_test.rb @@ -17,7 +17,7 @@ class AppLoaderTest < ActiveSupport::TestCase end end - def write(filename, contents=nil) + def write(filename, contents = nil) FileUtils.mkdir_p(File.dirname(filename)) File.write(filename, contents) end diff --git a/railties/test/application/assets_test.rb b/railties/test/application/assets_test.rb index e84e01a41b..f38cacd6da 100644 --- a/railties/test/application/assets_test.rb +++ b/railties/test/application/assets_test.rb @@ -375,7 +375,7 @@ module ApplicationTests class ::OmgController < ActionController::Base def index flash[:cool_story] = true - render text: "ok" + render plain: "ok" end end @@ -384,7 +384,7 @@ module ApplicationTests get "/assets/demo.js" assert_match "alert()", last_response.body - assert_equal nil, last_response.headers["Set-Cookie"] + assert_nil last_response.headers["Set-Cookie"] end test "files in any assets/ directories are not added to Sprockets" do @@ -475,9 +475,9 @@ module ApplicationTests class ::PostsController < ActionController::Base; end - get "/posts", {}, "HTTPS"=>"off" + get "/posts", {}, "HTTPS" => "off" assert_match('src="http://example.com/assets/application.self.js', last_response.body) - get "/posts", {}, "HTTPS"=>"on" + get "/posts", {}, "HTTPS" => "on" assert_match('src="https://example.com/assets/application.self.js', last_response.body) end diff --git a/railties/test/application/bin_setup_test.rb b/railties/test/application/bin_setup_test.rb index 0bbd25db2b..f62313f3e1 100644 --- a/railties/test/application/bin_setup_test.rb +++ b/railties/test/application/bin_setup_test.rb @@ -6,17 +6,10 @@ module ApplicationTests def setup build_app - - create_gemfile - update_boot_file_to_use_bundler - @old_gemfile_env = ENV["BUNDLE_GEMFILE"] - ENV["BUNDLE_GEMFILE"] = app_path + "/Gemfile" end def teardown teardown_app - - ENV["BUNDLE_GEMFILE"] = @old_gemfile_env end def test_bin_setup @@ -47,6 +40,7 @@ module ApplicationTests output = `bin/setup 2>&1` assert_equal(<<-OUTPUT, output) == Installing dependencies == +Resolving dependencies... The Gemfile's dependencies are satisfied == Preparing database == @@ -59,16 +53,5 @@ Created database 'db/test.sqlite3' OUTPUT end end - - private - def create_gemfile - app_file("Gemfile", "source 'https://rubygems.org'") - app_file("Gemfile", "gem 'rails', path: '#{RAILS_FRAMEWORK_ROOT}'", "a") - app_file("Gemfile", "gem 'sqlite3'", "a") - end - - def update_boot_file_to_use_bundler - app_file("config/boot.rb", "require 'bundler/setup'") - end end end diff --git a/railties/test/application/configuration/custom_test.rb b/railties/test/application/configuration/custom_test.rb index 13fc98f0d6..3c675eec71 100644 --- a/railties/test/application/configuration/custom_test.rb +++ b/railties/test/application/configuration/custom_test.rb @@ -28,7 +28,7 @@ module ApplicationTests assert_equal 3, x.payment_processing.retries assert_equal true, x.super_debugger assert_equal false, x.hyper_debugger - assert_equal nil, x.nil_debugger + assert_nil x.nil_debugger assert_nil x.i_do_not_exist.zomg end diff --git a/railties/test/application/configuration_test.rb b/railties/test/application/configuration_test.rb index 5dceaae96b..01a9807b6b 100644 --- a/railties/test/application/configuration_test.rb +++ b/railties/test/application/configuration_test.rb @@ -78,6 +78,18 @@ module ApplicationTests end end + test "Rails.env falls back to development if RAILS_ENV is blank and RACK_ENV is nil" do + with_rails_env("") do + assert_equal "development", Rails.env + end + end + + test "Rails.env falls back to development if RACK_ENV is blank and RAILS_ENV is nil" do + with_rack_env("") do + assert_equal "development", Rails.env + end + end + test "By default logs tags are not set in development" do restore_default_config @@ -369,26 +381,6 @@ module ApplicationTests end end - test "config.serve_static_files is deprecated" do - make_basic_app do |application| - assert_deprecated do - application.config.serve_static_files = true - end - - assert application.config.public_file_server.enabled - end - end - - test "config.static_cache_control is deprecated" do - make_basic_app do |application| - assert_deprecated do - application.config.static_cache_control = "public, max-age=60" - end - - assert_equal application.config.static_cache_control, "public, max-age=60" - end - end - test "Use key_generator when secret_key_base is set" do make_basic_app do |application| application.secrets.secret_key_base = "b3c631c314c0bbca50c1b2843150fe33" @@ -398,7 +390,7 @@ module ApplicationTests class ::OmgController < ActionController::Base def index cookies.signed[:some_key] = "some_value" - render text: cookies[:some_key] + render plain: cookies[:some_key] end end @@ -614,7 +606,7 @@ module ApplicationTests app "development" assert_equal "b3c631c314c0bbca50c1b2843150fe33", app.config.secret_token - assert_equal nil, app.secrets.secret_key_base + assert_nil app.secrets.secret_key_base assert_equal app.key_generator.class, ActiveSupport::LegacyKeyGenerator end @@ -630,12 +622,26 @@ module ApplicationTests app "development" assert_equal "", app.config.secret_token - assert_equal nil, app.secrets.secret_key_base + assert_nil app.secrets.secret_key_base assert_raise ArgumentError, /\AA secret is required/ do app.key_generator end end + test "that nested keys are symbolized the same as parents for hashes more than one level deep" do + app_file "config/secrets.yml", <<-YAML + development: + smtp_settings: + address: "smtp.example.com" + user_name: "postmaster@example.com" + password: "697361616320736c6f616e2028656c6f7265737429" + YAML + + app "development" + + assert_equal "697361616320736c6f616e2028656c6f7265737429", app.secrets.smtp_settings[:password] + end + test "protect from forgery is the default in a new app" do make_basic_app @@ -704,7 +710,7 @@ module ApplicationTests end def update - render text: "update" + render plain: "update" end private @@ -978,7 +984,7 @@ module ApplicationTests class ::OmgController < ActionController::Base def index - render text: env["action_dispatch.show_exceptions"] + render plain: request.env["action_dispatch.show_exceptions"] end end @@ -1008,7 +1014,7 @@ module ApplicationTests app_file "app/controllers/posts_controller.rb", <<-RUBY class PostsController < ApplicationController def create - render text: params[:post].inspect + render plain: params[:post].inspect end end RUBY @@ -1029,7 +1035,7 @@ module ApplicationTests app_file "app/controllers/posts_controller.rb", <<-RUBY class PostsController < ActionController::Base def create - render text: params[:post].permitted? ? "permitted" : "forbidden" + render plain: params[:post].permitted? ? "permitted" : "forbidden" end end RUBY @@ -1043,7 +1049,7 @@ module ApplicationTests app "development" - post "/posts", post: { "title" =>"zomg" } + post "/posts", post: { "title" => "zomg" } assert_equal "permitted", last_response.body end @@ -1051,7 +1057,7 @@ module ApplicationTests app_file "app/controllers/posts_controller.rb", <<-RUBY class PostsController < ActionController::Base def create - render text: params.require(:post).permit(:name) + render plain: params.require(:post).permit(:name) end end RUBY @@ -1067,7 +1073,7 @@ module ApplicationTests assert_equal :raise, ActionController::Parameters.action_on_unpermitted_parameters - post "/posts", post: { "title" =>"zomg" } + post "/posts", post: { "title" => "zomg" } assert_match "We're sorry, but something went wrong", last_response.body end @@ -1090,7 +1096,7 @@ module ApplicationTests app_file "app/controllers/posts_controller.rb", <<-RUBY class PostsController < ActionController::Base def create - render text: params.permit(post: [:title]) + render plain: params.permit(post: [:title]) end end RUBY @@ -1107,7 +1113,7 @@ module ApplicationTests assert_equal :raise, ActionController::Parameters.action_on_unpermitted_parameters - post "/posts", post: { "title" =>"zomg" }, format: "json" + post "/posts", post: { "title" => "zomg" }, format: "json" assert_equal 200, last_response.status end @@ -1137,8 +1143,8 @@ module ApplicationTests class ::OmgController < ActionController::Base def index respond_to do |format| - format.html { render text: "HTML" } - format.xml { render text: "XML" } + format.html { render plain: "HTML" } + format.xml { render plain: "XML" } end end end @@ -1190,7 +1196,7 @@ module ApplicationTests application.config.session_store :disabled end - assert_equal nil, app.config.session_store + assert_nil app.config.session_store end test "default session store initializer sets session store to cookie store" do @@ -1518,5 +1524,24 @@ module ApplicationTests assert_equal :default, Rails.configuration.debug_exception_response_format end + + test "controller force_ssl declaration can be used even if session_store is disabled" do + make_basic_app do |application| + application.config.session_store :disabled + end + + class ::OmgController < ActionController::Base + force_ssl + + def index + render plain: "Yay! You're on Rails!" + end + end + + get "/" + + assert_equal 301, last_response.status + assert_equal "https://example.org/", last_response.location + end end end diff --git a/railties/test/application/console_test.rb b/railties/test/application/console_test.rb index 3b8062f74b..72f340df34 100644 --- a/railties/test/application/console_test.rb +++ b/railties/test/application/console_test.rb @@ -126,7 +126,7 @@ class FullStackConsoleTest < ActiveSupport::TestCase end end - assert output.include?(expected), "#{expected.inspect} expected, but got:\n\n#{output}" + assert_includes output, expected, "#{expected.inspect} expected, but got:\n\n#{output}" end def write_prompt(command, expected_output = nil) diff --git a/railties/test/application/generators_test.rb b/railties/test/application/generators_test.rb index d4008fe677..d2ce14f594 100644 --- a/railties/test/application/generators_test.rb +++ b/railties/test/application/generators_test.rb @@ -134,10 +134,10 @@ module ApplicationTests require "#{app_path}/config/environment" Rails.application.load_generators - assert Rails::Generators.hidden_namespaces.include?("assets") - assert Rails::Generators.hidden_namespaces.include?("helper") - assert Rails::Generators.hidden_namespaces.include?("js") - assert Rails::Generators.hidden_namespaces.include?("css") + assert_includes Rails::Generators.hidden_namespaces, "assets" + assert_includes Rails::Generators.hidden_namespaces, "helper" + assert_includes Rails::Generators.hidden_namespaces, "js" + assert_includes Rails::Generators.hidden_namespaces, "css" assert Rails::Generators.options[:rails][:api] assert_equal false, Rails::Generators.options[:rails][:assets] assert_equal false, Rails::Generators.options[:rails][:helper] @@ -169,5 +169,20 @@ module ApplicationTests assert File.exist?(File.join(rails_root, "app/views/notifier_mailer/foo.text.erb")) assert File.exist?(File.join(rails_root, "app/views/notifier_mailer/foo.html.erb")) end + + test "ARGV is mutated as expected" do + require "#{app_path}/config/environment" + Rails::Command.const_set("APP_PATH", "rails/all") + + FileUtils.cd(rails_root) do + ARGV = ["mailer", "notifier", "foo"] + Rails::Command.const_set("ARGV", ARGV) + quietly { Rails::Command.invoke :generate, ARGV } + + assert_equal ["notifier", "foo"], ARGV + end + + Rails::Command.send(:remove_const, "APP_PATH") + end end end diff --git a/railties/test/application/initializers/frameworks_test.rb b/railties/test/application/initializers/frameworks_test.rb index b2cd339c1a..90927159dd 100644 --- a/railties/test/application/initializers/frameworks_test.rb +++ b/railties/test/application/initializers/frameworks_test.rb @@ -185,7 +185,7 @@ module ApplicationTests test "if there's no config.active_support.bare, all of ActiveSupport is required" do use_frameworks [] require "#{app_path}/config/environment" - assert_nothing_raised { [1,2,3].sample } + assert_nothing_raised { [1, 2, 3].sample } end test "config.active_support.bare does not require all of ActiveSupport" do @@ -219,7 +219,7 @@ module ApplicationTests end require "#{app_path}/config/environment" ActiveRecord::Base.connection.drop_table("posts") # force drop posts table for test. - assert ActiveRecord::Base.connection.schema_cache.tables("posts") + assert ActiveRecord::Base.connection.schema_cache.data_sources("posts") end test "expire schema cache dump" do @@ -227,10 +227,8 @@ module ApplicationTests `rails generate model post title:string; bin/rails db:migrate db:schema:cache:dump db:rollback` end - silence_warnings { - require "#{app_path}/config/environment" - assert !ActiveRecord::Base.connection.schema_cache.tables("posts") - } + require "#{app_path}/config/environment" + assert !ActiveRecord::Base.connection.schema_cache.data_sources("posts") end test "active record establish_connection uses Rails.env if DATABASE_URL is not set" do diff --git a/railties/test/application/initializers/hooks_test.rb b/railties/test/application/initializers/hooks_test.rb index 0309d02730..36926c50ff 100644 --- a/railties/test/application/initializers/hooks_test.rb +++ b/railties/test/application/initializers/hooks_test.rb @@ -31,7 +31,7 @@ module ApplicationTests RUBY require "#{app_path}/config/environment" - assert_equal [1,2,3], $initialization_callbacks + assert_equal [1, 2, 3], $initialization_callbacks end test "hooks block works correctly with eager_load" do @@ -46,7 +46,7 @@ module ApplicationTests RUBY require "#{app_path}/config/environment" - assert_equal [1,2,3,4], $initialization_callbacks + assert_equal [1, 2, 3, 4], $initialization_callbacks end test "after_initialize runs after frameworks have been initialized" do diff --git a/railties/test/application/initializers/i18n_test.rb b/railties/test/application/initializers/i18n_test.rb index 0ddaf346e0..206e42703b 100644 --- a/railties/test/application/initializers/i18n_test.rb +++ b/railties/test/application/initializers/i18n_test.rb @@ -30,7 +30,7 @@ module ApplicationTests end def assert_no_fallbacks - assert !I18n.backend.class.included_modules.include?(I18n::Backend::Fallbacks) + assert_not_includes I18n.backend.class.included_modules, I18n::Backend::Fallbacks end # Locales @@ -62,8 +62,8 @@ module ApplicationTests "#{app_path}/config/locales/en.yml", "#{app_path}/config/another_locale.yml" ], Rails.application.config.i18n.load_path - assert I18n.load_path.include?("#{app_path}/config/locales/en.yml") - assert I18n.load_path.include?("#{app_path}/config/another_locale.yml") + assert_includes I18n.load_path, "#{app_path}/config/locales/en.yml" + assert_includes I18n.load_path, "#{app_path}/config/another_locale.yml" end test "load_path is populated before eager loaded models" do @@ -214,7 +214,7 @@ fr: test "config.i18n.fallbacks = true initializes I18n.fallbacks with default settings" do I18n::Railtie.config.i18n.fallbacks = true load_app - assert I18n.backend.class.included_modules.include?(I18n::Backend::Fallbacks) + assert_includes I18n.backend.class.included_modules, I18n::Backend::Fallbacks assert_fallbacks de: [:de, :en] end @@ -222,7 +222,7 @@ fr: I18n::Railtie.config.i18n.fallbacks = true I18n::Railtie.config.i18n.backend = Class.new(I18n::Backend::Simple).new load_app - assert I18n.backend.class.included_modules.include?(I18n::Backend::Fallbacks) + assert_includes I18n.backend.class.included_modules, I18n::Backend::Fallbacks assert_fallbacks de: [:de, :en] end diff --git a/railties/test/application/initializers/load_path_test.rb b/railties/test/application/initializers/load_path_test.rb index caab7c0c8a..dbefb22837 100644 --- a/railties/test/application/initializers/load_path_test.rb +++ b/railties/test/application/initializers/load_path_test.rb @@ -19,7 +19,7 @@ module ApplicationTests RUBY require "#{app_path}/config/environment" - assert $:.include?("#{app_path}/app/models") + assert_includes $:, "#{app_path}/app/models" end test "initializing an application allows to load code on lib path inside application class definition" do @@ -36,7 +36,7 @@ module ApplicationTests require "#{app_path}/config/environment" end - assert $:.include?("#{app_path}/lib") + assert_includes $:, "#{app_path}/lib" end test "initializing an application eager load any path under app" do diff --git a/railties/test/application/loading_test.rb b/railties/test/application/loading_test.rb index 38f96f3ab9..c75a25bc6f 100644 --- a/railties/test/application/loading_test.rb +++ b/railties/test/application/loading_test.rb @@ -357,7 +357,7 @@ class LoadingTest < ActiveSupport::TestCase assert Rails.application.initialized? end - protected + private def setup_ar! ActiveRecord::Base.establish_connection(adapter: "sqlite3", database: ":memory:") diff --git a/railties/test/application/middleware/cache_test.rb b/railties/test/application/middleware/cache_test.rb index cd1371359a..dc1d816dc5 100644 --- a/railties/test/application/middleware/cache_test.rb +++ b/railties/test/application/middleware/cache_test.rb @@ -19,7 +19,7 @@ module ApplicationTests class ExpiresController < ApplicationController def expires_header expires_in 10, public: !params[:private] - render text: SecureRandom.hex(16) + render plain: SecureRandom.hex(16) end def expires_etag @@ -32,12 +32,12 @@ module ApplicationTests end def keeps_if_modified_since - render :text => request.headers['If-Modified-Since'] + render plain: request.headers['If-Modified-Since'] end private def render_conditionally(headers) if stale?(headers.merge(public: !params[:private])) - render text: SecureRandom.hex(16) + render plain: SecureRandom.hex(16) end end end diff --git a/railties/test/application/middleware/session_test.rb b/railties/test/application/middleware/session_test.rb index 2873425703..959a629ede 100644 --- a/railties/test/application/middleware/session_test.rb +++ b/railties/test/application/middleware/session_test.rb @@ -70,7 +70,7 @@ module ApplicationTests end def read_session - render text: session[:foo].inspect + render plain: session[:foo].inspect end end RUBY @@ -111,7 +111,7 @@ module ApplicationTests end def read_cookie - render text: cookies[:foo].inspect + render plain: cookies[:foo].inspect end end RUBY @@ -149,15 +149,15 @@ module ApplicationTests end def read_session - render text: session[:foo] + render plain: session[:foo] end def read_encrypted_cookie - render text: cookies.encrypted[:_myapp_session]['foo'] + render plain: cookies.encrypted[:_myapp_session]['foo'] end def read_raw_cookie - render text: cookies[:_myapp_session] + render plain: cookies[:_myapp_session] end end RUBY @@ -173,7 +173,7 @@ module ApplicationTests secret = app.key_generator.generate_key("encrypted cookie") sign_secret = app.key_generator.generate_key("signed encrypted cookie") - encryptor = ActiveSupport::MessageEncryptor.new(secret, sign_secret) + encryptor = ActiveSupport::MessageEncryptor.new(secret[0, ActiveSupport::MessageEncryptor.key_len], sign_secret) get "/foo/read_raw_cookie" assert_equal 1, encryptor.decrypt_and_verify(last_response.body)["foo"] @@ -194,15 +194,15 @@ module ApplicationTests end def read_session - render text: session[:foo] + render plain: session[:foo] end def read_encrypted_cookie - render text: cookies.encrypted[:_myapp_session]['foo'] + render plain: cookies.encrypted[:_myapp_session]['foo'] end def read_raw_cookie - render text: cookies[:_myapp_session] + render plain: cookies[:_myapp_session] end end RUBY @@ -222,7 +222,7 @@ module ApplicationTests secret = app.key_generator.generate_key("encrypted cookie") sign_secret = app.key_generator.generate_key("signed encrypted cookie") - encryptor = ActiveSupport::MessageEncryptor.new(secret, sign_secret) + encryptor = ActiveSupport::MessageEncryptor.new(secret[0, ActiveSupport::MessageEncryptor.key_len], sign_secret) get "/foo/read_raw_cookie" assert_equal 1, encryptor.decrypt_and_verify(last_response.body)["foo"] @@ -249,15 +249,15 @@ module ApplicationTests end def read_session - render text: session[:foo] + render plain: session[:foo] end def read_encrypted_cookie - render text: cookies.encrypted[:_myapp_session]['foo'] + render plain: cookies.encrypted[:_myapp_session]['foo'] end def read_raw_cookie - render text: cookies[:_myapp_session] + render plain: cookies[:_myapp_session] end end RUBY @@ -281,7 +281,7 @@ module ApplicationTests secret = app.key_generator.generate_key("encrypted cookie") sign_secret = app.key_generator.generate_key("signed encrypted cookie") - encryptor = ActiveSupport::MessageEncryptor.new(secret, sign_secret) + encryptor = ActiveSupport::MessageEncryptor.new(secret[0, ActiveSupport::MessageEncryptor.key_len], sign_secret) get "/foo/read_raw_cookie" assert_equal 2, encryptor.decrypt_and_verify(last_response.body)["foo"] @@ -308,15 +308,15 @@ module ApplicationTests end def read_session - render text: session[:foo] + render plain: session[:foo] end def read_signed_cookie - render text: cookies.signed[:_myapp_session]['foo'] + render plain: cookies.signed[:_myapp_session]['foo'] end def read_raw_cookie - render text: cookies[:_myapp_session] + render plain: cookies[:_myapp_session] end end RUBY @@ -370,7 +370,7 @@ module ApplicationTests assert_equal 200, last_response.status assert_equal "It worked!", last_response.body - refute Rails.application.middleware.include?(ActionDispatch::Flash) + assert_not_includes Rails.application.middleware, ActionDispatch::Flash end test "cookie_only is set to true even if user tries to overwrite it" do diff --git a/railties/test/application/middleware_test.rb b/railties/test/application/middleware_test.rb index 1cc931b29e..0a6e5b52e9 100644 --- a/railties/test/application/middleware_test.rb +++ b/railties/test/application/middleware_test.rb @@ -30,10 +30,10 @@ module ApplicationTests "Rack::Runtime", "Rack::MethodOverride", "ActionDispatch::RequestId", - "Rails::Rack::Logger", # must come after Rack::MethodOverride to properly log overridden methods + "ActionDispatch::RemoteIp", + "Rails::Rack::Logger", "ActionDispatch::ShowExceptions", "ActionDispatch::DebugExceptions", - "ActionDispatch::RemoteIp", "ActionDispatch::Reloader", "ActionDispatch::Callbacks", "ActiveRecord::Migration::CheckPending", @@ -58,10 +58,10 @@ module ApplicationTests "ActiveSupport::Cache::Strategy::LocalCache", "Rack::Runtime", "ActionDispatch::RequestId", - "Rails::Rack::Logger", # must come after Rack::MethodOverride to properly log overridden methods + "ActionDispatch::RemoteIp", + "Rails::Rack::Logger", "ActionDispatch::ShowExceptions", "ActionDispatch::DebugExceptions", - "ActionDispatch::RemoteIp", "ActionDispatch::Reloader", "ActionDispatch::Callbacks", "Rack::Head", @@ -70,10 +70,41 @@ module ApplicationTests ], middleware end + test "middleware dependencies" do + boot! + + # The following array-of-arrays describes dependencies between + # middlewares: the first item in each list depends on the + # remaining items (and therefore must occur later in the + # middleware stack). + + dependencies = [ + # Logger needs a fully "corrected" request environment + %w(Rails::Rack::Logger Rack::MethodOverride ActionDispatch::RequestId ActionDispatch::RemoteIp), + + # Serving public/ doesn't invoke user code, so it should skip + # locks etc + %w(ActionDispatch::Executor ActionDispatch::Static), + + # Errors during reload must be reported + %w(ActionDispatch::Reloader ActionDispatch::ShowExceptions ActionDispatch::DebugExceptions), + + # Outright dependencies + %w(ActionDispatch::Static Rack::Sendfile), + %w(ActionDispatch::Flash ActionDispatch::Session::CookieStore), + %w(ActionDispatch::Session::CookieStore ActionDispatch::Cookies), + ] + + require "tsort" + sorted = TSort.tsort((middleware | dependencies.flatten).method(:each), + lambda { |n, &b| dependencies.each { |m, *ds| ds.each(&b) if m == n } }) + assert_equal sorted, middleware + end + test "Rack::Cache is not included by default" do boot! - assert !middleware.include?("Rack::Cache"), "Rack::Cache is not included in the default stack unless you set config.action_dispatch.rack_cache" + assert_not_includes middleware, "Rack::Cache", "Rack::Cache is not included in the default stack unless you set config.action_dispatch.rack_cache" end test "Rack::Cache is present when action_dispatch.rack_cache is set" do @@ -81,7 +112,7 @@ module ApplicationTests boot! - assert middleware.include?("Rack::Cache") + assert_includes middleware, "Rack::Cache" end test "ActiveRecord::Migration::CheckPending is present when active_record.migration_error is set to :page_load" do @@ -89,27 +120,27 @@ module ApplicationTests boot! - assert middleware.include?("ActiveRecord::Migration::CheckPending") + assert_includes middleware, "ActiveRecord::Migration::CheckPending" end test "ActionDispatch::SSL is present when force_ssl is set" do add_to_config "config.force_ssl = true" boot! - assert middleware.include?("ActionDispatch::SSL") + assert_includes middleware, "ActionDispatch::SSL" end test "ActionDispatch::SSL is configured with options when given" do add_to_config "config.force_ssl = true" - add_to_config "config.ssl_options = { host: 'example.com' }" + add_to_config "config.ssl_options = { redirect: { host: 'example.com' } }" boot! - assert_equal [{ host: "example.com" }], Rails.application.middleware.first.args + assert_equal [{ redirect: { host: "example.com" } }], Rails.application.middleware.first.args end test "removing Active Record omits its middleware" do use_frameworks [] boot! - assert !middleware.include?("ActiveRecord::Migration::CheckPending") + assert_not_includes middleware, "ActiveRecord::Migration::CheckPending" end test "includes executor" do @@ -139,20 +170,20 @@ module ApplicationTests test "removes static asset server if public_file_server.enabled is disabled" do add_to_config "config.public_file_server.enabled = false" boot! - assert !middleware.include?("ActionDispatch::Static") + assert_not_includes middleware, "ActionDispatch::Static" end test "can delete a middleware from the stack" do add_to_config "config.middleware.delete ActionDispatch::Static" boot! - assert !middleware.include?("ActionDispatch::Static") + assert_not_includes middleware, "ActionDispatch::Static" end test "can delete a middleware from the stack even if insert_before is added after delete" do add_to_config "config.middleware.delete Rack::Runtime" add_to_config "config.middleware.insert_before(Rack::Runtime, Rack::Config)" boot! - assert middleware.include?("Rack::Config") + assert_includes middleware, "Rack::Config" assert_not middleware.include?("Rack::Runtime") end @@ -160,21 +191,21 @@ module ApplicationTests add_to_config "config.middleware.delete Rack::Runtime" add_to_config "config.middleware.insert_after(Rack::Runtime, Rack::Config)" boot! - assert middleware.include?("Rack::Config") + assert_includes middleware, "Rack::Config" assert_not middleware.include?("Rack::Runtime") end test "includes exceptions middlewares even if action_dispatch.show_exceptions is disabled" do add_to_config "config.action_dispatch.show_exceptions = false" boot! - assert middleware.include?("ActionDispatch::ShowExceptions") - assert middleware.include?("ActionDispatch::DebugExceptions") + assert_includes middleware, "ActionDispatch::ShowExceptions" + assert_includes middleware, "ActionDispatch::DebugExceptions" end test "removes ActionDispatch::Reloader if cache_classes is true" do add_to_config "config.cache_classes = true" boot! - assert !middleware.include?("ActionDispatch::Reloader") + assert_not_includes middleware, "ActionDispatch::Reloader" end test "use middleware" do @@ -227,9 +258,9 @@ module ApplicationTests class ::OmgController < ActionController::Base def index if params[:nothing] - render text: "" + render plain: "" else - render text: "OMG" + render plain: "OMG" end end end @@ -239,23 +270,23 @@ module ApplicationTests get "/" assert_equal 200, last_response.status assert_equal "OMG", last_response.body - assert_equal "text/html; charset=utf-8", last_response.headers["Content-Type"] + assert_equal "text/plain; charset=utf-8", last_response.headers["Content-Type"] assert_equal "max-age=0, private, must-revalidate", last_response.headers["Cache-Control"] assert_equal etag, last_response.headers["Etag"] get "/", {}, "HTTP_IF_NONE_MATCH" => etag assert_equal 304, last_response.status assert_equal "", last_response.body - assert_equal nil, last_response.headers["Content-Type"] + assert_nil last_response.headers["Content-Type"] assert_equal "max-age=0, private, must-revalidate", last_response.headers["Cache-Control"] assert_equal etag, last_response.headers["Etag"] get "/?nothing=true" assert_equal 200, last_response.status assert_equal "", last_response.body - assert_equal "text/html; charset=utf-8", last_response.headers["Content-Type"] + assert_equal "text/plain; charset=utf-8", last_response.headers["Content-Type"] assert_equal "no-cache", last_response.headers["Cache-Control"] - assert_equal nil, last_response.headers["Etag"] + assert_nil last_response.headers["Etag"] end test "ORIGINAL_FULLPATH is passed to env" do diff --git a/railties/test/application/paths_test.rb b/railties/test/application/paths_test.rb index 8eb1d42b33..515205296c 100644 --- a/railties/test/application/paths_test.rb +++ b/railties/test/application/paths_test.rb @@ -55,9 +55,9 @@ module ApplicationTests test "booting up Rails yields a list of paths that are eager" do eager_load = @paths.eager_load - assert eager_load.include?(root("app/controllers")) - assert eager_load.include?(root("app/helpers")) - assert eager_load.include?(root("app/models")) + assert_includes eager_load, root("app/controllers") + assert_includes eager_load, root("app/helpers") + assert_includes eager_load, root("app/models") end test "environments has a glob equal to the current environment" do diff --git a/railties/test/application/rake/log_test.rb b/railties/test/application/rake/log_test.rb new file mode 100644 index 0000000000..fdd3c71fe8 --- /dev/null +++ b/railties/test/application/rake/log_test.rb @@ -0,0 +1,33 @@ +require "isolation/abstract_unit" + +module ApplicationTests + module RakeTests + class LogTest < ActiveSupport::TestCase + include ActiveSupport::Testing::Isolation + + def setup + build_app + end + + def teardown + teardown_app + end + + test "log:clear clear all environments log files by default" do + Dir.chdir(app_path) do + File.open("config/environments/staging.rb", "w") + + File.write("log/staging.log", "staging") + File.write("log/test.log", "test") + File.write("log/dummy.log", "dummy") + + `rails log:clear` + + assert_equal 0, File.size("log/test.log") + assert_equal 0, File.size("log/staging.log") + assert_equal 5, File.size("log/dummy.log") + end + end + end + end +end diff --git a/railties/test/application/rake/restart_test.rb b/railties/test/application/rake/restart_test.rb index 28da8164a7..6ebd2d5461 100644 --- a/railties/test/application/rake/restart_test.rb +++ b/railties/test/application/rake/restart_test.rb @@ -13,32 +13,32 @@ module ApplicationTests teardown_app end - test "rake restart touches tmp/restart.txt" do + test "rails restart touches tmp/restart.txt" do Dir.chdir(app_path) do - `rake restart` + `bin/rails restart` assert File.exist?("tmp/restart.txt") prev_mtime = File.mtime("tmp/restart.txt") sleep(1) - `rake restart` + `bin/rails restart` curr_mtime = File.mtime("tmp/restart.txt") assert_not_equal prev_mtime, curr_mtime end end - test "rake restart should work even if tmp folder does not exist" do + test "rails restart should work even if tmp folder does not exist" do Dir.chdir(app_path) do FileUtils.remove_dir("tmp") - `rake restart` + `bin/rails restart` assert File.exist?("tmp/restart.txt") end end - test "rake restart removes server.pid also" do + test "rails restart removes server.pid also" do Dir.chdir(app_path) do FileUtils.mkdir_p("tmp/pids") FileUtils.touch("tmp/pids/server.pid") - `rake restart` + `bin/rails restart` assert_not File.exist?("tmp/pids/server.pid") end end diff --git a/railties/test/application/rake_test.rb b/railties/test/application/rake_test.rb index 5fd5507453..70c7688789 100644 --- a/railties/test/application/rake_test.rb +++ b/railties/test/application/rake_test.rb @@ -132,43 +132,21 @@ module ApplicationTests assert_equal "Prefix Verb URI Pattern Controller#Action\n cart GET /cart(.:format) cart#show\n", output end - def test_rails_routes_with_controller_environment + def test_singular_resource_output_in_rake_routes app_file "config/routes.rb", <<-RUBY Rails.application.routes.draw do - get '/cart', to: 'cart#show' - get '/basketball', to: 'basketball#index' + resource :post end RUBY - output = Dir.chdir(app_path) { `bin/rails routes CONTROLLER=cart` } - assert_equal ["Passing `CONTROLLER` to `bin/rails routes` is deprecated and will be removed in Rails 5.1.", - "Please use `bin/rails routes -c controller_name` instead.", - "Prefix Verb URI Pattern Controller#Action", - " cart GET /cart(.:format) cart#show\n"].join("\n"), output - - output = Dir.chdir(app_path) { `bin/rails routes -c cart` } - assert_equal "Prefix Verb URI Pattern Controller#Action\n cart GET /cart(.:format) cart#show\n", output - end - - def test_rails_routes_with_namespaced_controller_environment - app_file "config/routes.rb", <<-RUBY - Rails.application.routes.draw do - namespace :admin do - resource :post - end - end - RUBY - expected_output = [" Prefix Verb URI Pattern Controller#Action", - " admin_post POST /admin/post(.:format) admin/posts#create", - " new_admin_post GET /admin/post/new(.:format) admin/posts#new", - "edit_admin_post GET /admin/post/edit(.:format) admin/posts#edit", - " GET /admin/post(.:format) admin/posts#show", - " PATCH /admin/post(.:format) admin/posts#update", - " PUT /admin/post(.:format) admin/posts#update", - " DELETE /admin/post(.:format) admin/posts#destroy\n"].join("\n") - - output = Dir.chdir(app_path) { `bin/rails routes -c Admin::PostController` } - assert_equal expected_output, output + expected_output = [" Prefix Verb URI Pattern Controller#Action", + " new_post GET /post/new(.:format) posts#new", + "edit_post GET /post/edit(.:format) posts#edit", + " post GET /post(.:format) posts#show", + " PATCH /post(.:format) posts#update", + " PUT /post(.:format) posts#update", + " DELETE /post(.:format) posts#destroy", + " POST /post(.:format) posts#create\n"].join("\n") output = Dir.chdir(app_path) { `bin/rails routes -c PostController` } assert_equal expected_output, output @@ -212,6 +190,31 @@ module ApplicationTests assert_equal "Prefix Verb URI Pattern Controller#Action\n cart GET /cart(.:format) cart#show\n", output end + def test_rails_routes_with_namespaced_controller_search_key + app_file "config/routes.rb", <<-RUBY + Rails.application.routes.draw do + namespace :admin do + resource :post + end + end + RUBY + expected_output = [" Prefix Verb URI Pattern Controller#Action", + " new_admin_post GET /admin/post/new(.:format) admin/posts#new", + "edit_admin_post GET /admin/post/edit(.:format) admin/posts#edit", + " admin_post GET /admin/post(.:format) admin/posts#show", + " PATCH /admin/post(.:format) admin/posts#update", + " PUT /admin/post(.:format) admin/posts#update", + " DELETE /admin/post(.:format) admin/posts#destroy", + " POST /admin/post(.:format) admin/posts#create\n"].join("\n") + + output = Dir.chdir(app_path) { `bin/rails routes -c Admin::PostController` } + assert_equal expected_output, output + + output = Dir.chdir(app_path) { `bin/rails routes -c PostController` } + assert_equal expected_output, output + end + + def test_rails_routes_displays_message_when_no_routes_are_defined app_file "config/routes.rb", <<-RUBY Rails.application.routes.draw do @@ -321,16 +324,6 @@ module ApplicationTests assert_no_match(/Errors running/, output) end - def test_db_test_clone_when_using_sql_format - add_to_config "config.active_record.schema_format = :sql" - output = Dir.chdir(app_path) do - `bin/rails generate scaffold user username:string; - bin/rails db:migrate; - bin/rails db:test:clone 2>&1 --trace` - end - assert_match(/Execute db:test:clone_structure/, output) - end - def test_db_test_prepare_when_using_sql_format add_to_config "config.active_record.schema_format = :sql" output = Dir.chdir(app_path) do @@ -367,14 +360,14 @@ module ApplicationTests bin/rails generate model product name:string; bin/rails db:migrate db:schema:cache:dump` end - assert File.exist?(File.join(app_path, "db", "schema_cache.dump")) + assert File.exist?(File.join(app_path, "db", "schema_cache.yml")) end def test_rake_clear_schema_cache Dir.chdir(app_path) do `bin/rails db:schema:cache:dump db:schema:cache:clear` end - assert !File.exist?(File.join(app_path, "db", "schema_cache.dump")) + assert !File.exist?(File.join(app_path, "db", "schema_cache.yml")) end def test_copy_templates diff --git a/railties/test/application/routing_test.rb b/railties/test/application/routing_test.rb index c86759de5a..c515e2b270 100644 --- a/railties/test/application/routing_test.rb +++ b/railties/test/application/routing_test.rb @@ -65,7 +65,7 @@ module ApplicationTests controller :foo, <<-RUBY class FooController < ApplicationController def index - render text: "foo" + render plain: "foo" end end RUBY @@ -156,7 +156,7 @@ module ApplicationTests controller :foo, <<-RUBY class FooController < ApplicationController def index - render text: my_blog_path + render plain: my_blog_path end end RUBY @@ -176,7 +176,7 @@ module ApplicationTests controller :foo, <<-RUBY class FooController < ApplicationController def index - render text: "foo" + render plain: "foo" end end RUBY @@ -184,7 +184,7 @@ module ApplicationTests controller :bar, <<-RUBY class BarController < ActionController::Base def index - render text: "bar" + render plain: "bar" end end RUBY @@ -206,7 +206,7 @@ module ApplicationTests controller "foo", <<-RUBY class FooController < ApplicationController def index - render text: "foo" + render plain: "foo" end end RUBY @@ -215,7 +215,7 @@ module ApplicationTests module Admin class FooController < ApplicationController def index - render text: "admin::foo" + render plain: "admin::foo" end end end @@ -268,11 +268,11 @@ module ApplicationTests controller :foo, <<-RUBY class FooController < ApplicationController def bar - render text: "bar" + render plain: "bar" end def baz - render text: "baz" + render plain: "baz" end end RUBY @@ -332,7 +332,7 @@ module ApplicationTests controller :foo, <<-RUBY class FooController < ApplicationController def index - render :text => "foo" + render plain: "foo" end end RUBY @@ -356,7 +356,7 @@ module ApplicationTests controller :foo, <<-RUBY class FooController < ApplicationController def index - render text: "foo" + render plain: "foo" end end RUBY @@ -364,7 +364,7 @@ module ApplicationTests controller :bar, <<-RUBY class BarController < ApplicationController def index - render text: "bar" + render plain: "bar" end end RUBY @@ -427,7 +427,7 @@ module ApplicationTests controller :foo, <<-RUBY class FooController < ApplicationController def index - render text: "foo" + render plain: "foo" end end RUBY @@ -435,7 +435,7 @@ module ApplicationTests controller :bar, <<-RUBY class BarController < ApplicationController def index - render text: "bar" + render plain: "bar" end end RUBY @@ -482,7 +482,7 @@ module ApplicationTests controller "yazilar", <<-RUBY class YazilarController < ApplicationController def index - render text: 'yazilar#index' + render plain: 'yazilar#index' end end RUBY diff --git a/railties/test/application/runner_test.rb b/railties/test/application/runner_test.rb index 4dc766dfda..7d058f6ee6 100644 --- a/railties/test/application/runner_test.rb +++ b/railties/test/application/runner_test.rb @@ -43,6 +43,15 @@ module ApplicationTests assert_match "42", Dir.chdir(app_path) { `bin/rails runner "bin/count_users.rb"` } end + def test_no_minitest_loaded_in_production_mode + app_file "bin/print_features.rb", <<-SCRIPT + p $LOADED_FEATURES.grep(/minitest/) + SCRIPT + assert_match "[]", Dir.chdir(app_path) { + `RAILS_ENV=production bin/rails runner "bin/print_features.rb"` + } + end + def test_should_set_dollar_0_to_file app_file "bin/dollar0.rb", <<-SCRIPT puts $0 @@ -59,6 +68,14 @@ module ApplicationTests assert_match "bin/program_name.rb", Dir.chdir(app_path) { `bin/rails runner "bin/program_name.rb"` } end + def test_passes_extra_args_to_file + app_file "bin/program_name.rb", <<-SCRIPT + p ARGV + SCRIPT + + assert_match %w( a b ).to_s, Dir.chdir(app_path) { `bin/rails runner "bin/program_name.rb" a b` } + end + def test_with_hook add_to_config <<-RUBY runner do |app| @@ -82,7 +99,7 @@ module ApplicationTests def test_runner_detects_bad_script_name output = Dir.chdir(app_path) { `bin/rails runner "iuiqwiourowe" 2>&1` } assert_not $?.success? - assert_match "undefined local variable or method `iuiqwiourowe' for main:Object", output + assert_match "undefined local variable or method `iuiqwiourowe' for", output end def test_environment_with_rails_env diff --git a/railties/test/application/test_runner_test.rb b/railties/test/application/test_runner_test.rb index b442891769..0939587960 100644 --- a/railties/test/application/test_runner_test.rb +++ b/railties/test/application/test_runner_test.rb @@ -495,7 +495,7 @@ module ApplicationTests create_test_file :models, "post", pass: false # This specifically verifies TEST for backwards compatibility with rake test # as bin/rails test already supports running tests from a single file more cleanly. - output = Dir.chdir(app_path) { `bin/rake test TEST=test/models/post_test.rb` } + output = Dir.chdir(app_path) { `bin/rake test TEST=test/models/post_test.rb` } assert_match "PostTest", output, "passing TEST= should run selected test" assert_no_match "AccountTest", output, "passing TEST= should only run selected test" @@ -504,7 +504,7 @@ module ApplicationTests def test_pass_rake_options create_test_file :models, "account" - output = Dir.chdir(app_path) { `bin/rake --rakefile Rakefile --trace=stdout test` } + output = Dir.chdir(app_path) { `bin/rake --rakefile Rakefile --trace=stdout test` } assert_match "1 runs, 1 assertions", output assert_match "Execute test", output @@ -512,26 +512,26 @@ module ApplicationTests def test_rails_db_create_all_restores_db_connection create_test_file :models, "account" - output = Dir.chdir(app_path) { `bin/rails db:create:all db:migrate && echo ".tables" | rails dbconsole` } + output = Dir.chdir(app_path) { `bin/rails db:create:all db:migrate && echo ".tables" | rails dbconsole` } assert_match "ar_internal_metadata", output, "tables should be dumped" end def test_rails_db_create_all_restores_db_connection_after_drop create_test_file :models, "account" Dir.chdir(app_path) { `bin/rails db:create:all` } # create all to avoid warnings - output = Dir.chdir(app_path) { `bin/rails db:drop:all db:create:all db:migrate && echo ".tables" | rails dbconsole` } + output = Dir.chdir(app_path) { `bin/rails db:drop:all db:create:all db:migrate && echo ".tables" | rails dbconsole` } assert_match "ar_internal_metadata", output, "tables should be dumped" end def test_rake_passes_TESTOPTS_to_minitest create_test_file :models, "account" - output = Dir.chdir(app_path) { `bin/rake test TESTOPTS=-v` } + output = Dir.chdir(app_path) { `bin/rake test TESTOPTS=-v` } assert_match "AccountTest#test_truth", output, "passing TEST= should run selected test" end def test_rake_passes_multiple_TESTOPTS_to_minitest create_test_file :models, "account" - output = Dir.chdir(app_path) { `bin/rake test TESTOPTS='-v --seed=1234'` } + output = Dir.chdir(app_path) { `bin/rake test TESTOPTS='-v --seed=1234'` } assert_match "AccountTest#test_truth", output, "passing TEST= should run selected test" assert_match "seed=1234", output, "passing TEST= should run selected test" end diff --git a/railties/test/application/test_test.rb b/railties/test/application/test_test.rb index ef65c7a893..32d2a6857c 100644 --- a/railties/test/application/test_test.rb +++ b/railties/test/application/test_test.rb @@ -12,7 +12,7 @@ module ApplicationTests teardown_app end - test "truth" do + test "simple successful test" do app_file "test/unit/foo_test.rb", <<-RUBY require 'test_helper' @@ -26,6 +26,38 @@ module ApplicationTests assert_successful_test_run "unit/foo_test.rb" end + test "after_run" do + app_file "test/unit/foo_test.rb", <<-RUBY + require 'test_helper' + + Minitest.after_run { puts "WORLD" } + Minitest.after_run { puts "HELLO" } + + class FooTest < ActiveSupport::TestCase + def test_truth + assert true + end + end + RUBY + + result = assert_successful_test_run "unit/foo_test.rb" + assert_equal ["HELLO", "WORLD"], result.scan(/HELLO|WORLD/) # only once and in correct order + end + + test "simple failed test" do + app_file "test/unit/foo_test.rb", <<-RUBY + require 'test_helper' + + class FooTest < ActiveSupport::TestCase + def test_truth + assert false + end + end + RUBY + + assert_unsuccessful_run "unit/foo_test.rb", "Failed assertion" + end + test "integration test" do controller "posts", <<-RUBY class PostsController < ActionController::Base @@ -101,7 +133,7 @@ module ApplicationTests File.delete "#{app_path}/config/initializers/disable_maintain_test_schema.rb" result = assert_successful_test_run("models/user_test.rb") - assert !result.include?("create_table(:users)") + assert_not_includes result, "create_table(:users)" end test "sql structure migrations" do @@ -289,7 +321,7 @@ Expected: ["id", "name"] def assert_unsuccessful_run(name, message) result = run_test_file(name) assert_not_equal 0, $?.to_i - assert result.include?(message) + assert_includes result, message result end diff --git a/railties/test/application/url_generation_test.rb b/railties/test/application/url_generation_test.rb index ced6c6b0a6..37f129475c 100644 --- a/railties/test/application/url_generation_test.rb +++ b/railties/test/application/url_generation_test.rb @@ -27,7 +27,7 @@ module ApplicationTests class ::OmgController < ::ApplicationController def index - render text: omg_path + render plain: omg_path end end diff --git a/railties/test/backtrace_cleaner_test.rb b/railties/test/backtrace_cleaner_test.rb index 17201d6f77..f71e56f323 100644 --- a/railties/test/backtrace_cleaner_test.rb +++ b/railties/test/backtrace_cleaner_test.rb @@ -15,7 +15,7 @@ class BacktraceCleanerTest < ActiveSupport::TestCase test "should format installed gems not in Gem.default_dir correctly" do target_dir = Gem.path.detect { |p| p != Gem.default_dir } # skip this test if default_dir is the only directory on Gem.path - if @target_dir + if target_dir backtrace = [ "#{target_dir}/gems/nosuchgem-1.2.3/lib/foo.rb" ] result = @cleaner.clean(backtrace, :all) assert_equal "nosuchgem (1.2.3) lib/foo.rb", result[0] diff --git a/railties/test/code_statistics_calculator_test.rb b/railties/test/code_statistics_calculator_test.rb index 2dba3c6e96..1bd4225f34 100644 --- a/railties/test/code_statistics_calculator_test.rb +++ b/railties/test/code_statistics_calculator_test.rb @@ -24,7 +24,7 @@ class CodeStatisticsCalculatorTest < ActiveSupport::TestCase end end - test "count number of methods in MiniTest file" do + test "count number of methods in Minitest file" do code = <<-RUBY class FooTest < ActionController::TestCase test 'expectation' do @@ -52,7 +52,7 @@ class CodeStatisticsCalculatorTest < ActiveSupport::TestCase assert_equal 3, @code_statistics_calculator.classes assert_equal 4, @code_statistics_calculator.methods - code_statistics_calculator_2 = CodeStatisticsCalculator.new(2, 3, 4, 5) + code_statistics_calculator_2 = CodeStatisticsCalculator.new(2, 3, 4, 5) @code_statistics_calculator.add(code_statistics_calculator_2) assert_equal 3, @code_statistics_calculator.lines diff --git a/railties/test/commands/console_test.rb b/railties/test/commands/console_test.rb index 96ac7c0661..4fc082e4ca 100644 --- a/railties/test/commands/console_test.rb +++ b/railties/test/commands/console_test.rb @@ -1,6 +1,7 @@ require "abstract_unit" require "env_helpers" -require "rails/commands/console" +require "rails/command" +require "rails/commands/console/console_command" class Rails::ConsoleTest < ActiveSupport::TestCase include EnvHelpers @@ -102,13 +103,21 @@ class Rails::ConsoleTest < ActiveSupport::TestCase end def test_rails_env_is_dev_when_argument_is_dev_and_dev_env_is_present - stubbed_console = Class.new(Rails::Console) do - def available_environments + Rails::Command::ConsoleCommand.class_eval do + alias_method :old_environments, :available_environments + + define_method :available_environments do ["dev"] end end - options = stubbed_console.parse_arguments(["dev"]) - assert_match("dev", options[:environment]) + + assert_match("dev", parse_arguments(["dev"])[:environment]) + ensure + Rails::Command::ConsoleCommand.class_eval do + undef_method :available_environments + alias_method :available_environments, :old_environments + undef_method :old_environments + end end attr_reader :output @@ -148,6 +157,21 @@ class Rails::ConsoleTest < ActiveSupport::TestCase end def parse_arguments(args) - Rails::Console.parse_arguments(args) + Rails::Command::ConsoleCommand.class_eval do + alias_method :old_perform, :perform + define_method(:perform) do + extract_environment_option_from_argument + + options + end + end + + Rails::Command.invoke(:console, args) + ensure + Rails::Command::ConsoleCommand.class_eval do + undef_method :perform + alias_method :perform, :old_perform + undef_method :old_perform + end end end diff --git a/railties/test/commands/dbconsole_test.rb b/railties/test/commands/dbconsole_test.rb index 286e7c16c1..0f8c5dbb79 100644 --- a/railties/test/commands/dbconsole_test.rb +++ b/railties/test/commands/dbconsole_test.rb @@ -1,6 +1,7 @@ require "abstract_unit" require "minitest/mock" -require "rails/commands/dbconsole" +require "rails/command" +require "rails/commands/dbconsole/dbconsole_command" class Rails::DBConsoleTest < ActiveSupport::TestCase def setup @@ -14,15 +15,15 @@ class Rails::DBConsoleTest < ActiveSupport::TestCase def test_config_with_db_config_only config_sample = { - "test"=> { - "adapter"=> "sqlite3", - "host"=> "localhost", - "port"=> "9000", - "database"=> "foo_test", - "user"=> "foo", - "password"=> "bar", - "pool"=> "5", - "timeout"=> "3000" + "test" => { + "adapter" => "sqlite3", + "host" => "localhost", + "port" => "9000", + "database" => "foo_test", + "user" => "foo", + "password" => "bar", + "pool" => "5", + "timeout" => "3000" } } app_db_config(config_sample) do @@ -97,16 +98,14 @@ class Rails::DBConsoleTest < ActiveSupport::TestCase end def test_rails_env_is_development_when_argument_is_dev - Rails::DBConsole.stub(:available_environments, ["development", "test"]) do - options = Rails::DBConsole.send(:parse_arguments, ["dev"]) - assert_match("development", options[:environment]) + stub_available_environments([ "development", "test" ]) do + assert_match("development", parse_arguments([ "dev" ])[:environment]) end end def test_rails_env_is_dev_when_argument_is_dev_and_dev_env_is_present - Rails::DBConsole.stub(:available_environments, ["dev"]) do - options = Rails::DBConsole.send(:parse_arguments, ["dev"]) - assert_match("dev", options[:environment]) + stub_available_environments([ "dev" ]) do + assert_match("dev", parse_arguments([ "dev" ])[:environment]) end end @@ -203,20 +202,16 @@ class Rails::DBConsoleTest < ActiveSupport::TestCase def test_print_help_short stdout = capture(:stdout) do - start({}, ["-h"]) + Rails::Command.invoke(:dbconsole, ["-h"]) end - assert aborted - assert_equal "", output - assert_match(/Usage:.*dbconsole/, stdout) + assert_match(/bin\/rails dbconsole \[environment\]/, stdout) end def test_print_help_long stdout = capture(:stdout) do - start({}, ["--help"]) + Rails::Command.invoke(:dbconsole, ["--help"]) end - assert aborted - assert_equal "", output - assert_match(/Usage:.*dbconsole/, stdout) + assert_match(/bin\/rails dbconsole \[environment\]/, stdout) end attr_reader :aborted, :output @@ -230,21 +225,22 @@ class Rails::DBConsoleTest < ActiveSupport::TestCase end end - def dbconsole - @dbconsole ||= Class.new(Rails::DBConsole) do + def make_dbconsole + Class.new(Rails::DBConsole) do attr_reader :find_cmd_and_exec_args def find_cmd_and_exec(*args) @find_cmd_and_exec_args = args end - end.new(nil) + end end + attr_reader :dbconsole + def start(config = {}, argv = []) - dbconsole.stub(:config, config.stringify_keys) do - dbconsole.stub(:arguments, argv) do - capture_abort { dbconsole.start } - end + @dbconsole = make_dbconsole.new(parse_arguments(argv)) + @dbconsole.stub(:config, config.stringify_keys) do + capture_abort { @dbconsole.start } end end @@ -258,4 +254,41 @@ class Rails::DBConsoleTest < ActiveSupport::TestCase end end end + + def stub_available_environments(environments) + Rails::Command::DbconsoleCommand.class_eval do + alias_method :old_environments, :available_environments + + define_method :available_environments do + environments + end + end + + yield + ensure + Rails::Command::DbconsoleCommand.class_eval do + undef_method :available_environments + alias_method :available_environments, :old_environments + undef_method :old_environments + end + end + + def parse_arguments(args) + Rails::Command::DbconsoleCommand.class_eval do + alias_method :old_perform, :perform + define_method(:perform) do + extract_environment_option_from_argument + + options + end + end + + Rails::Command.invoke(:dbconsole, args) + ensure + Rails::Command::DbconsoleCommand.class_eval do + undef_method :perform + alias_method :perform, :old_perform + undef_method :old_perform + end + end end diff --git a/railties/test/commands/server_test.rb b/railties/test/commands/server_test.rb index c1ec73d95c..527529aa52 100644 --- a/railties/test/commands/server_test.rb +++ b/railties/test/commands/server_test.rb @@ -1,36 +1,41 @@ require "abstract_unit" require "env_helpers" -require "rails/commands/server" +require "rails/command" +require "rails/commands/server/server_command" class Rails::ServerTest < ActiveSupport::TestCase include EnvHelpers def test_environment_with_server_option - args = ["thin", "-e", "production"] - options = Rails::Server::Options.new.parse!(args) + args = ["thin", "-e", "production"] + options = parse_arguments(args) assert_equal "production", options[:environment] assert_equal "thin", options[:server] end def test_environment_without_server_option - args = ["-e", "production"] - options = Rails::Server::Options.new.parse!(args) + args = ["-e", "production"] + options = parse_arguments(args) assert_equal "production", options[:environment] assert_nil options[:server] end def test_server_option_without_environment - args = ["thin"] - options = Rails::Server::Options.new.parse!(args) - assert_nil options[:environment] - assert_equal "thin", options[:server] + args = ["thin"] + with_rack_env nil do + with_rails_env nil do + options = parse_arguments(args) + assert_equal "development", options[:environment] + assert_equal "thin", options[:server] + end + end end def test_environment_with_rails_env with_rack_env nil do with_rails_env "production" do - server = Rails::Server.new - assert_equal "production", server.options[:environment] + options = parse_arguments + assert_equal "production", options[:environment] end end end @@ -38,40 +43,39 @@ class Rails::ServerTest < ActiveSupport::TestCase def test_environment_with_rack_env with_rails_env nil do with_rack_env "production" do - server = Rails::Server.new - assert_equal "production", server.options[:environment] + options = parse_arguments + assert_equal "production", options[:environment] end end end def test_environment_with_port switch_env "PORT", "1234" do - server = Rails::Server.new - assert_equal 1234, server.options[:Port] + options = parse_arguments + assert_equal 1234, options[:Port] end end def test_environment_with_host switch_env "HOST", "1.2.3.4" do - server = Rails::Server.new - assert_equal "1.2.3.4", server.options[:Host] + options = parse_arguments + assert_equal "1.2.3.4", options[:Host] end end def test_caching_without_option args = [] - options = Rails::Server::Options.new.parse!(args) - merged_options = Rails::Server.new.default_options.merge(options) - assert_equal nil, merged_options[:caching] + options = parse_arguments(args) + assert_nil options[:caching] end def test_caching_with_option args = ["--dev-caching"] - options = Rails::Server::Options.new.parse!(args) + options = parse_arguments(args) assert_equal true, options[:caching] args = ["--no-dev-caching"] - options = Rails::Server::Options.new.parse!(args) + options = parse_arguments(args) assert_equal false, options[:caching] end @@ -79,38 +83,38 @@ class Rails::ServerTest < ActiveSupport::TestCase with_rack_env nil do with_rails_env nil do args = [] - options = Rails::Server::Options.new.parse!(args) + options = parse_arguments(args) assert_equal true, options[:log_stdout] args = ["-e", "development"] - options = Rails::Server::Options.new.parse!(args) + options = parse_arguments(args) assert_equal true, options[:log_stdout] args = ["-e", "production"] - options = Rails::Server::Options.new.parse!(args) + options = parse_arguments(args) assert_equal false, options[:log_stdout] with_rack_env "development" do args = [] - options = Rails::Server::Options.new.parse!(args) + options = parse_arguments(args) assert_equal true, options[:log_stdout] end with_rack_env "production" do args = [] - options = Rails::Server::Options.new.parse!(args) + options = parse_arguments(args) assert_equal false, options[:log_stdout] end with_rails_env "development" do args = [] - options = Rails::Server::Options.new.parse!(args) + options = parse_arguments(args) assert_equal true, options[:log_stdout] end with_rails_env "production" do args = [] - options = Rails::Server::Options.new.parse!(args) + options = parse_arguments(args) assert_equal false, options[:log_stdout] end end @@ -118,25 +122,29 @@ class Rails::ServerTest < ActiveSupport::TestCase end def test_default_options - server = Rails::Server.new - old_default_options = server.default_options + old_default_options = parse_arguments Dir.chdir("..") do - assert_equal old_default_options, server.default_options + default_options = parse_arguments + assert_equal old_default_options, default_options end end def test_restart_command_contains_customized_options original_args = ARGV.dup - args = ["-p", "4567"] + args = %w(-p 4567 -b 127.0.0.1 -c dummy_config.ru -d -e test -P tmp/server.pid -C) ARGV.replace args - options = Rails::Server::Options.new.parse! args - server = Rails::Server.new options - expected = "bin/rails server -p 4567" + options = parse_arguments(args) + expected = "bin/rails server -p 4567 -b 127.0.0.1 -c dummy_config.ru -d -e test -P tmp/server.pid -C" - assert_equal expected, server.default_options[:restart_cmd] + assert_equal expected, options[:restart_cmd] ensure ARGV.replace original_args end + + private + def parse_arguments(args = []) + Rails::Command::ServerCommand.new([], args).server_options + end end diff --git a/railties/test/generators/actions_test.rb b/railties/test/generators/actions_test.rb index 0a26897a4d..360e8e97d7 100644 --- a/railties/test/generators/actions_test.rb +++ b/railties/test/generators/actions_test.rb @@ -369,7 +369,7 @@ F assert_equal("", action(:log, :yes, "YES")) end - protected + private def action(*args, &block) capture(:stdout) { generator.send(*args, &block) } diff --git a/railties/test/generators/api_app_generator_test.rb b/railties/test/generators/api_app_generator_test.rb index bbb814ef4e..c54d9cc599 100644 --- a/railties/test/generators/api_app_generator_test.rb +++ b/railties/test/generators/api_app_generator_test.rb @@ -35,7 +35,6 @@ class ApiAppGeneratorTest < Rails::Generators::TestCase assert_file "Gemfile" do |content| assert_no_match(/gem 'coffee-rails'/, content) - assert_no_match(/gem 'jquery-rails'/, content) assert_no_match(/gem 'sass-rails'/, content) assert_no_match(/gem 'web-console'/, content) assert_match(/# gem 'jbuilder'/, content) @@ -106,10 +105,10 @@ class ApiAppGeneratorTest < Rails::Generators::TestCase %w(app/assets app/helpers app/views/layouts/application.html.erb + bin/yarn config/initializers/assets.rb config/initializers/cookies_serializer.rb lib/assets - vendor/assets test/helpers tmp/cache/assets public/404.html @@ -117,6 +116,8 @@ class ApiAppGeneratorTest < Rails::Generators::TestCase public/500.html public/apple-touch-icon-precomposed.png public/apple-touch-icon.png - public/favicon.ico) + public/favicon.icon + vendor/package.json + ) end end diff --git a/railties/test/generators/app_generator_test.rb b/railties/test/generators/app_generator_test.rb index acab83799d..20de2258c5 100644 --- a/railties/test/generators/app_generator_test.rb +++ b/railties/test/generators/app_generator_test.rb @@ -43,9 +43,6 @@ DEFAULT_APP_FILES = %w( test/mailers test/integration vendor - vendor/assets - vendor/assets/stylesheets - vendor/assets/javascripts tmp tmp/cache tmp/cache/assets @@ -356,12 +353,19 @@ class AppGeneratorTest < Rails::Generators::TestCase def test_generator_if_skip_active_record_is_given run_generator [destination_root, "--skip-active-record"] + assert_no_directory "db/" assert_no_file "config/database.yml" assert_no_file "app/models/application_record.rb" assert_file "config/application.rb", /#\s+require\s+["']active_record\/railtie["']/ assert_file "test/test_helper.rb" do |helper_content| assert_no_match(/fixtures :all/, helper_content) end + assert_file "bin/setup" do |setup_content| + assert_no_match(/db:setup/, setup_content) + end + assert_file "bin/update" do |update_content| + assert_no_match(/db:migrate/, update_content) + end assert_file "config/initializers/new_framework_defaults.rb" do |initializer_content| assert_no_match(/belongs_to_required_by_default/, initializer_content) @@ -398,7 +402,6 @@ class AppGeneratorTest < Rails::Generators::TestCase assert_match(/#\s+require\s+["']sprockets\/railtie["']/, content) end assert_file "Gemfile" do |content| - assert_no_match(/jquery-rails/, content) assert_no_match(/sass-rails/, content) assert_no_match(/uglifier/, content) assert_no_match(/coffee-rails/, content) @@ -411,6 +414,16 @@ class AppGeneratorTest < Rails::Generators::TestCase assert_no_match(/config\.assets\.js_compressor = :uglifier/, content) assert_no_match(/config\.assets\.css_compressor = :sass/, content) end + assert_file "config/initializers/new_framework_defaults.rb" do |content| + assert_no_match(/unknown_asset_fallback/, content) + end + end + + def test_generator_if_skip_yarn_is_given + run_generator [destination_root, "--skip-yarn"] + + assert_no_file "vendor/package.json" + assert_no_file "bin/yarn" end def test_generator_if_skip_action_cable_is_given @@ -438,29 +451,25 @@ class AppGeneratorTest < Rails::Generators::TestCase end end - def test_jquery_is_the_default_javascript_library + def test_rails_ujs_is_the_default_ujs_library run_generator assert_file "app/assets/javascripts/application.js" do |contents| - assert_match %r{^//= require jquery}, contents - assert_match %r{^//= require jquery_ujs}, contents + assert_match %r{^//= require rails-ujs}, contents end - assert_gem "jquery-rails" end - def test_other_javascript_libraries - run_generator [destination_root, "-j", "prototype"] + def test_inclusion_of_javascript_libraries_if_required + run_generator [destination_root, "-j", "jquery"] assert_file "app/assets/javascripts/application.js" do |contents| - assert_match %r{^//= require prototype}, contents - assert_match %r{^//= require prototype_ujs}, contents + assert_match %r{^//= require jquery}, contents end - assert_gem "prototype-rails" + assert_gem "jquery-rails" end def test_javascript_is_skipped_if_required run_generator [destination_root, "--skip-javascript"] assert_no_file "app/assets/javascripts" - assert_no_file "vendor/assets/javascripts" assert_file "app/views/layouts/application.html.erb" do |contents| assert_match(/stylesheet_link_tag\s+'application', media: 'all' %>/, contents) @@ -469,7 +478,6 @@ class AppGeneratorTest < Rails::Generators::TestCase assert_file "Gemfile" do |content| assert_no_match(/coffee-rails/, content) - assert_no_match(/jquery-rails/, content) assert_no_match(/uglifier/, content) end @@ -478,6 +486,30 @@ class AppGeneratorTest < Rails::Generators::TestCase end end + def test_coffeescript_is_skipped_if_required + run_generator [destination_root, "--skip-coffee"] + + assert_file "Gemfile" do |content| + assert_no_match(/coffee-rails/, content) + assert_match(/uglifier/, content) + end + end + + def test_generator_for_yarn + run_generator([destination_root]) + assert_file "vendor/package.json", /dependencies/ + assert_file "config/initializers/assets.rb", /node_modules/ + end + + def test_generator_for_yarn_skipped + run_generator([destination_root, "--skip-yarn"]) + assert_no_file "vendor/package.json" + + assert_file "config/initializers/assets.rb" do |content| + assert_no_match(/node_modules/, content) + end + end + def test_inclusion_of_jbuilder run_generator assert_gem "jbuilder" @@ -606,7 +638,7 @@ class AppGeneratorTest < Rails::Generators::TestCase def test_edge_option assert_generates_with_bundler edge: true - assert_file "Gemfile", %r{^gem\s+["']rails["'],\s+github:\s+["']#{Regexp.escape("rails/rails")}["'],\s+branch:\s+["']#{Regexp.escape("5-0-stable")}["']$} + assert_file "Gemfile", %r{^gem\s+["']rails["'],\s+github:\s+["']#{Regexp.escape("rails/rails")}["']$} end def test_spring @@ -716,7 +748,6 @@ class AppGeneratorTest < Rails::Generators::TestCase test/helpers test/integration tmp - vendor/assets/stylesheets ) folders_with_keep.each do |folder| assert_file("#{folder}/.keep") @@ -764,7 +795,7 @@ class AppGeneratorTest < Rails::Generators::TestCase assert_equal 3, @sequence_step end - protected + private def stub_rails_application(root) Rails.application.config.root = root diff --git a/railties/test/generators/controller_generator_test.rb b/railties/test/generators/controller_generator_test.rb index 9b986a636a..af86a0136f 100644 --- a/railties/test/generators/controller_generator_test.rb +++ b/railties/test/generators/controller_generator_test.rb @@ -65,7 +65,7 @@ class ControllerGeneratorTest < Rails::Generators::TestCase def test_add_routes run_generator - assert_file "config/routes.rb", /get 'account\/foo'/, /get 'account\/bar'/ + assert_file "config/routes.rb", /^ get 'account\/foo'/, /^ get 'account\/bar'/ end def test_skip_routes diff --git a/railties/test/generators/generator_test.rb b/railties/test/generators/generator_test.rb index c4e4747468..904bade658 100644 --- a/railties/test/generators/generator_test.rb +++ b/railties/test/generators/generator_test.rb @@ -20,7 +20,7 @@ module Rails end def test_construction - klass = make_builder_class + klass = make_builder_class assert klass.start(["new", "blah"]) end diff --git a/railties/test/generators/model_generator_test.rb b/railties/test/generators/model_generator_test.rb index 701d3ceaf2..2b9f3ed7f2 100644 --- a/railties/test/generators/model_generator_test.rb +++ b/railties/test/generators/model_generator_test.rb @@ -212,10 +212,10 @@ class ModelGeneratorTest < Rails::Generators::TestCase def test_migration_without_timestamps ActiveRecord::Base.timestamped_migrations = false run_generator ["account"] - assert_file "db/migrate/001_create_accounts.rb", /class CreateAccounts < ActiveRecord::Migration\[[0-9.]+\]/ + assert_file "db/migrate/001_create_accounts.rb", /class CreateAccounts < ActiveRecord::Migration\[[0-9.]+\]/ run_generator ["project"] - assert_file "db/migrate/002_create_projects.rb", /class CreateProjects < ActiveRecord::Migration\[[0-9.]+\]/ + assert_file "db/migrate/002_create_projects.rb", /class CreateProjects < ActiveRecord::Migration\[[0-9.]+\]/ ensure ActiveRecord::Base.timestamped_migrations = true end @@ -300,7 +300,7 @@ class ModelGeneratorTest < Rails::Generators::TestCase assert_file "test/fixtures/accounts.yml", /name: MyString/, /age: 1/ assert_generated_fixture("test/fixtures/accounts.yml", - "one"=>{ "name"=>"MyString", "age"=>1 }, "two"=>{ "name"=>"MyString", "age"=>1 }) + "one" => { "name" => "MyString", "age" => 1 }, "two" => { "name" => "MyString", "age" => 1 }) end def test_fixtures_use_the_references_ids @@ -308,7 +308,7 @@ class ModelGeneratorTest < Rails::Generators::TestCase assert_file "test/fixtures/line_items.yml", /product: one\n cart: one/ assert_generated_fixture("test/fixtures/line_items.yml", - "one"=>{ "product"=>"one", "cart"=>"one" }, "two"=>{ "product"=>"two", "cart"=>"two" }) + "one" => { "product" => "one", "cart" => "one" }, "two" => { "product" => "two", "cart" => "two" }) end def test_fixtures_use_the_references_ids_and_type @@ -316,15 +316,15 @@ class ModelGeneratorTest < Rails::Generators::TestCase assert_file "test/fixtures/line_items.yml", /product: one\n product_type: Product\n cart: one/ assert_generated_fixture("test/fixtures/line_items.yml", - "one"=>{ "product"=>"one", "product_type"=>"Product", "cart"=>"one" }, - "two"=>{ "product"=>"two", "product_type"=>"Product", "cart"=>"two" }) + "one" => { "product" => "one", "product_type" => "Product", "cart" => "one" }, + "two" => { "product" => "two", "product_type" => "Product", "cart" => "two" }) end def test_fixtures_respect_reserved_yml_keywords run_generator ["LineItem", "no:integer", "Off:boolean", "ON:boolean"] assert_generated_fixture("test/fixtures/line_items.yml", - "one"=>{ "no"=>1, "Off"=>false, "ON"=>false }, "two"=>{ "no"=>1, "Off"=>false, "ON"=>false }) + "one" => { "no" => 1, "Off" => false, "ON" => false }, "two" => { "no" => 1, "Off" => false, "ON" => false }) end def test_fixture_is_skipped @@ -343,7 +343,7 @@ class ModelGeneratorTest < Rails::Generators::TestCase ActiveRecord::Base.pluralize_table_names = false run_generator assert_generated_fixture("test/fixtures/account.yml", - "one"=>{ "name"=>"MyString", "age"=>1 }, "two"=>{ "name"=>"MyString", "age"=>1 }) + "one" => { "name" => "MyString", "age" => 1 }, "two" => { "name" => "MyString", "age" => 1 }) ensure ActiveRecord::Base.pluralize_table_names = original_pluralize_table_name end diff --git a/railties/test/generators/named_base_test.rb b/railties/test/generators/named_base_test.rb index c58468dfc1..3015b5363b 100644 --- a/railties/test/generators/named_base_test.rb +++ b/railties/test/generators/named_base_test.rb @@ -106,9 +106,9 @@ class NamedBaseTest < Rails::Generators::TestCase def test_hide_namespace g = generator ["Hidden"] g.class.stub(:namespace, "hidden") do - assert !Rails::Generators.hidden_namespaces.include?("hidden") + assert_not_includes Rails::Generators.hidden_namespaces, "hidden" g.class.hide! - assert Rails::Generators.hidden_namespaces.include?("hidden") + assert_includes Rails::Generators.hidden_namespaces, "hidden" end end @@ -131,7 +131,7 @@ class NamedBaseTest < Rails::Generators::TestCase assert_name g, "admin.foos", :controller_i18n_scope end - protected + private def assert_name(generator, value, method) assert_equal value, generator.send(method) diff --git a/railties/test/generators/plugin_generator_test.rb b/railties/test/generators/plugin_generator_test.rb index 0d8e6f8907..9921a80342 100644 --- a/railties/test/generators/plugin_generator_test.rb +++ b/railties/test/generators/plugin_generator_test.rb @@ -100,6 +100,14 @@ class PluginGeneratorTest < Rails::Generators::TestCase end end + def test_generating_adds_dummy_app_in_full_mode_without_sprockets + run_generator [destination_root, "-S", "--full"] + + assert_file "test/dummy/config/environments/production.rb" do |contents| + assert_no_match(/config\.assets/, contents) + end + end + def test_generating_adds_dummy_app_rake_tasks_without_unit_test_files run_generator [destination_root, "-T", "--mountable", "--dummy-path", "my_dummy_app"] assert_file "Rakefile", /APP_RAKEFILE/ @@ -205,7 +213,7 @@ class PluginGeneratorTest < Rails::Generators::TestCase def test_edge_option assert_generates_without_bundler(edge: true) - assert_file "Gemfile", %r{^gem\s+["']rails["'],\s+github:\s+["']#{Regexp.escape("rails/rails")}["'],\s+branch:\s+["']#{Regexp.escape("5-0-stable")}["']$} + assert_file "Gemfile", %r{^gem\s+["']rails["'],\s+github:\s+["']#{Regexp.escape("rails/rails")}["']$} end def test_generation_does_not_run_bundle_install_with_full_and_mountable @@ -499,7 +507,6 @@ class PluginGeneratorTest < Rails::Generators::TestCase assert_no_match("gemspec", contents) assert_match(/gem 'rails'/, contents) assert_match_sqlite3(contents) - assert_no_match(/# gem "jquery-rails"/, contents) end end @@ -707,7 +714,7 @@ class PluginGeneratorTest < Rails::Generators::TestCase end end - protected + private def action(*args, &block) silence(:stdout) { generator.send(*args, &block) } diff --git a/railties/test/generators/plugin_test_runner_test.rb b/railties/test/generators/plugin_test_runner_test.rb index 04b4b10254..0bdf3b2726 100644 --- a/railties/test/generators/plugin_test_runner_test.rb +++ b/railties/test/generators/plugin_test_runner_test.rb @@ -86,6 +86,12 @@ class PluginTestRunnerTest < ActiveSupport::TestCase assert_match(%r{cannot load such file.+test/not_exists\.rb}, error) end + def test_executed_only_once + create_test_file "foo" + result = run_test_command("test/foo_test.rb") + assert_equal 1, result.scan(/1 runs, 1 assertions, 0 failures/).length + end + private def plugin_path "#{@destination_root}/bukkits" diff --git a/railties/test/generators/shared_generator_tests.rb b/railties/test/generators/shared_generator_tests.rb index 27b2fc8955..08b0e34fe2 100644 --- a/railties/test/generators/shared_generator_tests.rb +++ b/railties/test/generators/shared_generator_tests.rb @@ -28,7 +28,7 @@ module SharedGeneratorTests def test_plugin_new_generate_pretend run_generator ["testapp", "--pretend"] - default_files.each { |path| assert_no_file File.join("testapp",path) } + default_files.each { |path| assert_no_file File.join("testapp", path) } end def test_invalid_database_option_raises_an_error diff --git a/railties/test/generators_test.rb b/railties/test/generators_test.rb index 3c22881080..68ba435393 100644 --- a/railties/test/generators_test.rb +++ b/railties/test/generators_test.rb @@ -229,7 +229,7 @@ class GeneratorsTest < Rails::Generators::TestCase def test_source_paths_for_not_namespaced_generators mspec = Rails::Generators.find_by_namespace :fixjour - assert mspec.source_paths.include?(File.join(Rails.root, "lib", "templates", "fixjour")) + assert_includes mspec.source_paths, File.join(Rails.root, "lib", "templates", "fixjour") end def test_usage_with_embedded_ruby @@ -239,8 +239,8 @@ class GeneratorsTest < Rails::Generators::TestCase end def test_hide_namespace - assert !Rails::Generators.hidden_namespaces.include?("special:namespace") + assert_not_includes Rails::Generators.hidden_namespaces, "special:namespace" Rails::Generators.hide_namespace("special:namespace") - assert Rails::Generators.hidden_namespaces.include?("special:namespace") + assert_includes Rails::Generators.hidden_namespaces, "special:namespace" end end diff --git a/railties/test/isolation/abstract_unit.rb b/railties/test/isolation/abstract_unit.rb index b9b11504dc..1902eac862 100644 --- a/railties/test/isolation/abstract_unit.rb +++ b/railties/test/isolation/abstract_unit.rb @@ -104,7 +104,7 @@ module TestHelpers # Build an application by invoking the generator and going through the whole stack. def build_app(options = {}) @prev_rails_env = ENV["RAILS_ENV"] - ENV["RAILS_ENV"] = "development" + ENV["RAILS_ENV"] = "development" ENV["SECRET_KEY_BASE"] ||= SecureRandom.hex(16) FileUtils.rm_rf(app_path) @@ -117,11 +117,6 @@ module TestHelpers end end - gemfile_path = "#{app_path}/Gemfile" - if options[:gemfile].blank? && File.exist?(gemfile_path) - File.delete gemfile_path - end - routes = File.read("#{app_path}/config/routes.rb") if routes =~ /(\n\s*end\s*)\Z/ File.open("#{app_path}/config/routes.rb", "w") do |f| @@ -167,7 +162,6 @@ module TestHelpers require "rails" require "action_controller/railtie" require "action_view/railtie" - require "action_dispatch/middleware/flash" @app = Class.new(Rails::Application) @app.config.eager_load = false @@ -192,7 +186,7 @@ module TestHelpers controller :foo, <<-RUBY class FooController < ApplicationController def index - render text: "foo" + render plain: "foo" end end RUBY diff --git a/railties/test/path_generation_test.rb b/railties/test/path_generation_test.rb index 579e50ac95..c0b03d0c15 100644 --- a/railties/test/path_generation_test.rb +++ b/railties/test/path_generation_test.rb @@ -38,7 +38,7 @@ class PathGenerationTest < ActiveSupport::TestCase host = uri_or_host.host unless path path ||= uri_or_host.path - params = { "PATH_INFO" => path, + params = { "PATH_INFO" => path, "REQUEST_METHOD" => method, "HTTP_HOST" => host } diff --git a/railties/test/paths_test.rb b/railties/test/paths_test.rb index a4f6922cb4..7b2551062a 100644 --- a/railties/test/paths_test.rb +++ b/railties/test/paths_test.rb @@ -103,7 +103,7 @@ class PathsTest < ActiveSupport::TestCase @root.add "app", with: "/app" @root["app"].autoload_once! assert @root["app"].autoload_once? - assert @root.autoload_once.include?(@root["app"].expanded.first) + assert_includes @root.autoload_once, @root["app"].expanded.first end end @@ -114,14 +114,14 @@ class PathsTest < ActiveSupport::TestCase @root["app"].skip_autoload_once! assert !@root["app"].autoload_once? - assert !@root.autoload_once.include?(@root["app"].expanded.first) + assert_not_includes @root.autoload_once, @root["app"].expanded.first end test "it is possible to add a path without assignment and specify it should be loaded only once" do File.stub(:exist?, true) do @root.add "app", with: "/app", autoload_once: true assert @root["app"].autoload_once? - assert @root.autoload_once.include?("/app") + assert_includes @root.autoload_once, "/app" end end @@ -129,8 +129,8 @@ class PathsTest < ActiveSupport::TestCase File.stub(:exist?, true) do @root.add "app", with: ["/app", "/app2"], autoload_once: true assert @root["app"].autoload_once? - assert @root.autoload_once.include?("/app") - assert @root.autoload_once.include?("/app2") + assert_includes @root.autoload_once, "/app" + assert_includes @root.autoload_once, "/app2" end end @@ -157,7 +157,7 @@ class PathsTest < ActiveSupport::TestCase @root["app"] = "/app" @root["app"].eager_load! assert @root["app"].eager_load? - assert @root.eager_load.include?(@root["app"].to_a.first) + assert_includes @root.eager_load, @root["app"].to_a.first end end @@ -168,14 +168,14 @@ class PathsTest < ActiveSupport::TestCase @root["app"].skip_eager_load! assert !@root["app"].eager_load? - assert !@root.eager_load.include?(@root["app"].to_a.first) + assert_not_includes @root.eager_load, @root["app"].to_a.first end test "it is possible to add a path without assignment and mark it as eager" do File.stub(:exist?, true) do @root.add "app", with: "/app", eager_load: true assert @root["app"].eager_load? - assert @root.eager_load.include?("/app") + assert_includes @root.eager_load, "/app" end end @@ -183,8 +183,8 @@ class PathsTest < ActiveSupport::TestCase File.stub(:exist?, true) do @root.add "app", with: ["/app", "/app2"], eager_load: true assert @root["app"].eager_load? - assert @root.eager_load.include?("/app") - assert @root.eager_load.include?("/app2") + assert_includes @root.eager_load, "/app" + assert_includes @root.eager_load, "/app2" end end @@ -193,8 +193,8 @@ class PathsTest < ActiveSupport::TestCase @root.add "app", with: "/app", eager_load: true, autoload_once: true assert @root["app"].eager_load? assert @root["app"].autoload_once? - assert @root.eager_load.include?("/app") - assert @root.autoload_once.include?("/app") + assert_includes @root.eager_load, "/app" + assert_includes @root.autoload_once, "/app" end end diff --git a/railties/test/rails_info_test.rb b/railties/test/rails_info_test.rb index fc4175719e..9f4c5bb025 100644 --- a/railties/test/rails_info_test.rb +++ b/railties/test/rails_info_test.rb @@ -48,13 +48,13 @@ class InfoTest < ActiveSupport::TestCase end html = Rails::Info.to_html - assert html.include?('<tr><td class="name">Middleware</td>') + assert_includes html, '<tr><td class="name">Middleware</td>' properties.value_for("Middleware").each do |value| - assert html.include?("<li>#{CGI.escapeHTML(value)}</li>") + assert_includes html, "<li>#{CGI.escapeHTML(value)}</li>" end end - protected + private def properties Rails::Info.properties end diff --git a/railties/test/railties/engine_test.rb b/railties/test/railties/engine_test.rb index 0c8896a715..52d691b73b 100644 --- a/railties/test/railties/engine_test.rb +++ b/railties/test/railties/engine_test.rb @@ -133,7 +133,7 @@ module RailtiesTest boot_rails Dir.chdir(app_path) do - output = `bundle exec rake railties:install:migrations`.split("\n") + output = `bundle exec rake railties:install:migrations`.split("\n") assert_match(/Copied migration \d+_create_users.bukkits.rb from bukkits/, output.first) assert_match(/Copied migration \d+_create_blogs.blog_engine.rb from blog_engine/, output.last) @@ -169,7 +169,7 @@ module RailtiesTest boot_rails Dir.chdir(app_path) do - output = `bundle exec rake railties:install:migrations`.split("\n") + output = `bundle exec rake railties:install:migrations`.split("\n") assert_match(/Copied migration \d+_create_users.core_engine.rb from core_engine/, output.first) assert_match(/Copied migration \d+_create_keys.api_engine.rb from api_engine/, output.last) @@ -327,7 +327,7 @@ module RailtiesTest controller "foo", <<-RUBY class FooController < ActionController::Base def index - render :text => "foo" + render plain: "foo" end end RUBY @@ -341,7 +341,7 @@ module RailtiesTest @plugin.write "app/controllers/bar_controller.rb", <<-RUBY class BarController < ActionController::Base def index - render :text => "bar" + render plain: "bar" end end RUBY @@ -436,7 +436,7 @@ YAML @plugin.write "app/controllers/admin/foo/bar_controller.rb", <<-RUBY class Admin::Foo::BarController < ApplicationController def index - render text: "Rendered from namespace" + render plain: "Rendered from namespace" end end RUBY @@ -536,7 +536,7 @@ YAML controller "foo", <<-RUBY class FooController < ActionController::Base def index - render text: params[:username] + render plain: params[:username] end end RUBY @@ -700,7 +700,7 @@ YAML end def show - render text: foo_path + render plain: foo_path end def from_app @@ -712,7 +712,7 @@ YAML end def polymorphic_path_without_namespace - render text: polymorphic_path(Post.new) + render plain: polymorphic_path(Post.new) end end RUBY @@ -835,7 +835,7 @@ YAML @plugin.write "app/controllers/bukkits/awesome/foo_controller.rb", <<-RUBY class Bukkits::Awesome::FooController < ActionController::Base def index - render :text => "ok" + render plain: "ok" end end RUBY @@ -890,7 +890,7 @@ YAML boot_rails - assert_equal AppTemplate.railtie_namespace, AppTemplate::Engine + assert_equal AppTemplate::Engine, AppTemplate.railtie_namespace end test "properly reload routes" do @@ -1220,7 +1220,7 @@ YAML fullpath: \#{request.fullpath} path: \#{request.path} TEXT - render text: text + render plain: text end end end @@ -1257,7 +1257,7 @@ YAML app_file "app/controllers/bar_controller.rb", <<-RUBY class BarController < ApplicationController def index - render text: bukkits.bukkit_path + render plain: bukkits.bukkit_path end end RUBY @@ -1278,7 +1278,7 @@ YAML @plugin.write "app/controllers/bukkits/bukkit_controller.rb", <<-RUBY class Bukkits::BukkitController < ActionController::Base def index - render text: main_app.bar_path + render plain: main_app.bar_path end end RUBY @@ -1306,7 +1306,7 @@ YAML app_file "app/controllers/bar_controller.rb", <<-RUBY class BarController < ApplicationController def index - render text: bukkits.bukkit_path + render plain: bukkits.bukkit_path end end RUBY @@ -1327,7 +1327,7 @@ YAML @plugin.write "app/controllers/bukkits/bukkit_controller.rb", <<-RUBY class Bukkits::BukkitController < ActionController::Base def index - render text: main_app.bar_path + render plain: main_app.bar_path end end RUBY diff --git a/railties/test/railties/generators_test.rb b/railties/test/railties/generators_test.rb index 732898d0c0..5c691b9ec4 100644 --- a/railties/test/railties/generators_test.rb +++ b/railties/test/railties/generators_test.rb @@ -29,7 +29,7 @@ module RailtiesTests `#{Gem.ruby} #{RAILS_FRAMEWORK_ROOT}/railties/exe/rails #{cmd}` end - def build_engine(is_mountable=false) + def build_engine(is_mountable = false) FileUtils.rm_rf(engine_path) FileUtils.mkdir_p(engine_path) diff --git a/railties/test/railties/mounted_engine_test.rb b/railties/test/railties/mounted_engine_test.rb index 9db42c0c38..5838d0d7e7 100644 --- a/railties/test/railties/mounted_engine_test.rb +++ b/railties/test/railties/mounted_engine_test.rb @@ -50,7 +50,7 @@ module ApplicationTests @simple_plugin.write "app/controllers/weblogs_controller.rb", <<-RUBY class WeblogsController < ActionController::Base def index - render text: request.url + render plain: request.url end end RUBY @@ -74,7 +74,7 @@ module ApplicationTests module Metrics class GeneratingController < ActionController::Base def generate_blog_route - render text: blog.post_path(1) + render plain: blog.post_path(1) end def generate_blog_route_in_view @@ -122,14 +122,14 @@ module ApplicationTests module Blog class PostsController < ActionController::Base def index - render text: blog.post_path(1) + render plain: blog.post_path(1) end def generate_application_route path = main_app.url_for(controller: "/main", action: "index", only_path: true) - render text: path + render plain: path end def application_route_in_view @@ -137,7 +137,7 @@ module ApplicationTests end def engine_polymorphic_path - render text: polymorphic_path(Post.new) + render plain: polymorphic_path(Post.new) end def engine_asset_path @@ -150,7 +150,7 @@ module ApplicationTests app_file "app/controllers/application_generating_controller.rb", <<-RUBY class ApplicationGeneratingController < ActionController::Base def engine_route - render text: blog.posts_path + render plain: blog.posts_path end def engine_route_in_view @@ -158,7 +158,7 @@ module ApplicationTests end def weblog_engine_route - render text: weblog.weblogs_path + render plain: weblog.weblogs_path end def weblog_engine_route_in_view @@ -166,15 +166,15 @@ module ApplicationTests end def url_for_engine_route - render text: blog.url_for(controller: "blog/posts", action: "index", user: "john", only_path: true) + render plain: blog.url_for(controller: "blog/posts", action: "index", user: "john", only_path: true) end def polymorphic_route - render text: polymorphic_url([blog, Blog::Post.new]) + render plain: polymorphic_url([blog, Blog::Post.new]) end def application_polymorphic_path - render text: polymorphic_path(Blog::Post.new) + render plain: polymorphic_path(Blog::Post.new) end end RUBY diff --git a/railties/test/railties/railtie_test.rb b/railties/test/railties/railtie_test.rb index 755ac23cb1..30cd525266 100644 --- a/railties/test/railties/railtie_test.rb +++ b/railties/test/railties/railtie_test.rb @@ -135,7 +135,7 @@ module RailtiesTest require "rdoc/task" Rails.application.load_tasks - assert $ran_block.include?("my_tie") + assert_includes $ran_block, "my_tie" end test "generators block is executed when MyApp.load_generators is called" do |