class ViewComponent::Base

def __vc_collection_counter_parameter

Other tags:
    Private: -
def __vc_collection_counter_parameter
  :"#{__vc_collection_parameter}_counter"
end

def __vc_collection_iteration_parameter

Other tags:
    Private: -
def __vc_collection_iteration_parameter
  :"#{__vc_collection_parameter}_iteration"
end

def __vc_collection_parameter

Other tags:
    Private: -
def __vc_collection_parameter
  provided_collection_parameter || name && name.demodulize.underscore.chomp("_component").to_sym
end

def __vc_compile(raise_errors: false, force: false)

Other tags:
    Private: -
def __vc_compile(raise_errors: false, force: false)
  __vc_compiler.compile(raise_errors: raise_errors, force: force)
end

def __vc_compiled?

Other tags:
    Private: -
def __vc_compiled?
  __vc_compiler.compiled?
end

def __vc_compiler

Other tags:
    Private: -
def __vc_compiler
  @__vc_compiler ||= Compiler.new(self)
end

def __vc_content_set_by_with_content_defined?

def __vc_content_set_by_with_content_defined?
  defined?(@__vc_content_set_by_with_content)
end

def __vc_counter_argument_present?

Other tags:
    Private: -
def __vc_counter_argument_present?
  initialize_parameter_names.include?(__vc_collection_counter_parameter)
end

def __vc_ensure_compiled

Other tags:
    Private: -
def __vc_ensure_compiled
  __vc_compile unless __vc_compiled?
end

def __vc_iteration_argument_present?

Other tags:
    Private: -
def __vc_iteration_argument_present?
  initialize_parameter_names.include?(__vc_collection_iteration_parameter)
end

def __vc_render_in_block_provided?

def __vc_render_in_block_provided?
  defined?(@view_context) && @view_context && @__vc_render_in_block
end

def __vc_request

Other tags:
    Private: -
def __vc_request
  # The current request (if present, as mailers/jobs/etc do not have a request)
  @__vc_request ||= controller.request if controller.respond_to?(:request)
end

def __vc_validate_collection_parameter!(validate_default: false)

Other tags:
    Private: -
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?
  # If Ruby can't parse the component class, then the initialize
  # parameters will be empty and ViewComponent will not be able to render
  # the component.
  if initialize_parameters.empty?
    raise EmptyOrInvalidInitializerError.new(name, parameter)
  end
  raise MissingCollectionArgumentError.new(name, parameter)
end

def __vc_validate_initialization_parameters!

Other tags:
    Private: -
def __vc_validate_initialization_parameters!
  return unless initialize_parameter_names.include?(:content)
  raise ReservedParameterError.new(name, :content)
end

def before_render

Returns:
  • (void) -
def before_render
  # noop
end

def config

Returns:
  • (ActiveSupport::OrderedOptions) -
def config
  module_parents.each do |m|
    config = m.try(:config).try(:view_component)
    return config if config
  end
  ViewComponent::Config.current
end

def content

Returns:
  • (String) -
def content
  @__vc_content_evaluated = true
  return @__vc_content if defined?(@__vc_content)
  @__vc_content =
    if __vc_render_in_block_provided?
      view_context.capture(self, &@__vc_render_in_block)
    elsif __vc_content_set_by_with_content_defined?
      @__vc_content_set_by_with_content
    end
end

def content?

Returns:
  • (Boolean) -
def content?
  __vc_render_in_block_provided? || __vc_content_set_by_with_content_defined?
end

def content_evaluated?

def content_evaluated?
  defined?(@__vc_content_evaluated) && @__vc_content_evaluated
end

def controller

Returns:
  • (ActionController::Base) -
def controller
  raise ControllerCalledBeforeRenderError if view_context.nil?
  @__vc_controller ||= view_context.controller
end

def helpers

Returns:
  • (ActionView::Base) -
def helpers
  raise HelpersCalledBeforeRenderError if view_context.nil?
  # Attempt to re-use the original view_context passed to the first
  # component rendered in the rendering pipeline. This prevents the
  # instantiation of a new view_context via `controller.view_context` which
  # always returns a new instance of the view context class.
  #
  # This allows ivars to remain persisted when using the same helper via
  # `helpers` across multiple components and partials.
  @__vc_helpers ||= __vc_original_view_context || controller.view_context
end

def inherited(child)

Other tags:
    Private: -
