diff options
Diffstat (limited to 'railties/lib/rails')
128 files changed, 1936 insertions, 1874 deletions
diff --git a/railties/lib/rails/all.rb b/railties/lib/rails/all.rb index 01ceb80972..eabe566829 100644 --- a/railties/lib/rails/all.rb +++ b/railties/lib/rails/all.rb @@ -4,9 +4,8 @@ require "rails" active_record action_controller action_mailer - active_resource rails/test_unit - sprockets + sprockets/rails ).each do |framework| begin require "#{framework}/railtie" diff --git a/railties/lib/rails/application.rb b/railties/lib/rails/application.rb index 82fffe86bb..ae872f2bb0 100644 --- a/railties/lib/rails/application.rb +++ b/railties/lib/rails/application.rb @@ -1,7 +1,4 @@ -require 'active_support/core_ext/hash/reverse_merge' -require 'active_support/file_update_checker' require 'fileutils' -require 'rails/plugin' require 'rails/engine' module Rails @@ -10,7 +7,7 @@ module Rails # # == Initialization # - # Rails::Application is responsible for executing all railties, engines and plugin + # Rails::Application is responsible for executing all railties and engines # initializers. It also executes some bootstrap initializers (check # Rails::Application::Bootstrap) and finishing initializers, after all the others # are executed (check Rails::Application::Finisher). @@ -19,8 +16,8 @@ module Rails # # Besides providing the same configuration as Rails::Engine and Rails::Railtie, # the application object has several specific configurations, for example - # "allow_concurrency", "cache_classes", "consider_all_requests_local", "filter_parameters", - # "logger", "reload_plugins" and so forth. + # "cache_classes", "consider_all_requests_local", "filter_parameters", + # "logger" and so forth. # # Check Rails::Application::Configuration to see them all. # @@ -33,11 +30,29 @@ module Rails # # The Application is also responsible for building the middleware stack. # + # == Booting process + # + # The application is also responsible for setting up and executing the booting + # process. From the moment you require "config/application.rb" in your app, + # the booting process goes like this: + # + # 1) require "config/boot.rb" to setup load paths + # 2) require railties and engines + # 3) Define Rails.application as "class MyApp::Application < Rails::Application" + # 4) Run config.before_configuration callbacks + # 5) Load config/environments/ENV.rb + # 6) Run config.before_initialize callbacks + # 7) Run Railtie#initializer defined by railties, engines and application. + # One by one, each engine sets up its load paths, routes and runs its config/initializers/* files. + # 9) Custom Railtie#initializers added by railties, engines and applications are executed + # 10) Build the middleware stack and run to_prepare callbacks + # 11) Run config.before_eager_load and eager_load if cache classes is true + # 12) Run config.after_initialize callbacks + # class Application < Engine autoload :Bootstrap, 'rails/application/bootstrap' autoload :Configuration, 'rails/application/configuration' autoload :Finisher, 'rails/application/finisher' - autoload :Railties, 'rails/application/railties' autoload :RoutesReloader, 'rails/application/routes_reloader' class << self @@ -50,16 +65,67 @@ module Rails end end - attr_accessor :assets, :sandbox + attr_accessor :assets, :sandbox, :queue_consumer alias_method :sandbox?, :sandbox + attr_reader :reloaders + attr_writer :queue delegate :default_url_options, :default_url_options=, :to => :routes def initialize super - @initialized = false + @initialized = false + @reloaders = [] + @routes_reloader = nil + @env_config = nil + @ordered_railties = nil + @railties = nil + @queue = nil + end + + # Returns true if the application is initialized. + def initialized? + @initialized + end + + # Implements call according to the Rack API. It simples + # dispatch the request to the underlying middleware stack. + def call(env) + env["ORIGINAL_FULLPATH"] = build_original_fullpath(env) + super(env) + end + + # Reload application routes regardless if they changed or not. + def reload_routes! + routes_reloader.reload! end + # Stores some of the Rails initial environment parameters which + # will be used by middlewares and engines to configure themselves. + # Currently stores: + # + # * "action_dispatch.parameter_filter" => config.filter_parameters, + # * "action_dispatch.secret_token" => config.secret_token, + # * "action_dispatch.show_exceptions" => config.action_dispatch.show_exceptions, + # * "action_dispatch.show_detailed_exceptions" => config.consider_all_requests_local, + # * "action_dispatch.logger" => Rails.logger, + # * "action_dispatch.backtrace_cleaner" => Rails.backtrace_cleaner + # + # These parameters will be used by middlewares and engines to configure themselves + # + def env_config + @env_config ||= super.merge({ + "action_dispatch.parameter_filter" => config.filter_parameters, + "action_dispatch.secret_token" => config.secret_token, + "action_dispatch.show_exceptions" => config.action_dispatch.show_exceptions, + "action_dispatch.show_detailed_exceptions" => config.consider_all_requests_local, + "action_dispatch.logger" => Rails.logger, + "action_dispatch.backtrace_cleaner" => Rails.backtrace_cleaner + }) + end + + ## Rails internal API + # This method is called just after an application inherits from Rails::Application, # allowing the developer to load classes in lib and use them during application # configuration. @@ -74,7 +140,7 @@ module Rails # Rails application, you will need to add lib to $LOAD_PATH on your own in case # you need to load files in lib/ during the application configuration as well. def add_lib_to_load_path! #:nodoc: - path = config.root.join('lib').to_s + path = File.join config.root, 'lib' $LOAD_PATH.unshift(path) if File.exists?(path) end @@ -83,105 +149,180 @@ module Rails require environment if environment end - def reload_routes! - routes_reloader.reload! + def routes_reloader #:nodoc: + @routes_reloader ||= RoutesReloader.new end - def routes_reloader - @routes_reloader ||= RoutesReloader.new + # Returns an array of file paths appended with a hash of + # directories-extensions suitable for ActiveSupport::FileUpdateChecker + # API. + def watchable_args #:nodoc: + files, dirs = config.watchable_files.dup, config.watchable_dirs.dup + + ActiveSupport::Dependencies.autoload_paths.each do |path| + dirs[path.to_s] = [:rb] + end + + [files, dirs] end - def initialize!(group=:default) + # Initialize the application passing the given group. By default, the + # group is :default but sprockets precompilation passes group equals + # to assets if initialize_on_precompile is false to avoid booting the + # whole app. + def initialize!(group=:default) #:nodoc: raise "Application has been already initialized." if @initialized run_initializers(group, self) @initialized = true self end - def load_tasks(app=self) - initialize_tasks - super - self + def initializers #:nodoc: + Bootstrap.initializers_for(self) + + railties_initializers(super) + + Finisher.initializers_for(self) end - def load_console(app=self) - initialize_console - super - self + def config #:nodoc: + @config ||= Application::Configuration.new(find_root_with_flag("config.ru", Dir.pwd)) end - # Rails.application.env_config stores some of the Rails initial environment parameters. - # Currently stores: - # - # * action_dispatch.parameter_filter" => config.filter_parameters, - # * action_dispatch.secret_token" => config.secret_token, - # * action_dispatch.show_exceptions" => config.action_dispatch.show_exceptions - # - # These parameters will be used by middlewares and engines to configure themselves. - # - def env_config - @env_config ||= super.merge({ - "action_dispatch.parameter_filter" => config.filter_parameters, - "action_dispatch.secret_token" => config.secret_token, - "action_dispatch.show_exceptions" => config.action_dispatch.show_exceptions - }) + def queue #:nodoc: + @queue ||= Queueing::Container.new(build_queue) end - def initializers - Bootstrap.initializers_for(self) + - super + - Finisher.initializers_for(self) + def build_queue #:nodoc: + config.queue.new end - def config - @config ||= Application::Configuration.new(find_root_with_flag("config.ru", Dir.pwd)) + def to_app #:nodoc: + self end - def to_app - self + def helpers_paths #:nodoc: + config.helpers_paths + end + + def railties #:nodoc: + @railties ||= Rails::Railtie.subclasses.map(&:instance) + + Rails::Engine.subclasses.map(&:instance) end protected alias :build_middleware_stack :app - def default_middleware_stack + def run_tasks_blocks(app) #:nodoc: + railties.each { |r| r.run_tasks_blocks(app) } + super + require "rails/tasks" + config = self.config + task :environment do + config.eager_load = false + require_environment! + end + end + + def run_generators_blocks(app) #:nodoc: + railties.each { |r| r.run_generators_blocks(app) } + super + end + + def run_runner_blocks(app) #:nodoc: + railties.each { |r| r.run_runner_blocks(app) } + super + end + + def run_console_blocks(app) #:nodoc: + railties.each { |r| r.run_console_blocks(app) } + super + end + + # Returns the ordered railties for this application considering railties_order. + def ordered_railties #:nodoc: + @ordered_railties ||= begin + order = config.railties_order.map do |railtie| + if railtie == :main_app + self + elsif railtie.respond_to?(:instance) + railtie.instance + else + railtie + end + end + + all = (railties - order) + all.push(self) unless (all + order).include?(self) + order.push(:all) unless order.include?(:all) + + index = order.index(:all) + order[index] = all + order.reverse.flatten + end + end + + def railties_initializers(current) #:nodoc: + initializers = [] + ordered_railties.each do |r| + if r == self + initializers += current + else + initializers += r.initializers + end + end + initializers + end + + def reload_dependencies? #:nodoc: + config.reload_classes_only_on_change != true || reloaders.map(&:updated?).any? + end + + def default_middleware_stack #:nodoc: ActionDispatch::MiddlewareStack.new.tap do |middleware| + app = self if rack_cache = config.action_controller.perform_caching && config.action_dispatch.rack_cache require "action_dispatch/http/rack_cache" middleware.use ::Rack::Cache, rack_cache end if config.force_ssl - require "rack/ssl" - middleware.use ::Rack::SSL, config.ssl_options + middleware.use ::ActionDispatch::SSL, config.ssl_options + end + + if config.action_dispatch.x_sendfile_header.present? + middleware.use ::Rack::Sendfile, config.action_dispatch.x_sendfile_header end if config.serve_static_assets middleware.use ::ActionDispatch::Static, paths["public"].first, config.static_cache_control end - middleware.use ::Rack::Lock unless config.allow_concurrency + middleware.use ::Rack::Lock unless config.cache_classes middleware.use ::Rack::Runtime middleware.use ::Rack::MethodOverride middleware.use ::ActionDispatch::RequestId middleware.use ::Rails::Rack::Logger, config.log_tags # must come after Rack::MethodOverride to properly log overridden methods - middleware.use ::ActionDispatch::ShowExceptions, config.consider_all_requests_local + middleware.use ::ActionDispatch::ShowExceptions, config.exceptions_app || ActionDispatch::PublicExceptions.new(Rails.public_path) + middleware.use ::ActionDispatch::DebugExceptions, app middleware.use ::ActionDispatch::RemoteIp, config.action_dispatch.ip_spoofing_check, config.action_dispatch.trusted_proxies - if config.action_dispatch.x_sendfile_header.present? - middleware.use ::Rack::Sendfile, config.action_dispatch.x_sendfile_header + + unless config.cache_classes + middleware.use ::ActionDispatch::Reloader, lambda { app.reload_dependencies? } end - middleware.use ::ActionDispatch::Reloader unless config.cache_classes + middleware.use ::ActionDispatch::Callbacks middleware.use ::ActionDispatch::Cookies if config.session_store + if config.force_ssl && !config.session_options.key?(:secure) + config.session_options[:secure] = true + end middleware.use config.session_store, config.session_options middleware.use ::ActionDispatch::Flash end middleware.use ::ActionDispatch::ParamsParser - middleware.use ::ActionDispatch::Head + middleware.use ::Rack::Head middleware.use ::Rack::ConditionalGet middleware.use ::Rack::ETag, "no-cache" @@ -191,20 +332,16 @@ module Rails end end - def initialize_tasks - self.class.rake_tasks do - require "rails/tasks" - task :environment do - $rails_rake_task = true - require_environment! - end - end - end + def build_original_fullpath(env) #:nodoc: + path_info = env["PATH_INFO"] + query_string = env["QUERY_STRING"] + script_name = env["SCRIPT_NAME"] - def initialize_console - require "pp" - require "rails/console/app" - require "rails/console/helpers" + if query_string.present? + "#{script_name}#{path_info}?#{query_string}" + else + "#{script_name}#{path_info}" + end end end end diff --git a/railties/lib/rails/application/bootstrap.rb b/railties/lib/rails/application/bootstrap.rb index c2cb121e42..a1bc95550b 100644 --- a/railties/lib/rails/application/bootstrap.rb +++ b/railties/lib/rails/application/bootstrap.rb @@ -13,53 +13,60 @@ module Rails require "active_support/all" unless config.active_support.bare end - # Preload all frameworks specified by the Configuration#frameworks. - # Used by Passenger to ensure everything's loaded before forking and - # to avoid autoload race conditions in JRuby. - initializer :preload_frameworks, :group => :all do - ActiveSupport::Autoload.eager_autoload! if config.preload_frameworks + initializer :set_eager_load, :group => :all do + if config.eager_load.nil? + warn <<-INFO +config.eager_load is set to nil. Please update your config/environments/*.rb files accordingly: + + * development - set it to false + * test - set it to false (unless you use a tool that preloads your test environment) + * production - set it to true + +INFO + config.eager_load = config.cache_classes + end end # Initialize the logger early in the stack in case we need to log some deprecation. initializer :initialize_logger, :group => :all do Rails.logger ||= config.logger || begin path = config.paths["log"].first - logger = ActiveSupport::TaggedLogging.new(ActiveSupport::BufferedLogger.new(path)) - logger.level = ActiveSupport::BufferedLogger.const_get(config.log_level.to_s.upcase) - logger.auto_flushing = false if Rails.env.production? + unless File.exist? File.dirname path + FileUtils.mkdir_p File.dirname path + end + + f = File.open path, 'a' + f.binmode + f.sync = config.autoflush_log # if true make sure every write flushes + + logger = ActiveSupport::Logger.new f + logger.formatter = config.log_formatter + logger = ActiveSupport::TaggedLogging.new(logger) + logger.level = ActiveSupport::Logger.const_get(config.log_level.to_s.upcase) logger rescue StandardError - logger = ActiveSupport::TaggedLogging.new(ActiveSupport::BufferedLogger.new(STDERR)) - logger.level = ActiveSupport::BufferedLogger::WARN + logger = ActiveSupport::TaggedLogging.new(ActiveSupport::Logger.new(STDERR)) + logger.level = ActiveSupport::Logger::WARN logger.warn( "Rails Error: Unable to access log file. Please ensure that #{path} exists and is chmod 0666. " + "The log level has been raised to WARN and the output directed to STDERR until the problem is fixed." ) logger end - at_exit { Rails.logger.flush if Rails.logger.respond_to?(:flush) } end # Initialize cache early in the stack so railties can make use of it. initializer :initialize_cache, :group => :all do - unless defined?(RAILS_CACHE) - silence_warnings { Object.const_set "RAILS_CACHE", ActiveSupport::Cache.lookup_store(config.cache_store) } + unless Rails.cache + Rails.cache = ActiveSupport::Cache.lookup_store(config.cache_store) - if RAILS_CACHE.respond_to?(:middleware) - config.middleware.insert_before("Rack::Runtime", RAILS_CACHE.middleware) + if Rails.cache.respond_to?(:middleware) + config.middleware.insert_before("Rack::Runtime", Rails.cache.middleware) end end end - initializer :set_clear_dependencies_hook, :group => :all do - ActionDispatch::Reloader.to_cleanup do - ActiveSupport::DescendantsTracker.clear - ActiveSupport::Dependencies.clear - end - end - # Sets the dependency loading mechanism. - # TODO: Remove files from the $" and always use require. initializer :initialize_dependency_mechanism, :group => :all do ActiveSupport::Dependencies.mechanism = config.cache_classes ? :require : :load end diff --git a/railties/lib/rails/application/configuration.rb b/railties/lib/rails/application/configuration.rb index 8f5b28faf8..7f05b2e7e1 100644 --- a/railties/lib/rails/application/configuration.rb +++ b/railties/lib/rails/application/configuration.rb @@ -1,17 +1,18 @@ -require 'active_support/core_ext/string/encoding' require 'active_support/core_ext/kernel/reporting' +require 'active_support/file_update_checker' require 'rails/engine/configuration' module Rails class Application class Configuration < ::Rails::Engine::Configuration - attr_accessor :allow_concurrency, :asset_host, :asset_path, :assets, - :cache_classes, :cache_store, :consider_all_requests_local, - :dependency_loading, :filter_parameters, - :force_ssl, :helpers_paths, :logger, :log_tags, :preload_frameworks, - :reload_plugins, :secret_token, :serve_static_assets, - :ssl_options, :static_cache_control, :session_options, - :time_zone, :whiny_nils + attr_accessor :asset_host, :asset_path, :assets, :autoflush_log, + :cache_classes, :cache_store, :consider_all_requests_local, :console, + :eager_load, :exceptions_app, :file_watcher, :filter_parameters, + :force_ssl, :helpers_paths, :logger, :log_formatter, :log_tags, + :railties_order, :relative_url_root, :secret_token, + :serve_static_assets, :ssl_options, :static_cache_control, :session_options, + :time_zone, :reload_classes_only_on_change, + :queue, :queue_consumer attr_writer :log_level attr_reader :encoding @@ -19,27 +20,35 @@ module Rails def initialize(*) super self.encoding = "utf-8" - @allow_concurrency = false - @consider_all_requests_local = false - @filter_parameters = [] - @helpers_paths = [] - @dependency_loading = true - @serve_static_assets = true - @static_cache_control = nil - @force_ssl = false - @ssl_options = {} - @session_store = :cookie_store - @session_options = {} - @time_zone = "UTC" - @log_level = nil - @middleware = app_middleware - @generators = app_generators - @cache_store = [ :file_store, "#{root}/tmp/cache/" ] + @consider_all_requests_local = false + @filter_parameters = [] + @helpers_paths = [] + @serve_static_assets = true + @static_cache_control = nil + @force_ssl = false + @ssl_options = {} + @session_store = :cookie_store + @session_options = {} + @time_zone = "UTC" + @log_level = nil + @middleware = app_middleware + @generators = app_generators + @cache_store = [ :file_store, "#{root}/tmp/cache/" ] + @railties_order = [:all] + @relative_url_root = ENV["RAILS_RELATIVE_URL_ROOT"] + @reload_classes_only_on_change = true + @file_watcher = ActiveSupport::FileUpdateChecker + @exceptions_app = nil + @autoflush_log = true + @log_formatter = ActiveSupport::Logger::SimpleFormatter.new + @queue = Rails::Queueing::Queue + @queue_consumer = Rails::Queueing::ThreadedConsumer + @eager_load = nil @assets = ActiveSupport::OrderedOptions.new @assets.enabled = false @assets.paths = [] - @assets.precompile = [ Proc.new{ |path| !File.extname(path).in?(['.js', '.css']) }, + @assets.precompile = [ Proc.new { |path| !%w(.js .css).include?(File.extname(path)) }, /(?:\/|\\|\A)application\.(css|js)$/ ] @assets.prefix = "/assets" @assets.version = '' @@ -51,6 +60,7 @@ module Rails @assets.js_compressor = nil @assets.css_compressor = nil @assets.initialize_on_precompile = true + @assets.logger = nil end def compiled_asset_path @@ -59,17 +69,9 @@ module Rails def encoding=(value) @encoding = value - if "ruby".encoding_aware? - silence_warnings do - Encoding.default_external = value - Encoding.default_internal = value - end - else - $KCODE = value - if $KCODE == "NONE" - raise "The value you specified for config.encoding is " \ - "invalid. The possible values are UTF8, SJIS, or EUC" - end + silence_warnings do + Encoding.default_external = value + Encoding.default_internal = value end end @@ -88,15 +90,12 @@ module Rails end end - # Enable threaded mode. Allows concurrent requests to controller actions and - # multiple database connections. Also disables automatic dependency loading - # after boot, and disables reloading code on every request, as these are - # fundamentally incompatible with thread safety. def threadsafe! - self.preload_frameworks = true - self.cache_classes = true - self.dependency_loading = false - self.allow_concurrency = true + ActiveSupport::Deprecation.warn "config.threadsafe! is deprecated. Rails applications " \ + "behave by default as thread safe in production as long as config.cache_classes and " \ + "config.eager_load are set to true" + @cache_classes = true + @eager_load = true self end @@ -105,7 +104,7 @@ module Rails # YAML::load. def database_configuration require 'erb' - YAML::load(ERB.new(IO.read(paths["config/database"].first)).result) + YAML.load ERB.new(IO.read(paths["config/database"].first)).result end def log_level @@ -113,11 +112,10 @@ module Rails end def colorize_logging - @colorize_logging + ActiveSupport::LogSubscriber.colorize_logging end def colorize_logging=(val) - @colorize_logging = val ActiveSupport::LogSubscriber.colorize_logging = val self.generators.colorize_logging = val end @@ -139,6 +137,11 @@ module Rails @session_options = args.shift || {} end end + + def whiny_nils=(*) + ActiveSupport::Deprecation.warn "config.whiny_nils option " \ + "is deprecated and no longer works", caller + end end end end diff --git a/railties/lib/rails/application/finisher.rb b/railties/lib/rails/application/finisher.rb index 028c8814c4..1952a0fc3a 100644 --- a/railties/lib/rails/application/finisher.rb +++ b/railties/lib/rails/application/finisher.rb @@ -19,16 +19,12 @@ module Rails end end - initializer :add_to_prepare_blocks do - config.to_prepare_blocks.each do |block| - ActionDispatch::Reloader.to_prepare(&block) - end - end - initializer :add_builtin_route do |app| if Rails.env.development? app.routes.append do - match '/rails/info/properties' => "rails/info#properties" + get '/rails/info/properties' => "rails/info#properties" + get '/rails/info/routes' => "rails/info#routes" + get '/rails/info' => "rails/info#index" end end end @@ -37,40 +33,75 @@ module Rails build_middleware_stack end - initializer :run_prepare_callbacks do - ActionDispatch::Reloader.prepare! - end - initializer :define_main_app_helper do |app| app.routes.define_mounted_helper(:main_app) end + initializer :add_to_prepare_blocks do + config.to_prepare_blocks.each do |block| + ActionDispatch::Reloader.to_prepare(&block) + end + end + + # This needs to happen before eager load so it happens + # in exactly the same point regardless of config.cache_classes + initializer :run_prepare_callbacks do + ActionDispatch::Reloader.prepare! + end + initializer :eager_load! do - if config.cache_classes && !$rails_rake_task + if config.eager_load ActiveSupport.run_load_hooks(:before_eager_load, self) - eager_load! + config.eager_load_namespaces.each(&:eager_load!) end end + # All initialization is done, including eager loading in production initializer :finisher_hook do ActiveSupport.run_load_hooks(:after_initialize, self) end - # Force routes to be loaded just at the end and add it to to_prepare callbacks - # This needs to be after the finisher hook to ensure routes added in the hook - # are still loaded. - initializer :set_routes_reloader do |app| - reloader = lambda { app.routes_reloader.execute_if_updated } - reloader.call - ActionDispatch::Reloader.to_prepare(&reloader) + # Set app reload just after the finisher hook to ensure + # routes added in the hook are still loaded. + initializer :set_routes_reloader_hook do + reloader = routes_reloader + reloader.execute_if_updated + self.reloaders << reloader + ActionDispatch::Reloader.to_prepare { reloader.execute_if_updated } + end + + # Set app reload just after the finisher hook to ensure + # paths added in the hook are still loaded. + initializer :set_clear_dependencies_hook, :group => :all do + callback = lambda do + ActiveSupport::DescendantsTracker.clear + ActiveSupport::Dependencies.clear + end + + if config.reload_classes_only_on_change + reloader = config.file_watcher.new(*watchable_args, &callback) + self.reloaders << reloader + # We need to set a to_prepare callback regardless of the reloader result, i.e. + # models should be reloaded if any of the reloaders (i18n, routes) were updated. + ActionDispatch::Reloader.to_prepare(:prepend => true){ reloader.execute } + else + ActionDispatch::Reloader.to_cleanup(&callback) + end end # Disable dependency loading during request cycle initializer :disable_dependency_loading do - if config.cache_classes && !config.dependency_loading + if config.eager_load ActiveSupport::Dependencies.unhook! end end + + initializer :activate_queue_consumer do |app| + if config.queue == Rails::Queueing::Queue + app.queue_consumer = config.queue_consumer.start(app.queue) + at_exit { app.queue_consumer.shutdown } + end + end end end end diff --git a/railties/lib/rails/application/railties.rb b/railties/lib/rails/application/railties.rb deleted file mode 100644 index 8f3a3e8bbb..0000000000 --- a/railties/lib/rails/application/railties.rb +++ /dev/null @@ -1,13 +0,0 @@ -require 'rails/engine/railties' - -module Rails - class Application < Engine - class Railties < Rails::Engine::Railties - def all(&block) - @all ||= railties + engines + plugins - @all.each(&block) if block - @all - end - end - end -end diff --git a/railties/lib/rails/application/route_inspector.rb b/railties/lib/rails/application/route_inspector.rb deleted file mode 100644 index 8252f21aa7..0000000000 --- a/railties/lib/rails/application/route_inspector.rb +++ /dev/null @@ -1,44 +0,0 @@ -module Rails - class Application - ## - # This class is just used for displaying route information when someone - # executes `rake routes`. People should not use this class. - class RouteInspector # :nodoc: - def format all_routes, filter = nil - if filter - all_routes = all_routes.select{ |route| route.defaults[:controller] == filter } - end - - routes = all_routes.collect do |route| - route_reqs = route.requirements - - rack_app = route.app unless route.app.class.name.to_s =~ /^ActionDispatch::Routing/ - - controller = route_reqs[:controller] || ':controller' - action = route_reqs[:action] || ':action' - - endpoint = rack_app ? rack_app.inspect : "#{controller}##{action}" - constraints = route_reqs.except(:controller, :action) - - reqs = endpoint - reqs += " #{constraints.inspect}" unless constraints.empty? - - verb = route.verb.source.gsub(/[$^]/, '') - - {:name => route.name.to_s, :verb => verb, :path => route.path.spec.to_s, :reqs => reqs} - end - - # Skip the route if it's internal info route - routes.reject! { |r| r[:path] =~ %r{/rails/info/properties|^/assets} } - - name_width = routes.map{ |r| r[:name].length }.max - verb_width = routes.map{ |r| r[:verb].length }.max - path_width = routes.map{ |r| r[:path].length }.max - - routes.map do |r| - "#{r[:name].rjust(name_width)} #{r[:verb].ljust(verb_width)} #{r[:path].ljust(path_width)} #{r[:reqs]}" - end - end - end - end -end diff --git a/railties/lib/rails/application/routes_reloader.rb b/railties/lib/rails/application/routes_reloader.rb index 1d1f5e1b06..6f9a200aa9 100644 --- a/railties/lib/rails/application/routes_reloader.rb +++ b/railties/lib/rails/application/routes_reloader.rb @@ -1,10 +1,13 @@ +require "active_support/core_ext/module/delegation" + module Rails class Application - class RoutesReloader < ::ActiveSupport::FileUpdateChecker - attr_reader :route_sets + class RoutesReloader + attr_reader :route_sets, :paths + delegate :execute_if_updated, :execute, :updated?, :to => :updater def initialize - super([]) { reload! } + @paths = [] @route_sets = [] end @@ -16,7 +19,15 @@ module Rails revert end - protected + private + + def updater + @updater ||= begin + updater = ActiveSupport::FileUpdateChecker.new(paths) { reload! } + updater.execute + updater + end + end def clear! route_sets.each do |routes| @@ -31,7 +42,7 @@ module Rails def finalize! route_sets.each do |routes| - ActiveSupport.on_load(:action_controller) { routes.finalize! } + routes.finalize! end end diff --git a/railties/lib/rails/backtrace_cleaner.rb b/railties/lib/rails/backtrace_cleaner.rb index 36fd9aea19..8cc8eb1103 100644 --- a/railties/lib/rails/backtrace_cleaner.rb +++ b/railties/lib/rails/backtrace_cleaner.rb @@ -17,26 +17,11 @@ module Rails private def add_gem_filters - return unless defined?(Gem) - - gems_paths = (Gem.path + [Gem.default_dir]).uniq.map!{ |p| Regexp.escape(p) } + gems_paths = (Gem.path | [Gem.default_dir]).map { |p| Regexp.escape(p) } return if gems_paths.empty? gems_regexp = %r{(#{gems_paths.join('|')})/gems/([^/]+)-([\w.]+)/(.*)} add_filter { |line| line.sub(gems_regexp, '\2 (\3) \4') } end end - - # For installing the BacktraceCleaner in the test/unit - module BacktraceFilterForTestUnit #:nodoc: - def self.included(klass) - klass.send :alias_method_chain, :filter_backtrace, :cleaning - end - - def filter_backtrace_with_cleaning(backtrace, prefix=nil) - backtrace = filter_backtrace_without_cleaning(backtrace, prefix) - backtrace = backtrace.first.split("\n") if backtrace.size == 1 - Rails.backtrace_cleaner.clean(backtrace) - end - end end diff --git a/railties/lib/rails/code_statistics.rb b/railties/lib/rails/code_statistics.rb index e6822b75b7..1aed2796c1 100644 --- a/railties/lib/rails/code_statistics.rb +++ b/railties/lib/rails/code_statistics.rb @@ -26,7 +26,7 @@ class CodeStatistics #:nodoc: Hash[@pairs.map{|pair| [pair.first, calculate_directory_statistics(pair.last)]}] end - def calculate_directory_statistics(directory, pattern = /.*\.rb$/) + def calculate_directory_statistics(directory, pattern = /.*\.(rb|js|coffee)$/) stats = { "lines" => 0, "codelines" => 0, "classes" => 0, "methods" => 0 } Dir.foreach(directory) do |file_name| @@ -37,13 +37,33 @@ class CodeStatistics #:nodoc: next unless file_name =~ pattern - f = File.open(directory + "/" + file_name) + comment_started = false + + case file_name + when /.*\.js$/ + comment_pattern = /^\s*\/\// + else + comment_pattern = /^\s*#/ + end - while line = f.gets - stats["lines"] += 1 - stats["classes"] += 1 if line =~ /class [A-Z]/ - stats["methods"] += 1 if line =~ /def [a-z]/ - stats["codelines"] += 1 unless line =~ /^\s*$/ || line =~ /^\s*#/ + File.open(directory + "/" + file_name) do |f| + while line = f.gets + stats["lines"] += 1 + if(comment_started) + if line =~ /^=end/ + comment_started = false + end + next + else + if line =~ /^=begin/ + comment_started = true + next + end + end + stats["classes"] += 1 if line =~ /^\s*class\s+[_A-Z]/ + stats["methods"] += 1 if line =~ /^\s*def\s+[_a-z]/ + stats["codelines"] += 1 unless line =~ /^\s*$/ || line =~ comment_pattern + end end end @@ -82,13 +102,7 @@ class CodeStatistics #:nodoc: m_over_c = (statistics["methods"] / statistics["classes"]) rescue m_over_c = 0 loc_over_m = (statistics["codelines"] / statistics["methods"]) - 2 rescue loc_over_m = 0 - start = if TEST_TYPES.include? name - "| #{name.ljust(20)} " - else - "| #{name.ljust(20)} " - end - - puts start + + puts "| #{name.ljust(20)} " + "| #{statistics["lines"].to_s.rjust(5)} " + "| #{statistics["codelines"].to_s.rjust(5)} " + "| #{statistics["classes"].to_s.rjust(7)} " + diff --git a/railties/lib/rails/commands.rb b/railties/lib/rails/commands.rb index ada150ceec..9c5dc8f188 100644 --- a/railties/lib/rails/commands.rb +++ b/railties/lib/rails/commands.rb @@ -1,5 +1,3 @@ -require 'active_support/core_ext/object/inclusion' - ARGV << '--help' if ARGV.empty? aliases = { @@ -36,9 +34,17 @@ when 'benchmarker', 'profiler' when 'console' require 'rails/commands/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 + ARGV.shift if ARGV.first && ARGV.first[0] != '-' + require APP_PATH Rails.application.require_environment! - Rails::Console.start(Rails.application) + Rails::Console.start(Rails.application, options) when 'server' # Change to the application's path if there is no config.ru file in current dir. @@ -57,23 +63,26 @@ when 'server' when 'dbconsole' require 'rails/commands/dbconsole' - require APP_PATH - Rails::DBConsole.start(Rails.application) + Rails::DBConsole.start when 'application', 'runner' require "rails/commands/#{command}" when 'new' - 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) + if %w(-h --help).include?(ARGV.first) + require 'rails/commands/application' + else + 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 when '--version', '-v' ARGV.unshift '--version' require 'rails/commands/application' else - puts "Error: Command not recognized" unless command.in?(['-h', '--help']) + puts "Error: Command not recognized" unless %w(-h --help).include?(command) puts <<-EOT Usage: rails COMMAND [ARGS] @@ -91,7 +100,7 @@ In addition to those, there are: destroy Undo code generated with "generate" (short-cut alias: "d") benchmarker See how fast a piece of code runs profiler Get profile information from a piece of code - plugin Install a plugin + plugin new Generates skeleton for developing a Rails plugin runner Run a piece of code in the application environment (short-cut alias: "r") All commands can be run with -h (or --help) for more information. diff --git a/railties/lib/rails/commands/application.rb b/railties/lib/rails/commands/application.rb index 60d1aed73a..2cb6d5ca2e 100644 --- a/railties/lib/rails/commands/application.rb +++ b/railties/lib/rails/commands/application.rb @@ -19,7 +19,6 @@ else end end -require 'rubygems' if ARGV.include?("--dev") require 'rails/generators' require 'rails/generators/rails/app/app_generator' diff --git a/railties/lib/rails/commands/benchmarker.rb b/railties/lib/rails/commands/benchmarker.rb index 6c52d0f70f..b745b45e17 100644 --- a/railties/lib/rails/commands/benchmarker.rb +++ b/railties/lib/rails/commands/benchmarker.rb @@ -21,7 +21,7 @@ def options options end -class BenchmarkerTest < ActionDispatch::PerformanceTest +class BenchmarkerTest < ActionDispatch::PerformanceTest #:nodoc: self.profile_options = options ARGV.each do |expression| diff --git a/railties/lib/rails/commands/console.rb b/railties/lib/rails/commands/console.rb index 32e361d421..92cee6b638 100644 --- a/railties/lib/rails/commands/console.rb +++ b/railties/lib/rails/commands/console.rb @@ -4,50 +4,88 @@ require 'irb/completion' module Rails class Console - def self.start(app) - new(app).start + class << self + def start(*args) + new(*args).start + end + + 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.on("--debugger", 'Enable the debugger.') { |v| options[:debugger] = v } + opt.parse!(arguments) + end + + if arguments.first && arguments.first[0] != '-' + env = arguments.first + options[:environment] = %w(production development test).detect {|e| e =~ /^#{env}/} || env + end + + options + end end - def initialize(app) - @app = app + attr_reader :options, :app, :console + + def initialize(app, options={}) + @app = app + @options = options + app.load_console + @console = app.config.console || IRB end - def start - options = {} - - OptionParser.new do |opt| - opt.banner = "Usage: console [environment] [options]" - opt.on('-s', '--sandbox', 'Rollback database modifications on exit.') { |v| options[:sandbox] = v } - opt.on("--debugger", 'Enable ruby-debugging for the console.') { |v| options[:debugger] = v } - opt.on('--irb', "DEPRECATED: Invoke `/your/choice/of/ruby script/rails console` instead") { |v| abort '--irb option is no longer supported. Invoke `/your/choice/of/ruby script/rails console` instead' } - opt.parse!(ARGV) - end + def sandbox? + options[:sandbox] + end - @app.sandbox = options[:sandbox] - @app.load_console + def environment + options[:environment] ||= ENV['RAILS_ENV'] || 'development' + end - if options[:debugger] - begin - require 'ruby-debug' - puts "=> Debugger enabled" - rescue Exception - puts "You need to install ruby-debug to run the console in debugging mode. With gems, use 'gem install ruby-debug'" - exit - end - end + def environment? + environment + end + + def set_environment! + Rails.env = environment + end + + def debugger? + options[:debugger] + end + + def start + app.sandbox = sandbox? + require_debugger if debugger? + set_environment! if environment? - if options[:sandbox] + if sandbox? puts "Loading #{Rails.env} environment in sandbox (Rails #{Rails.version})" puts "Any modifications you make will be rolled back on exit" else puts "Loading #{Rails.env} environment (Rails #{Rails.version})" end - IRB.start + + if defined?(console::ExtendCommandBundle) + console::ExtendCommandBundle.send :include, Rails::ConsoleMethods + end + console.start end - end -end -# Has to set the RAILS_ENV before config/application is required -if ARGV.first && !ARGV.first.index("-") && env = ARGV.shift # has to shift the env ARGV so IRB doesn't freak - ENV['RAILS_ENV'] = %w(production development test).detect {|e| e =~ /^#{env}/} || env + def require_debugger + begin + require 'debugger' + puts "=> Debugger enabled" + rescue Exception + puts "You're missing the 'debugger' gem. Add it to your Gemfile, bundle, and try again." + exit + end + end + end end diff --git a/railties/lib/rails/commands/dbconsole.rb b/railties/lib/rails/commands/dbconsole.rb index b0ba76217a..cc0552184a 100644 --- a/railties/lib/rails/commands/dbconsole.rb +++ b/railties/lib/rails/commands/dbconsole.rb @@ -1,64 +1,23 @@ require 'erb' - -begin - require 'psych' -rescue LoadError -end - require 'yaml' require 'optparse' require 'rbconfig' module Rails class DBConsole - def self.start(app) - new(app).start + attr_reader :config, :arguments + + def self.start + new.start end - def initialize(app) - @app = app + def initialize(arguments = ARGV) + @arguments = arguments end def start - include_password = false - options = {} - OptionParser.new do |opt| - opt.banner = "Usage: dbconsole [environment] [options]" - opt.on("-p", "--include-password", "Automatically provide the password from database.yml") do |v| - 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("-h", "--header") do |h| - options['header'] = h - end - - opt.parse!(ARGV) - abort opt.to_s unless (0..1).include?(ARGV.size) - end - - unless config = YAML::load(ERB.new(IO.read("#{@app.root}/config/database.yml")).result)[Rails.env] - abort "No database is configured for the environment '#{Rails.env}'" - end - - - def find_cmd(*commands) - dirs_on_path = ENV['PATH'].to_s.split(File::PATH_SEPARATOR) - commands += commands.map{|cmd| "#{cmd}.exe"} if RbConfig::CONFIG['host_os'] =~ /mswin|mingw/ - - full_path_command = nil - found = commands.detect do |cmd| - dir = dirs_on_path.detect do |path| - full_path_command = File.join(path, cmd) - File.executable? full_path_command - end - end - found ? full_path_command : abort("Couldn't find database client: #{commands.join(', ')}. Check your $PATH and try again.") - end + options = parse_arguments(arguments) + ENV['RAILS_ENV'] = options[:environment] || environment case config["adapter"] when /^mysql/ @@ -70,7 +29,7 @@ module Rails 'encoding' => '--default-character-set' }.map { |opt, arg| "#{arg}=#{config[opt]}" if config[opt] }.compact - if config['password'] && include_password + if config['password'] && options['include_password'] args << "--password=#{config['password']}" elsif config['password'] && !config['password'].to_s.empty? args << "-p" @@ -78,46 +37,129 @@ module Rails args << config['database'] - exec(find_cmd('mysql', 'mysql5'), *args) + find_cmd_and_exec(['mysql', 'mysql5'], *args) when "postgresql", "postgres" 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"] && include_password - exec(find_cmd('psql'), config["database"]) + ENV['PGPASSWORD'] = config["password"].to_s if config["password"] && options['include_password'] + find_cmd_and_exec('psql', config["database"]) when "sqlite" - exec(find_cmd('sqlite'), config["database"]) + find_cmd_and_exec('sqlite', config["database"]) when "sqlite3" args = [] args << "-#{options['mode']}" if options['mode'] args << "-header" if options['header'] - args << config['database'] + args << File.expand_path(config['database'], Rails.root) - exec(find_cmd('sqlite3'), *args) + find_cmd_and_exec('sqlite3', *args) when "oracle", "oracle_enhanced" logon = "" if config['username'] logon = config['username'] - logon << "/#{config['password']}" if config['password'] && include_password + logon << "/#{config['password']}" if config['password'] && options['include_password'] logon << "@#{config['database']}" if config['database'] end - exec(find_cmd('sqlplus'), logon) + find_cmd_and_exec('sqlplus', logon) else abort "Unknown command-line client for #{config['database']}. Submit a Rails patch to add support!" end end - end -end -# Has to set the RAILS_ENV before config/application is required -if ARGV.first && !ARGV.first.index("-") && env = ARGV.first - ENV['RAILS_ENV'] = %w(production development test).detect {|e| e =~ /^#{env}/} || env + def config + @config ||= begin + cfg = begin + cfg = YAML.load(ERB.new(IO.read("config/database.yml")).result) + rescue SyntaxError, StandardError + require APP_PATH + Rails.application.config.database_configuration + end + + unless cfg[environment] + abort "No database is configured for the environment '#{environment}'" + end + + cfg[environment] + end + end + + def environment + if Rails.respond_to?(:env) + Rails.env + else + ENV["RAILS_ENV"] || ENV["RACK_ENV"] || "development" + end + end + + protected + + 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 + + if arguments.first && arguments.first[0] != '-' + env = arguments.first + options[:environment] = %w(production development test).detect {|e| e =~ /^#{env}/} || env + end + + options + end + + def find_cmd_and_exec(commands, *args) + commands = Array(commands) + + dirs_on_path = ENV['PATH'].to_s.split(File::PATH_SEPARATOR) + commands += commands.map{|cmd| "#{cmd}.exe"} if RbConfig::CONFIG['host_os'] =~ /mswin|mingw/ + + full_path_command = nil + found = commands.detect do |cmd| + dir = dirs_on_path.detect do |path| + full_path_command = File.join(path, cmd) + File.executable? full_path_command + end + end + + if found + exec full_path_command, *args + else + abort("Couldn't find database client: #{commands.join(', ')}. Check your $PATH and try again.") + end + end + end end diff --git a/railties/lib/rails/commands/destroy.rb b/railties/lib/rails/commands/destroy.rb index ae354eca97..9023c61bf2 100644 --- a/railties/lib/rails/commands/destroy.rb +++ b/railties/lib/rails/commands/destroy.rb @@ -1,7 +1,6 @@ require 'rails/generators' -require 'active_support/core_ext/object/inclusion' -if ARGV.first.in?([nil, "-h", "--help"]) +if [nil, "-h", "--help"].include?(ARGV.first) Rails::Generators.help 'destroy' exit end diff --git a/railties/lib/rails/commands/generate.rb b/railties/lib/rails/commands/generate.rb index 1fb2d98834..9f13cb0513 100644 --- a/railties/lib/rails/commands/generate.rb +++ b/railties/lib/rails/commands/generate.rb @@ -1,7 +1,6 @@ require 'rails/generators' -require 'active_support/core_ext/object/inclusion' -if ARGV.first.in?([nil, "-h", "--help"]) +if [nil, "-h", "--help"].include?(ARGV.first) Rails::Generators.help 'generate' exit end diff --git a/railties/lib/rails/commands/plugin.rb b/railties/lib/rails/commands/plugin.rb deleted file mode 100644 index 4df849447d..0000000000 --- a/railties/lib/rails/commands/plugin.rb +++ /dev/null @@ -1,542 +0,0 @@ -# Rails Plugin Manager. -# -# Installing plugins: -# -# $ rails plugin install continuous_builder asset_timestamping -# -# Specifying revisions: -# -# * Subversion revision is a single integer. -# -# * Git revision format: -# - full - 'refs/tags/1.8.0' or 'refs/heads/experimental' -# - short: 'experimental' (equivalent to 'refs/heads/experimental') -# 'tag 1.8.0' (equivalent to 'refs/tags/1.8.0') -# -# -# This is Free Software, copyright 2005 by Ryan Tomayko (rtomayko@gmail.com) -# and is licensed MIT: (http://www.opensource.org/licenses/mit-license.php) - -$verbose = false - -require 'open-uri' -require 'fileutils' -require 'tempfile' - -include FileUtils - -class RailsEnvironment - attr_reader :root - - def initialize(dir) - @root = dir - end - - def self.find(dir=nil) - dir ||= pwd - while dir.length > 1 - return new(dir) if File.exist?(File.join(dir, 'config', 'environment.rb')) - dir = File.dirname(dir) - end - end - - def self.default - @default ||= find - end - - def self.default=(rails_env) - @default = rails_env - end - - def install(name_uri_or_plugin) - if name_uri_or_plugin.is_a? String - if name_uri_or_plugin =~ /:\/\// - plugin = Plugin.new(name_uri_or_plugin) - else - plugin = Plugins[name_uri_or_plugin] - end - else - plugin = name_uri_or_plugin - end - if plugin - plugin.install - else - puts "Plugin not found: #{name_uri_or_plugin}" - end - end - - def use_svn? - require 'active_support/core_ext/kernel' - silence_stderr {`svn --version` rescue nil} - !$?.nil? && $?.success? - end - - def use_externals? - use_svn? && File.directory?("#{root}/vendor/plugins/.svn") - end - - def use_checkout? - # this is a bit of a guess. we assume that if the rails environment - # is under subversion then they probably want the plugin checked out - # instead of exported. This can be overridden on the command line - File.directory?("#{root}/.svn") - end - - def best_install_method - return :http unless use_svn? - case - when use_externals? then :externals - when use_checkout? then :checkout - else :export - end - end - - def externals - return [] unless use_externals? - ext = `svn propget svn:externals "#{root}/vendor/plugins"` - lines = ext.respond_to?(:lines) ? ext.lines : ext - lines.reject{ |line| line.strip == '' }.map do |line| - line.strip.split(/\s+/, 2) - end - end - - def externals=(items) - unless items.is_a? String - items = items.map{|name,uri| "#{name.ljust(29)} #{uri.chomp('/')}"}.join("\n") - end - Tempfile.open("svn-set-prop") do |file| - file.write(items) - file.flush - system("svn propset -q svn:externals -F \"#{file.path}\" \"#{root}/vendor/plugins\"") - end - end -end - -class Plugin - attr_reader :name, :uri - - def initialize(uri, name = nil) - @uri = uri - guess_name(uri) - end - - def self.find(name) - new(name) - end - - def to_s - "#{@name.ljust(30)}#{@uri}" - end - - def svn_url? - @uri =~ /svn(?:\+ssh)?:\/\/*/ - end - - def git_url? - @uri =~ /^git:\/\// || @uri =~ /\.git$/ - end - - def installed? - File.directory?("#{rails_env.root}/vendor/plugins/#{name}") \ - or rails_env.externals.detect{ |name, repo| self.uri == repo } - end - - def install(method=nil, options = {}) - method ||= rails_env.best_install_method? - if :http == method - method = :export if svn_url? - method = :git if git_url? - end - - uninstall if installed? and options[:force] - - unless installed? - send("install_using_#{method}", options) - run_install_hook - else - puts "already installed: #{name} (#{uri}). pass --force to reinstall" - end - end - - def uninstall - path = "#{rails_env.root}/vendor/plugins/#{name}" - if File.directory?(path) - puts "Removing 'vendor/plugins/#{name}'" if $verbose - run_uninstall_hook - rm_r path - else - puts "Plugin doesn't exist: #{path}" - end - - if rails_env.use_externals? - # clean up svn:externals - externals = rails_env.externals - externals.reject!{|n, u| name == n or name == u} - rails_env.externals = externals - end - end - - def info - tmp = "#{rails_env.root}/_tmp_about.yml" - if svn_url? - cmd = "svn export #{@uri} \"#{rails_env.root}/#{tmp}\"" - puts cmd if $verbose - system(cmd) - end - open(svn_url? ? tmp : File.join(@uri, 'about.yml')) do |stream| - stream.read - end rescue "No about.yml found in #{uri}" - ensure - FileUtils.rm_rf tmp if svn_url? - end - - private - - def run_install_hook - install_hook_file = "#{rails_env.root}/vendor/plugins/#{name}/install.rb" - load install_hook_file if File.exist? install_hook_file - end - - def run_uninstall_hook - uninstall_hook_file = "#{rails_env.root}/vendor/plugins/#{name}/uninstall.rb" - load uninstall_hook_file if File.exist? uninstall_hook_file - end - - def install_using_export(options = {}) - svn_command :export, options - end - - def install_using_checkout(options = {}) - svn_command :checkout, options - end - - def install_using_externals(options = {}) - externals = rails_env.externals - externals.push([@name, uri]) - rails_env.externals = externals - install_using_checkout(options) - end - - def install_using_http(options = {}) - root = rails_env.root - mkdir_p "#{root}/vendor/plugins/#{@name}" - Dir.chdir "#{root}/vendor/plugins/#{@name}" do - puts "fetching from '#{uri}'" if $verbose - fetcher = RecursiveHTTPFetcher.new(uri, -1) - fetcher.quiet = true if options[:quiet] - fetcher.fetch - end - end - - def install_using_git(options = {}) - root = rails_env.root - mkdir_p(install_path = "#{root}/vendor/plugins/#{name}") - Dir.chdir install_path do - init_cmd = "git init" - init_cmd += " -q" if options[:quiet] and not $verbose - puts init_cmd if $verbose - system(init_cmd) - base_cmd = "git pull --depth 1 #{uri}" - base_cmd += " -q" if options[:quiet] and not $verbose - base_cmd += " #{options[:revision]}" if options[:revision] - puts base_cmd if $verbose - if system(base_cmd) - puts "removing: .git .gitignore" if $verbose - rm_rf %w(.git .gitignore) - else - rm_rf install_path - end - end - end - - def svn_command(cmd, options = {}) - root = rails_env.root - mkdir_p "#{root}/vendor/plugins" - base_cmd = "svn #{cmd} #{uri} \"#{root}/vendor/plugins/#{name}\"" - base_cmd += ' -q' if options[:quiet] and not $verbose - base_cmd += " -r #{options[:revision]}" if options[:revision] - puts base_cmd if $verbose - system(base_cmd) - end - - def guess_name(url) - @name = File.basename(url) - if @name == 'trunk' || @name.empty? - @name = File.basename(File.dirname(url)) - end - @name.gsub!(/\.git$/, '') if @name =~ /\.git$/ - end - - def rails_env - @rails_env || RailsEnvironment.default - end -end - -# load default environment and parse arguments -require 'optparse' -module Commands - class Plugin - attr_reader :environment, :script_name - def initialize - @environment = RailsEnvironment.default - @rails_root = RailsEnvironment.default.root - @script_name = File.basename($0) - end - - def environment=(value) - @environment = value - RailsEnvironment.default = value - end - - def options - OptionParser.new do |o| - o.set_summary_indent(' ') - o.banner = "Usage: plugin [OPTIONS] command" - o.define_head "Rails plugin manager." - - o.separator "" - o.separator "GENERAL OPTIONS" - - o.on("-r", "--root=DIR", String, - "Set an explicit rails app directory.", - "Default: #{@rails_root}") { |rails_root| @rails_root = rails_root; self.environment = RailsEnvironment.new(@rails_root) } - - o.on("-v", "--verbose", "Turn on verbose output.") { |verbose| $verbose = verbose } - o.on("-h", "--help", "Show this help message.") { puts o; exit } - - o.separator "" - o.separator "COMMANDS" - - o.separator " install Install plugin(s) from known repositories or URLs." - o.separator " remove Uninstall plugins." - - o.separator "" - o.separator "EXAMPLES" - o.separator " Install a plugin from a subversion URL:" - o.separator " #{@script_name} plugin install http://example.com/my_svn_plugin\n" - o.separator " Install a plugin from a git URL:" - o.separator " #{@script_name} plugin install git://github.com/SomeGuy/my_awesome_plugin.git\n" - o.separator " Install a plugin and add a svn:externals entry to vendor/plugins" - o.separator " #{@script_name} plugin install -x my_svn_plugin\n" - end - end - - def parse!(args=ARGV) - general, sub = split_args(args) - options.parse!(general) - - command = general.shift - if command =~ /^(install|remove)$/ - command = Commands.const_get(command.capitalize).new(self) - command.parse!(sub) - else - puts "Unknown command: #{command}" unless command.blank? - puts options - exit 1 - end - end - - def split_args(args) - left = [] - left << args.shift while args[0] and args[0] =~ /^-/ - left << args.shift if args[0] - [left, args] - end - - def self.parse!(args=ARGV) - Plugin.new.parse!(args) - end - end - - class Install - def initialize(base_command) - @base_command = base_command - @method = :http - @options = { :quiet => false, :revision => nil, :force => false } - end - - def options - OptionParser.new do |o| - o.set_summary_indent(' ') - o.banner = "Usage: #{@base_command.script_name} install PLUGIN [PLUGIN [PLUGIN] ...]" - o.define_head "Install one or more plugins." - o.separator "" - o.separator "Options:" - o.on( "-x", "--externals", - "Use svn:externals to grab the plugin.", - "Enables plugin updates and plugin versioning.") { |v| @method = :externals } - o.on( "-o", "--checkout", - "Use svn checkout to grab the plugin.", - "Enables updating but does not add a svn:externals entry.") { |v| @method = :checkout } - o.on( "-e", "--export", - "Use svn export to grab the plugin.", - "Exports the plugin, allowing you to check it into your local repository. Does not enable updates or add an svn:externals entry.") { |v| @method = :export } - o.on( "-q", "--quiet", - "Suppresses the output from installation.", - "Ignored if -v is passed (rails plugin -v install ...)") { |v| @options[:quiet] = true } - o.on( "-r REVISION", "--revision REVISION", - "Checks out the given revision from subversion or git.", - "Ignored if subversion/git is not used.") { |v| @options[:revision] = v } - o.on( "-f", "--force", - "Reinstalls a plugin if it's already installed.") { |v| @options[:force] = true } - o.separator "" - o.separator "You can specify plugin names as given in 'plugin list' output or absolute URLs to " - o.separator "a plugin repository." - end - end - - def determine_install_method - best = @base_command.environment.best_install_method - @method = :http if best == :http and @method == :export - case - when (best == :http and @method != :http) - msg = "Cannot install using subversion because `svn' cannot be found in your PATH" - when (best == :export and (@method != :export and @method != :http)) - msg = "Cannot install using #{@method} because this project is not under subversion." - when (best != :externals and @method == :externals) - msg = "Cannot install using externals because vendor/plugins is not under subversion." - end - if msg - puts msg - exit 1 - end - @method - end - - def parse!(args) - options.parse!(args) - if args.blank? - puts options - exit 1 - end - environment = @base_command.environment - install_method = determine_install_method - puts "Plugins will be installed using #{install_method}" if $verbose - args.each do |name| - ::Plugin.find(name).install(install_method, @options) - end - rescue StandardError => e - puts "Plugin not found: #{args.inspect}" - puts e.inspect if $verbose - exit 1 - end - end - - class Remove - def initialize(base_command) - @base_command = base_command - end - - def options - OptionParser.new do |o| - o.set_summary_indent(' ') - o.banner = "Usage: #{@base_command.script_name} remove name [name]..." - o.define_head "Remove plugins." - end - end - - def parse!(args) - options.parse!(args) - if args.blank? - puts options - exit 1 - end - root = @base_command.environment.root - args.each do |name| - ::Plugin.new(name).uninstall - end - end - end - - class Info - def initialize(base_command) - @base_command = base_command - end - - def options - OptionParser.new do |o| - o.set_summary_indent(' ') - o.banner = "Usage: #{@base_command.script_name} info name [name]..." - o.define_head "Shows plugin info at {url}/about.yml." - end - end - - def parse!(args) - options.parse!(args) - args.each do |name| - puts ::Plugin.find(name).info - puts - end - end - end -end - -class RecursiveHTTPFetcher - attr_accessor :quiet - def initialize(urls_to_fetch, level = 1, cwd = ".") - @level = level - @cwd = cwd - @urls_to_fetch = RUBY_VERSION >= '1.9' ? urls_to_fetch.lines : urls_to_fetch.to_a - @quiet = false - end - - def ls - @urls_to_fetch.collect do |url| - if url =~ /^svn(\+ssh)?:\/\/.*/ - `svn ls #{url}`.split("\n").map {|entry| "/#{entry}"} rescue nil - else - open(url) do |stream| - links("", stream.read) - end rescue nil - end - end.flatten - end - - def push_d(dir) - @cwd = File.join(@cwd, dir) - FileUtils.mkdir_p(@cwd) - end - - def pop_d - @cwd = File.dirname(@cwd) - end - - def links(base_url, contents) - links = [] - contents.scan(/href\s*=\s*\"*[^\">]*/i) do |link| - link = link.sub(/href="/i, "") - next if link =~ /svnindex.xsl$/ - next if link =~ /^(\w*:|)\/\// || link =~ /^\./ - links << File.join(base_url, link) - end - links - end - - def download(link) - puts "+ #{File.join(@cwd, File.basename(link))}" unless @quiet - open(link) do |stream| - File.open(File.join(@cwd, File.basename(link)), "wb") do |file| - file.write(stream.read) - end - end - end - - def fetch(links = @urls_to_fetch) - links.each do |l| - (l =~ /\/$/ || links == @urls_to_fetch) ? fetch_dir(l) : download(l) - end - end - - def fetch_dir(url) - @level += 1 - push_d(File.basename(url)) if @level > 0 - open(url) do |stream| - contents = stream.read - fetch(links(url, contents)) - end - pop_d if @level > 0 - @level -= 1 - end -end - -Commands::Plugin.parse! diff --git a/railties/lib/rails/commands/plugin_new.rb b/railties/lib/rails/commands/plugin_new.rb index 0287ba0638..4d7bf3c9f3 100644 --- a/railties/lib/rails/commands/plugin_new.rb +++ b/railties/lib/rails/commands/plugin_new.rb @@ -1,5 +1,3 @@ -require 'rubygems' if ARGV.include?("--dev") - if ARGV.first != "new" ARGV[0] = "--help" else diff --git a/railties/lib/rails/commands/profiler.rb b/railties/lib/rails/commands/profiler.rb index ea6347c918..3f6966b4f0 100644 --- a/railties/lib/rails/commands/profiler.rb +++ b/railties/lib/rails/commands/profiler.rb @@ -19,7 +19,7 @@ def options options end -class ProfilerTest < ActionDispatch::PerformanceTest +class ProfilerTest < ActionDispatch::PerformanceTest #:nodoc: self.profile_options = options ARGV.each do |expression| diff --git a/railties/lib/rails/commands/runner.rb b/railties/lib/rails/commands/runner.rb index e8cc5d9e3b..a672258aa6 100644 --- a/railties/lib/rails/commands/runner.rb +++ b/railties/lib/rails/commands/runner.rb @@ -9,8 +9,7 @@ if ARGV.first.nil? end ARGV.clone.options do |opts| - script_name = File.basename($0) - opts.banner = "Usage: runner [options] ('Some.ruby(code)' or a filename)" + opts.banner = "Usage: rails runner [options] ('Some.ruby(code)' or a filename)" opts.separator "" @@ -42,6 +41,7 @@ ENV["RAILS_ENV"] = options[:environment] require APP_PATH Rails.application.require_environment! + Rails.application.load_runner if code_or_file.nil? $stderr.puts "Run '#{$0} -h' for help." diff --git a/railties/lib/rails/commands/server.rb b/railties/lib/rails/commands/server.rb index 20484a10c8..a684129353 100644 --- a/railties/lib/rails/commands/server.rb +++ b/railties/lib/rails/commands/server.rb @@ -17,7 +17,7 @@ module Rails opts.on("-c", "--config=file", String, "Use custom rackup configuration file") { |v| options[:config] = v } opts.on("-d", "--daemon", "Make server run as a Daemon.") { options[:daemonize] = true } - opts.on("-u", "--debugger", "Enable ruby-debugging for the server.") { options[:debugger] = true } + opts.on("-u", "--debugger", "Enable the debugger") { options[:debugger] = true } opts.on("-e", "--environment=name", String, "Specifies the environment to run this server under (test/development/production).", "Default: development") { |v| options[:environment] = v } @@ -64,7 +64,16 @@ module Rails #Create required tmp directories if not found %w(cache pids sessions sockets).each do |dir_to_make| - FileUtils.mkdir_p(Rails.root.join('tmp', dir_to_make)) + FileUtils.mkdir_p(File.join(Rails.root, 'tmp', dir_to_make)) + end + + unless options[:daemonize] + wrapped_app # touch the app so the logger is set up + + console = ActiveSupport::Logger.new($stdout) + console.formatter = Rails.logger.formatter + + Rails.logger.extend(ActiveSupport::Logger.broadcast(console)) end super @@ -76,9 +85,17 @@ module Rails def middleware middlewares = [] - middlewares << [Rails::Rack::LogTailer, log_path] unless options[:daemonize] middlewares << [Rails::Rack::Debugger] if options[:debugger] middlewares << [::Rack::ContentLength] + + # FIXME: add Rack::Lock in the case people are using webrick. + # This is to remain backwards compatible for those who are + # running webrick in production. We should consider removing this + # in development. + if server.name == 'Rack::Handler::WEBrick' + middlewares << [::Rack::Lock] + end + Hash.new(middlewares) end @@ -89,6 +106,7 @@ module Rails def default_options super.merge({ :Port => 3000, + :DoNotReverseLookup => true, :environment => (ENV['RAILS_ENV'] || "development").dup, :daemonize => false, :debugger => false, diff --git a/railties/lib/rails/configuration.rb b/railties/lib/rails/configuration.rb index f8ad17773a..5fa7f043c6 100644 --- a/railties/lib/rails/configuration.rb +++ b/railties/lib/rails/configuration.rb @@ -1,39 +1,66 @@ require 'active_support/deprecation' require 'active_support/ordered_options' -require 'active_support/core_ext/hash/deep_dup' +require 'active_support/core_ext/object' require 'rails/paths' require 'rails/rack' module Rails module Configuration - class MiddlewareStackProxy #:nodoc: + # MiddlewareStackProxy is a proxy for the Rails middleware stack that allows + # you to configure middlewares in your application. It works basically as a + # command recorder, saving each command to be applied after initialization + # over the default middleware stack, so you can add, swap, or remove any + # middleware in Rails. + # + # You can add your own middlewares by using the +config.middleware.use+ method: + # + # config.middleware.use Magical::Unicorns + # + # This will put the <tt>Magical::Unicorns</tt> middleware on the end of the stack. + # You can use +insert_before+ if you wish to add a middleware before another: + # + # config.middleware.insert_before ActionDispatch::Head, Magical::Unicorns + # + # There's also +insert_after+ which will insert a middleware after another: + # + # config.middleware.insert_after ActionDispatch::Head, Magical::Unicorns + # + # Middlewares can also be completely swapped out and replaced with others: + # + # config.middleware.swap ActionDispatch::BestStandardsSupport, Magical::Unicorns + # + # And finally they can also be removed from the stack completely: + # + # config.middleware.delete ActionDispatch::BestStandardsSupport + # + class MiddlewareStackProxy def initialize @operations = [] end def insert_before(*args, &block) - @operations << [:insert_before, args, block] + @operations << [__method__, args, block] end alias :insert :insert_before def insert_after(*args, &block) - @operations << [:insert_after, args, block] + @operations << [__method__, args, block] end def swap(*args, &block) - @operations << [:swap, args, block] + @operations << [__method__, args, block] end def use(*args, &block) - @operations << [:use, args, block] + @operations << [__method__, args, block] end def delete(*args, &block) - @operations << [:delete, args, block] + @operations << [__method__, args, block] end - def merge_into(other) + def merge_into(other) #:nodoc: @operations.each do |operation, args, block| other.send(operation, *args, &block) end diff --git a/railties/lib/rails/console/app.rb b/railties/lib/rails/console/app.rb index 95c74baae2..2a69c26deb 100644 --- a/railties/lib/rails/console/app.rb +++ b/railties/lib/rails/console/app.rb @@ -1,32 +1,32 @@ require 'active_support/all' -require 'active_support/test_case' require 'action_controller' -# work around the at_exit hook in test/unit, which kills IRB -Test::Unit.run = true if Test::Unit.respond_to?(:run=) +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) + @app_integration_instance = nil if create + @app_integration_instance ||= new_session do |sess| + sess.host! "www.example.com" + end + end -# reference the global "app" instance, created on demand. To recreate the -# instance, pass a non-false value as the parameter. -def app(create=false) - @app_integration_instance = nil if create - @app_integration_instance ||= new_session do |sess| - sess.host! "www.example.com" - end -end + # create a new session. If a block is given, the new session will be yielded + # to the block before being returned. + def new_session + app = Rails.application + session = ActionDispatch::Integration::Session.new(app) + yield session if block_given? + session + end -# create a new session. If a block is given, the new session will be yielded -# to the block before being returned. -def new_session - app = Rails.application - session = ActionDispatch::Integration::Session.new(app) - yield session if block_given? - session -end - -# reloads the environment -def reload!(print=true) - puts "Reloading..." if print - ActionDispatch::Reloader.cleanup! - ActionDispatch::Reloader.prepare! - true + # reloads the environment + def reload!(print=true) + puts "Reloading..." if print + ActionDispatch::Reloader.cleanup! + ActionDispatch::Reloader.prepare! + true + end + end end diff --git a/railties/lib/rails/console/helpers.rb b/railties/lib/rails/console/helpers.rb index 212fc6125a..230d3d9d04 100644 --- a/railties/lib/rails/console/helpers.rb +++ b/railties/lib/rails/console/helpers.rb @@ -1,7 +1,11 @@ -def helper - @helper ||= ApplicationController.helpers -end +module Rails + module ConsoleMethods + def helper + @helper ||= ApplicationController.helpers + end -def controller - @controller ||= ApplicationController.new + def controller + @controller ||= ApplicationController.new + end + end end diff --git a/railties/lib/rails/deprecation.rb b/railties/lib/rails/deprecation.rb new file mode 100644 index 0000000000..c5811b2629 --- /dev/null +++ b/railties/lib/rails/deprecation.rb @@ -0,0 +1,18 @@ +require 'active_support/deprecation/proxy_wrappers' + +module Rails + class DeprecatedConstant < ActiveSupport::Deprecation::DeprecatedConstantProxy + def self.deprecate(old, current) + constant = new(old, current) + eval "::#{old} = constant" + end + + private + + def target + ::Kernel.eval @new_const.to_s + end + end + + DeprecatedConstant.deprecate('RAILS_CACHE', '::Rails.cache') +end diff --git a/railties/lib/rails/engine.rb b/railties/lib/rails/engine.rb index 1c9627734e..3a5caf9f62 100644 --- a/railties/lib/rails/engine.rb +++ b/railties/lib/rails/engine.rb @@ -2,7 +2,6 @@ require 'rails/railtie' require 'active_support/core_ext/module/delegation' require 'pathname' require 'rbconfig' -require 'rails/engine/railties' module Rails # <tt>Rails::Engine</tt> allows you to wrap a specific Rails application or subset of @@ -39,8 +38,6 @@ module Rails # and <tt>autoload_once_paths</tt>, which, differently from a <tt>Railtie</tt>, are scoped to # the current engine. # - # Example: - # # class MyEngine < Rails::Engine # # Add a load path for this specific Engine # config.autoload_paths << File.expand_path("../lib/some/path", __FILE__) @@ -148,7 +145,7 @@ module Rails # # # ENGINE/config/routes.rb # MyEngine::Engine.routes.draw do - # match "/" => "posts#index" + # get "/" => "posts#index" # end # # == Mount priority @@ -158,7 +155,7 @@ module Rails # # MyRailsApp::Application.routes.draw do # mount MyEngine::Engine => "/blog" - # match "/blog/omg" => "main#omg" + # get "/blog/omg" => "main#omg" # end # # +MyEngine+ is mounted at <tt>/blog</tt>, and <tt>/blog/omg</tt> points to application's @@ -167,7 +164,7 @@ module Rails # It's much better to swap that: # # MyRailsApp::Application.routes.draw do - # match "/blog/omg" => "main#omg" + # get "/blog/omg" => "main#omg" # mount MyEngine::Engine => "/blog" # end # @@ -179,8 +176,7 @@ module Rails # # * routes: when you mount an Engine with <tt>mount(MyEngine::Engine => '/my_engine')</tt>, # it's used as default :as option - # * some of the rake tasks are based on engine name, e.g. <tt>my_engine:install:migrations</tt>, - # <tt>my_engine:install:assets</tt> + # * rake task for installing migrations <tt>my_engine:install:migrations</tt> # # Engine name is set by default based on class name. For <tt>MyEngine::Engine</tt> it will be # <tt>my_engine_engine</tt>. You can change it manually using the <tt>engine_name</tt> method: @@ -228,7 +224,7 @@ module Rails # resources :articles # end # - # The routes above will automatically point to <tt>MyEngine::ApplicationContoller</tt>. Furthermore, you don't + # The routes above will automatically point to <tt>MyEngine::ArticlesController</tt>. Furthermore, you don't # need to use longer url helpers like <tt>my_engine_articles_path</tt>. Instead, you should simply use # <tt>articles_path</tt> as you would do with your application. # @@ -245,7 +241,7 @@ module Rails # # Additionally, an isolated engine will set its name according to namespace, so # MyEngine::Engine.engine_name will be "my_engine". It will also set MyEngine.table_name_prefix - # to "my_engine_", changing the MyEngine::Article model to use the my_engine_article table. + # to "my_engine_", changing the MyEngine::Article model to use the my_engine_articles table. # # == Using Engine's routes outside Engine # @@ -256,7 +252,7 @@ module Rails # # config/routes.rb # MyApplication::Application.routes.draw do # mount MyEngine::Engine => "/my_engine", :as => "my_engine" - # match "/foo" => "foo#index" + # get "/foo" => "foo#index" # end # # Now, you can use the <tt>my_engine</tt> helper inside your application: @@ -296,16 +292,16 @@ module Rails # If you want to share just a few specific helpers you can add them to application's # helpers in ApplicationController: # - # class ApplicationController < ActionController::Base - # helper MyEngine::SharedEngineHelper - # end + # class ApplicationController < ActionController::Base + # helper MyEngine::SharedEngineHelper + # end # - # If you want to include all of the engine's helpers, you can use #helpers method on an engine's + # If you want to include all of the engine's helpers, you can use #helper method on an engine's # instance: # - # class ApplicationController < ActionController::Base - # helper MyEngine::Engine.helpers - # end + # class ApplicationController < ActionController::Base + # helper MyEngine::Engine.helpers + # end # # It will include all of the helpers from engine's directory. Take into account that this does # not include helpers defined in controllers with helper_method or other similar solutions, @@ -326,29 +322,33 @@ module Rails # migration in the application and rerun copying migrations. # # If your engine has migrations, you may also want to prepare data for the database in - # the <tt>seeds.rb</tt> file. You can load that data using the <tt>load_seed</tt> method, e.g. + # the <tt>db/seeds.rb</tt> file. You can load that data using the <tt>load_seed</tt> method, e.g. # # MyEngine::Engine.load_seed # + # == Loading priority + # + # In order to change engine's priority you can use +config.railties_order+ in main application. + # 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 + # config.railties_order = [Blog::Engine, :main_app, :all] class Engine < Railtie autoload :Configuration, "rails/engine/configuration" - autoload :Railties, "rails/engine/railties" - - def load_generators(app=self) - initialize_generators - railties.all { |r| r.load_generators(app) } - Rails::Generators.configure!(app.config.generators) - super - self - end class << self attr_accessor :called_from, :isolated + alias :isolated? :isolated alias :engine_name :railtie_name + delegate :eager_load!, to: :instance + def inherited(base) unless base.abstract_railtie? + Rails::Railtie::Configuration.eager_load_namespaces << base + base.called_from = begin # Remove the line number from backtraces making sure we don't leave anything behind call_stack = caller.map { |p| p.sub(/:\d+.*/, '') } @@ -371,49 +371,93 @@ module Rails self.routes.default_scope = { :module => ActiveSupport::Inflector.underscore(mod.name) } self.isolated = true - unless mod.respond_to?(:_railtie) - name = engine_name - _railtie = self + unless mod.respond_to?(:railtie_namespace) + name, railtie = engine_name, self + mod.singleton_class.instance_eval do - define_method(:_railtie) do - _railtie - end + define_method(:railtie_namespace) { railtie } unless mod.respond_to?(:table_name_prefix) - define_method(:table_name_prefix) do - "#{name}_" - end + define_method(:table_name_prefix) { "#{name}_" } + end + + unless mod.respond_to?(:use_relative_model_naming?) + class_eval "def use_relative_model_naming?; true; end", __FILE__, __LINE__ + end + + unless mod.respond_to?(:railtie_helpers_paths) + define_method(:railtie_helpers_paths) { railtie.helpers_paths } + end + + unless mod.respond_to?(:railtie_routes_url_helpers) + define_method(:railtie_routes_url_helpers) { railtie.routes.url_helpers } end - end + end end end # Finds engine with given path def find(path) - expanded_path = File.expand_path path.to_s - Rails::Engine::Railties.engines.find { |engine| - File.expand_path(engine.root.to_s) == expanded_path - } + expanded_path = File.expand_path path + Rails::Engine.subclasses.each do |klass| + engine = klass.instance + return engine if File.expand_path(engine.root) == expanded_path + end + nil end end delegate :middleware, :root, :paths, :to => :config delegate :engine_name, :isolated?, :to => "self.class" - def load_tasks(app=self) - railties.all { |r| r.load_tasks(app) } + def initialize + @_all_autoload_paths = nil + @_all_load_paths = nil + @app = nil + @config = nil + @env_config = nil + @helpers = nil + @routes = nil super - paths["lib/tasks"].existent.sort.each { |ext| load(ext) } end + # Load console and invoke the registered hooks. + # Check <tt>Rails::Railtie.console</tt> for more info. def load_console(app=self) - railties.all { |r| r.load_console(app) } - super + require "pp" + require "rails/console/app" + require "rails/console/helpers" + run_console_blocks(app) + self end - def eager_load! - railties.all(&:eager_load!) + # Load Rails runner and invoke the registered hooks. + # Check <tt>Rails::Railtie.runner</tt> for more info. + 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) + require "rake" + run_tasks_blocks(app) + self + end + # Load rails generators and invoke the registered hooks. + # Check <tt>Rails::Railtie.generators</tt> for more info. + def load_generators(app=self) + require "rails/generators" + run_generators_blocks(app) + Rails::Generators.configure!(app.config.generators) + self + end + + # Eager load the application by loading all ruby + # files inside eager_load paths. + def eager_load! config.eager_load_paths.each do |load_path| matcher = /\A#{Regexp.escape(load_path)}\/(.*)\.rb\Z/ Dir.glob("#{load_path}/**/*.rb").sort.each do |file| @@ -422,20 +466,10 @@ module Rails end end - def railties - @railties ||= self.class::Railties.new(config) - end - + # Returns a module with all the helpers defined for the engine. def helpers @helpers ||= begin helpers = Module.new - - helpers_paths = if config.respond_to?(:helpers_paths) - config.helpers_paths - else - paths["app/helpers"].existent - end - all = ActionController::Base.all_helpers_from_path(helpers_paths) ActionController::Base.modules_for_helpers(all).each do |mod| helpers.send(:include, mod) @@ -444,6 +478,12 @@ module Rails end end + # Returns all registered helpers paths. + def helpers_paths + paths["app/helpers"].existent + end + + # Returns the underlying rack application for this engine. def app @app ||= begin config.middleware = config.middleware.merge_into(default_middleware_stack) @@ -451,33 +491,37 @@ module Rails end end + # Returns the endpoint for this engine. If none is registered, + # defaults to an ActionDispatch::Routing::RouteSet. def endpoint self.class.endpoint || routes end + # Define the Rack API for this engine. def call(env) - app.call(env.merge!(env_config)) + env.merge!(env_config) + if env['SCRIPT_NAME'] + env.merge! "ROUTES_#{routes.object_id}_SCRIPT_NAME" => env['SCRIPT_NAME'].dup + end + app.call(env) end + # Defines additional Rack env configuration that is added on each call. def env_config @env_config ||= { 'action_dispatch.routes' => routes } end + # Defines the routes for this engine. If a block is given to + # routes, it is appended to the engine. def routes @routes ||= ActionDispatch::Routing::RouteSet.new @routes.append(&Proc.new) if block_given? @routes end - def initializers - initializers = [] - railties.all { |r| initializers += r.initializers } - initializers += super - initializers - end - + # Define the configuration object for the engine. def config @config ||= Engine::Configuration.new(find_root_with_flag("lib")) end @@ -487,8 +531,8 @@ module Rails # # Blog::Engine.load_seed def load_seed - seed_file = paths["db/seeds"].existent.first - load(seed_file) if seed_file && File.exist?(seed_file) + seed_file = paths["db/seeds.rb"].existent.first + load(seed_file) if seed_file end # Add configured load paths to ruby load paths and remove duplicates. @@ -515,7 +559,7 @@ module Rails end initializer :add_routing_paths do |app| - paths = self.paths["config/routes"].existent + paths = self.paths["config/routes.rb"].existent if routes? || paths.any? app.routes_reloader.paths.unshift(*paths) @@ -532,14 +576,15 @@ module Rails initializer :add_view_paths do views = paths["app/views"].existent unless views.empty? - ActiveSupport.on_load(:action_controller){ prepend_view_path(views) } + ActiveSupport.on_load(:action_controller){ prepend_view_path(views) if respond_to?(:prepend_view_path) } ActiveSupport.on_load(:action_mailer){ prepend_view_path(views) } end end initializer :load_environment_config, :before => :load_environment_hook, :group => :all do - environment = paths["config/environments"].existent.first - require environment if environment + paths["config/environments"].existent.each do |environment| + require environment + end end initializer :append_assets_path, :group => :all do |app| @@ -574,27 +619,32 @@ module Rails desc "Copy migrations from #{railtie_name} to application" task :migrations do ENV["FROM"] = railtie_name - Rake::Task["railties:install:migrations"].invoke + if Rake::Task.task_defined?("railties:install:migrations") + Rake::Task["railties:install:migrations"].invoke + else + Rake::Task["app:railties:install:migrations"].invoke + end end end end end - protected + protected - def initialize_generators - require "rails/generators" + def run_tasks_blocks(*) #:nodoc: + super + paths["lib/tasks"].existent.sort.each { |ext| load(ext) } end - def routes? - defined?(@routes) + def routes? #:nodoc: + @routes end - def has_migrations? + def has_migrations? #:nodoc: paths["db/migrate"].existent.any? end - def find_root_with_flag(flag, default=nil) + def find_root_with_flag(flag, default=nil) #:nodoc: root_path = self.class.called_from while root_path && File.directory?(root_path) && !File.exist?("#{root_path}/#{flag}") @@ -605,23 +655,22 @@ module Rails root = File.exist?("#{root_path}/#{flag}") ? root_path : default raise "Could not find root path for #{self}" unless root - RbConfig::CONFIG['host_os'] =~ /mswin|mingw/ ? - Pathname.new(root).expand_path : Pathname.new(root).realpath + Pathname.new File.realpath root end - def default_middleware_stack + def default_middleware_stack #:nodoc: ActionDispatch::MiddlewareStack.new end - def _all_autoload_once_paths + def _all_autoload_once_paths #:nodoc: config.autoload_once_paths end - def _all_autoload_paths + def _all_autoload_paths #:nodoc: @_all_autoload_paths ||= (config.autoload_paths + config.eager_load_paths + config.autoload_once_paths).uniq end - def _all_load_paths + def _all_load_paths #:nodoc: @_all_load_paths ||= (config.paths.load_paths + _all_autoload_paths).uniq end end diff --git a/railties/lib/rails/engine/commands.rb b/railties/lib/rails/engine/commands.rb index b71119af77..072d16291b 100644 --- a/railties/lib/rails/engine/commands.rb +++ b/railties/lib/rails/engine/commands.rb @@ -1,5 +1,3 @@ -require 'active_support/core_ext/object/inclusion' - ARGV << '--help' if ARGV.empty? aliases = { @@ -25,7 +23,7 @@ when '--version', '-v' require 'rails/commands/application' else - puts "Error: Command not recognized" unless command.in?(['-h', '--help']) + puts "Error: Command not recognized" unless %w(-h --help).include?(command) puts <<-EOT Usage: rails COMMAND [ARGS] @@ -34,6 +32,10 @@ The common rails commands available for engines are: destroy Undo code generated with "generate" (short-cut alias: "d") 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). EOT exit(1) end diff --git a/railties/lib/rails/engine/configuration.rb b/railties/lib/rails/engine/configuration.rb index f424492bb4..6b18b1e249 100644 --- a/railties/lib/rails/engine/configuration.rb +++ b/railties/lib/rails/engine/configuration.rb @@ -5,7 +5,6 @@ module Rails class Configuration < ::Rails::Railtie::Configuration attr_reader :root attr_writer :middleware, :eager_load_paths, :autoload_once_paths, :autoload_paths - attr_accessor :plugins def initialize(root=nil) super() @@ -21,7 +20,7 @@ module Rails # Holds generators configuration: # # config.generators do |g| - # g.orm :datamapper, :migration => true + # g.orm :data_mapper, :migration => true # g.template_engine :haml # g.test_framework :rspec # end @@ -30,7 +29,7 @@ module Rails # # config.generators.colorize_logging = false # - def generators #:nodoc + def generators #:nodoc: @generators ||= Rails::Configuration::Generators.new yield(@generators) if block_given? @generators @@ -53,13 +52,12 @@ module Rails paths.add "config/environments", :glob => "#{Rails.env}.rb" paths.add "config/initializers", :glob => "**/*.rb" paths.add "config/locales", :glob => "*.{rb,yml}" - paths.add "config/routes", :with => "config/routes.rb" + paths.add "config/routes.rb" paths.add "db" paths.add "db/migrate" - paths.add "db/seeds", :with => "db/seeds.rb" + paths.add "db/seeds.rb" paths.add "vendor", :load_path => true paths.add "vendor/assets", :glob => "*" - paths.add "vendor/plugins" paths end end diff --git a/railties/lib/rails/engine/railties.rb b/railties/lib/rails/engine/railties.rb deleted file mode 100644 index d5ecd2e48d..0000000000 --- a/railties/lib/rails/engine/railties.rb +++ /dev/null @@ -1,33 +0,0 @@ -module Rails - class Engine < Railtie - class Railties - # TODO Write tests for this behavior extracted from Application - def initialize(config) - @config = config - end - - def all(&block) - @all ||= plugins - @all.each(&block) if block - @all - end - - def plugins - @plugins ||= begin - plugin_names = (@config.plugins || [:all]).map { |p| p.to_sym } - Plugin.all(plugin_names, @config.paths["vendor/plugins"].existent) - end - end - - def self.railties - @railties ||= ::Rails::Railtie.subclasses.map(&:instance) - end - - def self.engines - @engines ||= ::Rails::Engine.subclasses.map(&:instance) - end - - delegate :railties, :engines, :to => "self.class" - end - end -end diff --git a/railties/lib/rails/generators.rb b/railties/lib/rails/generators.rb index 27f8d13ce8..4fa990171d 100644 --- a/railties/lib/rails/generators.rb +++ b/railties/lib/rails/generators.rb @@ -38,11 +38,6 @@ module Rails :test_unit => { :fixture_replacement => '-r', - }, - - :plugin => { - :generator => '-g', - :tasks => '-r' } } @@ -57,16 +52,12 @@ module Rails :orm => false, :performance_tool => nil, :resource_controller => :controller, + :resource_route => true, :scaffold_controller => :scaffold_controller, :stylesheets => true, :stylesheet_engine => :css, :test_framework => false, :template_engine => :erb - }, - - :plugin => { - :generator => false, - :tasks => false } } @@ -80,7 +71,7 @@ module Rails hide_namespaces(*config.hidden_namespaces) end - def self.templates_path + def self.templates_path #:nodoc: @templates_path ||= [] end @@ -104,7 +95,6 @@ module Rails # some of them are not available by adding a fallback: # # Rails::Generators.fallbacks[:shoulda] = :test_unit - # def self.fallbacks @fallbacks ||= {} end @@ -124,8 +114,6 @@ module Rails # 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. # - # ==== Examples - # # find_by_namespace :webrat, :rails, :integration # # Will search for the following generators: @@ -134,7 +122,6 @@ module Rails # # 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 @@ -182,6 +169,7 @@ module Rails [ "rails", + "resource_route", "#{orm}:migration", "#{orm}:model", "#{orm}:observer", @@ -195,7 +183,6 @@ module Rails "#{test}:scaffold", "#{test}:view", "#{test}:performance", - "#{test}:plugin", "#{template}:controller", "#{template}:scaffold", "#{template}:mailer", @@ -246,7 +233,7 @@ module Rails rails.delete("plugin_new") print_list("rails", rails) - hidden_namespaces.each {|n| groups.delete(n.to_s) } + hidden_namespaces.each { |n| groups.delete(n.to_s) } groups.sort.each { |b, n| print_list(b, n) } end diff --git a/railties/lib/rails/generators/actions.rb b/railties/lib/rails/generators/actions.rb index b26839644e..c41acc7841 100644 --- a/railties/lib/rails/generators/actions.rb +++ b/railties/lib/rails/generators/actions.rb @@ -5,49 +5,11 @@ module Rails module Generators module Actions - # Install a plugin. You must provide either a Subversion url or Git url. - # - # For a Git-hosted plugin, you can specify a branch and - # whether it should be added as a submodule instead of cloned. - # - # For a Subversion-hosted plugin you can specify a revision. - # - # ==== Examples - # - # plugin 'restful-authentication', :git => 'git://github.com/technoweenie/restful-authentication.git' - # plugin 'restful-authentication', :git => 'git://github.com/technoweenie/restful-authentication.git', :branch => 'stable' - # plugin 'restful-authentication', :git => 'git://github.com/technoweenie/restful-authentication.git', :submodule => true - # plugin 'restful-authentication', :svn => 'svn://svnhub.com/technoweenie/restful-authentication/trunk' - # plugin 'restful-authentication', :svn => 'svn://svnhub.com/technoweenie/restful-authentication/trunk', :revision => 1234 - # - def plugin(name, options) - log :plugin, name - - if options[:git] && options[:submodule] - options[:git] = "-b #{options[:branch]} #{options[:git]}" if options[:branch] - in_root do - run "git submodule add #{options[:git]} vendor/plugins/#{name}", :verbose => false - end - elsif options[:git] || options[:svn] - options[:git] = "-b #{options[:branch]} #{options[:git]}" if options[:branch] - options[:svn] = "-r #{options[:revision]} #{options[:svn]}" if options[:revision] - in_root do - run_ruby_script "script/rails plugin install #{options[:svn] || options[:git]}", :verbose => false - end - else - log "! no git or svn provided for #{name}. Skipping..." - end - end - - # Adds an entry into Gemfile for the supplied gem. If env - # is specified, add the gem to the given environment. - # - # ==== Example + # Adds an entry into Gemfile for the supplied gem. # # gem "rspec", :group => :test # gem "technoweenie-restful-authentication", :lib => "restful-authentication", :source => "http://gems.github.com/" # gem "rails", "3.0", :git => "git://github.com/rails/rails" - # def gem(*args) options = args.extract_options! name, version = args @@ -64,43 +26,39 @@ module Rails log :gemfile, message options.each do |option, value| - parts << ":#{option} => #{value.inspect}" + parts << "#{option}: #{value.inspect}" end in_root do - str = "gem #{parts.join(", ")}\n" + str = "gem #{parts.join(", ")}" str = " " + str if @in_group + str = "\n" + str append_file "Gemfile", str, :verbose => false end end # Wraps gem entries inside a group. # - # ==== Example - # # gem_group :development, :test do # gem "rspec-rails" # end - # def gem_group(*names, &block) name = names.map(&:inspect).join(", ") log :gemfile, "group #{name}" in_root do - append_file "Gemfile", "\ngroup #{name} do\n", :force => true + append_file "Gemfile", "\ngroup #{name} do", :force => true @in_group = true instance_eval(&block) @in_group = false - append_file "Gemfile", "end\n", :force => true + append_file "Gemfile", "\nend\n", :force => true end end # Add the given source to Gemfile # - # ==== Example - # # add_source "http://gems.github.com/" def add_source(source, options={}) log :source, source @@ -115,6 +73,13 @@ module Rails # If options :env is specified, the line is appended to the corresponding # file in config/environments. # + # environment do + # "config.autoload_paths += %W(#{config.root}/extras)" + # end + # + # environment(nil, :env => "development") do + # "config.active_record.observers = :cacher" + # end def environment(data=nil, options={}, &block) sentinel = /class [a-z_:]+ < Rails::Application/i env_file_sentinel = /::Application\.configure do/ @@ -124,7 +89,7 @@ module Rails if options[:env].nil? inject_into_file 'config/application.rb', "\n #{data}", :after => sentinel, :verbose => false else - Array.wrap(options[:env]).each do |env| + Array(options[:env]).each do |env| inject_into_file "config/environments/#{env}.rb", "\n #{data}", :after => env_file_sentinel, :verbose => false end end @@ -134,12 +99,9 @@ module Rails # Run a command in git. # - # ==== Examples - # # git :init # git :add => "this.file that.rb" # git :add => "onefile.rb", :rm => "badfile.cxx" - # def git(commands={}) if commands.is_a?(Symbol) run "git #{commands}" @@ -153,15 +115,12 @@ module Rails # Create a new file in the vendor/ directory. Code can be specified # in a block or a data string can be given. # - # ==== Examples - # # vendor("sekrit.rb") do # sekrit_salt = "#{Time.now}--#{3.years.ago}--#{rand}--" # "salt = '#{sekrit_salt}'" # end # # vendor("foreign.rb", "# Foreign code is fun") - # def vendor(filename, data=nil, &block) log :vendor, filename create_file("vendor/#{filename}", data, :verbose => false, &block) @@ -170,14 +129,11 @@ module Rails # Create a new file in the lib/ directory. Code can be specified # in a block or a data string can be given. # - # ==== Examples - # # lib("crypto.rb") do # "crypted_special_value = '#{rand}--#{Time.now}--#{rand(1337)}--'" # end # # lib("foreign.rb", "# Foreign code is fun") - # def lib(filename, data=nil, &block) log :lib, filename create_file("lib/#{filename}", data, :verbose => false, &block) @@ -185,22 +141,19 @@ module Rails # Create a new Rakefile with the provided code (either in a block or a string). # - # ==== Examples - # # rakefile("bootstrap.rake") do # project = ask("What is the UNIX name of your project?") # # <<-TASK # namespace :#{project} do # task :bootstrap do - # puts "i like boots!" + # puts "I like boots!" # end # end # TASK # end # - # rakefile("seed.rake", "puts 'im plantin ur seedz'") - # + # rakefile('seed.rake', 'puts "Planting seeds"') def rakefile(filename, data=nil, &block) log :rakefile, filename create_file("lib/tasks/#{filename}", data, :verbose => false, &block) @@ -208,8 +161,6 @@ module Rails # Create a new initializer with the provided code (either in a block or a string). # - # ==== Examples - # # initializer("globals.rb") do # data = "" # @@ -221,7 +172,6 @@ module Rails # end # # initializer("api.rb", "API_KEY = '123456'") - # def initializer(filename, data=nil, &block) log :initializer, filename create_file("config/initializers/#{filename}", data, :verbose => false, &block) @@ -231,10 +181,7 @@ module Rails # The second parameter is the argument string that is passed to # the generator or an Array that is joined. # - # ==== Example - # # generate(:authenticated, "user session") - # def generate(what, *args) log :generate, what argument = args.map {|arg| arg.to_s }.flatten.join(" ") @@ -244,12 +191,9 @@ module Rails # Runs the supplied rake task # - # ==== Example - # # rake("db:migrate") # rake("db:migrate", :env => "production") # rake("gems:install", :sudo => true) - # def rake(command, options={}) log :rake, command env = options[:env] || ENV["RAILS_ENV"] || 'development' @@ -259,10 +203,7 @@ module Rails # Just run the capify command in root # - # ==== Example - # # capify! - # def capify! log :capify, "" in_root { run("#{extify(:capify)} .", :verbose => false) } @@ -270,25 +211,19 @@ module Rails # Make an entry in Rails routing file config/routes.rb # - # === Example - # - # route "root :to => 'welcome'" - # + # route "root :to => 'welcome#index'" def route(routing_code) log :route, routing_code - sentinel = /\.routes\.draw do(?:\s*\|map\|)?\s*$/ + sentinel = /\.routes\.draw do\s*$/ in_root do - inject_into_file 'config/routes.rb', "\n #{routing_code}\n", { :after => sentinel, :verbose => false } + inject_into_file 'config/routes.rb', "\n #{routing_code}", { :after => sentinel, :verbose => false } end end # Reads the given file at the source root and prints it in the console. # - # === Example - # # readme "README" - # def readme(path) log File.read(find_in_source_paths(path)) end @@ -298,7 +233,6 @@ module Rails # 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) if args.size == 1 say args.first.to_s unless options.quiet? @@ -309,7 +243,6 @@ module Rails end # Add an extension to the given name based on the platform. - # def extify(name) if RbConfig::CONFIG['host_os'] =~ /mswin|mingw/ "#{name}.bat" diff --git a/railties/lib/rails/generators/active_model.rb b/railties/lib/rails/generators/active_model.rb index 4b828340d2..0e51b9c568 100644 --- a/railties/lib/rails/generators/active_model.rb +++ b/railties/lib/rails/generators/active_model.rb @@ -11,7 +11,7 @@ module Rails # ActiveRecord::Generators::ActiveModel.find(Foo, "params[:id]") # # => "Foo.find(params[:id])" # - # Datamapper::Generators::ActiveModel.find(Foo, "params[:id]") + # DataMapper::Generators::ActiveModel.find(Foo, "params[:id]") # # => "Foo.get(params[:id])" # # On initialization, the ActiveModel accepts the instance name that will @@ -37,7 +37,7 @@ module Rails # GET show # GET edit - # PUT update + # PATCH/PUT update # DELETE destroy def self.find(klass, params=nil) "#{klass}.find(#{params})" @@ -58,13 +58,13 @@ module Rails "#{name}.save" end - # PUT update + # PATCH/PUT update def update_attributes(params=nil) "#{name}.update_attributes(#{params})" end # POST create - # PUT update + # PATCH/PUT update def errors "#{name}.errors" end diff --git a/railties/lib/rails/generators/app_base.rb b/railties/lib/rails/generators/app_base.rb index 0a79d6e86e..383bea9e54 100644 --- a/railties/lib/rails/generators/app_base.rb +++ b/railties/lib/rails/generators/app_base.rb @@ -49,6 +49,9 @@ module Rails class_option :skip_javascript, :type => :boolean, :aliases => "-J", :default => false, :desc => "Skip JavaScript files" + class_option :skip_index_html, :type => :boolean, :aliases => "-I", :default => false, + :desc => "Skip public/index.html and app/assets/images/rails.png files" + class_option :dev, :type => :boolean, :default => false, :desc => "Setup the #{name} with Gemfile pointing to your Rails checkout" @@ -60,9 +63,6 @@ module Rails class_option :help, :type => :boolean, :aliases => "-h", :group => :rails, :desc => "Show this help message and quit" - - class_option :old_style_hash, :type => :boolean, :default => false, - :desc => "Force using old style hash (:foo => 'bar') on Ruby >= 1.9" end def initialize(*args) @@ -123,7 +123,7 @@ module Rails end def database_gemfile_entry - options[:skip_active_record] ? "" : "gem '#{gem_for_database}'\n" + options[:skip_active_record] ? "" : "gem '#{gem_for_database}'" end def include_all_railties? @@ -137,22 +137,24 @@ module Rails def rails_gemfile_entry if options.dev? <<-GEMFILE.strip_heredoc - gem 'rails', :path => '#{Rails::Generators::RAILS_DEV_PATH}' - gem 'journey', :git => 'git://github.com/rails/journey.git' - gem 'arel', :git => 'git://github.com/rails/arel.git' + gem 'rails', path: '#{Rails::Generators::RAILS_DEV_PATH}' + gem 'journey', github: 'rails/journey' + gem 'arel', github: 'rails/arel' + gem 'activerecord-deprecated_finders', github: 'rails/activerecord-deprecated_finders' GEMFILE elsif options.edge? <<-GEMFILE.strip_heredoc - gem 'rails', :git => 'git://github.com/rails/rails.git' - gem 'journey', :git => 'git://github.com/rails/journey.git' - gem 'arel', :git => 'git://github.com/rails/arel.git' + gem 'rails', github: 'rails/rails' + gem 'journey', github: 'rails/journey' + gem 'arel', github: 'rails/arel' + gem 'activerecord-deprecated_finders', github: 'rails/activerecord-deprecated_finders' GEMFILE else <<-GEMFILE.strip_heredoc gem 'rails', '#{Rails::VERSION::STRING}' # Bundle edge Rails instead: - # gem 'rails', :git => 'git://github.com/rails/rails.git' + # gem 'rails', github: 'rails/rails' GEMFILE end end @@ -184,30 +186,54 @@ module Rails end end - def ruby_debugger_gemfile_entry - if RUBY_VERSION < "1.9" - "gem 'ruby-debug'" + def assets_gemfile_entry + return if options[:skip_sprockets] + + gemfile = if options.dev? || options.edge? + <<-GEMFILE + # Gems used only for assets and not required + # in production environments by default. + group :assets do + gem 'sprockets-rails', github: 'rails/sprockets-rails' + gem 'sass-rails', github: 'rails/sass-rails' + gem 'coffee-rails', github: 'rails/coffee-rails' + + # See https://github.com/sstephenson/execjs#readme for more supported runtimes + #{javascript_runtime_gemfile_entry} + gem 'uglifier', '>= 1.0.3' + end + GEMFILE else - "gem 'ruby-debug19', :require => 'ruby-debug'" + <<-GEMFILE + # Gems used only for assets and not required + # in production environments by default. + group :assets do + gem 'sprockets-rails', github: 'rails/sprockets-rails' + gem 'sass-rails', '~> 4.0.0.beta' + gem 'coffee-rails', '~> 4.0.0.beta' + + # See https://github.com/sstephenson/execjs#readme for more supported runtimes + #{javascript_runtime_gemfile_entry} + gem 'uglifier', '>= 1.0.3' + end + GEMFILE end - end - def assets_gemfile_entry - <<-GEMFILE.strip_heredoc - # Gems used only for assets and not required - # in production environments by default. - group :assets do - gem 'sass-rails', :git => 'git://github.com/rails/sass-rails.git' - gem 'coffee-rails', :git => 'git://github.com/rails/coffee-rails.git' - gem 'uglifier', '>= 1.0.3' - end - GEMFILE + gemfile.strip_heredoc.gsub(/^[ \t]*$/, '') end def javascript_gemfile_entry "gem '#{options[:javascript]}-rails'" unless options[:skip_javascript] end + def javascript_runtime_gemfile_entry + if defined?(JRUBY_VERSION) + "gem 'therubyrhino'\n" + else + "# gem 'therubyracer', platforms: :ruby\n" + end + end + def bundle_command(command) say_status :run, "bundle #{command}" @@ -221,11 +247,11 @@ module Rails # end-user gets the bundler commands called anyway, so no big deal. # # Thanks to James Tucker for the Gem tricks involved in this call. - print `"#{Gem.ruby}" -rubygems "#{Gem.bin_path('bundler', 'bundle')}" #{command}` + print `"#{Gem.ruby}" "#{Gem.bin_path('bundler', 'bundle')}" #{command}` end def run_bundle - bundle_command('install') unless options[:skip_gemfile] || options[:skip_bundle] + bundle_command('install') unless options[:skip_gemfile] || options[:skip_bundle] || options[:pretend] end def empty_directory_with_gitkeep(destination, config = {}) @@ -236,16 +262,6 @@ module Rails def git_keep(destination) create_file("#{destination}/.gitkeep") unless options[:skip_git] end - - # Returns Ruby 1.9 style key-value pair if current code is running on - # Ruby 1.9.x. Returns the old-style (with hash rocket) otherwise. - def key_value(key, value) - if options[:old_style_hash] || RUBY_VERSION < '1.9' - ":#{key} => #{value}" - else - "#{key}: #{value}" - end - end end end end diff --git a/railties/lib/rails/generators/base.rb b/railties/lib/rails/generators/base.rb index f38a487a4e..a3f8ebf476 100644 --- a/railties/lib/rails/generators/base.rb +++ b/railties/lib/rails/generators/base.rb @@ -8,7 +8,6 @@ rescue LoadError end require 'rails/generators/actions' -require 'active_support/core_ext/object/inclusion' module Rails module Generators @@ -20,6 +19,7 @@ module Rails include Rails::Generators::Actions add_runtime_options! + strict_args_position! # Returns the source root for this generator using default_source_root as default. def self.source_root(path=nil) @@ -31,10 +31,9 @@ module Rails # root otherwise uses a default description. def self.desc(description=nil) return super if description - usage = source_root && File.expand_path("../USAGE", source_root) - @desc ||= if usage && File.exist?(usage) - ERB.new(File.read(usage)).result(binding) + @desc ||= if usage_path + ERB.new(File.read(usage_path)).result(binding) else "Description:\n Create #{base_name.humanize.downcase} files for #{generator_name} generator." end @@ -48,6 +47,12 @@ module Rails @namespace ||= super.sub(/_generator$/, '').sub(/:generators:/, ':') end + # Convenience method to hide this generator from the available ones when + # running rails generator command. + def self.hide! + Rails::Generators.hide_namespace self.namespace + end + # Invoke a generator based on the value supplied by the user to the # given option named "name". A class option is created when this method # is invoked and you can set a hash to customize it. @@ -91,7 +96,7 @@ module Rails # # The lookup in this case for test_unit as input is: # - # "test_framework:awesome", "test_framework" + # "test_unit:awesome", "test_unit" # # Which is not the desired the lookup. You can change it by providing the # :as option: @@ -102,7 +107,7 @@ module Rails # # And now it will lookup at: # - # "test_framework:controller", "test_framework" + # "test_unit:controller", "test_unit" # # Similarly, if you want it to also lookup in the rails namespace, you just # need to provide the :base value: @@ -113,7 +118,7 @@ module Rails # # And the lookup is exactly the same as previously: # - # "rails:test_framework", "test_framework:controller", "test_framework" + # "rails:test_unit", "test_unit:controller", "test_unit" # # ==== Switches # @@ -128,13 +133,13 @@ module Rails # # ==== Boolean hooks # - # In some cases, you want to provide a boolean hook. For example, webrat + # In some cases, you may want to provide a boolean hook. For example, webrat # developers might want to have webrat available on controller generator. # This can be achieved as: # # Rails::Generators::ControllerGenerator.hook_for :webrat, :type => :boolean # - # Then, if you want, webrat to be invoked, just supply: + # Then, if you want webrat to be invoked, just supply: # # rails generate controller Account --webrat # @@ -146,7 +151,7 @@ module Rails # # You can also supply a block to hook_for to customize how the hook is # going to be invoked. The block receives two arguments, an instance - # of the current class and the klass to be invoked. + # of the current class and the class to be invoked. # # For example, in the resource generator, the controller should be invoked # with a pluralized class name. But by default it is invoked with the same @@ -165,7 +170,7 @@ module Rails names.each do |name| defaults = if options[:type] == :boolean { } - elsif default_value_for_option(name, options).in?([true, false]) + elsif [true, false].include?(default_value_for_option(name, options)) { :banner => "" } else { :desc => "#{name.to_s.humanize} to be invoked", :banner => "NAME" } @@ -182,10 +187,7 @@ module Rails # Remove a previously added hook. # - # ==== Examples - # # remove_hook_for :orm - # def self.remove_hook_for(*names) remove_invocation(*names) @@ -207,7 +209,8 @@ module Rails # root, you should use source_root. def self.default_source_root return unless base_name && generator_name - path = File.expand_path(File.join(base_name, generator_name, 'templates'), base_root) + return unless default_generator_root + path = File.join(default_generator_root, 'templates') path if File.exists?(path) end @@ -242,7 +245,6 @@ module Rails # Check whether the given class names are already taken by user # application or Ruby on Rails. - # def class_collisions(*class_names) #:nodoc: return unless behavior == :invoke @@ -254,17 +256,13 @@ module Rails nesting = class_name.split('::') last_name = nesting.pop - # Hack to limit const_defined? to non-inherited on 1.9 - extra = [] - extra << false unless Object.method(:const_defined?).arity == 1 - # Extract the last Module in the nesting last = nesting.inject(Object) do |last_module, nest| - break unless last_module.const_defined?(nest, *extra) + break unless last_module.const_defined?(nest, false) last_module.const_get(nest) end - if last && last.const_defined?(last_name.camelize, *extra) + if last && last.const_defined?(last_name.camelize, false) raise Error, "The name '#{class_name}' is either already used in your application " << "or reserved by Ruby on Rails. Please choose an alternative and run " << "this generator again." @@ -273,13 +271,11 @@ module Rails end # Use Rails default banner. - # def self.banner "rails generate #{namespace.sub(/^rails:/,'')} #{self.arguments.map{ |a| a.usage }.join(' ')} [options]".gsub(/\s+/, ' ') end # Sets the base_name taking into account the current class namespace. - # def self.base_name @base_name ||= begin if base = name.to_s.split('::').first @@ -290,7 +286,6 @@ 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 @generator_name ||= begin if generator = name.to_s.split('::').last @@ -302,20 +297,17 @@ module Rails # Return the default value for the option name given doing a lookup in # Rails::Generators.options. - # def self.default_value_for_option(name, options) default_for_option(Rails::Generators.options, name, options, options[:default]) end # Return default aliases for the option name given doing a lookup in # Rails::Generators.aliases. - # def self.default_aliases_for_option(name, options) default_for_option(Rails::Generators.aliases, name, options, options[:aliases]) end # Return default for the option name given doing a lookup in config. - # def self.default_for_option(config, name, options, default) if generator_name and c = config[generator_name.to_sym] and c.key?(name) c[name] @@ -329,14 +321,12 @@ module Rails end # Keep hooks configuration that are used on prepare_for_invocation. - # def self.hooks #:nodoc: @hooks ||= from_superclass(:hooks, {}) end # Prepare class invocation to search on Rails namespace if a previous # added hook is being used. - # def self.prepare_for_invocation(name, value) #:nodoc: return super unless value.is_a?(String) || value.is_a?(Symbol) @@ -352,7 +342,6 @@ 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! class_option :ruby, :type => :string, :aliases => "-r", :default => Thor::Util.ruby_command, :desc => "Path to the Ruby binary of your choice", :banner => "PATH" @@ -371,6 +360,19 @@ module Rails } end + def self.usage_path + paths = [ + source_root && File.expand_path("../USAGE", source_root), + default_generator_root && File.join(default_generator_root, "USAGE") + ] + paths.compact.detect { |path| File.exists? path } + end + + def self.default_generator_root + path = File.expand_path(File.join(base_name, generator_name), base_root) + path if File.exists?(path) + end + end end end diff --git a/railties/lib/rails/generators/erb/scaffold/templates/index.html.erb b/railties/lib/rails/generators/erb/scaffold/templates/index.html.erb index 7b1a2a1841..f5182bcc50 100644 --- a/railties/lib/rails/generators/erb/scaffold/templates/index.html.erb +++ b/railties/lib/rails/generators/erb/scaffold/templates/index.html.erb @@ -1,25 +1,27 @@ <h1>Listing <%= plural_table_name %></h1> <table> - <tr> -<% attributes.each do |attribute| -%> - <th><%= attribute.human_name %></th> -<% end -%> - <th></th> - <th></th> - <th></th> - </tr> + <thead> + <tr> + <% attributes.each do |attribute| -%> + <th><%= attribute.human_name %></th> + <% end -%> + <th></th> + <th></th> + <th></th> + </tr> + </thead> -<%% @<%= plural_table_name %>.each do |<%= singular_table_name %>| %> - <tr> -<% attributes.each do |attribute| -%> - <td><%%= <%= singular_table_name %>.<%= attribute.name %> %></td> -<% end -%> - <td><%%= link_to 'Show', <%= singular_table_name %> %></td> - <td><%%= link_to 'Edit', edit_<%= singular_table_name %>_path(<%= singular_table_name %>) %></td> - <td><%%= link_to 'Destroy', <%= singular_table_name %>, <%= key_value :confirm, "'Are you sure?'" %>, <%= key_value :method, ":delete" %> %></td> - </tr> -<%% end %> + <tbody> + <%%= content_tag_for(:tr, @<%= plural_table_name %>) do |<%= singular_table_name %>| %> + <% attributes.each do |attribute| -%> + <td><%%= <%= singular_table_name %>.<%= attribute.name %> %></td> + <% end -%> + <td><%%= link_to 'Show', <%= singular_table_name %> %></td> + <td><%%= link_to 'Edit', edit_<%= singular_table_name %>_path(<%= singular_table_name %>) %></td> + <td><%%= link_to 'Destroy', <%= singular_table_name %>, method: :delete, data: { confirm: 'Are you sure?' } %></td> + <%% end %> + </tbody> </table> <br /> diff --git a/railties/lib/rails/generators/erb/scaffold/templates/show.html.erb b/railties/lib/rails/generators/erb/scaffold/templates/show.html.erb index 67f263efbb..e15c963971 100644 --- a/railties/lib/rails/generators/erb/scaffold/templates/show.html.erb +++ b/railties/lib/rails/generators/erb/scaffold/templates/show.html.erb @@ -2,7 +2,7 @@ <% attributes.each do |attribute| -%> <p> - <b><%= attribute.human_name %>:</b> + <strong><%= attribute.human_name %>:</strong> <%%= @<%= singular_table_name %>.<%= attribute.name %> %> </p> diff --git a/railties/lib/rails/generators/generated_attribute.rb b/railties/lib/rails/generators/generated_attribute.rb index 816d82cac3..d2c2abf40c 100644 --- a/railties/lib/rails/generators/generated_attribute.rb +++ b/railties/lib/rails/generators/generated_attribute.rb @@ -1,14 +1,63 @@ require 'active_support/time' -require 'active_support/core_ext/object/inclusion' module Rails module Generators class GeneratedAttribute + INDEX_OPTIONS = %w(index uniq) + UNIQ_INDEX_OPTIONS = %w(uniq) + attr_accessor :name, :type + attr_reader :attr_options + attr_writer :index_name + + class << self + def parse(column_definition) + name, type, has_index = column_definition.split(':') + + # if user provided "name:index" instead of "name:string:index" + # type should be set blank so GeneratedAttribute's constructor + # could set it to :string + has_index, type = type, nil if INDEX_OPTIONS.include?(type) + + type, attr_options = *parse_type_and_options(type) + type = type.to_sym if type + + if type && reference?(type) + references_index = UNIQ_INDEX_OPTIONS.include?(has_index) ? { :unique => true } : true + attr_options[:index] = references_index + end + + new(name, type, has_index, attr_options) + end + + def reference?(type) + [:references, :belongs_to].include? type + end + + private + + # parse possible attribute options like :limit for string/text/binary/integer, :precision/:scale for decimals or :polymorphic for references/belongs_to + # when declaring options curly brackets should be used + def parse_type_and_options(type) + case type + when /(string|text|binary|integer)\{(\d+)\}/ + return $1, :limit => $2.to_i + when /decimal\{(\d+)[,.-](\d+)\}/ + return :decimal, :precision => $1.to_i, :scale => $2.to_i + when /(references|belongs_to)\{polymorphic\}/ + return $1, :polymorphic => true + else + return type, {} + end + end + end - def initialize(name, type) - type = :string if type.blank? - @name, @type = name, type.to_sym + def initialize(name, type=nil, index_type=false, attr_options={}) + @name = name + @type = type || :string + @has_index = INDEX_OPTIONS.include?(index_type) + @has_uniq_index = UNIQ_INDEX_OPTIONS.include?(index_type) + @attr_options = attr_options end def field_type @@ -41,12 +90,48 @@ module Rails end end + def plural_name + name.sub(/_id$/, '').pluralize + end + def human_name - name.to_s.humanize + name.humanize + end + + def index_name + @index_name ||= if reference? + polymorphic? ? %w(id type).map { |t| "#{name}_#{t}" } : "#{name}_id" + else + name + end + end + + def foreign_key? + !!(name =~ /_id$/) end def reference? - self.type.in?([:references, :belongs_to]) + self.class.reference?(type) + end + + def polymorphic? + self.attr_options.has_key?(:polymorphic) + end + + def has_index? + @has_index + end + + def has_uniq_index? + @has_uniq_index + end + + def inject_options + "".tap { |s| @attr_options.each { |k,v| s << ", #{k}: #{v.inspect}" } } + end + + def inject_index_options + has_uniq_index? ? ", unique: true" : "" end end end diff --git a/railties/lib/rails/generators/migration.rb b/railties/lib/rails/generators/migration.rb index 0c5c4f6e09..5bf98bb6e0 100644 --- a/railties/lib/rails/generators/migration.rb +++ b/railties/lib/rails/generators/migration.rb @@ -3,7 +3,6 @@ module Rails # Holds common methods for migrations. It assumes that migrations has the # [0-9]*_name format and can be used by another frameworks (like Sequel) # just by implementing the next migration version method. - # module Migration attr_reader :migration_number, :migration_file_name, :migration_class_name @@ -38,10 +37,7 @@ module Rails # The migration version, migration file name, migration class name are # available as instance variables in the template to be rendered. # - # ==== Examples - # # migration_template "migration.rb", "db/migrate/add_foo_to_bar.rb" - # def migration_template(source, destination=nil, config={}) destination = File.expand_path(destination || source, self.destination_root) diff --git a/railties/lib/rails/generators/named_base.rb b/railties/lib/rails/generators/named_base.rb index c6c0392f43..b61a5fc69d 100644 --- a/railties/lib/rails/generators/named_base.rb +++ b/railties/lib/rails/generators/named_base.rb @@ -9,9 +9,6 @@ module Rails class_option :skip_namespace, :type => :boolean, :default => false, :desc => "Skip namespace (affects only isolated applications)" - class_option :old_style_hash, :type => :boolean, :default => false, - :desc => "Force using old style hash (:foo => 'bar') on Ruby >= 1.9" - def initialize(args, *options) #:nodoc: @inside_template = nil # Unfreeze name in case it's given as a frozen string @@ -43,7 +40,7 @@ module Rails def indent(content, multiplier = 2) spaces = " " * multiplier - content = content.each_line.map {|line| "#{spaces}#{line}" }.join + content = content.each_line.map {|line| line.blank? ? line : "#{spaces}#{line}" }.join end def wrap_with_namespace(content) @@ -82,11 +79,16 @@ module Rails @class_path end + def namespaced_file_path + @namespaced_file_path ||= namespaced_class_path.join("/") + end + def namespaced_class_path - @namespaced_class_path ||= begin - namespace_path = namespace.name.split("::").map {|m| m.underscore } - namespace_path + @class_path - end + @namespaced_class_path ||= [namespaced_path] + @class_path + end + + def namespaced_path + @namespaced_path ||= namespace.name.split("::").map {|m| m.underscore }[0] end def class_name @@ -102,7 +104,7 @@ module Rails end def i18n_scope - @i18n_scope ||= file_path.gsub('/', '.') + @i18n_scope ||= file_path.tr('/', '.') end def table_name @@ -133,7 +135,7 @@ module Rails end def route_url - @route_url ||= class_path.collect{|dname| "/" + dname }.join('') + "/" + plural_file_name + @route_url ||= class_path.collect {|dname| "/" + dname }.join + "/" + plural_file_name end # Tries to retrieve the application name or simple return application. @@ -153,9 +155,8 @@ module Rails # Convert attributes array into GeneratedAttribute objects. def parse_attributes! #:nodoc: - self.attributes = (attributes || []).map do |key_value| - name, type = key_value.split(':') - Rails::Generators::GeneratedAttribute.new(name, type) + self.attributes = (attributes || []).map do |attr| + Rails::Generators::GeneratedAttribute.parse(attr) end end @@ -184,16 +185,6 @@ module Rails class_collisions "#{options[:prefix]}#{name}#{options[:suffix]}" end end - - # Returns Ruby 1.9 style key-value pair if current code is running on - # Ruby 1.9.x. Returns the old-style (with hash rocket) otherwise. - def key_value(key, value) - if options[:old_style_hash] || RUBY_VERSION < '1.9' - ":#{key} => #{value}" - else - "#{key}: #{value}" - end - end end end end diff --git a/railties/lib/rails/generators/rails/app/app_generator.rb b/railties/lib/rails/generators/rails/app/app_generator.rb index 3e32f758a4..c06b0f8994 100644 --- a/railties/lib/rails/generators/rails/app/app_generator.rb +++ b/railties/lib/rails/generators/rails/app/app_generator.rb @@ -38,7 +38,7 @@ module Rails end def readme - copy_file "README" + copy_file "README", "README.rdoc" end def gemfile @@ -97,6 +97,11 @@ module Rails def public_directory directory "public", "public", :recursive => false + if options[:skip_index_html] + remove_file "public/index.html" + remove_file 'app/assets/images/rails.png' + git_keep 'app/assets/images' + end end def script @@ -124,7 +129,6 @@ module Rails def vendor vendor_javascripts vendor_stylesheets - vendor_plugins end def vendor_javascripts @@ -134,10 +138,6 @@ module Rails def vendor_stylesheets empty_directory_with_gitkeep "vendor/assets/stylesheets" end - - def vendor_plugins - empty_directory_with_gitkeep "vendor/plugins" - end end module Generators diff --git a/railties/lib/rails/generators/rails/app/templates/Gemfile b/railties/lib/rails/generators/rails/app/templates/Gemfile index d3b8f4d595..55a6b3f4f2 100644 --- a/railties/lib/rails/generators/rails/app/templates/Gemfile +++ b/railties/lib/rails/generators/rails/app/templates/Gemfile @@ -1,11 +1,10 @@ -source 'http://rubygems.org' +source 'https://rubygems.org' <%= rails_gemfile_entry -%> <%= database_gemfile_entry -%> <%= "gem 'jruby-openssl'\n" if defined?(JRUBY_VERSION) -%> -<%= "gem 'json'\n" if RUBY_VERSION < "1.9.2" -%> <%= assets_gemfile_entry %> <%= javascript_gemfile_entry %> @@ -13,11 +12,14 @@ source 'http://rubygems.org' # To use ActiveModel has_secure_password # gem 'bcrypt-ruby', '~> 3.0.0' -# Use unicorn as the web server +# To use Jbuilder templates for JSON +# gem 'jbuilder' + +# Use unicorn as the app server # gem 'unicorn' # Deploy with Capistrano -# gem 'capistrano' +# gem 'capistrano', group: :development # To use debugger -# <%= ruby_debugger_gemfile_entry %> +# gem 'debugger' diff --git a/railties/lib/rails/generators/rails/app/templates/README b/railties/lib/rails/generators/rails/app/templates/README index 7c36f2356e..b5d7b6436b 100644 --- a/railties/lib/rails/generators/rails/app/templates/README +++ b/railties/lib/rails/generators/rails/app/templates/README @@ -86,8 +86,8 @@ programming in general. Debugger support is available through the debugger command when you start your Mongrel or WEBrick server with --debugger. This means that you can break out of execution at any point in the code, investigate and change the model, and then, -resume execution! You need to install ruby-debug to run the server in debugging -mode. With gems, use <tt>sudo gem install ruby-debug</tt>. Example: +resume execution! You need to install the 'debugger' gem to run the server in debugging +mode. Add gem 'debugger' to your Gemfile and run <tt>bundle</tt> to install it. Example: class WeblogController < ActionController::Base def index @@ -191,7 +191,6 @@ The default directory structure of a generated Ruby on Rails application: `-- vendor |-- assets `-- stylesheets - `-- plugins app Holds all the code that's specific to this particular application. @@ -256,6 +255,5 @@ test directory. vendor - External libraries that the application depends on. Also includes the plugins - subdirectory. If the app has frozen rails, those gems also go here, under - vendor/rails/. This directory is in the load path. + External libraries that the application depends on. If the app has frozen rails, + those gems also go here, under vendor/rails/. This directory is in the load path. diff --git a/railties/lib/rails/generators/rails/app/templates/Rakefile b/railties/lib/rails/generators/rails/app/templates/Rakefile index 4dc1023f1f..6eb23f68a3 100755..100644 --- a/railties/lib/rails/generators/rails/app/templates/Rakefile +++ b/railties/lib/rails/generators/rails/app/templates/Rakefile @@ -1,4 +1,3 @@ -#!/usr/bin/env rake # Add your own tasks in files placed in lib/tasks ending in .rake, # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. 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 3b5cc6648e..3192ec897b 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 @@ -10,4 +10,4 @@ * *= require_self *= require_tree . -*/ + */ diff --git a/railties/lib/rails/generators/rails/app/templates/app/controllers/application_controller.rb b/railties/lib/rails/generators/rails/app/templates/app/controllers/application_controller.rb deleted file mode 100644 index e8065d9505..0000000000 --- a/railties/lib/rails/generators/rails/app/templates/app/controllers/application_controller.rb +++ /dev/null @@ -1,3 +0,0 @@ -class ApplicationController < ActionController::Base - protect_from_forgery -end diff --git a/railties/lib/rails/generators/rails/app/templates/app/controllers/application_controller.rb.tt b/railties/lib/rails/generators/rails/app/templates/app/controllers/application_controller.rb.tt new file mode 100644 index 0000000000..6c0ef31725 --- /dev/null +++ b/railties/lib/rails/generators/rails/app/templates/app/controllers/application_controller.rb.tt @@ -0,0 +1,5 @@ +class ApplicationController < ActionController::Base + # Prevent CSRF attacks by raising an exception. + # For APIs, you may want to use :reset_session instead. + protect_from_forgery with: :exception +end 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 c63d1b6ac5..e0539aa8bb 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 @@ -2,7 +2,7 @@ <html> <head> <title><%= camelized %></title> - <%%= stylesheet_link_tag "application" %> + <%%= stylesheet_link_tag "application", media: "all" %> <%%= javascript_include_tag "application" %> <%%= csrf_meta_tags %> </head> diff --git a/railties/lib/rails/generators/rails/app/templates/config/application.rb b/railties/lib/rails/generators/rails/app/templates/config/application.rb index 13fbe9e526..1ac0248bcf 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/application.rb +++ b/railties/lib/rails/generators/rails/app/templates/config/application.rb @@ -7,15 +7,14 @@ require 'rails/all' <%= comment_if :skip_active_record %>require "active_record/railtie" require "action_controller/railtie" require "action_mailer/railtie" -require "active_resource/railtie" -<%= comment_if :skip_sprockets %>require "sprockets/railtie" +<%= comment_if :skip_sprockets %>require "sprockets/rails/railtie" <%= comment_if :skip_test_unit %>require "rails/test_unit/railtie" <% end -%> if defined?(Bundler) - # If you precompile assets before deploying to production, use this line - Bundler.require(*Rails.groups(:assets => %w(development test))) - # If you want your assets lazily compiled in production, use this line + # If you precompile assets before deploying to production, use this line. + Bundler.require(*Rails.groups(assets: %w(development test))) + # If you want your assets lazily compiled in production, use this line. # Bundler.require(:default, :assets, Rails.env) end @@ -28,13 +27,6 @@ module <%= app_const_base %> # Custom directories with classes and modules you want to be autoloadable. # config.autoload_paths += %W(#{config.root}/extras) - # Only load the plugins named here, in the order given (default is alphabetical). - # :all can be used as a placeholder for all plugins not explicitly named. - # config.plugins = [ :exception_notification, :ssl_requirement, :all ] - - # Activate observers that should always be running. - # config.active_record.observers = :cacher, :garbage_collector, :forum_observer - # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone. # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC. # config.time_zone = 'Central Time (US & Canada)' @@ -49,12 +41,26 @@ module <%= app_const_base %> # Configure sensitive parameters which will be filtered from the log file. config.filter_parameters += [:password] + # Use SQL instead of Active Record's schema dumper when creating the database. + # This is necessary if your schema can't be completely dumped by the schema dumper, + # like if you have constraints or database-specific column types. + # config.active_record.schema_format = :sql + + # Enforce whitelist mode for mass assignment. + # This will create an empty whitelist of attributes available for mass-assignment for all models + # in your app. As such, your models will need to explicitly whitelist or blacklist accessible + # parameters by using an attr_accessible or attr_protected declaration. + <%= comment_if :skip_active_record %>config.active_record.whitelist_attributes = true <% unless options.skip_sprockets? -%> - # Enable the asset pipeline + + # Enable the asset pipeline. config.assets.enabled = true - # Version of your assets, change this if you want to expire all your assets + # Version of your assets, change this if you want to expire all your assets. config.assets.version = '1.0' <% end -%> + + # Enable app-wide asynchronous ActionMailer. + # config.action_mailer.async = true end end diff --git a/railties/lib/rails/generators/rails/app/templates/config/boot.rb b/railties/lib/rails/generators/rails/app/templates/config/boot.rb index 4489e58688..3596736667 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/boot.rb +++ b/railties/lib/rails/generators/rails/app/templates/config/boot.rb @@ -1,5 +1,3 @@ -require 'rubygems' - # Set up gems listed in the Gemfile. ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__) diff --git a/railties/lib/rails/generators/rails/app/templates/config/databases/jdbcpostgresql.yml b/railties/lib/rails/generators/rails/app/templates/config/databases/jdbcpostgresql.yml index fe9466b366..e1a00d076f 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/databases/jdbcpostgresql.yml +++ b/railties/lib/rails/generators/rails/app/templates/config/databases/jdbcpostgresql.yml @@ -22,8 +22,8 @@ development: # Minimum log levels, in increasing order: # debug5, debug4, debug3, debug2, debug1, # log, notice, warning, error, fatal, and panic - # The server defaults to notice. - #min_messages: warning + # Defaults to warning. + #min_messages: notice # Warning: The database defined as "test" will be erased and # re-generated from your development database when you run "rake". 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 cce166c7c3..c3349912aa 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,5 +1,5 @@ # MySQL. Versions 4.1 and 5.0 are recommended. -# +# # Install the MYSQL driver # gem install mysql2 # @@ -11,7 +11,6 @@ development: adapter: mysql2 encoding: utf8 - reconnect: false database: <%= app_name %>_development pool: 5 username: root @@ -28,7 +27,6 @@ development: test: adapter: mysql2 encoding: utf8 - reconnect: false database: <%= app_name %>_test pool: 5 username: root @@ -42,7 +40,6 @@ test: production: adapter: mysql2 encoding: utf8 - reconnect: false database: <%= app_name %>_production pool: 5 username: root diff --git a/railties/lib/rails/generators/rails/app/templates/config/databases/postgresql.yml b/railties/lib/rails/generators/rails/app/templates/config/databases/postgresql.yml index f08f86aac3..07223a71c9 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/databases/postgresql.yml +++ b/railties/lib/rails/generators/rails/app/templates/config/databases/postgresql.yml @@ -24,6 +24,9 @@ development: # domain socket that doesn't need configuration. Windows does not have # domain sockets, so uncomment these lines. #host: localhost + + # The TCP port the server listens on. Defaults to 5432. + # If your server runs on a different port number, change accordingly. #port: 5432 # Schema search path. The server defaults to $user,public @@ -32,8 +35,8 @@ development: # Minimum log levels, in increasing order: # debug5, debug4, debug3, debug2, debug1, # log, notice, warning, error, fatal, and panic - # The server defaults to notice. - #min_messages: warning + # Defaults to warning. + #min_messages: notice # Warning: The database defined as "test" will be erased and # re-generated from your development database when you run "rake". diff --git a/railties/lib/rails/generators/rails/app/templates/config/environment.rb b/railties/lib/rails/generators/rails/app/templates/config/environment.rb index 1684986a59..e080ebd74e 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/environment.rb +++ b/railties/lib/rails/generators/rails/app/templates/config/environment.rb @@ -1,5 +1,5 @@ -# Load the rails application +# Load the rails application. require File.expand_path('../application', __FILE__) -# Initialize the rails application +# Initialize the rails application. <%= app_const %>.initialize! diff --git a/railties/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt index 47078e3af9..122e7e2b34 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt +++ b/railties/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt @@ -1,35 +1,47 @@ <%= app_const %>.configure do - # Settings specified here will take precedence over those in config/application.rb + # Settings specified here will take precedence over those in config/application.rb. # In the development environment your application's code is reloaded on # every request. This slows down response time but is perfect for development # since you don't have to restart the web server when you make code changes. config.cache_classes = false - # Log error messages when you accidentally call methods on nil. - config.whiny_nils = true + # Do not eager load code on boot. + config.eager_load = false - # Show full error reports and disable caching + # Show full error reports and disable caching. config.consider_all_requests_local = true config.action_controller.perform_caching = false - # Don't care if the mailer can't send + # Don't care if the mailer can't send. config.action_mailer.raise_delivery_errors = false - # Print deprecation notices to the Rails logger + # Print deprecation notices to the Rails logger. config.active_support.deprecation = :log - # Only use best-standards-support built into browsers + # Only use best-standards-support built into browsers. config.action_dispatch.best_standards_support = :builtin <%- unless options.skip_active_record? -%> - # Raise exception on mass assignment protection for ActiveRecord models + # Raise exception on mass assignment protection for Active Record models. config.active_record.mass_assignment_sanitizer = :strict + + # Log the query plan for queries taking more than this (works + # with SQLite, MySQL, and PostgreSQL). + config.active_record.auto_explain_threshold_in_seconds = 0.5 + + # Raise an error on page load if there are pending migrations + config.active_record.migration_error = :page_load <%- end -%> - # Do not compress assets + <%- unless options.skip_sprockets? -%> + # Do not compress assets. config.assets.compress = false - # Expands the lines which load the assets + # Debug mode disables concatenation and preprocessing of assets. config.assets.debug = true + <%- end -%> + + # In development, use an in-memory queue for queueing. + config.queue = Rails::Queueing::Queue end diff --git a/railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt index 50f2df3d35..a627636089 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt +++ b/railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt @@ -1,63 +1,86 @@ <%= app_const %>.configure do - # Settings specified here will take precedence over those in config/application.rb + # Settings specified here will take precedence over those in config/application.rb. - # Code is not reloaded between requests + # Code is not reloaded between requests. config.cache_classes = true - # Full error reports are disabled and caching is turned on + # Eager load code on boot. This eager loads most of Rails and + # your application in memory, allowing both thread web servers + # and those relying on copy on write to perform better. + # Rake tasks automatically ignore this option for performance. + config.eager_load = true + + # Full error reports are disabled and caching is turned on. config.consider_all_requests_local = false config.action_controller.perform_caching = true - # Disable Rails's static asset server (Apache or nginx will already do this) + # Disable Rails's static asset server (Apache or nginx will already do this). config.serve_static_assets = false - # Compress JavaScripts and CSS + <%- unless options.skip_sprockets? -%> + # Compress JavaScripts and CSS. config.assets.compress = true - # Don't fallback to assets pipeline if a precompiled asset is missed + # Don't fallback to assets pipeline if a precompiled asset is missed. config.assets.compile = false - # Generate digests for assets URLs + # Generate digests for assets URLs. config.assets.digest = true + <%- end -%> - # Defaults to Rails.root.join("public/assets") - # config.assets.manifest = YOUR_PATH - - # Specifies the header that your server uses for sending files + # Specifies the header that your server uses for sending files. # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for apache # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for nginx # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. # config.force_ssl = true - # See everything in the log (default is :info) - # config.log_level = :debug + # Set to :debug to see everything in the log. + config.log_level = :info - # Prepend all log lines with the following tags + # Prepend all log lines with the following tags. # config.log_tags = [ :subdomain, :uuid ] - # Use a different logger for distributed setups + # Use a different logger for distributed setups. # config.logger = ActiveSupport::TaggedLogging.new(SyslogLogger.new) - # Use a different cache store in production + # Use a different cache store in production. # config.cache_store = :mem_cache_store - # Enable serving of images, stylesheets, and JavaScripts from an asset server + # Enable serving of images, stylesheets, and JavaScripts from an asset server. # config.action_controller.asset_host = "http://assets.example.com" - # Precompile additional assets (application.js, application.css, and all non-JS/CSS are already added) + <%- unless options.skip_sprockets? -%> + # Precompile additional assets (application.js, application.css, and all non-JS/CSS are already added). # config.assets.precompile += %w( search.js ) + <%- end -%> - # Disable delivery errors, bad email addresses will be ignored + # Disable delivery errors, bad email addresses will be ignored. # config.action_mailer.raise_delivery_errors = false - # Enable threaded mode + # Enable threaded mode. # config.threadsafe! # Enable locale fallbacks for I18n (makes lookups for any locale fall back to - # the I18n.default_locale when a translation can not be found) + # the I18n.default_locale when a translation can not be found). config.i18n.fallbacks = true - # Send deprecation notices to registered listeners + # Send deprecation notices to registered listeners. config.active_support.deprecation = :notify + + <%- unless options.skip_active_record? -%> + # Log the query plan for queries taking more than this (works + # with SQLite, MySQL, and PostgreSQL). + # config.active_record.auto_explain_threshold_in_seconds = 0.5 + <%- end -%> + + # Disable automatic flushing of the log to improve performance. + # config.autoflush_log = false + + # Use default logging formatter so that PID and timestamp are not suppressed. + config.log_formatter = ::Logger::Formatter.new + + # Default the production mode queue to an in-memory queue. You will probably + # want to replace this with an out-of-process queueing solution. + config.queue = Rails::Queueing::Queue end diff --git a/railties/lib/rails/generators/rails/app/templates/config/environments/test.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/environments/test.rb.tt index 80198cc21e..8ab27eb6e1 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/environments/test.rb.tt +++ b/railties/lib/rails/generators/rails/app/templates/config/environments/test.rb.tt @@ -1,5 +1,5 @@ <%= app_const %>.configure do - # Settings specified here will take precedence over those in config/application.rb + # Settings specified here will take precedence over those in config/application.rb. # The test environment is used exclusively to run your application's # test suite. You never need to work with it otherwise. Remember that @@ -7,38 +7,38 @@ # and recreated between test runs. Don't rely on the data there! config.cache_classes = true - # Configure static asset server for tests with Cache-Control for performance + # Do not eager load code on boot. This avoids loading your whole application + # just for the purpose of running a single test. If you are using a tool that + # preloads Rails for running tests, you may have to set it to true. + config.eager_load = false + + # Configure static asset server for tests with Cache-Control for performance. config.serve_static_assets = true config.static_cache_control = "public, max-age=3600" - # Log error messages when you accidentally call methods on nil - config.whiny_nils = true - - # Show full error reports and disable caching + # Show full error reports and disable caching. config.consider_all_requests_local = true config.action_controller.perform_caching = false - # Raise exceptions instead of rendering exception templates + # Raise exceptions instead of rendering exception templates. config.action_dispatch.show_exceptions = false - # Disable request forgery protection in test environment - config.action_controller.allow_forgery_protection = false + # Disable request forgery protection in test environment. + config.action_controller.allow_forgery_protection = false # Tell Action Mailer not to deliver emails to the real world. # The :test delivery method accumulates sent emails in the # ActionMailer::Base.deliveries array. config.action_mailer.delivery_method = :test - # Use SQL instead of Active Record's schema dumper when creating the test database. - # This is necessary if your schema can't be completely dumped by the schema dumper, - # like if you have constraints or database-specific column types - # config.active_record.schema_format = :sql - <%- unless options.skip_active_record? -%> - # Raise exception on mass assignment protection for ActiveRecord models + # Raise exception on mass assignment protection for Active Record models. config.active_record.mass_assignment_sanitizer = :strict <%- end -%> - # Print deprecation notices to the stderr + # Print deprecation notices to the stderr. config.active_support.deprecation = :stderr + + # Use the testing queue. + config.queue = Rails::Queueing::TestQueue end diff --git a/railties/lib/rails/generators/rails/app/templates/config/initializers/inflections.rb b/railties/lib/rails/generators/rails/app/templates/config/initializers/inflections.rb index 5d8d9be237..9262c3379f 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/initializers/inflections.rb +++ b/railties/lib/rails/generators/rails/app/templates/config/initializers/inflections.rb @@ -1,8 +1,9 @@ # Be sure to restart your server when you modify this file. -# Add new inflection rules using the following format -# (all these examples are active by default): -# ActiveSupport::Inflector.inflections do |inflect| +# Add new inflection rules using the following format. Inflections +# are locale specific, and you may define rules for as many different +# locales as you wish. All of these examples are active by default: +# ActiveSupport::Inflector.inflections(:en) do |inflect| # inflect.plural /^(ox)$/i, '\1en' # inflect.singular /^(ox)en/i, '\1' # inflect.irregular 'person', 'people' @@ -10,6 +11,6 @@ # end # # These inflection rules are supported but not enabled by default: -# ActiveSupport::Inflector.inflections do |inflect| +# ActiveSupport::Inflector.inflections(:en) do |inflect| # inflect.acronym 'RESTful' # end diff --git a/railties/lib/rails/generators/rails/app/templates/config/initializers/secret_token.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/initializers/secret_token.rb.tt index a3143f1346..e02397aaf9 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/initializers/secret_token.rb.tt +++ b/railties/lib/rails/generators/rails/app/templates/config/initializers/secret_token.rb.tt @@ -4,4 +4,6 @@ # If you change this key, all old signed cookies will become invalid! # Make sure the secret is at least 30 characters and all random, # no regular words or you'll be exposed to dictionary attacks. +# Make sure your secret_token is kept private +# if you're sharing your code publicly. <%= app_const %>.config.secret_token = '<%= app_secret %>' diff --git a/railties/lib/rails/generators/rails/app/templates/config/initializers/session_store.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/initializers/session_store.rb.tt index ddfe4ba1e1..ff676280cb 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/initializers/session_store.rb.tt +++ b/railties/lib/rails/generators/rails/app/templates/config/initializers/session_store.rb.tt @@ -1,8 +1,8 @@ # Be sure to restart your server when you modify this file. -<%= app_const %>.config.session_store :cookie_store, <%= key_value :key, "'_#{app_name}_session'" %> +<%= app_const %>.config.session_store :cookie_store, key: <%= "'_#{app_name}_session'" %> # Use the database for sessions instead of the cookie-based default, # which shouldn't be used to store highly confidential information -# (create the session table with "rails generate session_migration") +# (create the session table with "rails generate session_migration"). # <%= app_const %>.config.session_store :active_record_store diff --git a/railties/lib/rails/generators/rails/app/templates/config/initializers/wrap_parameters.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/initializers/wrap_parameters.rb.tt index d640f578da..280f777cc0 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/initializers/wrap_parameters.rb.tt +++ b/railties/lib/rails/generators/rails/app/templates/config/initializers/wrap_parameters.rb.tt @@ -5,12 +5,12 @@ # Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array. ActiveSupport.on_load(:action_controller) do - wrap_parameters <%= key_value :format, "[:json]" %> + wrap_parameters format: [:json] if respond_to?(:wrap_parameters) end <%- unless options.skip_active_record? -%> -# Disable root element in JSON by default. -ActiveSupport.on_load(:active_record) do - self.include_root_in_json = false -end +# To enable root element in JSON for ActiveRecord objects. +# ActiveSupport.on_load(:active_record) do +# self.include_root_in_json = true +# end <%- end -%> diff --git a/railties/lib/rails/generators/rails/app/templates/config/locales/en.yml b/railties/lib/rails/generators/rails/app/templates/config/locales/en.yml index 179c14ca52..0653957166 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/locales/en.yml +++ b/railties/lib/rails/generators/rails/app/templates/config/locales/en.yml @@ -1,5 +1,23 @@ -# Sample localization file for English. Add more files in this directory for other locales. -# See https://github.com/svenfuchs/rails-i18n/tree/master/rails%2Flocale for starting points. +# Files in the config/locales directory are used for internationalization +# and are automatically loaded by Rails. If you want to use locales other +# than English, add the necessary files in this directory. +# +# To use the locales, use `I18n.t`: +# +# I18n.t 'hello' +# +# In views, this is aliased to just `t`: +# +# <%= t('hello') %> +# +# To use a different locale, set it with `I18n.locale`: +# +# I18n.locale = :es +# +# This would use the information in config/locales/es.yml. +# +# To learn more, please read the Rails Internationalization guide +# available at http://guides.rubyonrails.org/i18n.html. en: hello: "Hello world" diff --git a/railties/lib/rails/generators/rails/app/templates/config/routes.rb b/railties/lib/rails/generators/rails/app/templates/config/routes.rb index ea81748464..f6b1ef1feb 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/routes.rb +++ b/railties/lib/rails/generators/rails/app/templates/config/routes.rb @@ -2,13 +2,17 @@ # The priority is based upon order of creation: # first created -> highest priority. + # You can have the root of your site routed with "root" + # just remember to delete public/index.html. + # root to: 'welcome#index' + # Sample of regular route: - # match 'products/:id' => 'catalog#view' - # Keep in mind you can assign values other than :controller and :action + # get 'products/:id' => 'catalog#view' + # Keep in mind you can assign values other than :controller and :action. # Sample of named route: - # match 'products/:id/purchase' => 'catalog#purchase', :as => :purchase - # This route can be invoked with purchase_url(:id => product.id) + # get 'products/:id/purchase' => 'catalog#purchase', as: :purchase + # This route can be invoked with purchase_url(id: product.id). # Sample resource route (maps HTTP verbs to controller actions automatically): # resources :products @@ -31,11 +35,11 @@ # resource :seller # end - # Sample resource route with more complex sub-resources + # Sample resource route with more complex sub-resources: # resources :products do # resources :comments # resources :sales do - # get 'recent', :on => :collection + # get 'recent', on: :collection # end # end @@ -46,13 +50,6 @@ # resources :products # end - # You can have the root of your site routed with "root" - # just remember to delete public/index.html. - # root :to => 'welcome#index' - - # See how all your routes lay out with "rake routes" - # This is a legacy wild controller route that's not recommended for RESTful applications. - # Note: This route will make all actions in every controller accessible via GET requests. - # match ':controller(/:action(/:id))(.:format)' + # See how all your routes lay out with "rake routes". end diff --git a/railties/lib/rails/generators/rails/app/templates/db/seeds.rb.tt b/railties/lib/rails/generators/rails/app/templates/db/seeds.rb.tt index f75c5dd941..4edb1e857e 100644 --- a/railties/lib/rails/generators/rails/app/templates/db/seeds.rb.tt +++ b/railties/lib/rails/generators/rails/app/templates/db/seeds.rb.tt @@ -3,5 +3,5 @@ # # Examples: # -# cities = City.create([{ <%= key_value :name, "'Chicago'" %> }, { <%= key_value :name, "'Copenhagen'" %> }]) -# Mayor.create(<%= key_value :name, "'Emanuel'" %>, <%= key_value :city, "cities.first" %>) +# cities = City.create([{ name: 'Chicago' }, { name: 'Copenhagen' }]) +# Mayor.create(name: 'Emanuel', city: cities.first) diff --git a/railties/lib/rails/generators/rails/app/templates/gitignore b/railties/lib/rails/generators/rails/app/templates/gitignore index eb3489a986..8910bf5a06 100644 --- a/railties/lib/rails/generators/rails/app/templates/gitignore +++ b/railties/lib/rails/generators/rails/app/templates/gitignore @@ -9,6 +9,7 @@ # Ignore the default SQLite database. /db/*.sqlite3 +/db/*.sqlite3-journal # Ignore all logfiles and tempfiles. /log/*.log diff --git a/railties/lib/rails/generators/rails/app/templates/public/404.html b/railties/lib/rails/generators/rails/app/templates/public/404.html index 9a48320a5f..3d875c342e 100644 --- a/railties/lib/rails/generators/rails/app/templates/public/404.html +++ b/railties/lib/rails/generators/rails/app/templates/public/404.html @@ -2,7 +2,7 @@ <html> <head> <title>The page you were looking for doesn't exist (404)</title> - <style type="text/css"> + <style> body { background-color: #fff; color: #666; text-align: center; font-family: arial, sans-serif; } div.dialog { width: 25em; @@ -22,5 +22,6 @@ <h1>The page you were looking for doesn't exist.</h1> <p>You may have mistyped the address or the page may have moved.</p> </div> + <p>If you are the application owner check the logs for more information.</p> </body> </html> diff --git a/railties/lib/rails/generators/rails/app/templates/public/422.html b/railties/lib/rails/generators/rails/app/templates/public/422.html index 83660ab187..3f1bfb3417 100644 --- a/railties/lib/rails/generators/rails/app/templates/public/422.html +++ b/railties/lib/rails/generators/rails/app/templates/public/422.html @@ -2,7 +2,7 @@ <html> <head> <title>The change you wanted was rejected (422)</title> - <style type="text/css"> + <style> body { background-color: #fff; color: #666; text-align: center; font-family: arial, sans-serif; } div.dialog { width: 25em; diff --git a/railties/lib/rails/generators/rails/app/templates/public/500.html b/railties/lib/rails/generators/rails/app/templates/public/500.html index f3648a0dbc..012977d3d2 100644 --- a/railties/lib/rails/generators/rails/app/templates/public/500.html +++ b/railties/lib/rails/generators/rails/app/templates/public/500.html @@ -2,7 +2,7 @@ <html> <head> <title>We're sorry, but something went wrong (500)</title> - <style type="text/css"> + <style> body { background-color: #fff; color: #666; text-align: center; font-family: arial, sans-serif; } div.dialog { width: 25em; @@ -21,5 +21,6 @@ <div class="dialog"> <h1>We're sorry, but something went wrong.</h1> </div> + <p>If you are the application owner check the logs for more information.</p> </body> </html> diff --git a/railties/lib/rails/generators/rails/app/templates/public/index.html b/railties/lib/rails/generators/rails/app/templates/public/index.html index 9d9811a5bf..dd09a96de9 100644 --- a/railties/lib/rails/generators/rails/app/templates/public/index.html +++ b/railties/lib/rails/generators/rails/app/templates/public/index.html @@ -2,7 +2,7 @@ <html> <head> <title>Ruby on Rails: Welcome aboard</title> - <style type="text/css" media="screen"> + <style media="screen"> body { margin: 0; margin-bottom: 25px; @@ -59,7 +59,7 @@ #header { - background-image: url("/assets/rails.png"); + background-image: url("assets/rails.png"); background-repeat: no-repeat; background-position: top left; height: 64px; @@ -171,7 +171,7 @@ font-style: italic; } </style> - <script type="text/javascript"> + <script> function about() { info = document.getElementById('about-content'); if (window.XMLHttpRequest) diff --git a/railties/lib/rails/generators/rails/app/templates/public/robots.txt b/railties/lib/rails/generators/rails/app/templates/public/robots.txt index 085187fa58..1a3a5e4dd2 100644 --- a/railties/lib/rails/generators/rails/app/templates/public/robots.txt +++ b/railties/lib/rails/generators/rails/app/templates/public/robots.txt @@ -1,5 +1,5 @@ # See http://www.robotstxt.org/wc/norobots.html for documentation on how to use the robots.txt file # # To ban all spiders from the entire site uncomment the next two lines: -# User-Agent: * +# User-agent: * # Disallow: / diff --git a/railties/lib/rails/generators/rails/app/templates/test/performance/browsing_test.rb b/railties/lib/rails/generators/rails/app/templates/test/performance/browsing_test.rb index 3fea27b916..d09ce5ad34 100644 --- a/railties/lib/rails/generators/rails/app/templates/test/performance/browsing_test.rb +++ b/railties/lib/rails/generators/rails/app/templates/test/performance/browsing_test.rb @@ -3,10 +3,10 @@ require 'rails/performance_test_help' class BrowsingTest < ActionDispatch::PerformanceTest # Refer to the documentation for all available options - # self.profile_options = { :runs => 5, :metrics => [:wall_time, :memory] - # :output => 'tmp/performance', :formats => [:flat] } + # self.profile_options = { runs: 5, metrics: [:wall_time, :memory], + # output: 'tmp/performance', formats: [:flat] } - def test_homepage + test "homepage" do get '/' end end 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 a8f7aeac7d..9afda2d0df 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 @@ -4,7 +4,9 @@ require 'rails/test_help' class ActiveSupport::TestCase <% unless options[:skip_active_record] -%> - # Setup all fixtures in test/fixtures/*.(yml|csv) for all tests in alphabetical order. + ActiveRecord::Migration.check_pending! + + # Setup all fixtures in test/fixtures/*.yml for all tests in alphabetical order. # # Note: You'll currently still have to declare fixtures explicitly in integration tests # -- they do not yet inherit this setting diff --git a/railties/lib/rails/generators/rails/controller/templates/controller.rb b/railties/lib/rails/generators/rails/controller/templates/controller.rb index 52243f4a2f..633e0b3177 100644 --- a/railties/lib/rails/generators/rails/controller/templates/controller.rb +++ b/railties/lib/rails/generators/rails/controller/templates/controller.rb @@ -1,3 +1,7 @@ +<% if namespaced? -%> +require_dependency "<%= namespaced_path %>/application_controller" + +<% end -%> <% module_namespacing do -%> class <%= class_name %>Controller < ApplicationController <% actions.each do |action| -%> diff --git a/railties/lib/rails/generators/rails/migration/migration_generator.rb b/railties/lib/rails/generators/rails/migration/migration_generator.rb index 39fa5b63b1..f87dce1502 100644 --- a/railties/lib/rails/generators/rails/migration/migration_generator.rb +++ b/railties/lib/rails/generators/rails/migration/migration_generator.rb @@ -1,7 +1,7 @@ module Rails module Generators class MigrationGenerator < NamedBase #metagenerator - argument :attributes, :type => :array, :default => [], :banner => "field:type field:type" + argument :attributes, :type => :array, :default => [], :banner => "field[:type][:index] field[:type][:index]" hook_for :orm, :required => true end end diff --git a/railties/lib/rails/generators/rails/model/USAGE b/railties/lib/rails/generators/rails/model/USAGE index 67f76aad01..c46c86076e 100644 --- a/railties/lib/rails/generators/rails/model/USAGE +++ b/railties/lib/rails/generators/rails/model/USAGE @@ -19,6 +19,55 @@ Description: then the generator will create a module with a table_name_prefix method to prefix the model's table name with the module name (e.g. admin_account) +Available field types: + + Just after the field name you can specify a type like text or boolean. + It will generate the column with the associated SQL type. For instance: + + `rails generate model post title:string body:text` + + will generate a title column with a varchar type and a body column with a text + type. You can use the following types: + + integer + primary_key + decimal + float + boolean + binary + string + text + date + time + datetime + timestamp + + You can also consider `references` as a kind of type. For instance, if you run: + + `rails generate model photo title:string album:references` + + It will generate an album_id column. You should generate this kind of fields when + you will use a `belongs_to` association for instance. `references` also support + the polymorphism, you could enable the polymorphism like this: + + `rails generate model product supplier:references{polymorphic}` + + You can also specify some options just after the field type. You can use the + following options: + + limit Set the maximum size of the field giving a number between curly braces + default Set a default value for the field + precision Defines the precision for the decimal fields + scale Defines the scale for the decimal fields + uniq Defines the field values as unique + index Will add an index on the field + + Examples: + + `rails generate model user pseudo:string{30}` + `rails generate model user pseudo:string:uniq` + + Examples: `rails generate model account` diff --git a/railties/lib/rails/generators/rails/model/model_generator.rb b/railties/lib/rails/generators/rails/model/model_generator.rb index 629d5eed3f..9bb29b784e 100644 --- a/railties/lib/rails/generators/rails/model/model_generator.rb +++ b/railties/lib/rails/generators/rails/model/model_generator.rb @@ -1,7 +1,7 @@ module Rails module Generators class ModelGenerator < NamedBase #metagenerator - argument :attributes, :type => :array, :default => [], :banner => "field:type field:type" + argument :attributes, :type => :array, :default => [], :banner => "field[:type][:index] field[:type][:index]" hook_for :orm, :required => true end end diff --git a/railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb b/railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb index 4baa2110e7..4f937ad65a 100644 --- a/railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb +++ b/railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb @@ -39,7 +39,7 @@ module Rails end def gitignore - copy_file "gitignore", ".gitignore" + template "gitignore", ".gitignore" end def lib @@ -133,6 +133,16 @@ task :default => :test end chmod "script", 0755, :verbose => false end + + def gemfile_entry + return unless inside_application? + + gemfile_in_app_path = File.join(rails_app_path, "Gemfile") + if File.exist? gemfile_in_app_path + entry = "gem '#{name}', path: '#{relative_path}'" + append_file gemfile_in_app_path, entry + end + end end module Generators @@ -145,7 +155,7 @@ task :default => :test :desc => "Create dummy application at given path" class_option :full, :type => :boolean, :default => false, - :desc => "Generate rails engine with integration tests" + :desc => "Generate a rails engine with bundled Rails application for testing" class_option :mountable, :type => :boolean, :default => false, :desc => "Generate mountable isolated application" @@ -153,6 +163,10 @@ task :default => :test class_option :skip_gemspec, :type => :boolean, :default => false, :desc => "Skip gemspec file" + class_option :skip_gemfile_entry, :type => :boolean, :default => false, + :desc => "If creating plugin in application's directory " + + "skip adding entry to Gemfile" + def initialize(*args) raise Error, "Options should be given after the plugin name. For details run: rails plugin --help" if args[0].blank? @@ -208,12 +222,28 @@ task :default => :test create_dummy_app end + def update_gemfile + build(:gemfile_entry) unless options[:skip_gemfile_entry] + end + def finish_template build(:leftovers) end public_task :apply_rails_template, :run_bundle + def name + @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.downcase! + + underscored + end + end + protected def app_templates_dir @@ -246,8 +276,8 @@ task :default => :test "rails plugin new #{self.arguments.map(&:usage).join(' ')} [options]" end - def name - @name ||= File.basename(destination_root) + def original_name + @original_name ||= File.basename(destination_root) end def camelized @@ -255,12 +285,14 @@ task :default => :test end def valid_const? - if camelized =~ /^\d/ - raise Error, "Invalid plugin name #{name}. Please give a name which does not start with numbers." + if original_name =~ /[^0-9a-zA-Z_]+/ + raise Error, "Invalid plugin name #{original_name}. Please give a name which use only alphabetic or numeric or \"_\" characters." + elsif camelized =~ /^\d/ + raise Error, "Invalid plugin name #{original_name}. Please give a name which does not start with numbers." elsif RESERVED_NAMES.include?(name) - raise Error, "Invalid plugin name #{name}. Please give a name which does not match one of the reserved rails words." + raise Error, "Invalid plugin name #{original_name}. Please give a name which does not match one of the reserved rails words." elsif Object.const_defined?(camelized) - raise Error, "Invalid plugin name #{name}, constant #{camelized} is already in use. Please choose another plugin name." + raise Error, "Invalid plugin name #{original_name}, constant #{camelized} is already in use. Please choose another plugin name." end end @@ -270,7 +302,7 @@ task :default => :test dummy_application_path = File.expand_path("#{dummy_path}/config/application.rb", destination_root) unless options[:pretend] || !File.exists?(dummy_application_path) contents = File.read(dummy_application_path) - contents[(contents.index("module Dummy"))..-1] + contents[(contents.index(/module ([\w]+)\n(.*)class Application/m))..-1] end end end @@ -301,6 +333,19 @@ end def mute(&block) shell.mute(&block) end + + def rails_app_path + APP_PATH.sub("/config/application", "") if defined?(APP_PATH) + end + + def inside_application? + rails_app_path && app_path =~ /^#{rails_app_path}/ + end + + def relative_path + return unless inside_application? + app_path.sub(/^#{rails_app_path}\//, '') + end end end end diff --git a/railties/lib/rails/generators/rails/plugin_new/templates/%name%.gemspec b/railties/lib/rails/generators/rails/plugin_new/templates/%name%.gemspec index 8588e88077..568ed653b7 100644 --- a/railties/lib/rails/generators/rails/plugin_new/templates/%name%.gemspec +++ b/railties/lib/rails/generators/rails/plugin_new/templates/%name%.gemspec @@ -13,7 +13,7 @@ Gem::Specification.new do |s| s.summary = "TODO: Summary of <%= camelized %>." s.description = "TODO: Description of <%= camelized %>." - s.files = Dir["{app,config,db,lib}/**/*"] + ["MIT-LICENSE", "Rakefile", "README.rdoc"] + s.files = Dir["{app,config,db,lib}/**/*", "MIT-LICENSE", "Rakefile", "README.rdoc"] <% unless options.skip_test_unit? -%> s.test_files = Dir["test/**/*"] <% end -%> @@ -22,6 +22,8 @@ Gem::Specification.new do |s| <% if full? && !options[:skip_javascript] -%> # s.add_dependency "<%= "#{options[:javascript]}-rails" %>" <% end -%> +<% unless options[:skip_active_record] -%> s.add_development_dependency "<%= gem_for_database %>" +<% end -%> end diff --git a/railties/lib/rails/generators/rails/plugin_new/templates/Gemfile b/railties/lib/rails/generators/rails/plugin_new/templates/Gemfile index f4efd3af74..7448b386c5 100644 --- a/railties/lib/rails/generators/rails/plugin_new/templates/Gemfile +++ b/railties/lib/rails/generators/rails/plugin_new/templates/Gemfile @@ -1,17 +1,32 @@ source "http://rubygems.org" +<% if options[:skip_gemspec] -%> +<%= '# ' if options.dev? || options.edge? -%>gem "rails", "~> <%= Rails::VERSION::STRING %>" +<% if full? && !options[:skip_javascript] -%> +# gem "<%= "#{options[:javascript]}-rails" %>" +<% end -%> +<% else -%> # Declare your gem's dependencies in <%= name %>.gemspec. # Bundler will treat runtime dependencies like base dependencies, and # development dependencies will be added by default to the :development group. gemspec +<% end -%> +<% unless options[:javascript] == 'jquery' -%> # jquery-rails is used by the dummy application gem "jquery-rails" +<% end -%> +<% if options[:skip_gemspec] -%> +group :development do + gem "<%= gem_for_database %>" +end +<% else -%> # Declare any dependencies that are still in development here instead of in # your gemspec. These might include edge Rails or gems from your path or # Git. Remember to move these dependencies to your gemspec before releasing # your gem to rubygems.org. +<% end -%> <% if options.dev? || options.edge? -%> # Your gem is dependent on dev or edge Rails. Once you can lock this @@ -20,4 +35,4 @@ gem "jquery-rails" <% end -%> # To use debugger -# <%= ruby_debugger_gemfile_entry %> +# gem 'debugger' diff --git a/railties/lib/rails/generators/rails/plugin_new/templates/Rakefile b/railties/lib/rails/generators/rails/plugin_new/templates/Rakefile index 6ed6adcf1b..1369140537 100755..100644 --- a/railties/lib/rails/generators/rails/plugin_new/templates/Rakefile +++ b/railties/lib/rails/generators/rails/plugin_new/templates/Rakefile @@ -1,16 +1,10 @@ -#!/usr/bin/env rake begin require 'bundler/setup' rescue LoadError puts 'You must `gem install bundler` and `bundle install` to run rake tasks' end -begin - require 'rdoc/task' -rescue LoadError - require 'rdoc/rdoc' - require 'rake/rdoctask' - RDoc::Task = Rake::RDocTask -end + +require 'rdoc/task' RDoc::Task.new(:rdoc) do |rdoc| rdoc.rdoc_dir = 'rdoc' @@ -20,7 +14,7 @@ RDoc::Task.new(:rdoc) do |rdoc| rdoc.rdoc_files.include('lib/**/*.rb') end -<% if full? && !options[:skip_active_record] -%> +<% if full? && !options[:skip_active_record] && !options[:skip_test_unit] -%> APP_RAKEFILE = File.expand_path("../<%= dummy_path -%>/Rakefile", __FILE__) load 'rails/tasks/engine.rake' <% end %> diff --git a/railties/lib/rails/generators/rails/plugin_new/templates/app/views/layouts/%name%/application.html.erb.tt b/railties/lib/rails/generators/rails/plugin_new/templates/app/views/layouts/%name%/application.html.erb.tt index 01550dec2f..bd983fb90f 100644 --- a/railties/lib/rails/generators/rails/plugin_new/templates/app/views/layouts/%name%/application.html.erb.tt +++ b/railties/lib/rails/generators/rails/plugin_new/templates/app/views/layouts/%name%/application.html.erb.tt @@ -2,7 +2,7 @@ <html> <head> <title><%= camelized %></title> - <%%= stylesheet_link_tag "<%= name %>/application" %> + <%%= stylesheet_link_tag "<%= name %>/application", :media => "all" %> <%%= javascript_include_tag "<%= name %>/application" %> <%%= csrf_meta_tags %> </head> diff --git a/railties/lib/rails/generators/rails/plugin_new/templates/gitignore b/railties/lib/rails/generators/rails/plugin_new/templates/gitignore index 1463de6dfb..086d87818a 100644 --- a/railties/lib/rails/generators/rails/plugin_new/templates/gitignore +++ b/railties/lib/rails/generators/rails/plugin_new/templates/gitignore @@ -1,6 +1,10 @@ .bundle/ log/*.log pkg/ -test/dummy/db/*.sqlite3 -test/dummy/log/*.log -test/dummy/tmp/
\ No newline at end of file +<% unless options[:skip_test_unit] && options[:dummy_path] == 'test/dummy' -%> +<%= dummy_path %>/db/*.sqlite3 +<%= dummy_path %>/db/*.sqlite3-journal +<%= dummy_path %>/log/*.log +<%= dummy_path %>/tmp/ +<%= dummy_path %>/.sass-cache +<% end -%>
\ No newline at end of file diff --git a/railties/lib/rails/generators/rails/plugin_new/templates/rails/application.rb b/railties/lib/rails/generators/rails/plugin_new/templates/rails/application.rb index 996ea79e67..2f9b7fc962 100644 --- a/railties/lib/rails/generators/rails/plugin_new/templates/rails/application.rb +++ b/railties/lib/rails/generators/rails/plugin_new/templates/rails/application.rb @@ -7,8 +7,7 @@ require 'rails/all' <%= comment_if :skip_active_record %>require "active_record/railtie" require "action_controller/railtie" require "action_mailer/railtie" -require "active_resource/railtie" -<%= comment_if :skip_sprockets %>require "sprockets/railtie" +<%= comment_if :skip_sprockets %>require "sprockets/rails/railtie" <%= comment_if :skip_test_unit %>require "rails/test_unit/railtie" <% end -%> diff --git a/railties/lib/rails/generators/rails/plugin_new/templates/rails/boot.rb b/railties/lib/rails/generators/rails/plugin_new/templates/rails/boot.rb index eba0681370..c78bfb7f63 100644 --- a/railties/lib/rails/generators/rails/plugin_new/templates/rails/boot.rb +++ b/railties/lib/rails/generators/rails/plugin_new/templates/rails/boot.rb @@ -1,4 +1,3 @@ -require 'rubygems' gemfile = File.expand_path('../../../../Gemfile', __FILE__) if File.exist?(gemfile) diff --git a/railties/lib/rails/generators/rails/plugin_new/templates/test/test_helper.rb b/railties/lib/rails/generators/rails/plugin_new/templates/test/test_helper.rb index dcd3b276e3..1e26a313cd 100644 --- a/railties/lib/rails/generators/rails/plugin_new/templates/test/test_helper.rb +++ b/railties/lib/rails/generators/rails/plugin_new/templates/test/test_helper.rb @@ -8,3 +8,8 @@ Rails.backtrace_cleaner.remove_silencers! # Load support files Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f } + +# Load fixtures from the engine +if ActiveSupport::TestCase.method_defined?(:fixture_path=) + ActiveSupport::TestCase.fixture_path = File.expand_path("../fixtures", __FILE__) +end diff --git a/railties/lib/rails/generators/rails/resource/resource_generator.rb b/railties/lib/rails/generators/rails/resource/resource_generator.rb index c7345f3cfb..3a0586ee43 100644 --- a/railties/lib/rails/generators/rails/resource/resource_generator.rb +++ b/railties/lib/rails/generators/rails/resource/resource_generator.rb @@ -14,13 +14,7 @@ module Rails class_option :actions, :type => :array, :banner => "ACTION ACTION", :default => [], :desc => "Actions for the resource controller" - def add_resource_route - return if options[:actions].present? - route_config = regular_class_path.collect{|namespace| "namespace :#{namespace} do " }.join(" ") - route_config << "resources :#{file_name.pluralize}" - route_config << " end" * regular_class_path.size - route route_config - end + hook_for :resource_route, :required => true end end end diff --git a/railties/lib/rails/generators/rails/resource_route/resource_route_generator.rb b/railties/lib/rails/generators/rails/resource_route/resource_route_generator.rb new file mode 100644 index 0000000000..6a5d62803c --- /dev/null +++ b/railties/lib/rails/generators/rails/resource_route/resource_route_generator.rb @@ -0,0 +1,13 @@ +module Rails + module Generators + class ResourceRouteGenerator < NamedBase + def add_resource_route + return if options[:actions].present? + route_config = regular_class_path.collect{ |namespace| "namespace :#{namespace} do " }.join(" ") + route_config << "resources :#{file_name.pluralize}" + route_config << " end" * regular_class_path.size + route route_config + end + end + end +end diff --git a/railties/lib/rails/generators/rails/scaffold/USAGE b/railties/lib/rails/generators/rails/scaffold/USAGE index be1d113ed8..4a3eb2c7c7 100644 --- a/railties/lib/rails/generators/rails/scaffold/USAGE +++ b/railties/lib/rails/generators/rails/scaffold/USAGE @@ -7,23 +7,29 @@ Description: under_scored, as the first argument, and an optional list of attribute pairs. - Attribute pairs are field:type arguments specifying the - model's attributes. Timestamps are added by default, so you don't have to - specify them by hand as 'created_at:datetime updated_at:datetime'. + Attributes are field arguments specifying the model's attributes. You can + optionally pass the type and an index to each field. For instance: + "title body:text tracking_id:integer:uniq" will generate a title field of + string type, a body with text type and a tracking_id as an integer with an + unique index. "index" could also be given instead of "uniq" if one desires + a non unique index. + + Timestamps are added by default, so you don't have to specify them by hand + as 'created_at:datetime updated_at:datetime'. You don't have to think up every attribute up front, but it helps to sketch out a few so you can start working with the resource immediately. - For example, 'scaffold post title:string body:text published:boolean' - gives you a model with those three attributes, a controller that handles + For example, 'scaffold post title body:text published:boolean' gives + you a model with those three attributes, a controller that handles the create/show/update/destroy, forms to create and edit your posts, and - an index that lists them all, as well as a resources :posts - declaration in config/routes.rb. + an index that lists them all, as well as a resources :posts declaration + in config/routes.rb. If you want to remove all the generated files, run 'rails destroy scaffold ModelName'. Examples: `rails generate scaffold post` - `rails generate scaffold post title:string body:text published:boolean` - `rails generate scaffold purchase order_id:integer amount:decimal` + `rails generate scaffold post title body:text published:boolean` + `rails generate scaffold purchase amount:decimal tracking_id:integer:uniq` diff --git a/railties/lib/rails/generators/rails/scaffold_controller/USAGE b/railties/lib/rails/generators/rails/scaffold_controller/USAGE index 673f69bc81..5cd51b62d4 100644 --- a/railties/lib/rails/generators/rails/scaffold_controller/USAGE +++ b/railties/lib/rails/generators/rails/scaffold_controller/USAGE @@ -1,8 +1,7 @@ Description: - Stubs out a scaffolded controller and its views. Pass the model name, - either CamelCased or under_scored, and a list of views as arguments. - The controller name is retrieved as a pluralized version of the model - name. + Stubs out a scaffolded controller, its seven RESTful actions and related + views. Pass the model name, either CamelCased or under_scored. The + controller name is retrieved as a pluralized version of the model name. To create a controller within a module, specify the model name as a path like 'parent_module/controller_name'. diff --git a/railties/lib/rails/generators/rails/scaffold_controller/scaffold_controller_generator.rb b/railties/lib/rails/generators/rails/scaffold_controller/scaffold_controller_generator.rb index 2271c6f9c1..0618b16984 100644 --- a/railties/lib/rails/generators/rails/scaffold_controller/scaffold_controller_generator.rb +++ b/railties/lib/rails/generators/rails/scaffold_controller/scaffold_controller_generator.rb @@ -11,7 +11,7 @@ module Rails :desc => "ORM to generate the controller for" def create_controller_files - template 'controller.rb', File.join('app/controllers', class_path, "#{controller_file_name}_controller.rb") + template "controller.rb", File.join('app/controllers', class_path, "#{controller_file_name}_controller.rb") end hook_for :template_engine, :test_framework, :as => :scaffold diff --git a/railties/lib/rails/generators/rails/scaffold_controller/templates/controller.rb b/railties/lib/rails/generators/rails/scaffold_controller/templates/controller.rb index 4ff15fd288..b3e74f9b02 100644 --- a/railties/lib/rails/generators/rails/scaffold_controller/templates/controller.rb +++ b/railties/lib/rails/generators/rails/scaffold_controller/templates/controller.rb @@ -1,3 +1,7 @@ +<% if namespaced? -%> +require_dependency "<%= namespaced_file_path %>/application_controller" + +<% end -%> <% module_namespacing do -%> class <%= controller_class_name %>Controller < ApplicationController # GET <%= route_url %> @@ -7,7 +11,7 @@ class <%= controller_class_name %>Controller < ApplicationController respond_to do |format| format.html # index.html.erb - format.json { render <%= key_value :json, "@#{plural_table_name}" %> } + format.json { render json: <%= "@#{plural_table_name}" %> } end end @@ -18,7 +22,7 @@ class <%= controller_class_name %>Controller < ApplicationController respond_to do |format| format.html # show.html.erb - format.json { render <%= key_value :json, "@#{singular_table_name}" %> } + format.json { render json: <%= "@#{singular_table_name}" %> } end end @@ -29,7 +33,7 @@ class <%= controller_class_name %>Controller < ApplicationController respond_to do |format| format.html # new.html.erb - format.json { render <%= key_value :json, "@#{singular_table_name}" %> } + format.json { render json: <%= "@#{singular_table_name}" %> } end end @@ -45,27 +49,27 @@ class <%= controller_class_name %>Controller < ApplicationController respond_to do |format| if @<%= orm_instance.save %> - format.html { redirect_to @<%= singular_table_name %>, <%= key_value :notice, "'#{human_name} was successfully created.'" %> } - format.json { render <%= key_value :json, "@#{singular_table_name}" %>, <%= key_value :status, ':created' %>, <%= key_value :location, "@#{singular_table_name}" %> } + format.html { redirect_to @<%= singular_table_name %>, notice: <%= "'#{human_name} was successfully created.'" %> } + format.json { render json: <%= "@#{singular_table_name}" %>, status: :created, location: <%= "@#{singular_table_name}" %> } else - format.html { render <%= key_value :action, '"new"' %> } - format.json { render <%= key_value :json, "@#{orm_instance.errors}" %>, <%= key_value :status, ':unprocessable_entity' %> } + format.html { render action: "new" } + format.json { render json: <%= "@#{orm_instance.errors}" %>, status: :unprocessable_entity } end end end - # PUT <%= route_url %>/1 - # PUT <%= route_url %>/1.json + # PATCH/PUT <%= route_url %>/1 + # PATCH/PUT <%= route_url %>/1.json def update @<%= singular_table_name %> = <%= orm_class.find(class_name, "params[:id]") %> respond_to do |format| if @<%= orm_instance.update_attributes("params[:#{singular_table_name}]") %> - format.html { redirect_to @<%= singular_table_name %>, <%= key_value :notice, "'#{human_name} was successfully updated.'" %> } + format.html { redirect_to @<%= singular_table_name %>, notice: <%= "'#{human_name} was successfully updated.'" %> } format.json { head :no_content } else - format.html { render <%= key_value :action, '"edit"' %> } - format.json { render <%= key_value :json, "@#{orm_instance.errors}" %>, <%= key_value :status, ':unprocessable_entity' %> } + format.html { render action: "edit" } + format.json { render json: <%= "@#{orm_instance.errors}" %>, status: :unprocessable_entity } end end end diff --git a/railties/lib/rails/generators/rails/task/USAGE b/railties/lib/rails/generators/rails/task/USAGE new file mode 100644 index 0000000000..dbe9bbaf08 --- /dev/null +++ b/railties/lib/rails/generators/rails/task/USAGE @@ -0,0 +1,9 @@ +Description: + Stubs out a new Rake task. Pass the namespace name, and a list of tasks as arguments. + + This generates a task file in lib/tasks. + +Example: + `rails generate task feeds fetch erase add` + + Task: lib/tasks/feeds.rake
\ No newline at end of file diff --git a/railties/lib/rails/generators/rails/task/task_generator.rb b/railties/lib/rails/generators/rails/task/task_generator.rb new file mode 100644 index 0000000000..8a62d9e8eb --- /dev/null +++ b/railties/lib/rails/generators/rails/task/task_generator.rb @@ -0,0 +1,12 @@ +module Rails + module Generators + class TaskGenerator < NamedBase + argument :actions, :type => :array, :default => [], :banner => "action action" + + def create_task_files + template 'task.rb', File.join('lib/tasks', "#{file_name}.rake") + end + + end + end +end diff --git a/railties/lib/rails/generators/rails/task/templates/task.rb b/railties/lib/rails/generators/rails/task/templates/task.rb new file mode 100644 index 0000000000..b7407bd6dc --- /dev/null +++ b/railties/lib/rails/generators/rails/task/templates/task.rb @@ -0,0 +1,8 @@ +namespace :<%= file_name %> do +<% actions.each do |action| -%> + desc "TODO" + task :<%= action %> => :environment do + end + +<% end -%> +end diff --git a/railties/lib/rails/generators/resource_helpers.rb b/railties/lib/rails/generators/resource_helpers.rb index b34bc4a524..48833869e5 100644 --- a/railties/lib/rails/generators/resource_helpers.rb +++ b/railties/lib/rails/generators/resource_helpers.rb @@ -50,7 +50,7 @@ module Rails end def controller_i18n_scope - @controller_i18n_scope ||= controller_file_path.gsub('/', '.') + @controller_i18n_scope ||= controller_file_path.tr('/', '.') end # Loads the ORM::Generators::ActiveModel class. This class is responsible @@ -64,7 +64,7 @@ module Rails end begin - "#{options[:orm].to_s.classify}::Generators::ActiveModel".constantize + "#{options[:orm].to_s.camelize}::Generators::ActiveModel".constantize rescue NameError Rails::Generators::ActiveModel end @@ -73,7 +73,7 @@ module Rails # Initialize ORM::Generators::ActiveModel to access instance methods. def orm_instance(name=singular_table_name) - @orm_instance ||= @orm_class.new(name) + @orm_instance ||= orm_class.new(name) end end end diff --git a/railties/lib/rails/generators/test_case.rb b/railties/lib/rails/generators/test_case.rb index 7319fb79f6..2ff340755a 100644 --- a/railties/lib/rails/generators/test_case.rb +++ b/railties/lib/rails/generators/test_case.rb @@ -31,15 +31,22 @@ module Rails include FileUtils class_attribute :destination_root, :current_path, :generator_class, :default_arguments - delegate :destination_root, :current_path, :generator_class, :default_arguments, :to => :'self.class' # Generators frequently change the current path using +FileUtils.cd+. # So we need to store the path at file load and revert back to it after each test. self.current_path = File.expand_path(Dir.pwd) self.default_arguments = [] - setup :destination_root_is_set?, :ensure_current_path - teardown :ensure_current_path + def setup + destination_root_is_set? + ensure_current_path + super + end + + def teardown + ensure_current_path + super + end # Sets which generator should be tested: # @@ -79,8 +86,8 @@ module Rails # # Finally, when a block is given, it yields the file content: # - # assert_file "app/controller/products_controller.rb" do |controller| - # assert_instance_method :index, content do |index| + # assert_file "app/controllers/products_controller.rb" do |controller| + # assert_instance_method :index, controller do |index| # assert_match(/Product\.all/, index) # end # end @@ -135,7 +142,7 @@ module Rails # Asserts a given migration does not exist. You need to supply an absolute path or a # path relative to the configured destination: # - # assert_no_file "config/random.rb" + # assert_no_migration "db/migrate/create_products.rb" # def assert_no_migration(relative) file_name = migration_file_name(relative) @@ -159,8 +166,8 @@ module Rails # Asserts the given method exists in the given content. When a block is given, # it yields the content of the method. # - # assert_file "app/controller/products_controller.rb" do |controller| - # assert_instance_method :index, content do |index| + # assert_file "app/controllers/products_controller.rb" do |controller| + # assert_instance_method :index, controller do |index| # assert_match(/Product\.all/, index) # end # end @@ -182,7 +189,7 @@ module Rails # Asserts the given attribute type gets a proper default value: # - # assert_field_type :string, "MyString" + # assert_field_default_value :string, "MyString" # def assert_field_default_value(attribute_type, value) assert_equal(value, create_generated_attribute(attribute_type).default) @@ -218,8 +225,8 @@ module Rails # # create_generated_attribute(:string, 'name') # - def create_generated_attribute(attribute_type, name = 'test') - Rails::Generators::GeneratedAttribute.new(name, attribute_type.to_s) + def create_generated_attribute(attribute_type, name = 'test', index = nil) + Rails::Generators::GeneratedAttribute.parse([name, attribute_type, index].compact.join(':')) end protected diff --git a/railties/lib/rails/generators/test_unit/performance/templates/performance_test.rb b/railties/lib/rails/generators/test_unit/performance/templates/performance_test.rb index d296b26b16..2f25dcf832 100644 --- a/railties/lib/rails/generators/test_unit/performance/templates/performance_test.rb +++ b/railties/lib/rails/generators/test_unit/performance/templates/performance_test.rb @@ -3,10 +3,10 @@ require 'rails/performance_test_help' class <%= class_name %>Test < ActionDispatch::PerformanceTest # Refer to the documentation for all available options - # self.profile_options = { :runs => 5, :metrics => [:wall_time, :memory] + # self.profile_options = { :runs => 5, :metrics => [:wall_time, :memory], # :output => 'tmp/performance', :formats => [:flat] } - def test_homepage + test "homepage" do get '/' end end diff --git a/railties/lib/rails/generators/test_unit/plugin/templates/test_helper.rb b/railties/lib/rails/generators/test_unit/plugin/templates/test_helper.rb index 2ca36a1e44..c9af2ca832 100644 --- a/railties/lib/rails/generators/test_unit/plugin/templates/test_helper.rb +++ b/railties/lib/rails/generators/test_unit/plugin/templates/test_helper.rb @@ -1,3 +1,2 @@ -require 'rubygems' -require 'test/unit' +require 'minitest/autorun' require 'active_support' diff --git a/railties/lib/rails/generators/test_unit/scaffold/scaffold_generator.rb b/railties/lib/rails/generators/test_unit/scaffold/scaffold_generator.rb index f7e907a017..ca7fee3b6e 100644 --- a/railties/lib/rails/generators/test_unit/scaffold/scaffold_generator.rb +++ b/railties/lib/rails/generators/test_unit/scaffold/scaffold_generator.rb @@ -8,10 +8,27 @@ module TestUnit check_class_collision :suffix => "ControllerTest" + argument :attributes, :type => :array, :default => [], :banner => "field:type field:type" + def create_test_files - template 'functional_test.rb', - File.join('test/functional', controller_class_path, "#{controller_file_name}_controller_test.rb") + template "functional_test.rb", + File.join("test/functional", controller_class_path, "#{controller_file_name}_controller_test.rb") end + + private + + def attributes_hash + return if accessible_attributes.empty? + + accessible_attributes.map do |a| + name = a.name + "#{name}: @#{singular_table_name}.#{name}" + end.sort.join(', ') + end + + def accessible_attributes + attributes.reject(&:reference?) + end end end end diff --git a/railties/lib/rails/generators/test_unit/scaffold/templates/functional_test.rb b/railties/lib/rails/generators/test_unit/scaffold/templates/functional_test.rb index 9ec2e34545..30e1650555 100644 --- a/railties/lib/rails/generators/test_unit/scaffold/templates/functional_test.rb +++ b/railties/lib/rails/generators/test_unit/scaffold/templates/functional_test.rb @@ -19,30 +19,30 @@ class <%= controller_class_name %>ControllerTest < ActionController::TestCase test "should create <%= singular_table_name %>" do assert_difference('<%= class_name %>.count') do - post :create, <%= key_value singular_table_name, "@#{singular_table_name}.attributes" %> + post :create, <%= "#{singular_table_name}: { #{attributes_hash} }" %> end assert_redirected_to <%= singular_table_name %>_path(assigns(:<%= singular_table_name %>)) end test "should show <%= singular_table_name %>" do - get :show, <%= key_value :id, "@#{singular_table_name}" %> + get :show, id: <%= "@#{singular_table_name}" %> assert_response :success end test "should get edit" do - get :edit, <%= key_value :id, "@#{singular_table_name}" %> + get :edit, id: <%= "@#{singular_table_name}" %> assert_response :success end test "should update <%= singular_table_name %>" do - put :update, <%= key_value :id, "@#{singular_table_name}" %>, <%= key_value singular_table_name, "@#{singular_table_name}.attributes" %> + put :update, id: <%= "@#{singular_table_name}" %>, <%= "#{singular_table_name}: { #{attributes_hash} }" %> assert_redirected_to <%= singular_table_name %>_path(assigns(:<%= singular_table_name %>)) end test "should destroy <%= singular_table_name %>" do assert_difference('<%= class_name %>.count', -1) do - delete :destroy, <%= key_value :id, "@#{singular_table_name}" %> + delete :destroy, id: <%= "@#{singular_table_name}" %> end assert_redirected_to <%= index_helper %>_path diff --git a/railties/lib/rails/info.rb b/railties/lib/rails/info.rb index a1e15092b2..aacc1be2fc 100644 --- a/railties/lib/rails/info.rb +++ b/railties/lib/rails/info.rb @@ -23,7 +23,7 @@ module Rails end def frameworks - %w( active_record action_pack active_resource action_mailer active_support ) + %w( active_record action_pack action_mailer active_support ) end def framework_version(framework) @@ -83,7 +83,7 @@ module Rails end # Versions of each Rails framework (Active Record, Action Pack, - # Active Resource, Action Mailer, and Active Support). + # Action Mailer, and Active Support). frameworks.each do |framework| property "#{framework.titlecase} version" do framework_version(framework) diff --git a/railties/lib/rails/info_controller.rb b/railties/lib/rails/info_controller.rb index 6b4bdb2921..512803aeac 100644 --- a/railties/lib/rails/info_controller.rb +++ b/railties/lib/rails/info_controller.rb @@ -1,15 +1,33 @@ +require 'action_dispatch/routing/inspector' + class Rails::InfoController < ActionController::Base + self.view_paths = File.join(File.dirname(__FILE__), 'templates') + layout 'application' + + before_filter :require_local! + + def index + redirect_to '/rails/info/routes' + end + def properties - if consider_all_requests_local? || request.local? - render :inline => Rails::Info.to_html - else - render :text => '<p>For security purposes, this information is only available to local requests.</p>', :status => :forbidden - end + @info = Rails::Info.to_html + end + + def routes + inspector = ActionDispatch::Routing::RoutesInspector.new + @info = inspector.format(_routes.routes).join("\n") end protected - def consider_all_requests_local? - Rails.application.config.consider_all_requests_local + def require_local! + unless local_request? + render :text => '<p>For security purposes, this information is only available to local requests.</p>', :status => :forbidden + end + end + + def local_request? + Rails.application.config.consider_all_requests_local || request.local? end end diff --git a/railties/lib/rails/initializable.rb b/railties/lib/rails/initializable.rb index 04d5b55c69..1a0b6d1e1a 100644 --- a/railties/lib/rails/initializable.rb +++ b/railties/lib/rails/initializable.rb @@ -2,7 +2,7 @@ require 'tsort' module Rails module Initializable - def self.included(base) + def self.included(base) #:nodoc: base.extend ClassMethods end @@ -51,7 +51,7 @@ module Rails def run_initializers(group=:default, *args) return if instance_variable_defined?(:@ran) - initializers.tsort.each do |initializer| + initializers.tsort_each do |initializer| initializer.run(*args) if initializer.belongs_to?(group) end @ran = true diff --git a/railties/lib/rails/paths.rb b/railties/lib/rails/paths.rb index b37421c09c..3c2210aaf9 100644 --- a/railties/lib/rails/paths.rb +++ b/railties/lib/rails/paths.rb @@ -1,5 +1,3 @@ -require 'set' - module Rails module Paths # This object is an extended hash that behaves as root of the <tt>Rails::Paths</tt> system. @@ -10,19 +8,19 @@ module Rails # root.add "app/controllers", :eager_load => true # # The command above creates a new root object and add "app/controllers" as a path. - # This means we can get a +Rails::Paths::Path+ object back like below: + # This means we can get a <tt>Rails::Paths::Path</tt> object back like below: # # path = root["app/controllers"] # path.eager_load? # => true # path.is_a?(Rails::Paths::Path) # => true # - # The +Path+ object is simply an array and allows you to easily add extra paths: + # The +Path+ object is simply an enumerable and allows you to easily add extra paths: # - # path.is_a?(Array) # => true - # path.inspect # => ["app/controllers"] + # path.is_a?(Enumerable) # => true + # path.to_ary.inspect # => ["app/controllers"] # # path << "lib/controllers" - # path.inspect # => ["app/controllers", "lib/controllers"] + # path.to_ary.inspect # => ["app/controllers", "lib/controllers"] # # Notice that when you add a path using +add+, the path object created already # contains the path with the same path value given to +add+. In some situations, @@ -43,25 +41,39 @@ module Rails # root["app/controllers"].existent # => ["/rails/app/controllers"] # # Check the <tt>Rails::Paths::Path</tt> documentation for more information. - class Root < ::Hash + class Root attr_accessor :path def initialize(path) - raise "Argument should be a String of the physical root path" if path.is_a?(Array) @current = nil @path = path - @root = self - super() + @root = {} end def []=(path, value) - value = Path.new(self, path, value) unless value.is_a?(Path) - super(path, value) + glob = self[path] ? self[path].glob : nil + add(path, :with => value, :glob => glob) end def add(path, options={}) with = options[:with] || path - self[path] = Path.new(self, path, with, options) + @root[path] = Path.new(self, path, [with].flatten, options) + end + + def [](path) + @root[path] + end + + def values + @root.values + end + + def keys + @root.keys + end + + def values_at(*list) + @root.values_at(*list) end def all_paths @@ -100,14 +112,14 @@ module Rails end end - class Path < Array + class Path + include Enumerable + attr_reader :path attr_accessor :glob - def initialize(root, current, *paths) - options = paths.last.is_a?(::Hash) ? paths.pop : {} - super(paths.flatten) - + def initialize(root, current, paths, options = {}) + @paths = paths @current = current @root = root @glob = options[:glob] @@ -148,6 +160,27 @@ module Rails RUBY end + def each(&block) + @paths.each(&block) + end + + def <<(path) + @paths << path + end + alias :push :<< + + def concat(paths) + @paths.concat paths + end + + def unshift(path) + @paths.unshift path + end + + def to_ary + @paths + end + # Expands all paths against the root and return all unique values. def expanded raise "You need to set a path root" unless @root.path @@ -156,8 +189,10 @@ module Rails each do |p| path = File.expand_path(p, @root.path) - if @glob - result.concat Dir[File.join(path, @glob)].sort + if @glob && File.directory?(path) + result.concat Dir.chdir(path) { + Dir.glob(@glob).map { |file| File.join path, file }.sort + } else result << path end diff --git a/railties/lib/rails/performance_test_help.rb b/railties/lib/rails/performance_test_help.rb index 4ac38981d0..b1285efde2 100644 --- a/railties/lib/rails/performance_test_help.rb +++ b/railties/lib/rails/performance_test_help.rb @@ -1,3 +1,3 @@ ActionController::Base.perform_caching = true ActiveSupport::Dependencies.mechanism = :require -Rails.logger.level = ActiveSupport::BufferedLogger::INFO +Rails.logger.level = ActiveSupport::Logger::INFO diff --git a/railties/lib/rails/plugin.rb b/railties/lib/rails/plugin.rb deleted file mode 100644 index 3e27688bb9..0000000000 --- a/railties/lib/rails/plugin.rb +++ /dev/null @@ -1,91 +0,0 @@ -require 'rails/engine' -require 'active_support/core_ext/array/conversions' - -module Rails - # Rails::Plugin is nothing more than a Rails::Engine, but since it's loaded too late - # in the boot process, it does not have the same configuration powers as a bare - # Rails::Engine. - # - # Opposite to Rails::Railtie and Rails::Engine, you are not supposed to inherit from - # Rails::Plugin. Rails::Plugin is automatically configured to be an engine by simply - # placing inside vendor/plugins. Since this is done automatically, you actually cannot - # declare a Rails::Engine inside your Plugin, otherwise it would cause the same files - # to be loaded twice. This means that if you want to ship an Engine as gem it cannot - # be used as plugin and vice-versa. - # - # Besides this conceptual difference, the only difference between Rails::Engine and - # Rails::Plugin is that plugins automatically load the file "init.rb" at the plugin - # root during the boot process. - # - class Plugin < Engine - def self.global_plugins - @global_plugins ||= [] - end - - def self.inherited(base) - raise "You cannot inherit from Rails::Plugin" - end - - def self.all(list, paths) - plugins = [] - paths.each do |path| - Dir["#{path}/*"].each do |plugin_path| - plugin = new(plugin_path) - next unless list.include?(plugin.name) || list.include?(:all) - if global_plugins.include?(plugin.name) - warn "WARNING: plugin #{plugin.name} from #{path} was not loaded. Plugin with the same name has been already loaded." - next - end - global_plugins << plugin.name - plugins << plugin - end - end - - plugins.sort_by do |p| - [list.index(p.name) || list.index(:all), p.name.to_s] - end - end - - attr_reader :name, :path - - def railtie_name - name.to_s - end - - def initialize(root) - @name = File.basename(root).to_sym - config.root = root - end - - def config - @config ||= Engine::Configuration.new - end - - initializer :handle_lib_autoload, :before => :set_load_path do |app| - autoload = if app.config.reload_plugins - config.autoload_paths - else - config.autoload_once_paths - end - - autoload.concat paths["lib"].existent - end - - initializer :load_init_rb, :before => :load_config_initializers do |app| - init_rb = File.expand_path("init.rb", root) - if File.file?(init_rb) - # This double assignment is to prevent an "unused variable" warning on Ruby 1.9.3. - config = config = app.config - # TODO: think about evaling initrb in context of Engine (currently it's - # always evaled in context of Rails::Application) - eval(File.read(init_rb), binding, init_rb) - end - end - - initializer :sanity_check_railties_collision do - if Engine.subclasses.map { |k| k.root.to_s }.include?(root.to_s) - raise "\"#{name}\" is a Railtie/Engine and cannot be installed as a plugin" - end - end - end -end diff --git a/railties/lib/rails/queueing.rb b/railties/lib/rails/queueing.rb new file mode 100644 index 0000000000..baf6811d3e --- /dev/null +++ b/railties/lib/rails/queueing.rb @@ -0,0 +1,107 @@ +require "thread" +require 'delegate' + +module Rails + module Queueing + # A container for multiple queues. This class delegates to a default Queue + # so that <tt>Rails.queue.push</tt> and friends will Just Work. To use this class + # with multiple queues: + # + # # In your configuration: + # Rails.queue[:image_queue] = SomeQueue.new + # Rails.queue[:mail_queue] = SomeQueue.new + # + # # In your app code: + # Rails.queue[:mail_queue].push SomeJob.new + # + class Container < DelegateClass(::Queue) + def initialize(default_queue) + @queues = { :default => default_queue } + super(default_queue) + end + + def [](queue_name) + @queues[queue_name] + end + + def []=(queue_name, queue) + @queues[queue_name] = queue + end + end + + # A Queue that simply inherits from STDLIB's Queue. Everytime this + # queue is used, Rails automatically sets up a ThreadedConsumer + # to consume it. + class Queue < ::Queue + end + + # In test mode, the Rails queue is backed by an Array so that assertions + # can be made about its contents. The test queue provides a +jobs+ + # method to make assertions about the queue's contents and a +drain+ + # method to drain the queue and run the jobs. + # + # Jobs are run in a separate thread to catch mistakes where code + # assumes that the job is run in the same thread. + class TestQueue < ::Queue + # Get a list of the jobs off this queue. This method may not be + # available on production queues. + def jobs + @que.dup + end + + # Marshal and unmarshal job before pushing it onto the queue. This will + # raise an exception on any attempts in tests to push jobs that can't (or + # shouldn't) be marshalled. + def push(job) + super Marshal.load(Marshal.dump(job)) + end + + # Drain the queue, running all jobs in a different thread. This method + # may not be available on production queues. + def drain + # run the jobs in a separate thread so assumptions of synchronous + # jobs are caught in test mode. + Thread.new { pop.run until empty? }.join + end + end + + # The threaded consumer will run jobs in a background thread in + # development mode or in a VM where running jobs on a thread in + # production mode makes sense. + # + # When the process exits, the consumer pushes a nil onto the + # queue and joins the thread, which will ensure that all jobs + # are executed before the process finally dies. + class ThreadedConsumer + def self.start(queue) + new(queue).start + end + + def initialize(queue) + @queue = queue + end + + def start + @thread = Thread.new do + while job = @queue.pop + begin + job.run + rescue Exception => e + handle_exception e + end + end + end + self + end + + def shutdown + @queue.push nil + @thread.join + end + + def handle_exception(e) + Rails.logger.error "Job Error: #{e.message}\n#{e.backtrace.join("\n")}" + end + end + end +end diff --git a/railties/lib/rails/rack/debugger.rb b/railties/lib/rails/rack/debugger.rb index 831188eeee..902361ce77 100644 --- a/railties/lib/rails/rack/debugger.rb +++ b/railties/lib/rails/rack/debugger.rb @@ -6,13 +6,13 @@ module Rails ARGV.clear # clear ARGV so that rails server options aren't passed to IRB - require 'ruby-debug' + require 'debugger' ::Debugger.start ::Debugger.settings[:autoeval] = true if ::Debugger.respond_to?(:settings) puts "=> Debugger enabled" rescue LoadError - puts "You need to install ruby-debug to run the server in debugging mode. With gems, use 'gem install ruby-debug'" + puts "You're missing the 'debugger' gem. Add it to your Gemfile, bundle, and try again." exit end diff --git a/railties/lib/rails/rack/log_tailer.rb b/railties/lib/rails/rack/log_tailer.rb index 830d840894..18f22e8089 100644 --- a/railties/lib/rails/rack/log_tailer.rb +++ b/railties/lib/rails/rack/log_tailer.rb @@ -4,10 +4,13 @@ module Rails def initialize(app, log = nil) @app = app - path = Pathname.new(log || "#{File.expand_path(Rails.root)}/log/#{Rails.env}.log").cleanpath - @cursor = ::File.size(path) + path = Pathname.new(log || "#{::File.expand_path(Rails.root)}/log/#{Rails.env}.log").cleanpath - @file = ::File.open(path, 'r') + @cursor = @file = nil + if ::File.exists?(path) + @cursor = ::File.size(path) + @file = ::File.open(path, 'r') + end end def call(env) @@ -17,6 +20,7 @@ module Rails end def tail! + return unless @cursor @file.seek @cursor unless @file.eof? diff --git a/railties/lib/rails/railtie.rb b/railties/lib/rails/railtie.rb index e8fb1f3d98..fba685c769 100644 --- a/railties/lib/rails/railtie.rb +++ b/railties/lib/rails/railtie.rb @@ -9,7 +9,7 @@ module Rails # Rails and/or modify the initialization process. # # Every major component of Rails (Action Mailer, Action Controller, - # Action View, Active Record and Active Resource) is a Railtie. Each of + # Action View and Active Record) is a Railtie. Each of # them is responsible for their own initialization. This makes Rails itself # absent of any component hooks, allowing other components to be used in # place of any of the Rails defaults. @@ -22,7 +22,7 @@ module Rails # # * creating initializers # * configuring a Rails framework for the application, like setting a generator - # * adding config.* keys to the environment + # * +adding config.*+ keys to the environment # * setting up a subscriber with ActiveSupport::Notifications # * adding rake tasks # @@ -103,11 +103,11 @@ module Rails # end # end # - # == Application, Plugin and Engine + # == Application and Engine # # A Rails::Engine is nothing more than a Railtie with some initializers already set. - # And since Rails::Application and Rails::Plugin are engines, the same configuration - # described here can be used in all three. + # And since Rails::Application is an engine, the same configuration described here + # can be used in both. # # Be sure to look at the documentation of those specific classes for more information. # @@ -117,7 +117,7 @@ module Rails include Initializable - ABSTRACT_RAILTIES = %w(Rails::Railtie Rails::Plugin Rails::Engine Rails::Application) + ABSTRACT_RAILTIES = %w(Rails::Railtie Rails::Engine Rails::Application) class << self private :new @@ -145,6 +145,12 @@ module Rails @load_console end + def runner(&blk) + @load_runner ||= [] + @load_runner << blk if blk + @load_runner + end + def generators(&blk) @generators ||= [] @generators << blk if blk @@ -162,7 +168,7 @@ module Rails protected def generate_railtie_name(class_or_module) - ActiveSupport::Inflector.underscore(class_or_module).gsub("/", "_") + ActiveSupport::Inflector.underscore(class_or_module).tr("/", "_") end end @@ -172,31 +178,35 @@ module Rails @config ||= Railtie::Configuration.new end - def eager_load! + def railtie_namespace + @railtie_namespace ||= self.class.parents.detect { |n| n.respond_to?(:railtie_namespace) } end - def load_console(app=self) + protected + + def run_console_blocks(app) #:nodoc: self.class.console.each { |block| block.call(app) } end - def load_tasks(app=self) - extend Rake::DSL if defined? Rake::DSL - self.class.rake_tasks.each { |block| block.call(app) } + def run_generators_blocks(app) #:nodoc: + self.class.generators.each { |block| block.call(app) } + end + + def run_runner_blocks(app) #:nodoc: + self.class.runner.each { |block| block.call(app) } + end + + def run_tasks_blocks(app) #:nodoc: + extend Rake::DSL + self.class.rake_tasks.each { |block| instance_exec(app, &block) } - # load also tasks from all superclasses + # Load also tasks from all superclasses klass = self.class.superclass + while klass.respond_to?(:rake_tasks) - klass.rake_tasks.each { |t| self.instance_exec(app, &t) } + klass.rake_tasks.each { |t| instance_exec(app, &t) } klass = klass.superclass end end - - def load_generators(app=self) - self.class.generators.each { |block| block.call(app) } - end - - def railtie_namespace - @railtie_namespace ||= self.class.parents.detect { |n| n.respond_to?(:_railtie) } - end end end diff --git a/railties/lib/rails/railtie/configuration.rb b/railties/lib/rails/railtie/configuration.rb index f888684117..9dc8843887 100644 --- a/railties/lib/rails/railtie/configuration.rb +++ b/railties/lib/rails/railtie/configuration.rb @@ -7,6 +7,28 @@ module Rails @@options ||= {} end + # Expose the eager_load_namespaces at "module" level for convenience. + def self.eager_load_namespaces #:nodoc: + @@eager_load_namespaces ||= [] + end + + # All namespaces that are eager loaded + def eager_load_namespaces + @@eager_load_namespaces ||= [] + end + + # Add files that should be watched for change. + def watchable_files + @@watchable_files ||= [] + end + + # Add directories that should be watched for change. + # The key of the hashes should be directories and the values should + # be an array of extensions to match in each directory. + def watchable_dirs + @@watchable_dirs ||= {} + end + # This allows you to modify the application's middlewares from Engines. # # All operations you run on the app_middleware will be replayed on the @@ -31,7 +53,7 @@ module Rails ActiveSupport.on_load(:before_configuration, :yield => true, &block) end - # Third configurable block to run. Does not run if config.cache_classes + # Third configurable block to run. Does not run if +config.cache_classes+ # set to false. def before_eager_load(&block) ActiveSupport.on_load(:before_eager_load, :yield => true, &block) diff --git a/railties/lib/rails/ruby_version_check.rb b/railties/lib/rails/ruby_version_check.rb index 4d57c5973c..4536fedaa3 100644 --- a/railties/lib/rails/ruby_version_check.rb +++ b/railties/lib/rails/ruby_version_check.rb @@ -1,8 +1,8 @@ -if RUBY_VERSION < '1.8.7' +if RUBY_VERSION < '1.9.3' desc = defined?(RUBY_DESCRIPTION) ? RUBY_DESCRIPTION : "ruby #{RUBY_VERSION} (#{RUBY_RELEASE_DATE})" abort <<-end_message - Rails 3 requires Ruby 1.8.7 or 1.9.2. + Rails 4 requires Ruby 1.9.3+. You're running #{desc} @@ -10,14 +10,4 @@ if RUBY_VERSION < '1.8.7' Please upgrade to continue. end_message -elsif RUBY_VERSION > '1.9' and RUBY_VERSION < '1.9.2' - $stderr.puts <<-end_message - - Rails 3 doesn't officially support Ruby 1.9.1 since recent stable - releases have segfaulted the test suite. Please upgrade to Ruby 1.9.2. - - You're running - #{RUBY_DESCRIPTION} - - end_message end diff --git a/railties/lib/rails/rubyprof_ext.rb b/railties/lib/rails/rubyprof_ext.rb index f6e90357ce..017eba3a76 100644 --- a/railties/lib/rails/rubyprof_ext.rb +++ b/railties/lib/rails/rubyprof_ext.rb @@ -12,7 +12,7 @@ module Prof #:nodoc: io.puts " time seconds seconds calls ms/call ms/call name" sum = 0.0 - for r in results + results.each do |r| sum += r.self_time name = if r.method_class.nil? diff --git a/railties/lib/rails/source_annotation_extractor.rb b/railties/lib/rails/source_annotation_extractor.rb index 1eed763aa3..31e34023c0 100644 --- a/railties/lib/rails/source_annotation_extractor.rb +++ b/railties/lib/rails/source_annotation_extractor.rb @@ -14,6 +14,9 @@ # of the line (or closing ERB comment tag) is considered to be their text. class SourceAnnotationExtractor class Annotation < Struct.new(:line, :tag, :text) + def self.directories + @@directories ||= %w(app config lib script test) + (ENV['SOURCE_ANNOTATION_DIRECTORIES'] || '').split(',') + end # Returns a representation of the annotation that looks like this: # @@ -22,7 +25,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={}) - s = "[%3d] " % line + s = "[#{line.to_s.rjust(options[:indent])}] " s << "[#{tag}] " if options[:tag] s << text end @@ -30,8 +33,9 @@ class SourceAnnotationExtractor # Prints all annotations with tag +tag+ under the root directories +app+, +config+, +lib+, # +script+, and +test+ (recursively). Only filenames with extension - # +.builder+, +.rb+, +.rxml+, +.rhtml+, or +.erb+ are taken into account. The +options+ - # hash is passed to each annotation's +to_s+. + # +.builder+, +.rb+, +.erb+, +.haml+, +.slim+, +.css+, +.scss+, +.js+, and + # +.coffee+ are taken into account. The +options+ hash is passed to each + # annotation's +to_s+. # # This class method is the single entry point for the rake tasks. def self.enumerate(tag, options={}) @@ -46,16 +50,15 @@ class SourceAnnotationExtractor end # Returns a hash that maps filenames under +dirs+ (recursively) to arrays - # with their annotations. Only files with annotations are included, and only - # those with extension +.builder+, +.rb+, +.rxml+, +.rhtml+, and +.erb+ - # are taken into account. - def find(dirs=%w(app config lib script test)) + # with their annotations. + def find(dirs = Annotation.directories) dirs.inject({}) { |h, dir| h.update(find_in(dir)) } end # Returns a hash that maps filenames under +dir+ (recursively) to arrays # with their annotations. Only files with annotations are included, and only - # those with extension +.builder+, +.rb+, +.rxml+, +.rhtml+, and +.erb+ + # those with extension +.builder+, +.rb+, +.erb+, +.haml+, +.slim+, +.css+, + # +.scss+, +.js+, and +.coffee+ # are taken into account. def find_in(dir) results = {} @@ -65,10 +68,16 @@ class SourceAnnotationExtractor if File.directory?(item) results.update(find_in(item)) - elsif item =~ /\.(builder|(r(?:b|xml|js)))$/ + elsif item =~ /\.(builder|rb|coffee)$/ results.update(extract_annotations_from(item, /#\s*(#{tag}):?\s*(.*)$/)) - elsif item =~ /\.(rhtml|erb)$/ + elsif item =~ /\.(css|scss|js)$/ + results.update(extract_annotations_from(item, /\/\/\s*(#{tag}):?\s*(.*)$/)) + elsif item =~ /\.erb$/ results.update(extract_annotations_from(item, /<%\s*#\s*(#{tag}):?\s*(.*?)\s*%>/)) + elsif item =~ /\.haml$/ + results.update(extract_annotations_from(item, /-\s*#\s*(#{tag}):?\s*(.*)$/)) + elsif item =~ /\.slim$/ + results.update(extract_annotations_from(item, /\/\s*\s*(#{tag}):?\s*(.*)$/)) end end @@ -91,6 +100,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={}) + options[:indent] = results.map { |f, a| a.map(&:line) }.flatten.max.to_s.size results.keys.sort.each do |file| puts "#{file}:" results[file].each do |note| diff --git a/railties/lib/rails/tasks/documentation.rake b/railties/lib/rails/tasks/documentation.rake index 2072a2b947..2851ca4189 100644 --- a/railties/lib/rails/tasks/documentation.rake +++ b/railties/lib/rails/tasks/documentation.rake @@ -1,10 +1,4 @@ -begin - require 'rdoc/task' -rescue LoadError - require 'rdoc/rdoc' - require 'rake/rdoctask' - RDoc::Task = Rake::RDocTask -end +require 'rdoc/task' # Monkey-patch to remove redoc'ing and clobber descriptions to cut down on rake -T noise class RDocTaskWithoutDescriptions < RDoc::Task @@ -55,7 +49,7 @@ namespace :doc do rdoc.rdoc_files.include('app/**/*.rb') rdoc.rdoc_files.include('lib/**/*.rb') } - Rake::Task['doc:app'].comment = "Generate docs for the app -- also available doc:rails, doc:guides, doc:plugins (options: TEMPLATE=/rdoc-template.rb, TITLE=\"Custom Title\")" + Rake::Task['doc:app'].comment = "Generate docs for the app -- also available doc:rails, doc:guides (options: TEMPLATE=/rdoc-template.rb, TITLE=\"Custom Title\")" # desc 'Generate documentation for the Rails framework.' RDocTaskWithoutDescriptions.new("rails") { |rdoc| @@ -63,7 +57,7 @@ namespace :doc do rdoc.template = "#{ENV['template']}.rb" if ENV['template'] rdoc.title = "Rails Framework Documentation" rdoc.options << '--line-numbers' - rdoc.rdoc_files.include('README') + rdoc.rdoc_files.include('README.rdoc') gem_path('actionmailer') do |actionmailer| %w(README.rdoc CHANGELOG.md MIT-LICENSE lib/action_mailer/base.rb).each do |file| @@ -89,67 +83,23 @@ namespace :doc do end end - gem_path('activeresource') do |activeresource| - %w(README.rdoc CHANGELOG.md lib/active_resource.rb lib/active_resource/*).each do |file| - rdoc.rdoc_files.include("#{activeresource}/#{file}") - end - end - gem_path('activesupport') do |activesupport| - %w(README.rdoc CHANGELOG lib/active_support/**/*.rb).each do |file| + %w(README.rdoc CHANGELOG.md lib/active_support/**/*.rb).each do |file| rdoc.rdoc_files.include("#{activesupport}/#{file}") end end gem_path('railties') do |railties| - %w(README.rdoc CHANGELOG lib/{*.rb,commands/*.rb,generators/*.rb}).each do |file| + %w(README.rdoc CHANGELOG.md lib/{*.rb,commands/*.rb,generators/*.rb}).each do |file| rdoc.rdoc_files.include("#{railties}/#{file}") end end } - plugins = FileList['vendor/plugins/**'].collect { |plugin| File.basename(plugin) } - - # desc "Generate documentation for all installed plugins" - task :plugins => plugins.collect { |plugin| "doc:plugins:#{plugin}" } - - # desc "Remove plugin documentation" - task :clobber_plugins do - rm_rf 'doc/plugins' rescue nil - end - # desc "Generate Rails Guides" task :guides do # FIXME: Reaching outside lib directory is a bad idea require File.expand_path('../../../../guides/rails_guides', __FILE__) RailsGuides::Generator.new(Rails.root.join("doc/guides")).generate end - - namespace :plugins do - # Define doc tasks for each plugin - plugins.each do |plugin| - # desc "Generate documentation for the #{plugin} plugin" - task(plugin => :environment) do - plugin_base = "vendor/plugins/#{plugin}" - options = [] - files = Rake::FileList.new - options << "-o doc/plugins/#{plugin}" - options << "--title '#{plugin.titlecase} Plugin Documentation'" - options << '--line-numbers' - options << '--charset' << 'utf-8' - options << '-T html' - - files.include("#{plugin_base}/lib/**/*.rb") - if File.exist?("#{plugin_base}/README") - files.include("#{plugin_base}/README") - options << "--main '#{plugin_base}/README'" - end - files.include("#{plugin_base}/CHANGELOG") if File.exist?("#{plugin_base}/CHANGELOG") - - options << files.to_s - - sh %(rdoc #{options * ' '}) - end - end - end end diff --git a/railties/lib/rails/tasks/engine.rake b/railties/lib/rails/tasks/engine.rake index eea8abe7d2..70370be3f5 100644 --- a/railties/lib/rails/tasks/engine.rake +++ b/railties/lib/rails/tasks/engine.rake @@ -60,7 +60,7 @@ namespace :db do end def find_engine_path(path) - return if path == "/" + return File.expand_path(Dir.pwd) if path == "/" if Rails::Engine.find(path) path diff --git a/railties/lib/rails/tasks/framework.rake b/railties/lib/rails/tasks/framework.rake index 206ce39773..f9cff5b627 100644 --- a/railties/lib/rails/tasks/framework.rake +++ b/railties/lib/rails/tasks/framework.rake @@ -20,7 +20,7 @@ namespace :rails do project_templates = "#{Rails.root}/lib/templates" default_templates = { "erb" => %w{controller mailer scaffold}, - "rails" => %w{controller helper scaffold_controller stylesheets} } + "rails" => %w{controller helper scaffold_controller assets} } default_templates.each do |type, names| local_template_type_dir = File.join(project_templates, type) diff --git a/railties/lib/rails/tasks/misc.rake b/railties/lib/rails/tasks/misc.rake index 0dcca36d8b..0a9b9ff4ff 100644 --- a/railties/lib/rails/tasks/misc.rake +++ b/railties/lib/rails/tasks/misc.rake @@ -1,10 +1,3 @@ -task :rails_env do - # TODO Do we really need this? - unless defined? RAILS_ENV - RAILS_ENV = ENV['RAILS_ENV'] ||= 'development' - end -end - desc 'Generate a cryptographically secure secret key (this is typically used to generate a secret for cookie sessions).' task :secret do require 'securerandom' diff --git a/railties/lib/rails/tasks/routes.rake b/railties/lib/rails/tasks/routes.rake index 7dc54144da..95f47566ef 100644 --- a/railties/lib/rails/tasks/routes.rake +++ b/railties/lib/rails/tasks/routes.rake @@ -1,9 +1,7 @@ desc 'Print out all defined routes in match order, with names. Target specific controller with CONTROLLER=x.' task :routes => :environment do - Rails.application.reload_routes! all_routes = Rails.application.routes.routes - - require 'rails/application/route_inspector' - inspector = Rails::Application::RouteInspector.new + require 'action_dispatch/routing/inspector' + inspector = ActionDispatch::Routing::RoutesInspector.new puts inspector.format(all_routes, ENV['CONTROLLER']).join "\n" end diff --git a/railties/lib/rails/tasks/statistics.rake b/railties/lib/rails/tasks/statistics.rake index 40f8c1034a..67a6d2d2ac 100644 --- a/railties/lib/rails/tasks/statistics.rake +++ b/railties/lib/rails/tasks/statistics.rake @@ -2,6 +2,8 @@ STATS_DIRECTORIES = [ %w(Controllers app/controllers), %w(Helpers app/helpers), %w(Models app/models), + %w(Mailers app/mailers), + %w(Javascripts app/assets/javascripts), %w(Libraries lib/), %w(APIs app/apis), %w(Integration\ tests test/integration), diff --git a/railties/lib/rails/tasks/tmp.rake b/railties/lib/rails/tasks/tmp.rake index 0d6c10328f..0968765b4f 100644 --- a/railties/lib/rails/tasks/tmp.rake +++ b/railties/lib/rails/tasks/tmp.rake @@ -2,10 +2,16 @@ namespace :tmp do desc "Clear session, cache, and socket files from tmp/ (narrow w/ tmp:sessions:clear, tmp:cache:clear, tmp:sockets:clear)" task :clear => [ "tmp:sessions:clear", "tmp:cache:clear", "tmp:sockets:clear"] + tmp_dirs = [ 'tmp/sessions', + 'tmp/cache', + 'tmp/sockets', + 'tmp/pids', + 'tmp/cache/assets' ] + + tmp_dirs.each { |d| directory d } + desc "Creates tmp directories for sessions, cache, sockets, and pids" - task :create do - FileUtils.mkdir_p(%w( tmp/sessions tmp/cache tmp/sockets tmp/pids tmp/cache/assets )) - end + task :create => tmp_dirs namespace :sessions do # desc "Clears all files in tmp/sessions" diff --git a/railties/lib/rails/templates/layouts/application.html.erb b/railties/lib/rails/templates/layouts/application.html.erb new file mode 100644 index 0000000000..53276d3e7c --- /dev/null +++ b/railties/lib/rails/templates/layouts/application.html.erb @@ -0,0 +1,32 @@ +<!DOCTYPE html> +<html lang="en"> +<head> + <meta charset="utf-8" /> + <title>Routes</title> + <style> + body { background-color: #fff; color: #333; } + + body, p, ol, ul, td { + font-family: helvetica, verdana, arial, sans-serif; + font-size: 13px; + line-height: 18px; + } + + pre { + background-color: #eee; + padding: 10px; + font-size: 11px; + white-space: pre-wrap; + } + + a { color: #000; } + a:visited { color: #666; } + a:hover { color: #fff; background-color:#000; } + </style> +</head> +<body> +<h2>Your App: <%= link_to 'properties', '/rails/info/properties' %> | <%= link_to 'routes', '/rails/info/routes' %></h2> +<%= yield %> + +</body> +</html> diff --git a/railties/lib/rails/templates/rails/info/properties.html.erb b/railties/lib/rails/templates/rails/info/properties.html.erb new file mode 100644 index 0000000000..d47cbab202 --- /dev/null +++ b/railties/lib/rails/templates/rails/info/properties.html.erb @@ -0,0 +1 @@ +<%= @info.html_safe %>
\ No newline at end of file diff --git a/railties/lib/rails/templates/rails/info/routes.html.erb b/railties/lib/rails/templates/rails/info/routes.html.erb new file mode 100644 index 0000000000..890f6f5b03 --- /dev/null +++ b/railties/lib/rails/templates/rails/info/routes.html.erb @@ -0,0 +1,9 @@ +<h2> + Routes +</h2> + +<p> + Routes match in priority from top to bottom +</p> + +<p><pre><%= @info %></pre></p>
\ No newline at end of file diff --git a/railties/lib/rails/test_help.rb b/railties/lib/rails/test_help.rb index 8d0d8cacac..581ceaf9ce 100644 --- a/railties/lib/rails/test_help.rb +++ b/railties/lib/rails/test_help.rb @@ -2,38 +2,25 @@ # so fixtures aren't loaded into that environment abort("Abort testing: Your Rails environment is running in production mode!") if Rails.env.production? -require 'test/unit' +require 'minitest/autorun' require 'active_support/test_case' require 'action_controller/test_case' require 'action_dispatch/testing/integration' -if defined?(Test::Unit::Util::BacktraceFilter) && ENV['BACKTRACE'].nil? - require 'rails/backtrace_cleaner' - Test::Unit::Util::BacktraceFilter.module_eval { include Rails::BacktraceFilterForTestUnit } -end - -if defined?(MiniTest) - # Enable turn if it is available - begin - require 'turn' +# Enable turn if it is available +begin + require 'turn' - if MiniTest::Unit.respond_to?(:use_natural_language_case_names=) - MiniTest::Unit.use_natural_language_case_names = true - end - rescue LoadError + Turn.config do |c| + c.natural = true end +rescue LoadError end if defined?(ActiveRecord::Base) - require 'active_record/test_case' - class ActiveSupport::TestCase include ActiveRecord::TestFixtures self.fixture_path = "#{Rails.root}/test/fixtures/" - - setup do - ActiveRecord::IdentityMap.clear - end end ActionDispatch::IntegrationTest.fixture_path = ActiveSupport::TestCase.fixture_path diff --git a/railties/lib/rails/test_unit/sub_test_task.rb b/railties/lib/rails/test_unit/sub_test_task.rb new file mode 100644 index 0000000000..87b6f9b5a4 --- /dev/null +++ b/railties/lib/rails/test_unit/sub_test_task.rb @@ -0,0 +1,8 @@ +module Rails + # Silence the default description to cut down on `rake -T` noise. + class SubTestTask < Rake::TestTask + def desc(string) + # Ignore the description. + end + end +end diff --git a/railties/lib/rails/test_unit/testing.rake b/railties/lib/rails/test_unit/testing.rake index 8bcceb9b2c..0de4afe905 100644 --- a/railties/lib/rails/test_unit/testing.rake +++ b/railties/lib/rails/test_unit/testing.rake @@ -1,35 +1,6 @@ require 'rbconfig' require 'rake/testtask' - -# Monkey-patch to silence the description from Rake::TestTask to cut down on rake -T noise -class TestTaskWithoutDescription < Rake::TestTask - # Create the tasks defined by this task lib. - def define - lib_path = @libs.join(File::PATH_SEPARATOR) - task @name do - run_code = '' - RakeFileUtils.verbose(@verbose) do - run_code = - case @loader - when :direct - "-e 'ARGV.each{|f| load f}'" - when :testrb - "-S testrb #{fix}" - when :rake - rake_loader - end - @ruby_opts.unshift( "-I\"#{lib_path}\"" ) - @ruby_opts.unshift( "-w" ) if @warning - ruby @ruby_opts.join(" ") + - " \"#{run_code}\" " + - file_list.collect { |fn| "\"#{fn}\"" }.join(' ') + - " #{option_list}" - end - end - self - end -end - +require 'rails/test_unit/sub_test_task' TEST_CHANGES_SINCE = Time.now - 600 @@ -74,22 +45,9 @@ end task :default => :test -desc 'Runs test:units, test:functionals, test:integration together (also available: test:benchmark, test:profile, test:plugins)' +desc 'Runs test:units, test:functionals, test:integration together (also available: test:benchmark, test:profile)' task :test do - tests_to_run = ENV['TEST'] ? ["test:single"] : %w(test:units test:functionals test:integration) - errors = tests_to_run.collect do |task| - begin - Rake::Task[task].invoke - nil - rescue => e - { :task => task, :exception => e } - end - end.compact - - if errors.any? - puts errors.map { |e| "Errors running #{e[:task]}! #{e[:exception].inspect}" }.join("\n") - abort - end + Rake::Task[ENV['TEST'] ? 'test:single' : 'test:run'].invoke end namespace :test do @@ -97,6 +55,22 @@ namespace :test do # Placeholder task for other Railtie and plugins to enhance. See Active Record for an example. end + task :run do + errors = %w(test:units test:functionals test:integration).collect do |task| + begin + Rake::Task[task].invoke + nil + rescue => e + { :task => task, :exception => e } + end + end.compact + + if errors.any? + puts errors.map { |e| "Errors running #{e[:task]}! #{e[:exception].inspect}" }.join("\n") + abort + end + end + Rake::TestTask.new(:recent => "test:prepare") do |t| since = TEST_CHANGES_SINCE touched = FileList['test/**/*_test.rb'].select { |path| File.mtime(path) > since } + @@ -113,7 +87,7 @@ namespace :test do if File.directory?(".svn") changed_since_checkin = silence_stderr { `svn status` }.split.map { |path| path.chomp[7 .. -1] } elsif File.directory?(".git") - changed_since_checkin = silence_stderr { `git ls-files --modified --others` }.split.map { |path| path.chomp } + changed_since_checkin = silence_stderr { `git ls-files --modified --others --exclude-standard` }.split.map { |path| path.chomp } else abort "Not a Subversion or Git checkout." end @@ -121,16 +95,9 @@ namespace :test do models = changed_since_checkin.select { |path| path =~ /app[\\\/]models[\\\/].*\.rb$/ } controllers = changed_since_checkin.select { |path| path =~ /app[\\\/]controllers[\\\/].*\.rb$/ } - unit_tests = models.map do |model| - file = "test/unit/#{File.basename(model, '.rb')}_test.rb" - file if File.exist?(file) - end - functional_tests = controllers.map do |controller| - file = "test/functional/#{File.basename(controller, '.rb')}_test.rb" - file if File.exist?(file) - end - - (unit_tests.uniq + functional_tests.uniq).compact + unit_tests = models.map { |model| "test/unit/#{File.basename(model, '.rb')}_test.rb" } + functional_tests = controllers.map { |controller| "test/functional/#{File.basename(controller, '.rb')}_test.rb" } + (unit_tests + functional_tests).uniq.select { |file| File.exist?(file) } end t.libs << 'test' @@ -141,39 +108,29 @@ namespace :test do t.libs << "test" end - TestTaskWithoutDescription.new(:units => "test:prepare") do |t| + Rails::SubTestTask.new(:units => "test:prepare") do |t| t.libs << "test" t.pattern = 'test/unit/**/*_test.rb' end - TestTaskWithoutDescription.new(:functionals => "test:prepare") do |t| + Rails::SubTestTask.new(:functionals => "test:prepare") do |t| t.libs << "test" t.pattern = 'test/functional/**/*_test.rb' end - TestTaskWithoutDescription.new(:integration => "test:prepare") do |t| + Rails::SubTestTask.new(:integration => "test:prepare") do |t| t.libs << "test" t.pattern = 'test/integration/**/*_test.rb' end - TestTaskWithoutDescription.new(:benchmark => 'test:prepare') do |t| + Rails::SubTestTask.new(:benchmark => 'test:prepare') do |t| t.libs << 'test' t.pattern = 'test/performance/**/*_test.rb' t.options = '-- --benchmark' end - TestTaskWithoutDescription.new(:profile => 'test:prepare') do |t| + Rails::SubTestTask.new(:profile => 'test:prepare') do |t| t.libs << 'test' t.pattern = 'test/performance/**/*_test.rb' end - - TestTaskWithoutDescription.new(:plugins => :environment) do |t| - t.libs << "test" - - if ENV['PLUGIN'] - t.pattern = "vendor/plugins/#{ENV['PLUGIN']}/test/**/*_test.rb" - else - t.pattern = 'vendor/plugins/*/**/test/**/*_test.rb' - end - end end diff --git a/railties/lib/rails/version.rb b/railties/lib/rails/version.rb index 254227ecf7..ec878f9dcf 100644 --- a/railties/lib/rails/version.rb +++ b/railties/lib/rails/version.rb @@ -1,7 +1,7 @@ module Rails module VERSION #:nodoc: - MAJOR = 3 - MINOR = 2 + MAJOR = 4 + MINOR = 0 TINY = 0 PRE = "beta" |