# frozen_string_literal: true class NicePartials::Partial::Section < NicePartials::Partial::Content class RequiredError < ArgumentError; end class Empty < BasicObject def initialize(section) @section = section end delegate :blank?, :present?, :presence, to: :@section def nil? true end def method_missing(...) present? ? super : "" end end # Returns self if `present?`, or raises. # Useful to declare content that you require to be supplied during a `render` call. # # <%= partial.title.required.div class: "text-xl" %> def required present? ? self : raise(RequiredError, "Section expected to have content, but wasn't supplied during render") end # Returns self if `present?`, or returns a Null object that won't output any content. # Useful to declare optional content sections, that you also don't want to print any HTML elements for. # # <%= partial.title.optional.div class: "text-xl" %> # => "" # Won't output an empty `
` that can mess with HTML markups. def optional present? ? self : Empty.new(self) end def yield(*arguments) chunks.each { append @view_context.capture(*arguments, &_1) } self end def present? chunks.present? || super end undef_method :p # Remove Kernel.p here to pipe through method_missing and hit tag proxy. # Implements our proxying to the `@view_context` or `@view_context.tag`. # # `@view_context` proxying forwards the message and automatically appends any content, so you can do things like: # # <% partial.body.render "form", tangible_thing: @tangible_thing %> # <% partial.body.link_to @document.name, @document %> # <% partial.body.t ".body" %> # # `@view_context.tag` proxy lets you build bespoke elements based on content and options provided: # # <% partial.title "Some title content", class: "xl" %> # Write the content and options to the `title` # <% partial.title.h2 ", appended" %> # =>

Some title content, appended

# # Note that NicePartials don't support deep merging attributes out of the box. def method_missing(meth, *arguments, **keywords, &block) if meth != :p && @view_context.respond_to?(meth) append @view_context.public_send(meth, *arguments, **keywords, &block) else @view_context.tag.public_send(meth, @content + arguments.first.to_s, **options.merge(keywords), &block) end end def respond_to_missing?(...) @view_context.respond_to?(...) end private def capture(block) if block&.arity&.nonzero? chunks << block else super end end def chunks @chunks ||= [] end end