def inherited(child)
  # Compile so child will inherit compiled `call_*` template methods that
  # `compile` defines
  __vc_compile
  # Give the child its own personal #render_template_for to protect against the case when
  # eager loading is disabled and the parent component is rendered before the child. In
  # such a scenario, the parent will override ViewComponent::Base#render_template_for,
  # meaning it will not be called for any children and thus not compile their templates.
  if !child.instance_methods(false).include?(:render_template_for) && !child.__vc_compiled?
    child.class_eval <<~RUBY, __FILE__, __LINE__ + 1
      def render_template_for(requested_details)
        # Force compilation here so the compiler always redefines render_template_for.
        # This is mostly a safeguard to prevent infinite recursion.
        self.class.__vc_compile(raise_errors: true, force: true)
        # .__vc_compile replaces this method; call the new one
        render_template_for(requested_details)
      end
    RUBY
  end
  # If Rails application is loaded, add application url_helpers to the component context
  # we need to check this to use this gem as a dependency
  if defined?(Rails) && Rails.application && !(child < Rails.application.routes.url_helpers)
    child.include Rails.application.routes.url_helpers
  end
  # Derive the source location of the component Ruby file from the call stack.
  # We need to ignore `inherited` frames here as they indicate that `inherited`
  # has been re-defined by the consuming application, likely in ApplicationComponent.
  # We use `base_label` method here instead of `label` to avoid cases where the method
  # owner is included in a prefix like `ApplicationComponent.inherited`.
  child.identifier = caller_locations(1, 10).reject { |l| l.base_label == "inherited" }[0].path
  # If Rails application is loaded, removes the first part of the path and the extension.
  if defined?(Rails) && Rails.application
    child.virtual_path = child.identifier.gsub(
      /(.*#{Regexp.quote(ViewComponent::Base.config.view_component_path)})|(\.rb)/, ""
    )
  end
  # Set collection parameter to the extended component
  child.with_collection_parameter provided_collection_parameter
  if instance_methods(false).include?(:render_template_for)
    vc_ancestor_calls = defined?(@__vc_ancestor_calls) ? @__vc_ancestor_calls.dup : []
    vc_ancestor_calls.unshift(instance_method(:render_template_for))
    child.instance_variable_set(:@__vc_ancestor_calls, vc_ancestor_calls)
  end
  super
end

def initialize_parameter_names

def initialize_parameter_names
  return attribute_names.map(&:to_sym) if respond_to?(:attribute_names)
  initialize_parameters.map(&:last)
end

def initialize_parameters

def initialize_parameters
  @initialize_parameters ||= instance_method(:initialize).parameters
end

def maybe_escape_html(text)

def maybe_escape_html(text)
  return text if @current_template && !@current_template.html?
  return text if text.blank?
  if text.html_safe?
    text
  else
    yield
    html_escape(text)
  end
end

def method_missing(method_name, *args) # rubocop:disable Style/MissingRespondToMissing

Other tags:
    Private: -
def method_missing(method_name, *args) # rubocop:disable Style/MissingRespondToMissing
  super
rescue => e # rubocop:disable Style/RescueStandardError
  e.set_backtrace e.backtrace.tap(&:shift)
  raise e, <<~MESSAGE.chomp if view_context && e.is_a?(NameError) && helpers.respond_to?(method_name)
    #{e.message}
    You may be trying to call a method provided as a view helper. Did you mean `helpers.#{method_name}`?
  MESSAGE
  raise
end

def output_postamble

Returns:
  • (String) -
def output_postamble
  @@default_output_postamble ||= "".html_safe
end

def output_preamble

Returns:
  • (String) -
def output_preamble
  @@default_output_preamble ||= "".html_safe
end

def provided_collection_parameter

def provided_collection_parameter
  @provided_collection_parameter ||= nil
end

def render(options = {}, args = {}, &block)

Other tags:
    Private: -
def render(options = {}, args = {}, &block)
  if options.respond_to?(:set_original_view_context)
    options.set_original_view_context(self.__vc_original_view_context)
    @view_context.render(options, args, &block)
  else
    __vc_original_view_context.render(options, args, &block)
  end
end

def render?

Returns:
  • (Boolean) -
def render?
  true
end

def render_in(view_context, &block)

Returns:
  • (String) -
def render_in(view_context, &block)
  self.class.__vc_compile(raise_errors: true)
  @view_context = view_context
  self.__vc_original_view_context ||= view_context
  @output_buffer = view_context.output_buffer
  @lookup_context ||= view_context.lookup_context
  # For content_for
  @view_flow ||= view_context.view_flow
  # For i18n
  @virtual_path ||= virtual_path
  # Describes the inferred request constraints (locales, formats, variants)
  @__vc_requested_details ||= @lookup_context.vc_requested_details
  # For caching, such as #cache_if
  @current_template = nil unless defined?(@current_template)
  old_current_template = @current_template
  if block && defined?(@__vc_content_set_by_with_content)
    raise DuplicateContentError.new(self.class.name)
  end
  @__vc_content_evaluated = false
  @__vc_render_in_block = block
  before_render
  if render?
    value = nil
    @output_buffer.with_buffer do
      rendered_template = render_template_for(@__vc_requested_details).to_s
      # Avoid allocating new string when output_preamble and output_postamble are blank
      value = if output_preamble.blank? && output_postamble.blank?
        rendered_template
      else
        safe_output_preamble + rendered_template + safe_output_postamble
      end
    end
    value
  else
    ""
  end
ensure
  @current_template = old_current_template
end

def render_parent

double-rendering.
parent template considering the current variant and emits the result without
`super` also doesn't consider the current variant. `render_parent` renders the

```
<% super %> # doesn't double-render
<%= super %> # double-renders
```erb

double render if they emit the result.
Subclass components that call `super` inside their template code will cause a
def render_parent
  render_parent_to_string
  nil
end

def render_parent_to_string

When rendering the parent inside an .erb template, use `#render_parent` instead.

```
end
"
#{render_parent_to_string}
"
def call
```ruby

to be used inside custom #call methods when a string result is desired, eg.
Renders the parent component to a string and returns it. This method is meant
def render_parent_to_string
  @__vc_parent_render_level ||= 0 # ensure a good starting value
  begin
    target_render = self.class.instance_variable_get(:@__vc_ancestor_calls)[@__vc_parent_render_level]
    @__vc_parent_render_level += 1
    target_render.bind_call(self, @__vc_requested_details)
  ensure
    @__vc_parent_render_level -= 1
  end
end

def request

Returns:
  • (ActionDispatch::Request) -
def request
  __vc_request
end

def safe_output_postamble

def safe_output_postamble
  maybe_escape_html(output_postamble) do
    Kernel.warn("WARNING: The #{self.class} component was provided an HTML-unsafe postamble. The postamble will be automatically escaped, but you may want to investigate.")
  end
end

def safe_output_preamble

def safe_output_preamble
  maybe_escape_html(output_preamble) do
    Kernel.warn("WARNING: The #{self.class} component was provided an HTML-unsafe preamble. The preamble will be automatically escaped, but you may want to investigate.")
  end
end

def set_original_view_context(view_context)

Returns:
  • (void) -

Parameters:
  • view_context (ActionView::Base) -- The original view context.
def set_original_view_context(view_context)
  # noop
end

def sidecar_files(extensions)

Parameters:
  • extensions (Array) -- Extensions of which to return matching sidecar files.
def sidecar_files(extensions)
  return [] unless identifier
  extensions = extensions.join(",")
  # view files in a directory named like the component
  directory = File.dirname(identifier)
  filename = File.basename(identifier, ".rb")
  component_name = name.demodulize.underscore
  # Add support for nested components defined in the same file.
  #
  # for example
  #
  # class MyComponent < ViewComponent::Base
  #   class MyOtherComponent < ViewComponent::Base
  #   end
  # end
  #
  # Without this, `MyOtherComponent` will not look for `my_component/my_other_component.html.erb`
  nested_component_files =
    if name.include?("::") && component_name != filename
      Dir["#{directory}/#{filename}/#{component_name}.*{#{extensions}}"]
    else
      []
    end
  # view files in the same directory as the component
  sidecar_files = Dir["#{directory}/#{component_name}.*{#{extensions}}"]
  sidecar_directory_files = Dir["#{directory}/#{component_name}/#{filename}.*{#{extensions}}"]
  (sidecar_files - [identifier] + sidecar_directory_files + nested_component_files).uniq
end

def splatted_keyword_argument_present?

def splatted_keyword_argument_present?
  initialize_parameters.flatten.include?(:keyrest) &&
    !initialize_parameters.include?([:keyrest, :**]) # Un-named splatted keyword args don't count!
end

def strip_trailing_whitespace(value = true)

Parameters:
  • value (Boolean) -- Whether to strip newlines.

Deprecated:
  • Use the new component-local configuration option instead.
def strip_trailing_whitespace(value = true)
  ViewComponent::Deprecation.deprecation_warning(
    "strip_trailing_whitespace",
    <<~DOC
      Use the new component-local configuration option instead:
      class #{self.class.name} < ViewComponent::Base
        configure_view_component do |config|
          config.strip_trailing_whitespace = #{value}
        end
      end
    DOC
  )
  view_component_config.strip_trailing_whitespace = value
end

def strip_trailing_whitespace?

Returns:
  • (Boolean) -
def strip_trailing_whitespace?
  view_component_config.strip_trailing_whitespace
end

def view_cache_dependencies

Other tags:
    Private: -
def view_cache_dependencies
  []
end

def virtual_path

Other tags:
    Private: -
def virtual_path
  self.class.virtual_path
end

def with_collection(collection, spacer_component: nil, **args)

Parameters:
  • args (Arguments) -- Arguments to pass to the ViewComponent every time.
  • spacer_component (ViewComponent::Base) -- Component instance to be rendered between items.
  • collection (Enumerable) -- A list of items to pass the ViewComponent one at a time.
def with_collection(collection, spacer_component: nil, **args)
  Collection.new(self, collection, spacer_component, **args)
end

def with_collection_parameter(parameter)

Parameters:
  • parameter (Symbol) -- The parameter name used when rendering elements of a collection.
def with_collection_parameter(parameter)
  @provided_collection_parameter = parameter
  @initialize_parameters = nil
end