class Bridgetown::Component

Attributes

source_location[RW]
site[R]

@return [Bridgetown::Site]

view_context[R]

@return [Bridgetown::RubyTemplateView, Bridgetown::Component]

Public Class Methods

component_template_content() click to toggle source

Read the template file.

@return [String]

# File lib/bridgetown-core/component.rb, line 83
def component_template_content
  @_tmpl_content ||= File.read(component_template_path)
end
component_template_path() click to toggle source

Find the first matching template path based on source location and extension.

@return [String]

# File lib/bridgetown-core/component.rb, line 58
def component_template_path
  @_tmpl_path ||= begin
    stripped_path = File.join(
      File.dirname(source_location),
      File.basename(source_location, ".*")
    )
    supported_template_extensions.each do |ext|
      test_path = "#{stripped_path}.#{ext}"
      break test_path if File.exist?(test_path)

      test_path = "#{stripped_path}.html.#{ext}"
      break test_path if File.exist?(test_path)
    end
  end

  unless @_tmpl_path.is_a?(String)
    raise "#{name}: no matching template could be found in #{File.dirname(source_location)}"
  end

  @_tmpl_path
end
inherited(child) click to toggle source
Calls superclass method
# File lib/bridgetown-core/component.rb, line 18
def inherited(child)
  # Code cribbed from ViewComponent by GitHub:
  # Derive the source location of the component Ruby file from the call stack
  child.source_location = caller_locations(1, 10).reject do |l|
    l.label == "inherited"
  end[0].absolute_path

  super
end
renderer_for_ext(ext, &block) click to toggle source

Return the appropriate template renderer for a given extension. TODO: make this extensible

@param ext [String] erb, slim, etc.

# File lib/bridgetown-core/component.rb, line 32
def renderer_for_ext(ext, &block)
  @_tmpl ||= case ext
             when "erb"
               include ERBCapture
               Tilt::ErubiTemplate.new(component_template_path,
                                       outvar: "@_erbout",
                                       bufval: "Bridgetown::OutputBuffer.new",
                                       engine_class: Bridgetown::ERBEngine,
                                       &block)
             when "serb" # requires serbea
               include Serbea::Helpers
               Tilt::SerbeaTemplate.new(component_template_path, &block)
             when "slim" # requires bridgetown-slim
               Slim::Template.new(component_template_path, &block)
             when "haml" # requires bridgetown-haml
               Tilt::HamlTemplate.new(component_template_path, &block)
             else
               raise NameError
             end
rescue NameError, LoadError
  raise "No component rendering engine could be found for .#{ext} templates"
end
supported_template_extensions() click to toggle source

A list of extensions supported by the renderer TODO: make this extensible

@return [Array<String>]

# File lib/bridgetown-core/component.rb, line 91
def supported_template_extensions
  %w(erb serb slim haml)
end

Public Instance Methods

_renderer() click to toggle source
# File lib/bridgetown-core/component.rb, line 162
def _renderer
  @_renderer ||= begin
    ext = File.extname(self.class.component_template_path).delete_prefix(".")
    self.class.renderer_for_ext(ext) { self.class.component_template_content }
  end
end
before_render() click to toggle source

Subclasses can override this method to perform tasks before a render.

# File lib/bridgetown-core/component.rb, line 154
def before_render; end
call() click to toggle source

Typically not used but here as a compatibility nod toward ViewComponent.

# File lib/bridgetown-core/component.rb, line 149
def call
  nil
end
content() click to toggle source

If a content block was originally passed into via `render`, capture its output.

@return [String] or nil

# File lib/bridgetown-core/component.rb, line 99
def content
  @_content ||= begin
    view_context.capture(self, &@_content_block) if @_content_block
  end
end
method_missing(method, *args, &block) click to toggle source
Calls superclass method
# File lib/bridgetown-core/component.rb, line 170
               def method_missing(method, *args, &block)
  if helpers.respond_to?(method.to_sym)
    helpers.send method.to_sym, *args, &block
  else
    super
  end
end
render(item, options = {}, &block) click to toggle source

Provide a render helper for evaluation within the component context.

@param item [Object] a component supporting `render_in` or a partial name @param options [Hash] passed to the `partial` helper if needed @return [String]

# File lib/bridgetown-core/component.rb, line 110
def render(item, options = {}, &block)
  if item.respond_to?(:render_in)
    result = ""
    capture do # this ensures no leaky interactions between BT<=>VC blocks
      result = item.render_in(self, &block)
    end
    result&.html_safe
  else
    partial(item, options, &block)&.html_safe
  end
end
render?() click to toggle source

Subclasses can override this method to determine if the component should be rendered based on initialized data or other logic.

# File lib/bridgetown-core/component.rb, line 158
def render?
  true
end
render_in(view_context, &block) click to toggle source

This is where the magic happens. Render the component within a view context.

@param view_context [Bridgetown::RubyTemplateView]

# File lib/bridgetown-core/component.rb, line 125
def render_in(view_context, &block)
  @view_context = view_context
  @_content_block = block

  if render?
    before_render
    template
  else
    ""
  end
rescue StandardError => e
  Bridgetown.logger.error "Component error:",
                          "#{self.class} encountered an error while "\
                          "rendering `#{self.class.component_template_path}'"
  raise e
end
respond_to_missing?(method, include_private = false) click to toggle source
Calls superclass method
# File lib/bridgetown-core/component.rb, line 178
def respond_to_missing?(method, include_private = false)
  helpers.respond_to?(method.to_sym, include_private) || super
end
template() click to toggle source

Subclasses can override this method to return a string from their own template handling.

# File lib/bridgetown-core/component.rb, line 144
def template
  call || _renderer.render(self)
end