Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Enhanced Rails Metal - the load order of metals can now be configured [

…#2057 state:resolved]

Signed-off-by: Joshua Peek <josh@joshpeek.com>
  • Loading branch information...
commit 4d4d2c3896ed5a5d74da833c5c3132f406f4eab7 1 parent 818556e
@simonjefford simonjefford authored josh committed
View
6 railties/lib/initializer.rb
@@ -559,6 +559,7 @@ def initialize_i18n
end
def initialize_metal
+ Rails::Rack::Metal.requested_metals = configuration.metals
Rails::Rack::Metal.metal_paths += plugin_loader.engine_metal_paths
configuration.middleware.insert_before(
@@ -715,6 +716,11 @@ def plugins=(plugins)
@plugins = plugins.nil? ? nil : plugins.map { |p| p.to_sym }
end
+ # The list of metals to load. If this is set to <tt>nil</tt>, all metals will
+ # be loaded in alphabetical order. If this is set to <tt>[]</tt>, 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
# <tt>vendor/plugins</tt>.
attr_accessor :plugin_paths
View
16 railties/lib/rails/rack/metal.rb
@@ -8,16 +8,26 @@ class Metal
cattr_accessor :metal_paths
self.metal_paths = ["#{Rails.root}/app/metal"]
+ cattr_accessor :requested_metals
def self.metals
matcher = /#{Regexp.escape('/app/metal/')}(.*)\.rb\Z/
metal_glob = metal_paths.map{ |base| "#{base}/**/*.rb" }
+ all_metals = {}
Dir[*metal_glob].sort.map do |file|
- path = file.match(matcher)[1]
- require path
- path.classify.constantize
+ file = file.match(matcher)[1]
+ 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)
View
5 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
View
5 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
View
5 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
View
7 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
View
7 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
View
57 railties/test/metal_test.rb
@@ -0,0 +1,57 @@
+require 'abstract_unit'
+require 'initializer'
+
+class MetalTest < Test::Unit::TestCase
+ 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
+ use_appdir("multiplemetals") do
+ Rails::Rack::Metal.requested_metals = ["MetalB", "MetalA"]
+ assert_equal(["MetalB", "MetalA"], found_metals_as_string_array)
+ end
+ end
+
+ def test_metals_not_listed_should_not_load
+ use_appdir("multiplemetals") do
+ Rails::Rack::Metal.requested_metals = ["MetalB"]
+ assert_equal(["MetalB"], found_metals_as_string_array)
+ end
+ end
+p
+ 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
+ use_appdir("subfolders") do
+ Rails::Rack::Metal.requested_metals = ["Folder::MetalB"]
+ assert_equal(["Folder::MetalB"], found_metals_as_string_array)
+ end
+ end
+
+ private
+
+ def use_appdir(root)
+ dir = "#{File.dirname(__FILE__)}/fixtures/metal/#{root}"
+ Rails::Rack::Metal.metal_paths = ["#{dir}/app/metal"]
+ Rails::Rack::Metal.requested_metals = nil
+ $LOAD_PATH << "#{dir}/app/metal"
+ yield
+ end
+
+ def found_metals_as_string_array
+ Rails::Rack::Metal.metals.map { |m| m.to_s }
+ end
+end

5 comments on commit 4d4d2c3

@alloy

A debug remnant at: http://github.com/rails/rails/blob/4d4d2c3896ed5a5d74da833c5c3132f406f4eab7/railties/test/metal_test.rb#L30 :)

@libc

What about :all, as in plugins?

@peternash

Seems to cause a problem if plugins include an “app” directory. Rails fails to start with:

vendor/rails/railties/lib/rails/rack/metal.rb:18:in `[]’: wrong number of arguments (2 for 1) (ArgumentError)

Looks like initializer.rb is setting metal_paths at line 563 so it’s an array of all the “app” paths including the plugins and the “Dir” at line 18 of metal.rb is baulking on the array.

@simonjefford

With some help from Peter, I’ve tracked this down to a problem with Ruby 1.8.5. I’ll try and get a fix sorted tonight.

@danigb

I have the same problem. ruby —version = ruby 1.8.6 (2007-03-13 patchlevel 0) [i686-linux] rails —version = Rails 2.3.1

rake db:migrate =

  • Execute environment rake aborted! wrong number of arguments (2 for 1) /usr/lib/ruby/gems/1.8/gems/rails-2.3.1/lib/rails/rack/metal.rb:18:in `[]’ /usr/lib/ruby/gems/1.8/gems/rails-2.3.1/lib/rails/rack/metal.rb:18:in `metals’ … how can i solve it?!? thanks
Please sign in to comment.
Something went wrong with that request. Please try again.