lib/roda/plugins/hash_branch_view_subdir.rb



# frozen-string-literal: true

#
class Roda
  module RodaPlugins
    # The hash_branch_view_subdir plugin builds on the hash_branches and view_options
    # plugins, automatically appending a view subdirectory for any matching hash branch
    # taken. In cases where you are using a separate view subdirectory per hash branch,
    # this can result in DRYer code. Example:
    #
    #   plugin :hash_branch_view_subdir
    #
    #   route do |r|
    #     r.hash_branches
    #   end
    #
    #   hash_branch 'foo' do |r|
    #     # view subdirectory here is 'foo'
    #     r.hash_branches('foo')
    #   end
    #
    #   hash_branch 'foo', 'bar' do |r|
    #     # view subdirectory here is 'foo/bar'
    #   end
    module HashBranchViewSubdir
      def self.load_dependencies(app)
        app.plugin :hash_branches
        app.plugin :view_options
      end

      def self.configure(app)
        app.opts[:hash_branch_view_subdir_methods] ||= {}
      end

      module ClassMethods
        # Freeze the hash_branch_view_subdir metadata when freezing the app.
        def freeze
          opts[:hash_branch_view_subdir_methods].freeze.each_value(&:freeze)
          super
        end

        # Duplicate hash_branch_view_subdir metadata in subclass.
        def inherited(subclass)
          super

          h = subclass.opts[:hash_branch_view_subdir_methods]
          opts[:hash_branch_view_subdir_methods].each do |namespace, routes|
            h[namespace] = routes.dup
          end
        end

        # Automatically append a view subdirectory for a successful hash_branch route,
        # by modifying the generated method to append the view subdirectory before
        # dispatching to the original block.
        def hash_branch(namespace='', segment, &block)
          meths = opts[:hash_branch_view_subdir_methods][namespace] ||= {}

          if block
            meth = meths[segment] = define_roda_method(meths[segment] || "_hash_branch_view_subdir_#{namespace}_#{segment}", 1, &convert_route_block(block))
            super do |*_|
              append_view_subdir(segment)
              send(meth, @_request)
            end
          else
            if meth = meths.delete(segment)
              remove_method(meth)
            end
            super
          end
        end
      end
    end

    register_plugin(:hash_branch_view_subdir, HashBranchViewSubdir)
  end
end