class ViewComponent::Base

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_render_in_block_provided?

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

def before_render

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

def collection_counter_parameter

Other tags:
    Private: -
def collection_counter_parameter
  "#{collection_parameter}_counter".to_sym
end

def collection_iteration_parameter

Other tags:
    Private: -
def collection_iteration_parameter
  "#{collection_parameter}_iteration".to_sym
end

def collection_parameter

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

def compile(raise_errors: false, force: false)

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

def compiled?

Other tags:
    Private: -
def compiled?
  compiler.compiled?
end

def compiler

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

def config

Returns:
  • (ActiveSupport::OrderedOptions) -
def config
  @config ||= ActiveSupport::OrderedOptions.new
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 counter_argument_present?

Other tags:
    Private: -
def counter_argument_present?
  initialize_parameter_names.include?(collection_counter_parameter)
end

def ensure_compiled

Other tags:
    Private: -
def ensure_compiled
  compile unless compiled?
end

def format

Other tags:
    Private: -
def format
  @__vc_variant if defined?(@__vc_variant)
end

def format

Other tags:
    Private: -
def format
  :html
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 identifier

Other tags:
    Private: -
def identifier
  source_location
end

def inherited(child)

Other tags:
    Private: -
def inherited(child)
  # Compile so child will inherit compiled `call_*` template methods that
  # `compile` defines
  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.compiled?
    child.class_eval <<~RUBY, __FILE__, __LINE__ + 1
      def render_template_for(variant = nil)
        # Force compilation here so the compiler always redefines render_template_for.
        # This is mostly a safeguard to prevent infinite recursion.
        self.class.compile(raise_errors: true, force: true)
        # .compile replaces this method; call the new one
        render_template_for(variant)
      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.
  child.source_location = caller_locations(1, 10).reject { |l| l.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.source_location.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
  super
end

def initialize(*)

Other tags:
    Private: -
def initialize(*)
end

def initialize_parameter_names

def initialize_parameter_names
  return attribute_names.map(&:to_sym) if respond_to?(:attribute_names)
  return attribute_types.keys.map(&:to_sym) if Rails::VERSION::MAJOR <= 5 && respond_to?(:attribute_types)
  initialize_parameters.map(&:last)
end

def initialize_parameters

def initialize_parameters
  instance_method(:initialize).parameters
end

def iteration_argument_present?

Other tags:
    Private: -
def iteration_argument_present?
  initialize_parameter_names.include?(collection_iteration_parameter)
end

def output_postamble

Returns:
  • (String) -
def output_postamble
  ""
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)
    super
  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.compile(raise_errors: true)
  @view_context = view_context
  self.__vc_original_view_context ||= view_context
  @output_buffer = ActionView::OutputBuffer.new
  @lookup_context ||= view_context.lookup_context
  # required for path helpers in older Rails versions
  @view_renderer ||= view_context.view_renderer
  # For content_for
  @view_flow ||= view_context.view_flow
  # For i18n
  @virtual_path ||= virtual_path
  # For template variants (+phone, +desktop, etc.)
  @__vc_variant ||= @lookup_context.variants.first
  # For caching, such as #cache_if
  @current_template = nil unless defined?(@current_template)
  old_current_template = @current_template
  @current_template = self
  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?
    render_template_for(@__vc_variant).to_s + output_postamble
  else
    ""
  end
ensure
  @current_template = old_current_template
end

def render_parent

Calls `super`, returning `nil` to avoid rendering the result twice.

```
<% super %> # does not 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
  mtd = @__vc_variant ? "call_#{@__vc_variant}" : "call"
  method(mtd).super_method.call
  nil
end

def request

Returns:
  • (ActionDispatch::Request) -
def request
  @request ||= controller.request if controller.respond_to?(:request)
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)
  self.__vc_original_view_context = view_context
end

def short_identifier

Other tags:
    Private: -
def short_identifier
  @short_identifier ||= defined?(Rails.root) ? source_location.sub("#{Rails.root}/", "") : source_location
end

def sidecar_files(extensions)

Parameters:
  • extensions (Array) -- Extensions of which to return matching sidecar files.
def sidecar_files(extensions)
  return [] unless source_location
  extensions = extensions.join(",")
  # view files in a directory named like the component
  directory = File.dirname(source_location)
  filename = File.basename(source_location, ".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 - [source_location] + 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.
def strip_trailing_whitespace(value = true)
  self.__vc_strip_trailing_whitespace = value
end

def strip_trailing_whitespace?

Returns:
  • (Boolean) -
def strip_trailing_whitespace?
  __vc_strip_trailing_whitespace
end

def type

Other tags:
    Private: -
def type
  "text/html"
end

def validate_collection_parameter!(validate_default: false)

Other tags:
    Private: - TODO: add documentation
def validate_collection_parameter!(validate_default: false)
  parameter = validate_default ? 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 validate_initialization_parameters!

Other tags:
    Private: - TODO: add documentation
def validate_initialization_parameters!
  return unless initialize_parameter_names.include?(RESERVED_PARAMETER)
  raise ReservedParameterError.new(name, RESERVED_PARAMETER)
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, **args)

Parameters:
  • args (Arguments) -- Arguments to pass to the ViewComponent every time.
  • collection (Enumerable) -- A list of items to pass the ViewComponent one at a time.
def with_collection(collection, **args)
  Collection.new(self, collection, **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
end