Skip to content

Commit

Permalink
Merge pull request #8 from david-uhlig/broaden-viewcomponent-detection
Browse files Browse the repository at this point in the history
Expand ViewComponent detection logic
  • Loading branch information
loomchild authored Jan 19, 2025
2 parents a81e688 + adc05ad commit 531176b
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 7 deletions.
13 changes: 6 additions & 7 deletions lib/theo-rails/theo.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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)
Expand Down
25 changes: 25 additions & 0 deletions spec/theo-rails/theo_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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 }

Expand Down Expand Up @@ -146,6 +155,22 @@ class WidgetComponent < ViewComponent::Base
%(<Widget collection="widgets" attr1="value1" attr2="value2" />),
%(<%= render WidgetComponent.with_collection(widgets, 'attr1': 'value1', 'attr2': 'value2') %>)
end

context 'component without "Component" suffix' do
include_examples 'theo to erb', 'evaluates simple component',
%(<Button />),
%(<%= render Button.new() %>)
end

context 'competing component names' do
include_examples 'theo to erb', 'evaluates direct match',
%(<Avatar />),
%(<%= render Avatar.new() %>)

include_examples 'theo to erb', 'evaluates direct match with "Component" suffix',
%(<AvatarComponent />),
%(<%= render AvatarComponent.new() %>)
end
end

context 'erb compatibility' do
Expand Down

0 comments on commit 531176b

Please sign in to comment.