diff --git a/lib/theo-rails/theo.rb b/lib/theo-rails/theo.rb index 35ba258..f3cc877 100644 --- a/lib/theo-rails/theo.rb +++ b/lib/theo-rails/theo.rb @@ -46,8 +46,8 @@ def process(source) locals = attributes.empty? ? '' : attributes.map { |k, v| "'#{k}': #{v}" }.join(', ') - is_component = view_component_exists?(partial) - is_partial = !is_component + component = resolve_view_component(partial) + is_partial = component.nil? if is_partial partial = partial.delete_prefix('_').underscore @@ -65,8 +65,6 @@ def process(source) output = "<%= render partial: '#{partial}'#{collection}#{locals} %>" end else - component = "#{partial}Component" - if content output = "<%= render #{component}.new(#{locals}) do#{yields} %>#{process(content)}<% end %>" elsif collection @@ -107,11 +105,12 @@ def view_component_loaded? @view_component_loaded ||= Object.const_defined?('ViewComponent') end - def view_component_exists?(component) + def resolve_view_component(component) return unless view_component_loaded? - is_capitalized = /^[A-Z]/.match?(component) - is_capitalized && Object.const_defined?("#{component}Component") + # safe_constantize ensures PascalCase + klass = component.safe_constantize || "#{component}Component".safe_constantize + klass.name if klass && klass < ViewComponent::Base end def translate_location(spot, backtrace_location, source) diff --git a/spec/theo-rails/theo_spec.rb b/spec/theo-rails/theo_spec.rb index 208d5e9..5062a71 100644 --- a/spec/theo-rails/theo_spec.rb +++ b/spec/theo-rails/theo_spec.rb @@ -3,6 +3,15 @@ class WidgetComponent < ViewComponent::Base end +class Button < ViewComponent::Base +end + +class Avatar < ViewComponent::Base +end + +class AvatarComponent < ViewComponent::Base +end + RSpec.shared_examples 'theo to erb' do |name, input, output| let(:theo) { Theo::Rails::Theo.new } @@ -146,6 +155,22 @@ class WidgetComponent < ViewComponent::Base %(), %(<%= render WidgetComponent.with_collection(widgets, 'attr1': 'value1', 'attr2': 'value2') %>) end + + context 'component without "Component" suffix' do + include_examples 'theo to erb', 'evaluates simple component', + %(