Skip to content

Commit

Permalink
Delegate missing Rails::Initializable::Collection methods to inner array
Browse files Browse the repository at this point in the history
Previously, Rails::Initializable::Collection extended Array, but now it
doesn't. The inner structure has changed enough so that we need to
implement addition methods, but we can keep every other subtractive
method as-is.
  • Loading branch information
gmcgibbon committed Nov 14, 2024
1 parent 6230bd3 commit ed3b72a
Show file tree
Hide file tree
Showing 2 changed files with 74 additions and 1 deletion.
15 changes: 14 additions & 1 deletion railties/lib/rails/initializable.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# frozen_string_literal: true

require "tsort"
require "active_support/core_ext/module/delegation"

module Rails
module Initializable
Expand Down Expand Up @@ -38,6 +39,8 @@ class Collection
include Enumerable
include TSort

delegate_missing_to :@collection

def initialize(initializers = nil)
@order = Hash.new { |hash, key| hash[key] = Set.new }
@resolve = Hash.new { |hash, key| hash[key] = Set.new }
Expand Down Expand Up @@ -73,13 +76,23 @@ def <<(initializer)
@order[initializer.before] << initializer.name if initializer.before
@order[initializer.name] << initializer.after if initializer.after
@resolve[initializer.name] << initializer
self
end

def concat(initializers)
def push(*initializers)
initializers.each(&method(:<<))
self
end

alias_method(:append, :push)

def concat(*initializer_collections)
initializer_collections.each do |initializers|
initializers.each(&method(:<<))
end
self
end

def has?(name)
@resolve.key?(name)
end
Expand Down
60 changes: 60 additions & 0 deletions railties/test/initializable_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -277,4 +277,64 @@ class OverriddenInitializerTest < ActiveSupport::TestCase
assert_equal [1, 2, 3, 4], $arr
end
end

class CollectionTest < ActiveSupport::TestCase
test "delegates missing to collection array" do
initializable = Class.new do
include Rails::Initializable
end

Array.public_instance_methods.each do |method_name|
assert(
initializable.initializers.respond_to?(method_name),
"Expected Initializable::Collection to respond to #{method_name}, but does not.",
)
end
end

test "concat" do
one = collection(:a, :b)
two = collection(:c, :d)
initializers = one.initializers.concat(two.initializers)
initializer_names = initializers.tsort_each.map(&:name)

assert_equal [:a, :b, :c, :d], initializer_names
end

test "push" do
one = collection(:a, :b, :c)
two = collection(:d)
initializers = one.initializers.push(two.initializers.first)
initializer_names = initializers.tsort_each.map(&:name)

assert_equal [:a, :b, :c, :d], initializer_names
end

test "append" do
one = collection(:a)
two = collection(:b, :c)
initializers = one.initializers.append(two.initializers.first)
initializer_names = initializers.tsort_each.map(&:name)

assert_equal [:a, :b], initializer_names
end

test "<<" do
one = collection(:a, :b)
two = collection(:c)
initializers = (one.initializers << two.initializers.first)
initializer_names = initializers.tsort_each.map(&:name)

assert_equal [:a, :b, :c], initializer_names
end

private

def collection(*names)
Class.new do
include Rails::Initializable
names.each { |name| initializer(name) { } }
end
end
end
end

0 comments on commit ed3b72a

Please sign in to comment.