class Dry::View::PartBuilder

Decorates exposure values with matching parts

@api private

Attributes

namespace[R]
render_env[R]

Public Class Methods

new(namespace: nil, render_env: nil) click to toggle source

Returns a new instance of PartBuilder

@api private

# File lib/dry/view/part_builder.rb, line 22
def initialize(namespace: nil, render_env: nil)
  @namespace = namespace
  @render_env = render_env
end

Public Instance Methods

call(name, value, **options) click to toggle source

Decorates an exposure value

@param name [Symbol] exposure name @param value [Object] exposure value @param options [Hash] exposure options

@return [Dry::View::Part] decorated value

@api private

# File lib/dry/view/part_builder.rb, line 43
def call(name, value, **options)
  builder = value.respond_to?(:to_ary) ? :build_collection_part : :build_part

  send(builder, name, value, **options)
end
for_render_env(render_env) click to toggle source

@api private

# File lib/dry/view/part_builder.rb, line 28
def for_render_env(render_env)
  return self if render_env == self.render_env

  self.class.new(namespace: namespace, render_env: render_env)
end

Private Instance Methods

build_collection_part(name, value, **options) click to toggle source
# File lib/dry/view/part_builder.rb, line 61
def build_collection_part(name, value, **options)
  collection_as = collection_options(name: name, **options)[:as]
  item_name, item_as = collection_item_options(name: name, **options).values_at(:name, :as)

  arr = value.to_ary.map { |obj|
    build_part(item_name, obj, **options.merge(as: item_as))
  }

  build_part(name, arr, **options.merge(as: collection_as))
end
build_part(name, value, **options) click to toggle source
# File lib/dry/view/part_builder.rb, line 51
def build_part(name, value, **options)
  klass = part_class(name: name, **options)

  klass.new(
    name: name,
    value: value,
    render_env: render_env
  )
end
collection_item_options(name:, **options) click to toggle source

rubocop:enable Lint/UnusedMethodArgument

# File lib/dry/view/part_builder.rb, line 80
def collection_item_options(name:, **options)
  singular_name = inflector.singularize(name).to_sym
  singular_as =
    if options[:as].is_a?(Array)
      options[:as].last if options[:as].length > 1
    else
      options[:as]
    end

  if singular_as && !singular_as.is_a?(Class)
    singular_as = inflector.singularize(singular_as.to_s)
  end

  options.merge(
    name: singular_name,
    as: singular_as
  )
end
collection_options(name:, **options) click to toggle source

rubocop:disable Lint/UnusedMethodArgument

# File lib/dry/view/part_builder.rb, line 73
def collection_options(name:, **options)
  collection_as = options[:as].is_a?(Array) ? options[:as].first : nil

  options.merge(as: collection_as)
end
inflector() click to toggle source

rubocop:enable Metrics/PerceivedComplexity

# File lib/dry/view/part_builder.rb, line 135
def inflector
  render_env.inflector
end
part_class(name:, fallback_class: Part, **options) click to toggle source
# File lib/dry/view/part_builder.rb, line 99
def part_class(name:, fallback_class: Part, **options)
  name = options[:as] || name

  if name.is_a?(Class)
    name
  else
    fetch_or_store(namespace, name, fallback_class) do
      resolve_part_class(name: name, fallback_class: fallback_class)
    end
  end
end
resolve_part_class(name:, fallback_class:) click to toggle source

rubocop:disable Metrics/PerceivedComplexity

# File lib/dry/view/part_builder.rb, line 112
def resolve_part_class(name:, fallback_class:)
  return fallback_class unless namespace

  name = inflector.camelize(name.to_s)

  # Give autoloaders a chance to act
  begin
    klass = namespace.const_get(name)
  rescue NameError # rubocop:disable Lint/HandleExceptions
  end

  if !klass && namespace.const_defined?(name, false)
    klass = namespace.const_get(name)
  end

  if klass && klass < Part
    klass
  else
    fallback_class
  end
end