Skip to content

Commit bac7a24

Browse files
authored
Reduce allocations in #with_collection (#2333)
* Add test of number of allocations when rendering with with_collection * Ensure one-time initializations are done before testing allocations * Cache calculated collection parameter * Cache collection_counter_parameter * Cache collection_iteration_parameter * Cache initialize_parameter_names * Add expected number of allocations for all tested Ruby/Rails combinations * Remove code handling obsolete Rails version
1 parent 4199293 commit bac7a24

2 files changed

Lines changed: 35 additions & 8 deletions

File tree

lib/view_component/base.rb

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -660,12 +660,12 @@ def validate_initialization_parameters!
660660

661661
# @private
662662
def collection_parameter
663-
provided_collection_parameter || name && name.demodulize.underscore.chomp("_component").to_sym
663+
@provided_collection_parameter ||= name && name.demodulize.underscore.chomp("_component").to_sym
664664
end
665665

666666
# @private
667667
def collection_counter_parameter
668-
:"#{collection_parameter}_counter"
668+
@collection_counter_parameter ||= :"#{collection_parameter}_counter"
669669
end
670670

671671
# @private
@@ -675,7 +675,7 @@ def counter_argument_present?
675675

676676
# @private
677677
def collection_iteration_parameter
678-
:"#{collection_parameter}_iteration"
678+
@collection_iteration_parameter ||= :"#{collection_parameter}_iteration"
679679
end
680680

681681
# @private
@@ -691,11 +691,12 @@ def splatted_keyword_argument_present?
691691
end
692692

693693
def initialize_parameter_names
694-
return attribute_names.map(&:to_sym) if respond_to?(:attribute_names)
695-
696-
return attribute_types.keys.map(&:to_sym) if Rails::VERSION::MAJOR <= 5 && respond_to?(:attribute_types)
697-
698-
initialize_parameters.map(&:last)
694+
@initialize_parameter_names ||=
695+
if respond_to?(:attribute_names)
696+
attribute_names.map(&:to_sym)
697+
else
698+
initialize_parameters.map(&:last)
699+
end
699700
end
700701

701702
def initialize_parameters

test/sandbox/test/rendering_test.rb

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -612,6 +612,32 @@ def test_render_collection
612612
assert_selector("p", text: "Mints counter: 1")
613613
end
614614

615+
def test_render_collection_inline_allocations
616+
# Stabilize compilation status ahead of testing allocations to simulate rendering
617+
# performance with compiled component
618+
ViewComponent::CompileCache.cache.delete(ProductComponent)
619+
ProductComponent.ensure_compiled
620+
621+
allocations =
622+
if Rails.version.to_f < 8.0
623+
{"3.3.8" => 128, "3.2.8" => 125, "3.1.7" => 125, "3.0.7" => 122}
624+
elsif Rails.version.split(".").first(2).map(&:to_i) == [8, 0]
625+
{"3.5.0" => 121, "3.4.4" => 121, "3.3.8" => 128}
626+
else
627+
{"3.4.4" => 119}
628+
end
629+
630+
products = [Product.new(name: "Radio clock"), Product.new(name: "Mints")]
631+
notice = "On sale"
632+
# Ensure any one-time allocations are done
633+
render_inline(ProductComponent.with_collection(products, notice: notice))
634+
635+
assert_allocations(**allocations) do
636+
render_inline(ProductComponent.with_collection(products, notice: notice))
637+
end
638+
assert_selector("h1", text: "Product", count: 2)
639+
end
640+
615641
def test_render_collection_custom_collection_parameter_name
616642
coupons = [Coupon.new(percent_off: 20), Coupon.new(percent_off: 50)]
617643
render_inline(ProductCouponComponent.with_collection(coupons))

0 commit comments

Comments
 (0)