diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 9ab9a2296..84a0c8f45 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -10,6 +10,10 @@ nav_order: 5 ## main +* Resolve an issue where slots starting with `call` would cause a `NameError` + + *Blake Williams* + * Add `use_helper` API. *Reegan Viljoen* diff --git a/lib/view_component/compiler.rb b/lib/view_component/compiler.rb index 72c7367c4..c5ee5b8bd 100644 --- a/lib/view_component/compiler.rb +++ b/lib/view_component/compiler.rb @@ -219,12 +219,12 @@ def inline_calls component_class.included_modules ) - view_component_ancestors.flat_map { |ancestor| ancestor.instance_methods(false).grep(/^call/) }.uniq + view_component_ancestors.flat_map { |ancestor| ancestor.instance_methods(false).grep(/^call(_|$)/) }.uniq end end def inline_calls_defined_on_self - @inline_calls_defined_on_self ||= component_class.instance_methods(false).grep(/^call/) + @inline_calls_defined_on_self ||= component_class.instance_methods(false).grep(/^call(_|$)/) end def variants diff --git a/lib/view_component/errors.rb b/lib/view_component/errors.rb index 36f9ee570..b896f53d1 100644 --- a/lib/view_component/errors.rb +++ b/lib/view_component/errors.rb @@ -104,7 +104,10 @@ class InvalidSlotDefinitionError < BaseError "string, or callable (that is proc, lambda, etc)" end - class SlotPredicateNameError < StandardError + class InvalidSlotNameError < StandardError + end + + class SlotPredicateNameError < InvalidSlotNameError MESSAGE = "COMPONENT declares a slot named SLOT_NAME, which ends with a question mark.\n\n" \ "This isn't allowed because the ViewComponent framework already provides predicate " \ @@ -126,7 +129,7 @@ def initialize(klass_name, slot_name) end end - class ReservedSingularSlotNameError < StandardError + class ReservedSingularSlotNameError < InvalidSlotNameError MESSAGE = "COMPONENT declares a slot named SLOT_NAME, which is a reserved word in the ViewComponent framework.\n\n" \ "To fix this issue, choose a different name." @@ -136,7 +139,7 @@ def initialize(klass_name, slot_name) end end - class ReservedPluralSlotNameError < StandardError + class ReservedPluralSlotNameError < InvalidSlotNameError MESSAGE = "COMPONENT declares a slot named SLOT_NAME, which is a reserved word in the ViewComponent framework.\n\n" \ "To fix this issue, choose a different name." diff --git a/lib/view_component/slotable.rb b/lib/view_component/slotable.rb index ecb4826a2..d46094b3c 100644 --- a/lib/view_component/slotable.rb +++ b/lib/view_component/slotable.rb @@ -295,6 +295,7 @@ def validate_plural_slot_name(slot_name) raise ReservedPluralSlotNameError.new(name, slot_name) end + raise_if_slot_conflicts_with_call(slot_name) raise_if_slot_ends_with_question_mark(slot_name) raise_if_slot_registered(slot_name) end @@ -308,6 +309,7 @@ def validate_singular_slot_name(slot_name) raise ReservedSingularSlotNameError.new(name, slot_name) end + raise_if_slot_conflicts_with_call(slot_name) raise_if_slot_ends_with_question_mark(slot_name) raise_if_slot_registered(slot_name) end @@ -322,6 +324,12 @@ def raise_if_slot_registered(slot_name) def raise_if_slot_ends_with_question_mark(slot_name) raise SlotPredicateNameError.new(name, slot_name) if slot_name.to_s.ends_with?("?") end + + def raise_if_slot_conflicts_with_call(slot_name) + if slot_name.start_with?("call_") + raise InvalidSlotNameError, "Slot cannot start with 'call_'. Please rename #{slot_name}" + end + end end def get_slot(slot_name) diff --git a/test/sandbox/test/slotable_test.rb b/test/sandbox/test/slotable_test.rb index 3a931167e..086f418e5 100644 --- a/test/sandbox/test/slotable_test.rb +++ b/test/sandbox/test/slotable_test.rb @@ -719,4 +719,26 @@ def test_slot_with_content_shorthand assert component.title.content? end + + def test_slot_names_cannot_start_with_call_ + assert_raises ViewComponent::InvalidSlotNameError do + Class.new(ViewComponent::Base) do + renders_one :call_out_title + end + end + + assert_raises ViewComponent::InvalidSlotNameError do + Class.new(ViewComponent::Base) do + renders_many :call_out_titles + end + end + end + + def test_slot_names_can_start_with_call + assert_nothing_raised do + Class.new(ViewComponent::Base) do + renders_one :callhome_et + end + end + end end