require 'hanami/view/rendering/null_local' require 'hanami/view/rendering/options' require 'hanami/utils/escape' require 'hanami/utils/basic_object' module Hanami module View module Rendering # List of render types that exactly one of must be included when calling `#render`. # For example, when calling `<%= render something: 'my_thing', locals: {} %>`, # 'something' must be one of the values listed here. # # @since 1.1.0 # @api private KNOWN_RENDER_TYPES = [:partial, :template].freeze # Scope for layout rendering # # @since 0.1.0 class LayoutScope < Utils::BasicObject # Initialize the scope # # @param layout [Hanami::Layout] the layout to render # @param scope [Hanami::View::Rendering::Scope] the scope of the current # view # # @api private # @since 0.1.0 def initialize(layout, scope) @layout = layout @scope = scope @view = nil @locals = nil end # Render a partial or a template within a layout template. # # @param options [Hash] # @option options [String] :partial the partial template to render # @option options [String] :template the template to render # # @return [String] the output of the rendering process # # @raise [Hanami::Error::UnknownRenderTypeError] if the given type to # be rendered is unknown # # @since 0.1.0 # # @example Rendering partial # # Given a partial under: # # templates/shared/_sidebar.html.erb # # # # In the layout template: # # templates/application.html.erb # # # # Use like this: # <%= render partial: 'shared/sidebar' %> # # @example Rendering template # # Given a template under: # # templates/articles/index.html.erb # # # # In the layout template: # # templates/application.html.erb # # # # Use like this: # <%= render template: 'articles/index' %> # # @example Rendering partial, using optional :locals # # Given a partial under: # # templates/shared/_sidebar.html.erb # # # # In the layout template: # # templates/application.html.erb # # # # Use like this: # <%= render partial: 'shared/sidebar', locals: { user: current_user } %> # # # # # `user` will be available in the scope of the sidebar rendering # # @example Rendering partial, passing a block # # Given a partial under: # # templates/shared/_sidebar.html.erb # # # # In the layout template: # # templates/application.html.erb # # # # Use like this: # <%= render(partial: 'shared/sidebar') { ... } %> # # # # # Then if you call `yield` inside the partial, it will call the # # passed block. def render(options, &block) renderer(options).render(&block) end # Returns the requested format. # # @return [Symbol] the requested format (eg. :html, :json, :xml, etc..) # # @since 0.1.0 def format @scope.format end # The current view. # # @return [Hanami::View] the current view # # @since 0.1.0 def view @view || @scope.view end # The current locals. # # @return [Hash] the current locals # # @since 0.1.0 def locals (@locals || @scope.locals).dup end # It tries to invoke a method for the view or a local for the given key. # If the lookup fails, it returns a null object. # # @return [Object,Hanami::View::Rendering::NullLocal] the returning value # # @since 0.7.0 # # @example Safe method navigation # <% if local(:plan).overdue? %> #