# frozen-string-literal: true

#
class Roda
  module RodaPlugins
    # The shared_vars plugin adds a +shared+ method for storing
    # shared variables across nested Roda apps.
    #
    #   class API < Roda
    #     plugin :shared_vars
    #     route do |r|
    #       user = shared[:user]
    #       # ...
    #     end
    #   end
    #
    #   class App < Roda
    #     plugin :shared_vars
    #
    #     route do |r|
    #       r.on Integer do |user_id|
    #         shared[:user] = User[user_id]
    #         r.run API
    #       end
    #     end
    #   end
    #
    # If you pass a hash to shared, it will update the shared
    # vars with the content of the hash:
    #
    #   route do |r|
    #     r.on Integer do |user_id|
    #       shared(user: User[user_id])
    #       r.run API
    #     end
    #   end
    #
    # You can also pass a block to shared, which will set the
    # shared variables only for the given block, restoring the
    # previous shared variables afterward:
    #
    #   route do |r|
    #     r.on Integer do |user_id|
    #       shared(user: User[user_id]) do
    #         r.run API
    #       end
    #     end
    #   end
    module SharedVars
      module InstanceMethods
        # Returns the current shared vars for the request.  These are
        # stored in the request's environment, so they will be implicitly
        # shared with other apps using this plugin.
        #
        # If the +vars+ argument is given, it should be a hash that will be
        # merged into the current shared vars.
        #
        # If a block is given, a +vars+ argument must be provided, and it will
        # only make the changes to the shared vars for the duration of the
        # block, restoring the previous shared vars before the block returns.
        def shared(vars=nil)
          h = env['roda.shared'] ||= {}

          if defined?(yield)
            if vars
              begin
                env['roda.shared'] = h.merge(vars)
                yield
              ensure
                env['roda.shared'] = h
              end
            else
              raise RodaError, "must pass a vars hash when calling shared with a block"
            end
          elsif vars
            h.merge!(vars)
          end

          h
        end
      end
    end

    register_plugin(:shared_vars, SharedVars)
  end
end
