Class: Dry::View Abstract

Inherits:
Object
  • Object
show all
Extended by:
Configurable, Core::Cache
Defined in:
lib/dry/view.rb,
lib/dry/view/part.rb,
lib/dry/view/path.rb,
lib/dry/view/tilt.rb,
lib/dry/view/scope.rb,
lib/dry/view/errors.rb,
lib/dry/view/context.rb,
lib/dry/view/version.rb,
lib/dry/view/exposure.rb,
lib/dry/view/rendered.rb,
lib/dry/view/renderer.rb,
lib/dry/view/tilt/erb.rb,
lib/dry/view/exposures.rb,
lib/dry/view/tilt/haml.rb,
lib/dry/view/tilt/erbse.rb,
lib/dry/view/part_builder.rb,
lib/dry/view/scope_builder.rb,
lib/dry/view/render_environment.rb,
lib/dry/view/decorated_attributes.rb,
lib/dry/view/render_environment_missing.rb

Overview

This class is abstract.

Subclass this and provide your own configuration and exposures to define your own view (along with a custom #initialize if you wish to inject dependencies into your subclass)

A standalone, template-based view rendering system that offers everything you need to write well-factored view code.

This represents a single view, holding the configuration and exposures necessary for rendering its template.

Defined Under Namespace

Modules: DecoratedAttributes, Tilt Classes: Context, Exposure, Exposures, Part, PartBuilder, Path, RenderEnvironment, RenderEnvironmentMissing, Rendered, Renderer, Scope, ScopeBuilder, TemplateNotFoundError, UndefinedConfigError

Constant Summary collapse

DEFAULT_RENDERER_OPTIONS =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

{default_encoding: "utf-8"}.freeze
VERSION =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

"0.7.0"

Instance Attribute Summary collapse

Configuration collapse

Exposures collapse

Render environment collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeView

Returns an instance of the view. This binds the defined exposures to the view instance.

Subclasses can define their own #initialize to accept injected dependencies, but must call super() to ensure the standard view initialization can proceed.



440
441
442
# File 'lib/dry/view.rb', line 440

def initialize
  @exposures = self.class.exposures.bind(self)
end

Instance Attribute Details

#exposuresExposures (readonly)

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

The view's bound exposures

Returns:



430
431
432
# File 'lib/dry/view.rb', line 430

def exposures
  @exposures
end

Class Method Details

.config.default_context=(context) ⇒ Object

Set the default context object to use when rendering. This will be used unless another context object is applied at render-time to View#call

Defaults to a frozen instance of Dry::View::Context.

Parameters:

See Also:



121
# File 'lib/dry/view.rb', line 121

setting :default_context, Context.new.freeze

.config.default_format=(format) ⇒ Object

Set the default format to use when rendering.

Defaults to :html.

Parameters:

  • format (Symbol)


131
# File 'lib/dry/view.rb', line 131

setting :default_format, :html

.expose(name, **options, &block) ⇒ Object .expose(name, **options) ⇒ Object .expose(name, **options) ⇒ Object .expose(*names, **options) ⇒ Object

Overloads:

  • .expose(name, **options, &block) ⇒ Object

    Define a value to be passed to the template. The return value of the block will be decorated by a matching Part and passed to the template.

    The block will be evaluated with the view instance as its self. The block's parameters will determine what it is given:

    • To receive other exposure values, provide positional parameters matching the exposure names. These exposures will already by decorated by their Parts.
    • To receive the view's input arguments (whatever is passed to View#call), provide matching keyword parameters. You can provide default values for these parameters to make the corresponding input keys optional
    • To receive the Context object, provide a context: keyword parameter
    • To receive the view's input arguments in their entirety, provide a keywords splat parameter (i.e. **input)

    Examples:

    Accessing input arguments

    expose :article do |slug:|
      article_repo.find_by_slug(slug)
    end

    Accessing other exposures

    expose :articles do
      article_repo.listing
    end
    
    expose :featured_articles do |articles|
      articles.select(&:featured?)
    end

    Parameters:

    • name (Symbol)

      name for the exposure

    • options (Hash)

      the exposure's options

    Options Hash (**options):

    • :layout (Boolean)

      expose this value to the layout (defaults to false)

    • :decorate (Boolean)

      decorate this value in a matching Part (defaults to true)

    • :as (Symbol, Class)

      an alternative name or class to use when finding a matching Part

  • .expose(name, **options) ⇒ Object

    Define a value to be passed to the template, provided by an instance method matching the name. The method's return value will be decorated by a matching Part and passed to the template.

    The method's parameters will determine what it is given:

    • To receive other exposure values, provide positional parameters matching the exposure names. These exposures will already by decorated by their Parts.
    • To receive the view's input arguments (whatever is passed to View#call), provide matching keyword parameters. You can provide default values for these parameters to make the corresponding input keys optional
    • To receive the Context object, provide a context: keyword parameter
    • To receive the view's input arguments in their entirey, provide a keywords splat parameter (i.e. **input)

    Examples:

    Accessing input arguments

    expose :article
    
    def article(slug:)
      article_repo.find_by_slug(slug)
    end

    Accessing other exposures

    expose :articles
    expose :featured_articles
    
    def articles
      article_repo.listing
    end
    
    def featured_articles
      articles.select(&:featured?)
    end

    Parameters:

    • name (Symbol)

      name for the exposure

    • options (Hash)

      the exposure's options

    Options Hash (**options):

    • :layout (Boolean)

      expose this value to the layout (defaults to false)

    • :decorate (Boolean)

      decorate this value in a matching Part (defaults to true)

    • :as (Symbol, Class)

      an alternative name or class to use when finding a matching Part

  • .expose(name, **options) ⇒ Object

    Define a single value to pass through from the input data (when there is no instance method matching the name). This value will be decorated by a matching Part and passed to the template.

    Parameters:

    • name (Symbol)

      name for the exposure

    • options (Hash)

      the exposure's options

    Options Hash (**options):

    • :layout (Boolean)

      expose this value to the layout (defaults to false)

    • :decorate (Boolean)

      decorate this value in a matching Part (defaults to true)

    • :as (Symbol, Class)

      an alternative name or class to use when finding a matching Part

    • :default (Boolean)

      a default value to provide if there is no matching input data

  • .expose(*names, **options) ⇒ Object

    Define multiple values to pass through from the input data (when there is no instance methods matching their names). These values will be decorated by matching Parts and passed through to the template.

    The provided options will be applied to all the exposures.

    Parameters:

    • names (Symbol)

      names for the exposures

    • options (Hash)

      the exposure's options

    Options Hash (**options):

    • :layout (Boolean)

      expose this value to the layout (defaults to false)

    • :decorate (Boolean)

      decorate this value in a matching Part (defaults to true)

    • :as (Symbol, Class)

      an alternative name or class to use when finding a matching Part

    • :default (Boolean)

      a default value to provide if there is no matching input data

See Also:



334
335
336
337
338
339
340
341
342
# File 'lib/dry/view.rb', line 334

def self.expose(*names, **options, &block)
  if names.length == 1
    exposures.add(names.first, block, options)
  else
    names.each do |name|
      exposures.add(name, options)
    end
  end
end

.exposuresExposures

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns the defined exposures. These are unbound, since bound exposures are only created when initializing a View instance.

Returns:



354
355
356
# File 'lib/dry/view.rb', line 354

def self.exposures
  @exposures ||= Exposures.new
end

.config.inflector=(inflector) ⇒ Object

Set an inflector to provide to the part_builder and scope_builder.

Defaults to Dry::Inflector.new.

Parameters:

  • inflector


183
# File 'lib/dry/view.rb', line 183

setting :inflector, Dry::Inflector.new

.inherited(klass) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



221
222
223
224
225
226
# File 'lib/dry/view.rb', line 221

def self.inherited(klass)
  super
  exposures.each do |name, exposure|
    klass.exposures.import(name, exposure)
  end
end

.config.layout=(name) ⇒ Object

Set the name of the layout to render templates within. Layouts will be looked up within the configured layouts_dir, within the configured paths.

A false or nil value will use no layout. Defaults to nil.

Parameters:

  • name (String, FalseClass, nil)

    layout name, or false to indicate no layout



86
# File 'lib/dry/view.rb', line 86

setting :layout, false

.layout_env(format: config.default_format, context: config.default_context) ⇒ RenderEnvironment

Returns a render environment for the view and the given options, chdir'ed into the view's layout directory. This is the environment used when rendering the view's layout.

Parameters:

  • format (Symbol) (defaults to: config.default_format)

    template format to use (defaults to the default_format setting)

  • context (Context) (defaults to: config.default_context)

    context object to use (defaults to the default_context setting)

Returns:



401
402
403
# File 'lib/dry/view.rb', line 401

def self.layout_env(**args)
  render_env(**args).chdir(layout_path)
end

.layout_pathObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



420
421
422
# File 'lib/dry/view.rb', line 420

def self.layout_path
  File.join(config.layouts_dir, config.layout)
end

.config.layouts_dir=(dir) ⇒ Object

Set the name of the directory (within the configured paths) holding the layouts. Defaults to "layouts"

Parameters:

  • dir (String)

    directory name



95
# File 'lib/dry/view.rb', line 95

setting :layouts_dir, "layouts"

.config.part_builder=(part_builder) ⇒ Object

Set a custom part builder class

Parameters:

  • part_builder (Class)

See Also:



152
# File 'lib/dry/view.rb', line 152

setting :part_builder, PartBuilder

.config.scope_namespace=(namespace) ⇒ Object

Set a namespace that will be searched when building scope classes.

Parameters:

  • namespace (Module, Class)

See Also:



142
# File 'lib/dry/view.rb', line 142

setting :part_namespace

.config.paths=(paths) ⇒ Object

Set an array of directories that will be searched for all templates (templates, partials, and layouts).

These will be converted into Path objects and used for template lookup when rendering.

This is a required setting.

Parameters:

  • paths (String, Path, Array<String, Path>)

    the paths



61
62
63
# File 'lib/dry/view.rb', line 61

setting :paths do |paths|
  Array(paths).map { |path| Path[path] }
end

.private_expose(*names, **options, &block) ⇒ Object



345
346
347
# File 'lib/dry/view.rb', line 345

def self.private_expose(*names, **options, &block)
  expose(*names, **options, private: true, &block)
end

.render_env(format: config.default_format, context: config.default_context) ⇒ RenderEnvironment

Returns a render environment for the view and the given options. This environment isn't chdir'ed into any particular directory.

Parameters:

  • format (Symbol) (defaults to: config.default_format)

    template format to use (defaults to the default_format setting)

  • context (Context) (defaults to: config.default_context)

    context object to use (defaults to the default_context setting)

Returns:

See Also:



373
374
375
# File 'lib/dry/view.rb', line 373

def self.render_env(format: config.default_format, context: config.default_context)
  RenderEnvironment.prepare(renderer(format), config, context)
end

.renderer(format) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns renderer for the view and provided format



408
409
410
411
412
413
414
415
416
417
# File 'lib/dry/view.rb', line 408

def self.renderer(format)
  fetch_or_store(:renderer, config, format) {
    Renderer.new(
      config.paths,
      format: format,
      engine_mapping: config.renderer_engine_mapping,
      **config.renderer_options,
    )
  }
end

.config.renderer_engine_mapping=(mapping) ⇒ Object

A hash specifying the (Tilt-compatible) template engine class to use for a given format. Template engine detection is automatic based on format; use this setting only if you want to force a non-preferred engine.

Examples:

config.renderer_engine_mapping = {erb: Tilt::ErubiTemplate}

Parameters:

  • mapping (Hash<Symbol, Class>)

    engine mapping

See Also:



216
# File 'lib/dry/view.rb', line 216

setting :renderer_engine_mapping

.config.renderer_options=(options) ⇒ Object

A hash of options to pass to the template engine. Template engines are provided by Tilt; see Tilt's documentation for what options your template engine may support.

Defaults to {default_encoding: "utf-8"}. Any options passed will be merged onto the defaults.

Parameters:

  • options (Hash)

    renderer options

See Also:



198
199
200
# File 'lib/dry/view.rb', line 198

setting :renderer_options, DEFAULT_RENDERER_OPTIONS do |options|
  DEFAULT_RENDERER_OPTIONS.merge(options.to_h).freeze
end

.config.scope=(scope_class) ⇒ Object

Set the scope class to use when rendering the view's template.

Configuring a custom scope class allows you to provide extra behaviour (alongside exposures) to the template.

Parameters:

  • scope_class (Class)

    scope class (inheriting from Dry::View::Scope)

See Also:



108
# File 'lib/dry/view.rb', line 108

setting :scope

.config.scope_builder=(scope_builder) ⇒ Object

Set a custom scope builder class

Parameters:

  • scope_builder (Class)

See Also:



173
# File 'lib/dry/view.rb', line 173

setting :scope_builder, ScopeBuilder

.config.scope_namespace=(namespace) ⇒ Object

Set a namespace that will be searched when building scope classes.

Parameters:

  • namespace (Module, Class)

See Also:



163
# File 'lib/dry/view.rb', line 163

setting :scope_namespace

.config.template=(name) ⇒ Object

Set the name of the template for rendering this view. Template name should be relative to the configured paths.

This is a required setting.

Parameters:

  • name (String)

    template name



74
# File 'lib/dry/view.rb', line 74

setting :template

.template_env(format: config.default_format, context: config.default_context) ⇒ RenderEnvironment

Returns a render environment for the view and the given options, chdir'ed into the view's template directory. This is the environment used when rendering the template, and is useful to to fetch independently when unit testing Parts and Scopes.

Parameters:

  • format (Symbol) (defaults to: config.default_format)

    template format to use (defaults to the default_format setting)

  • context (Context) (defaults to: config.default_context)

    context object to use (defaults to the default_context setting)

Returns:



388
389
390
# File 'lib/dry/view.rb', line 388

def self.template_env(**args)
  render_env(**args).chdir(config.template)
end

Instance Method Details

#call(format: config.default_format, context: config.default_context, **input) ⇒ Rendered

Render the view

Parameters:

  • format (Symbol) (defaults to: config.default_format)

    template format to use

  • context (Context) (defaults to: config.default_context)

    context object to use

  • input

    input data for preparing exposure values

Returns:



459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
# File 'lib/dry/view.rb', line 459

def call(format: config.default_format, context: config.default_context, **input)
  ensure_config

  env = self.class.render_env(format: format, context: context)
  template_env = self.class.template_env(format: format, context: context)

  locals = locals(template_env, input)
  output = env.template(config.template, template_env.scope(config.scope, locals))

  if layout?
    layout_env = self.class.layout_env(format: format, context: context)
    output = env.template(self.class.layout_path, layout_env.scope(config.scope, layout_locals(locals))) { output }
  end

  Rendered.new(output: output, locals: locals)
end

#configObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

The view's configuration



447
448
449
# File 'lib/dry/view.rb', line 447

def config
  self.class.config
end