diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index cb85aedbb..45f257ede 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -190,6 +190,10 @@ This release makes the following breaking changes: *Simon Fish* +* Deprecate `use_helper(s)`. Use `include MyHelper` or `helpers.` proxy instead. + + *Joel Hawksley* + * Reduce string allocations during compilation. *Jonathan del Strother* diff --git a/lib/view_component/base.rb b/lib/view_component/base.rb index 62308f264..0c6039a0e 100644 --- a/lib/view_component/base.rb +++ b/lib/view_component/base.rb @@ -620,7 +620,7 @@ def __vc_validate_collection_parameter!(validate_default: false) parameter = validate_default ? __vc_collection_parameter : provided_collection_parameter return unless parameter - return if initialize_parameter_names.include?(parameter) || splatted_keyword_argument_present? + return if __vc_initialize_parameter_names.include?(parameter) || splatted_keyword_argument_present? # If Ruby can't parse the component class, then the initialize # parameters will be empty and ViewComponent will not be able to render @@ -637,34 +637,34 @@ def __vc_validate_collection_parameter!(validate_default: false) # methods. # @private def __vc_validate_initialization_parameters! - return unless initialize_parameter_names.include?(:content) + return unless __vc_initialize_parameter_names.include?(:content) raise ReservedParameterError.new(name, :content) end # @private def __vc_collection_parameter - provided_collection_parameter || name && name.demodulize.underscore.chomp("_component").to_sym + @provided_collection_parameter ||= name && name.demodulize.underscore.chomp("_component").to_sym end # @private def __vc_collection_counter_parameter - :"#{__vc_collection_parameter}_counter" + @__vc_collection_counter_parameter ||= :"#{__vc_collection_parameter}_counter" end # @private def __vc_counter_argument_present? - initialize_parameter_names.include?(__vc_collection_counter_parameter) + __vc_initialize_parameter_names.include?(__vc_collection_counter_parameter) end # @private def __vc_collection_iteration_parameter - :"#{__vc_collection_parameter}_iteration" + @__vc_collection_iteration_parameter ||= :"#{__vc_collection_parameter}_iteration" end # @private def __vc_iteration_argument_present? - initialize_parameter_names.include?(__vc_collection_iteration_parameter) + __vc_initialize_parameter_names.include?(__vc_collection_iteration_parameter) end private @@ -674,10 +674,13 @@ def splatted_keyword_argument_present? !initialize_parameters.include?([:keyrest, :**]) # Un-named splatted keyword args don't count! end - def initialize_parameter_names - return attribute_names.map(&:to_sym) if respond_to?(:attribute_names) - - initialize_parameters.map(&:last) + def __vc_initialize_parameter_names + @__vc_initialize_parameter_names ||= + if respond_to?(:attribute_names) + attribute_names.map(&:to_sym) + else + initialize_parameters.map(&:last) + end end def initialize_parameters diff --git a/test/sandbox/test/rendering_test.rb b/test/sandbox/test/rendering_test.rb index 4abb62985..7fbb359ce 100644 --- a/test/sandbox/test/rendering_test.rb +++ b/test/sandbox/test/rendering_test.rb @@ -610,6 +610,25 @@ def test_render_collection assert_selector("p", text: "Mints counter: 1") end + def test_render_collection_inline_allocations + # Stabilize compilation status ahead of testing allocations to simulate rendering + # performance with compiled component + ViewComponent::CompileCache.cache.delete(ProductComponent) + ProductComponent.__vc_ensure_compiled + + allocations = {"3.5" => 79, "3.4" => 84, "3.3" => 110, "3.2" => 108} + + products = [Product.new(name: "Radio clock"), Product.new(name: "Mints")] + notice = "On sale" + # Ensure any one-time allocations are done + render_inline(ProductComponent.with_collection(products, notice: notice)) + + assert_allocations(**allocations) do + render_inline(ProductComponent.with_collection(products, notice: notice)) + end + assert_selector("h1", text: "Product", count: 2) + end + def test_render_collection_custom_collection_parameter_name coupons = [Coupon.new(percent_off: 20), Coupon.new(percent_off: 50)] render_inline(ProductCouponComponent.with_collection(coupons))