lib/dry/view/controller.rb in dry-view-0.2.2 vs lib/dry/view/controller.rb in dry-view-0.3.0

- old
+ new

@@ -2,10 +2,11 @@ require 'dry-equalizer' require 'dry/view/path' require 'dry/view/exposures' require 'dry/view/renderer' +require 'dry/view/decorator' require 'dry/view/scope' module Dry module View class Controller @@ -17,91 +18,126 @@ extend Dry::Configurable setting :paths setting :layout, false - setting :context, DEFAULT_CONTEXT setting :template setting :default_format, :html + setting :context, DEFAULT_CONTEXT + setting :decorator, Decorator.new attr_reader :config attr_reader :layout_dir attr_reader :layout_path attr_reader :template_path attr_reader :exposures + # @api public def self.paths Array(config.paths).map { |path| Dry::View::Path.new(path) } end + # @api private def self.renderer(format) renderers.fetch(format) { renderers[format] = Renderer.new(paths, format: format) } end + # @api private def self.renderers @renderers ||= {} end + # @api public 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 - def self.private_expose(*names, &block) - expose(*names, to_view: false, &block) + # @api public + def self.private_expose(*names, **options, &block) + expose(*names, **options.merge(private: true), &block) end + # @api private def self.exposures @exposures ||= Exposures.new end + # @api public def initialize @config = self.class.config @layout_dir = DEFAULT_LAYOUTS_DIR @layout_path = "#{layout_dir}/#{config.layout}" @template_path = config.template @exposures = self.class.exposures.bind(self) end - def call(format: config.default_format, **input) + # @api public + def call(format: config.default_format, context: config.context, **input) renderer = self.class.renderer(format) - template_content = renderer.(template_path, template_scope(renderer, **input)) + template_content = renderer.(template_path, template_scope(renderer, context, **input)) return template_content unless layout? - renderer.(layout_path, layout_scope(renderer, **input)) do + renderer.(layout_path, layout_scope(renderer, context)) do template_content end end + # @api public def locals(locals: EMPTY_LOCALS, **input) exposures.locals(input).merge(locals) end private def layout? !!config.layout end - def layout_scope(renderer, context: config.context, **) - scope(renderer.chdir(layout_dir), EMPTY_LOCALS, context) + def layout_scope(renderer, context) + scope(renderer.chdir(layout_dir), context) end - def template_scope(renderer, context: config.context, **input) - scope(renderer.chdir(template_path), locals(**input), context) + def template_scope(renderer, context, **input) + scope(renderer.chdir(template_path), context, locals(**input)) end - def scope(renderer, locals, context) - Scope.new(renderer, locals, context) + def scope(renderer, context, locals = EMPTY_LOCALS) + Scope.new( + renderer: renderer, + context: context, + locals: decorated_locals(renderer, context, locals) + ) + end + + def decorated_locals(renderer, context, locals) + decorator = self.class.config.decorator + + locals.each_with_object({}) { |(key, val), result| + # Decorate truthy values only + if val + options = exposures.key?(key) ? exposures[key].options : {} + + val = decorator.( + key, + val, + renderer: renderer, + context: context, + **options + ) + end + + result[key] = val + } end end end end