From c2edf3de2cc4d81399f5291fd57a48fc30b5df87 Mon Sep 17 00:00:00 2001 From: Simon Jefford Date: Sun, 22 Feb 2009 21:54:48 +0000 Subject: [PATCH] Enhanced Rails Metal - the load order of metals can now be configured Also added test coverage for the metal feature --- railties/lib/initializer.rb | 6 ++ railties/lib/rails/rack/metal.rb | 16 +++++- .../metal/multiplemetals/app/metal/metal_a.rb | 5 ++ .../metal/multiplemetals/app/metal/metal_b.rb | 5 ++ .../metal/singlemetal/app/metal/foo_metal.rb | 5 ++ .../metal/subfolders/app/metal/Folder/metal_a.rb | 7 ++ .../metal/subfolders/app/metal/Folder/metal_b.rb | 7 ++ railties/test/metal_test.rb | 60 ++++++++++++++++++++ 8 files changed, 109 insertions(+), 2 deletions(-) create mode 100644 railties/test/fixtures/metal/multiplemetals/app/metal/metal_a.rb create mode 100644 railties/test/fixtures/metal/multiplemetals/app/metal/metal_b.rb create mode 100644 railties/test/fixtures/metal/singlemetal/app/metal/foo_metal.rb create mode 100644 railties/test/fixtures/metal/subfolders/app/metal/Folder/metal_a.rb create mode 100644 railties/test/fixtures/metal/subfolders/app/metal/Folder/metal_b.rb create mode 100644 railties/test/metal_test.rb diff --git a/railties/lib/initializer.rb b/railties/lib/initializer.rb index a31ae94..7759e3e 100644 --- a/railties/lib/initializer.rb +++ b/railties/lib/initializer.rb @@ -545,6 +545,7 @@ Run `rake gems:install` to install the missing gems. end def initialize_metal + Rails::Rack::Metal.requested_metals = configuration.metals configuration.middleware.insert_before( :"ActionController::RewindableInput", Rails::Rack::Metal, :if => Rails::Rack::Metal.metals.any?) @@ -699,6 +700,11 @@ Run `rake gems:install` to install the missing gems. @plugins = plugins.nil? ? nil : plugins.map { |p| p.to_sym } end + # The list of metals to load. If this is set to nil, all metals will + # be loaded in alphabetical order. If this is set to [], no metals will + # be loaded. Otherwise metals will be loaded in the order specified + attr_accessor :metals + # The path to the root of the plugins directory. By default, it is in # vendor/plugins. attr_accessor :plugin_paths diff --git a/railties/lib/rails/rack/metal.rb b/railties/lib/rails/rack/metal.rb index b185227..4867df4 100644 --- a/railties/lib/rails/rack/metal.rb +++ b/railties/lib/rails/rack/metal.rb @@ -6,15 +6,27 @@ module Rails NotFoundResponse = [404, {}, []].freeze NotFound = lambda { NotFoundResponse } + cattr_accessor :requested_metals + def self.metals base = "#{Rails.root}/app/metal" matcher = /\A#{Regexp.escape(base)}\/(.*)\.rb\Z/ + all_metals = {} + Dir["#{base}/**/*.rb"].sort.map do |file| file.sub!(matcher, '\1') - require file - file.classify.constantize + all_metals[file.classify] = file end + + load_list = requested_metals || all_metals.keys + + load_list.map do |requested_metal| + if metal = all_metals[requested_metal] + require metal + requested_metal.constantize + end + end.compact end def initialize(app) diff --git a/railties/test/fixtures/metal/multiplemetals/app/metal/metal_a.rb b/railties/test/fixtures/metal/multiplemetals/app/metal/metal_a.rb new file mode 100644 index 0000000..b8e7001 --- /dev/null +++ b/railties/test/fixtures/metal/multiplemetals/app/metal/metal_a.rb @@ -0,0 +1,5 @@ +class MetalA < Rails::Rack::Metal + def self.call(env) + [200, { "Content-Type" => "text/html"}, "Hi"] + end +end diff --git a/railties/test/fixtures/metal/multiplemetals/app/metal/metal_b.rb b/railties/test/fixtures/metal/multiplemetals/app/metal/metal_b.rb new file mode 100644 index 0000000..adc2f45 --- /dev/null +++ b/railties/test/fixtures/metal/multiplemetals/app/metal/metal_b.rb @@ -0,0 +1,5 @@ +class MetalB < Rails::Rack::Metal + def self.call(env) + [200, { "Content-Type" => "text/html"}, "Hi"] + end +end diff --git a/railties/test/fixtures/metal/singlemetal/app/metal/foo_metal.rb b/railties/test/fixtures/metal/singlemetal/app/metal/foo_metal.rb new file mode 100644 index 0000000..9ade2ce --- /dev/null +++ b/railties/test/fixtures/metal/singlemetal/app/metal/foo_metal.rb @@ -0,0 +1,5 @@ +class FooMetal < Rails::Rack::Metal + def self.call(env) + [200, { "Content-Type" => "text/html"}, "Hi"] + end +end diff --git a/railties/test/fixtures/metal/subfolders/app/metal/Folder/metal_a.rb b/railties/test/fixtures/metal/subfolders/app/metal/Folder/metal_a.rb new file mode 100644 index 0000000..71a5a62 --- /dev/null +++ b/railties/test/fixtures/metal/subfolders/app/metal/Folder/metal_a.rb @@ -0,0 +1,7 @@ +module Folder + class MetalA < Rails::Rack::Metal + def self.call(env) + [200, { "Content-Type" => "text/html"}, "Hi"] + end + end +end diff --git a/railties/test/fixtures/metal/subfolders/app/metal/Folder/metal_b.rb b/railties/test/fixtures/metal/subfolders/app/metal/Folder/metal_b.rb new file mode 100644 index 0000000..430d7bf --- /dev/null +++ b/railties/test/fixtures/metal/subfolders/app/metal/Folder/metal_b.rb @@ -0,0 +1,7 @@ +module Folder + class MetalB < Rails::Rack::Metal + def self.call(env) + [200, { "Content-Type" => "text/html"}, "Hi"] + end + end +end diff --git a/railties/test/metal_test.rb b/railties/test/metal_test.rb new file mode 100644 index 0000000..7af8ecd --- /dev/null +++ b/railties/test/metal_test.rb @@ -0,0 +1,60 @@ +require 'abstract_unit' +require 'initializer' + +class MetalTest < Test::Unit::TestCase + def setup + Rails::Rack::Metal.requested_metals = nil + end + + def test_metals_should_return_list_of_found_metal_apps + use_appdir("singlemetal") do + assert_equal(["FooMetal"], found_metals_as_string_array) + end + end + + def test_metals_should_return_alphabetical_list_of_found_metal_apps + use_appdir("multiplemetals") do + assert_equal(["MetalA", "MetalB"], found_metals_as_string_array) + end + end + + def test_metals_load_order_should_be_overriden_by_requested_metals + Rails::Rack::Metal.requested_metals = ["MetalB", "MetalA"] + use_appdir("multiplemetals") do + assert_equal(["MetalB", "MetalA"], found_metals_as_string_array) + end + end + + def test_metals_not_listed_should_not_load + Rails::Rack::Metal.requested_metals = ["MetalB"] + use_appdir("multiplemetals") do + assert_equal(["MetalB"], found_metals_as_string_array) + end + end + + def test_metal_finding_should_work_with_subfolders + use_appdir("subfolders") do + assert_equal(["Folder::MetalA", "Folder::MetalB"], found_metals_as_string_array) + end + end + + def test_metal_finding_with_requested_metals_should_work_with_subfolders + Rails::Rack::Metal.requested_metals = ["Folder::MetalB"] + use_appdir("subfolders") do + assert_equal(["Folder::MetalB"], found_metals_as_string_array) + end + end + + private + + def use_appdir(root) + dir = "#{File.dirname(__FILE__)}/fixtures/metal/#{root}" + RAILS_ROOT.replace dir + $LOAD_PATH << "#{dir}/app/metal" + yield + end + + def found_metals_as_string_array + Rails::Rack::Metal.metals.map { |m| m.to_s } + end +end -- 1.6.0.4