class Grape::API

should subclass this class in order to build an API.
The API class is the primary entry point for creating Grape APIs. Users

def add_setup(**step)

Adds a new stage to the set up require to get a Grape::API up and running
def add_setup(**step)
  @setup << step
  last_response = nil
  @instances.each do |instance|
    last_response = replay_step_on(instance, **step)
  end
  refresh_mount_step if step[:method] != :mount
  last_response
end

def any_lazy?(args)

def any_lazy?(args)
  args.any?(Grape::Util::Lazy::Base)
end

def configure

`configuration` as normal.
The configuration set here is accessible from inside an API with
API. If no block is given, returns the configuration hash.
configuration hash to the block which you can use to configure your
Configure an API from the outside. If a block is given, it'll pass a
def configure
  config = @base_instance.configuration
  return config unless block_given?
  yield config
  self
end

def evaluate_arguments(configuration, *args)

def evaluate_arguments(configuration, *args)
  args.map do |argument|
    case argument
    when Grape::Util::Lazy::Base
      argument.evaluate_from(configuration)
    when Hash
      argument.transform_values { |value| evaluate_arguments(configuration, value).first }
    when Array
      evaluate_arguments(configuration, *argument)
    else
      argument
    end
  end
end

def inherited(api)

It will listen to the setup required to mount that endpoint, and replicate it on any new instance
When inherited, will create a list of all instances (times the API was mounted)
def inherited(api)
  super
  api.initial_setup(self == Grape::API ? Grape::API::Instance : @base_instance)
  api.override_all_methods!
end

def initial_setup(base_instance_parent)

an instance that will be used to create the set up but will not be mounted
Initialize the instance variables on the remountable class, and the base_instance
def initial_setup(base_instance_parent)
  @instances = []
  @setup = []
  @base_parent = base_instance_parent
  @base_instance = mount_instance
end

def mount_instance(configuration: nil)

too much, you may actually want to provide a new API rather than remount it.
depending on where the endpoint is mounted. Use with care, if you find yourself using configuration
For instance, a description could be done using: `desc configuration[:description]` if it may vary
The remountable class can have a configuration hash to provide some dynamic class-level variables.
def mount_instance(configuration: nil)
  instance = Class.new(@base_parent)
  instance.configuration = Grape::Util::EndpointConfiguration.new(configuration || {})
  instance.base = self
  replay_setup_on(instance)
  instance
end

def override_all_methods!

Redefines all methods so that are forwarded to add_setup and be recorded
def override_all_methods!
  (base_instance.methods - Class.methods - NON_OVERRIDABLE).each do |method_override|
    define_singleton_method(method_override) do |*args, **kwargs, &block|
      add_setup(method: method_override, args:, kwargs:, block:)
    end
  end
end

def refresh_mount_step

Updating all previously mounted classes in the case that new methods have been executed.
def refresh_mount_step
  @setup.each do |setup_step|
    next if setup_step[:method] != :mount
    refresh_mount_step = setup_step.merge(method: :refresh_mounted_api)
    @setup << refresh_mount_step
    @instances.each do |instance|
      replay_step_on(instance, **refresh_mount_step)
    end
  end
end

def replay_setup_on(instance)

on classes that inherit from Grape::API
Replays the set up to produce an API as defined in this class, can be called
def replay_setup_on(instance)
  @setup.each do |setup_step|
    replay_step_on(instance, **setup_step)
  end
end

def replay_step_on(instance, method:, args:, kwargs:, block:)

def replay_step_on(instance, method:, args:, kwargs:, block:)
  return if skip_immediate_run?(instance, args, kwargs)
  eval_args = evaluate_arguments(instance.configuration, *args)
  eval_kwargs = kwargs.deep_transform_values { |v| evaluate_arguments(instance.configuration, v).first }
  response = instance.__send__(method, *eval_args, **eval_kwargs, &block)
  return response if skip_immediate_run?(instance, [response], kwargs)
  evaluate_arguments(instance.configuration, response).first
end

def skip_immediate_run?(instance, args, kwargs)

Skips steps that contain arguments to be lazily executed (on re-mount time)
def skip_immediate_run?(instance, args, kwargs)
  instance.base_instance? &&
    (any_lazy?(args) || args.any? { |arg| arg.is_a?(Hash) && any_lazy?(arg.values) } || any_lazy?(kwargs.values))
end