diff options
Diffstat (limited to 'railties')
24 files changed, 247 insertions, 66 deletions
diff --git a/railties/lib/rails/application.rb b/railties/lib/rails/application.rb index 1680a6ed00..c7b19c964a 100644 --- a/railties/lib/rails/application.rb +++ b/railties/lib/rails/application.rb @@ -66,9 +66,10 @@ module Rails end end - attr_accessor :assets, :sandbox, :queue + attr_accessor :assets, :sandbox alias_method :sandbox?, :sandbox attr_reader :reloaders + attr_writer :queue delegate :default_url_options, :default_url_options=, :to => :routes diff --git a/railties/lib/rails/application/configuration.rb b/railties/lib/rails/application/configuration.rb index a36dad0e98..25bb680f69 100644 --- a/railties/lib/rails/application/configuration.rb +++ b/railties/lib/rails/application/configuration.rb @@ -43,7 +43,7 @@ module Rails @autoflush_log = true @log_formatter = ActiveSupport::Logger::SimpleFormatter.new @use_schema_cache_dump = true - @queue = Queue + @queue = Rails::Queueing::Queue @assets = ActiveSupport::OrderedOptions.new @assets.enabled = false diff --git a/railties/lib/rails/application/finisher.rb b/railties/lib/rails/application/finisher.rb index 6475b381f4..6a24e01f29 100644 --- a/railties/lib/rails/application/finisher.rb +++ b/railties/lib/rails/application/finisher.rb @@ -95,7 +95,7 @@ module Rails end initializer :activate_queue_consumer do |app| - if config.queue == Queue + if config.queue == Rails::Queueing::Queue consumer = Rails::Queueing::ThreadedConsumer.start(app.queue) at_exit { consumer.shutdown } end diff --git a/railties/lib/rails/application/routes_reloader.rb b/railties/lib/rails/application/routes_reloader.rb index 7f9190b01a..19f616ec50 100644 --- a/railties/lib/rails/application/routes_reloader.rb +++ b/railties/lib/rails/application/routes_reloader.rb @@ -24,12 +24,11 @@ module Rails def updater @updater ||= begin - dirs = @external_routes.inject({}) do |hash, dir| - hash.merge(dir.to_s => ["rb"]) + dirs = @external_routes.each_with_object({}) do |dir, hash| + hash[dir.to_s] = %w(rb) end updater = ActiveSupport::FileUpdateChecker.new(paths, dirs) { reload! } - updater.execute updater end diff --git a/railties/lib/rails/commands/runner.rb b/railties/lib/rails/commands/runner.rb index e8cc5d9e3b..2802981e7a 100644 --- a/railties/lib/rails/commands/runner.rb +++ b/railties/lib/rails/commands/runner.rb @@ -9,7 +9,6 @@ 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.separator "" diff --git a/railties/lib/rails/engine.rb b/railties/lib/rails/engine.rb index fa582f963c..c9654fc63d 100644 --- a/railties/lib/rails/engine.rb +++ b/railties/lib/rails/engine.rb @@ -486,8 +486,10 @@ module Rails end def routes - @routes ||= ActionDispatch::Routing::RouteSet.new - @routes.draw_paths.concat paths["config/routes"].paths + @routes ||= ActionDispatch::Routing::RouteSet.new.tap do |routes| + routes.draw_paths.concat paths["config/routes"].paths + end + @routes.append(&Proc.new) if block_given? @routes end @@ -619,7 +621,7 @@ module Rails end def routes? - defined?(@routes) + defined?(@routes) && @routes end def has_migrations? diff --git a/railties/lib/rails/generators/app_base.rb b/railties/lib/rails/generators/app_base.rb index 8c8ed5010f..b677e974c8 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" 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 303331a4f0..d78d97b2b4 100644 --- a/railties/lib/rails/generators/erb/scaffold/templates/index.html.erb +++ b/railties/lib/rails/generators/erb/scaffold/templates/index.html.erb @@ -1,23 +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> - <%%= 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 %>, confirm: 'Are you sure?', method: :delete %></td> - <%% 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 %>, confirm: 'Are you sure?', method: :delete %></td> + <%% end %> + </tbody> </table> <br /> diff --git a/railties/lib/rails/generators/rails/app/app_generator.rb b/railties/lib/rails/generators/rails/app/app_generator.rb index f0745df667..c06b0f8994 100644 --- a/railties/lib/rails/generators/rails/app/app_generator.rb +++ b/railties/lib/rails/generators/rails/app/app_generator.rb @@ -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 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 c486ae590e..24bcec854c 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 @@ -37,5 +37,5 @@ <%- end -%> # In development, use an in-memory queue for queueing - config.queue = Queue + 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 854e6e95cd..072aa8355d 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 @@ -79,5 +79,5 @@ # 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 = Queue + config.queue = Rails::Queueing::Queue end diff --git a/railties/lib/rails/queueing.rb b/railties/lib/rails/queueing.rb index b77940f821..2e187b8555 100644 --- a/railties/lib/rails/queueing.rb +++ b/railties/lib/rails/queueing.rb @@ -1,33 +1,33 @@ +require "thread" + module Rails module Queueing + # 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 +contents+ + # 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 - attr_reader :contents - - def initialize - @contents = [] + 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 + # 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. - t = Thread.new do - while job = @contents.pop - job.run - end - end - t.join - end - - # implement the Queue API - def push(object) - @contents << object + Thread.new { pop.run until empty? }.join end end @@ -50,7 +50,11 @@ module Rails def start @thread = Thread.new do while job = @queue.pop - job.run + begin + job.run + rescue Exception => e + Rails.logger.error "Job Error: #{e.message}\n#{e.backtrace.join("\n")}" + end end end self diff --git a/railties/lib/rails/source_annotation_extractor.rb b/railties/lib/rails/source_annotation_extractor.rb index a443c73962..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: # @@ -48,7 +51,7 @@ class SourceAnnotationExtractor # Returns a hash that maps filenames under +dirs+ (recursively) to arrays # with their annotations. - def find(dirs=%w(app config lib script test)) + def find(dirs = Annotation.directories) dirs.inject({}) { |h, dir| h.update(find_in(dir)) } end diff --git a/railties/railties.gemspec b/railties/railties.gemspec index e84b1d0644..7067253279 100644 --- a/railties/railties.gemspec +++ b/railties/railties.gemspec @@ -21,7 +21,11 @@ Gem::Specification.new do |s| s.rdoc_options << '--exclude' << '.' s.add_dependency('rake', '>= 0.8.7') - s.add_dependency('thor', '~> 0.14.6') + + # The current API of the Thor gem (0.14) will remain stable at least until Thor 2.0. Because + # Thor is so heavily used by other gems, we will accept Thor's semver guarantee to reduce + # the possibility of conflicts. + s.add_dependency('thor', '>= 0.14.6', '< 2.0') s.add_dependency('rdoc', '~> 3.4') s.add_dependency('activesupport', version) s.add_dependency('actionpack', version) diff --git a/railties/test/application/middleware/session_test.rb b/railties/test/application/middleware/session_test.rb index f4e77ee244..07134cc935 100644 --- a/railties/test/application/middleware/session_test.rb +++ b/railties/test/application/middleware/session_test.rb @@ -26,5 +26,25 @@ module ApplicationTests require "#{app_path}/config/environment" assert app.config.session_options[:secure], "Expected session to be marked as secure" end + + test "session is not loaded if it's not used" do + make_basic_app + + class ::OmgController < ActionController::Base + def index + if params[:flash] + flash[:notice] = "notice" + end + + render :nothing => true + end + end + + get "/?flash=true" + get "/" + + assert last_request.env["HTTP_COOKIE"] + assert !last_response.headers["Set-Cookie"] + end end end diff --git a/railties/test/application/queue_test.rb b/railties/test/application/queue_test.rb index 667565b031..ec809d7cc1 100644 --- a/railties/test/application/queue_test.rb +++ b/railties/test/application/queue_test.rb @@ -26,8 +26,8 @@ module ApplicationTests test "the queue is a Queue in development mode" do app("development") - assert_kind_of Queue, Rails.application.queue - assert_kind_of Queue, Rails.queue + assert_kind_of Rails::Queueing::Queue, Rails.application.queue + assert_kind_of Rails::Queueing::Queue, Rails.queue end test "in development mode, an enqueued job will be processed in a separate thread" do @@ -78,7 +78,7 @@ module ApplicationTests Rails.queue.push job end - assert_equal jobs, Rails.queue.contents + assert_equal jobs, Rails.queue.jobs end test "a custom queue implementation can be provided" do diff --git a/railties/test/application/rake/notes_test.rb b/railties/test/application/rake/notes_test.rb index d069703d30..05d73dfc5c 100644 --- a/railties/test/application/rake/notes_test.rb +++ b/railties/test/application/rake/notes_test.rb @@ -12,7 +12,7 @@ module ApplicationTests teardown_app end - test 'notes' do + test 'notes finds notes for certain file_types' do app_file "app/views/home/index.html.erb", "<% # TODO: note in erb %>" app_file "app/views/home/index.html.haml", "-# TODO: note in haml" app_file "app/views/home/index.html.slim", "/ TODO: note in slim" @@ -49,7 +49,79 @@ module ApplicationTests assert_equal ' ', line[1] end end + end + + test 'notes finds notes in default directories' do + app_file "app/controllers/some_controller.rb", "# TODO: note in app directory" + app_file "config/initializers/some_initializer.rb", "# TODO: note in config directory" + app_file "lib/some_file.rb", "# TODO: note in lib directory" + app_file "script/run_something.rb", "# TODO: note in script directory" + app_file "test/some_test.rb", 1000.times.map { "" }.join("\n") << "# TODO: note in test directory" + + app_file "some_other_dir/blah.rb", "# TODO: note in some_other directory" + + boot_rails + require 'rake' + require 'rdoc/task' + require 'rake/testtask' + + Rails.application.load_tasks + + Dir.chdir(app_path) do + output = `bundle exec rake notes` + lines = output.scan(/\[([0-9\s]+)\]/).flatten + + assert_match /note in app directory/, output + assert_match /note in config directory/, output + assert_match /note in lib directory/, output + assert_match /note in script directory/, output + assert_match /note in test directory/, output + assert_no_match /note in some_other directory/, output + + assert_equal 5, lines.size + + lines.each do |line_number| + assert_equal 4, line_number.size + end + end + end + + test 'notes finds notes in custom directories' do + app_file "app/controllers/some_controller.rb", "# TODO: note in app directory" + app_file "config/initializers/some_initializer.rb", "# TODO: note in config directory" + app_file "lib/some_file.rb", "# TODO: note in lib directory" + app_file "script/run_something.rb", "# TODO: note in script directory" + app_file "test/some_test.rb", 1000.times.map { "" }.join("\n") << "# TODO: note in test directory" + + app_file "some_other_dir/blah.rb", "# TODO: note in some_other directory" + + boot_rails + + require 'rake' + require 'rdoc/task' + require 'rake/testtask' + + Rails.application.load_tasks + + Dir.chdir(app_path) do + output = `SOURCE_ANNOTATION_DIRECTORIES='some_other_dir' bundle exec rake notes` + lines = output.scan(/\[([0-9\s]+)\]/).flatten + + assert_match /note in app directory/, output + assert_match /note in config directory/, output + assert_match /note in lib directory/, output + assert_match /note in script directory/, output + assert_match /note in test directory/, output + + assert_match /note in some_other directory/, output + + assert_equal 6, lines.size + + lines.each do |line_number| + assert_equal 4, line_number.size + end + end end private diff --git a/railties/test/application/routing_test.rb b/railties/test/application/routing_test.rb index 4560dcec69..977a5fc7e8 100644 --- a/railties/test/application/routing_test.rb +++ b/railties/test/application/routing_test.rb @@ -249,9 +249,7 @@ module ApplicationTests assert_equal 404, last_response.status end end - end - {"development" => "baz", "production" => "bar"}.each do |mode, expected| test "reloads routes when configuration is changed in #{mode}" do controller :foo, <<-RUBY class FooController < ApplicationController diff --git a/railties/test/engine_test.rb b/railties/test/engine_test.rb new file mode 100644 index 0000000000..68406dce4c --- /dev/null +++ b/railties/test/engine_test.rb @@ -0,0 +1,24 @@ +require 'abstract_unit' + +class EngineTest < ActiveSupport::TestCase + it "reports routes as available only if they're actually present" do + engine = Class.new(Rails::Engine) do + def initialize(*args) + @routes = nil + super + end + end + + assert !engine.routes? + end + + it "does not add more paths to routes on each call" do + engine = Class.new(Rails::Engine) + + engine.routes + length = engine.routes.draw_paths.length + + engine.routes + assert_equal length, engine.routes.draw_paths.length + end +end diff --git a/railties/test/generators/app_generator_test.rb b/railties/test/generators/app_generator_test.rb index ef6877ed30..94983c504c 100644 --- a/railties/test/generators/app_generator_test.rb +++ b/railties/test/generators/app_generator_test.rb @@ -250,6 +250,13 @@ class AppGeneratorTest < Rails::Generators::TestCase end end + def test_generator_if_skip_index_html_is_given + run_generator [destination_root, "--skip-index-html"] + assert_no_file "public/index.html" + assert_no_file "app/assets/images/rails.png" + assert_file "app/assets/images/.gitkeep" + end + def test_creation_of_a_test_directory run_generator assert_file 'test' diff --git a/railties/test/isolation/abstract_unit.rb b/railties/test/isolation/abstract_unit.rb index 7957186ba2..f2dc0c71b1 100644 --- a/railties/test/isolation/abstract_unit.rb +++ b/railties/test/isolation/abstract_unit.rb @@ -18,7 +18,6 @@ RAILS_FRAMEWORK_ROOT = File.expand_path("#{File.dirname(__FILE__)}/../../..") # These files do not require any others and are needed # to run the tests require "#{RAILS_FRAMEWORK_ROOT}/activesupport/lib/active_support/testing/isolation" -require "#{RAILS_FRAMEWORK_ROOT}/activesupport/lib/active_support/testing/declarative" require "#{RAILS_FRAMEWORK_ROOT}/activesupport/lib/active_support/core_ext/kernel/reporting" module TestHelpers @@ -268,7 +267,6 @@ class ActiveSupport::TestCase include TestHelpers::Paths include TestHelpers::Rack include TestHelpers::Generation - extend ActiveSupport::Testing::Declarative end # Create a scope and build a fixture rails app diff --git a/railties/test/queueing/test_queue_test.rb b/railties/test/queueing/test_queue_test.rb index de30e8cffd..78c6c617fe 100644 --- a/railties/test/queueing/test_queue_test.rb +++ b/railties/test/queueing/test_queue_test.rb @@ -3,9 +3,7 @@ require 'rails/queueing' class TestQueueTest < ActiveSupport::TestCase class Job - attr_reader :id - def initialize(id, &block) - @id = id + def initialize(&block) @block = block end @@ -18,18 +16,43 @@ class TestQueueTest < ActiveSupport::TestCase @queue = Rails::Queueing::TestQueue.new end + def test_drain_raises + @queue.push Job.new { raise } + assert_raises(RuntimeError) { @queue.drain } + end + + def test_jobs + @queue.push 1 + @queue.push 2 + assert_equal [1,2], @queue.jobs + end + def test_contents - assert_equal [], @queue.contents - job = Job.new(1) + assert @queue.empty? + job = Job.new @queue.push job - assert_equal [job], @queue.contents + refute @queue.empty? + assert_equal job, @queue.pop + end + + def test_order + processed = [] + + job1 = Job.new { processed << 1 } + job2 = Job.new { processed << 2 } + + @queue.push job1 + @queue.push job2 + @queue.drain + + assert_equal [1,2], processed end def test_drain t = nil ran = false - job = Job.new(1) do + job = Job.new do ran = true t = Thread.current end @@ -37,7 +60,7 @@ class TestQueueTest < ActiveSupport::TestCase @queue.push job @queue.drain - assert_equal [], @queue.contents + assert @queue.empty? assert ran, "The job runs synchronously when the queue is drained" assert_not_equal t, Thread.current end diff --git a/railties/test/queueing/threaded_consumer_test.rb b/railties/test/queueing/threaded_consumer_test.rb index d00a67d511..559de2a82d 100644 --- a/railties/test/queueing/threaded_consumer_test.rb +++ b/railties/test/queueing/threaded_consumer_test.rb @@ -15,7 +15,7 @@ class TestThreadConsumer < ActiveSupport::TestCase end def setup - @queue = Queue.new + @queue = Rails::Queueing::Queue.new @consumer = Rails::Queueing::ThreadedConsumer.start(@queue) end @@ -62,4 +62,20 @@ class TestThreadConsumer < ActiveSupport::TestCase assert_equal true, ran end + + test "log job that raises an exception" do + require "active_support/log_subscriber/test_helper" + logger = ActiveSupport::LogSubscriber::TestHelper::MockLogger.new + Rails.logger = logger + + job = Job.new(1) do + raise "RuntimeError: Error!" + end + + @queue.push job + sleep 0.1 + + assert_equal 1, logger.logged(:error).size + assert_match(/Job Error: RuntimeError: Error!/, logger.logged(:error).last) + end end diff --git a/railties/test/railties/engine_test.rb b/railties/test/railties/engine_test.rb index beae2c5f2c..9d9565e5f3 100644 --- a/railties/test/railties/engine_test.rb +++ b/railties/test/railties/engine_test.rb @@ -86,7 +86,6 @@ module RailtiesTest add_to_config "ActiveRecord::Base.timestamped_migrations = false" boot_rails - railties = Rails.application.railties.all.map(&:railtie_name) Dir.chdir(app_path) do output = `bundle exec rake bukkits:install:migrations` |