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.8.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.



444
445
446
# File 'lib/dry/view.rb', line 444

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:



434
435
436
# File 'lib/dry/view.rb', line 434

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, default: 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, default: :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:



338
339
340
341
342
343
344
345
346
# File 'lib/dry/view.rb', line 338

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:



358
359
360
# File 'lib/dry/view.rb', line 358

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, default: 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, default: 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:



405
406
407
# File 'lib/dry/view.rb', line 405

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.



424
425
426
# File 'lib/dry/view.rb', line 424

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, default: "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, default: 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, constructor: -> paths do
  Array(paths).map { |path| Path[path] }
end

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



349
350
351
# File 'lib/dry/view.rb', line 349

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:



377
378
379
# File 'lib/dry/view.rb', line 377

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



412
413
414
415
416
417
418
419
420
421
# File 'lib/dry/view.rb', line 412

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 ‘“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: DEFAULT_RENDERER_OPTIONS, constructor: -> options do
  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, default: 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:



392
393
394
# File 'lib/dry/view.rb', line 392

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:



463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
# File 'lib/dry/view.rb', line 463

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



451
452
453
# File 'lib/dry/view.rb', line 451

def config
  self.class.config
end