Class: ViewComponent::Slot

Inherits:
Object
  • Object
show all
Includes:
WithContentHelper
Defined in:
lib/view_component/slot.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(parent) ⇒ Slot

Returns a new instance of Slot.



11
12
13
# File 'lib/view_component/slot.rb', line 11

def initialize(parent)
  @parent = parent
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(symbol, *args, &block) ⇒ Object

Allow access to public component methods via the wrapper

for example

calling ‘header.name` (where `header` is a slot) will call `name` on the `HeaderComponent` instance.

Where the component may look like:

class MyComponent < ViewComponent::Base

has_one :header, HeaderComponent

class HeaderComponent < ViewComponent::Base
  def name
    @name
  end
end

end



104
105
106
# File 'lib/view_component/slot.rb', line 104

def method_missing(symbol, *args, &block)
  @__vc_component_instance.public_send(symbol, *args, &block)
end

Instance Attribute Details

#__vc_component_instance=(value) ⇒ Object (writeonly)

Sets the attribute __vc_component_instance

Parameters:

  • value

    the value to set the attribute __vc_component_instance to.



9
10
11
# File 'lib/view_component/slot.rb', line 9

def __vc_component_instance=(value)
  @__vc_component_instance = value
end

#__vc_content=(value) ⇒ Object (writeonly)

Sets the attribute __vc_content

Parameters:

  • value

    the value to set the attribute __vc_content to.



9
10
11
# File 'lib/view_component/slot.rb', line 9

def __vc_content=(value)
  @__vc_content = value
end

#__vc_content_block=(value) ⇒ Object (writeonly)

Sets the attribute __vc_content_block

Parameters:

  • value

    the value to set the attribute __vc_content_block to.



9
10
11
# File 'lib/view_component/slot.rb', line 9

def __vc_content_block=(value)
  @__vc_content_block = value
end

Instance Method Details

#content?Boolean

Returns:

  • (Boolean)


15
16
17
18
19
20
21
22
# File 'lib/view_component/slot.rb', line 15

def content?
  return true if defined?(@__vc_content) && @__vc_content.present?
  return true if defined?(@__vc_content_set_by_with_content) && @__vc_content_set_by_with_content.present?
  return true if defined?(@__vc_content_block) && @__vc_content_block.present?
  return false if !__vc_component_instance?

  @__vc_component_instance.content?
end

#html_safe?Boolean

Returns:

  • (Boolean)


109
110
111
112
113
# File 'lib/view_component/slot.rb', line 109

def html_safe?
  # :nocov:
  to_s.html_safe?
  # :nocov:
end

#respond_to_missing?(symbol, include_all = false) ⇒ Boolean

Returns:

  • (Boolean)


115
116
117
# File 'lib/view_component/slot.rb', line 115

def respond_to_missing?(symbol, include_all = false)
  __vc_component_instance? && @__vc_component_instance.respond_to?(symbol, include_all)
end

#to_sObject

Used to render the slot content in the template

There’s currently 3 different values that may be set, that we can render.

If the slot renderable is a component, the string class name of a component, or a function that returns a component, we render that component instance, returning the string.

If the slot renderable is a function and returns a string, it’s set as ‘@__vc_content` and is returned directly.

If there is no slot renderable, we evaluate the block passed to the slot and return it.



45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
# File 'lib/view_component/slot.rb', line 45

def to_s
  return @content if defined?(@content)

  view_context = @parent.send(:view_context)

  if defined?(@__vc_content_block) && defined?(@__vc_content_set_by_with_content)
    raise DuplicateSlotContentError.new(self.class.name)
  end

  @content =
    if __vc_component_instance?
      @__vc_component_instance.__vc_original_view_context = @parent.__vc_original_view_context

      if defined?(@__vc_content_block)
        # render_in is faster than `parent.render`
        @__vc_component_instance.render_in(view_context) do |*args|
          return @__vc_content_block.call(*args) if @__vc_content_block&.source_location.nil?

          block_context = @__vc_content_block.binding.receiver

          if block_context.class < ActionView::Base
            block_context.capture(*args, &@__vc_content_block)
          else
            @__vc_content_block.call(*args)
          end
        end
      else
        @__vc_component_instance.render_in(view_context)
      end
    elsif defined?(@__vc_content)
      @__vc_content
    elsif defined?(@__vc_content_block)
      view_context.capture(&@__vc_content_block)
    elsif defined?(@__vc_content_set_by_with_content)
      @__vc_content_set_by_with_content
    end

  @content = @content.to_s
end

#with_content(args) ⇒ Object



24
25
26
27
28
29
30
# File 'lib/view_component/slot.rb', line 24

def with_content(args)
  if __vc_component_instance?
    @__vc_component_instance.with_content(args)
  else
    super
  end
end