lib/grape/api.rb in grape-1.2.3 vs lib/grape/api.rb in grape-1.2.4
- old
+ new
@@ -4,11 +4,11 @@
module Grape
# The API class is the primary entry point for creating Grape APIs. Users
# should subclass this class in order to build an API.
class API
# Class methods that we want to call on the API rather than on the API object
- NON_OVERRIDABLE = (Class.new.methods + %i[call call!]).freeze
+ NON_OVERRIDABLE = (Class.new.methods + %i[call call! configuration]).freeze
class << self
attr_accessor :base_instance, :instances
# Rather than initializing an object of type Grape::API, create an object of type Instance
@@ -62,12 +62,10 @@
# Alleviates problems with autoloading by tring to search for the constant
def const_missing(*args)
if base_instance.const_defined?(*args)
base_instance.const_get(*args)
- elsif parent && parent.const_defined?(*args)
- parent.const_get(*args)
else
super
end
end
@@ -75,21 +73,21 @@
# For instance, a descripcion could be done using: `desc configuration[:description]` if it may vary
# depending on where the endpoint is mounted. Use with care, if you find yourself using configuration
# too much, you may actually want to provide a new API rather than remount it.
def mount_instance(opts = {})
instance = Class.new(@base_parent)
- instance.configuration = opts[:configuration] || {}
+ instance.configuration = Grape::Util::EndpointConfiguration.new(opts[:configuration] || {})
instance.base = self
replay_setup_on(instance)
instance
end
# Replays the set up to produce an API as defined in this class, can be called
# on classes that inherit from Grape::API
def replay_setup_on(instance)
- @setup.each do |setup_stage|
- instance.send(setup_stage[:method], *setup_stage[:args], &setup_stage[:block])
+ @setup.each do |setup_step|
+ replay_step_on(instance, setup_step)
end
end
def respond_to?(method, include_private = false)
super(method, include_private) || base_instance.respond_to?(method, include_private)
@@ -110,16 +108,45 @@
private
# Adds a new stage to the set up require to get a Grape::API up and running
def add_setup(method, *args, &block)
- setup_stage = { method: method, args: args, block: block }
- @setup << setup_stage
+ setup_step = { method: method, args: args, block: block }
+ @setup << setup_step
last_response = nil
@instances.each do |instance|
- last_response = instance.send(setup_stage[:method], *setup_stage[:args], &setup_stage[:block])
+ last_response = replay_step_on(instance, setup_step)
end
last_response
+ end
+
+ def replay_step_on(instance, setup_step)
+ return if skip_immediate_run?(instance, setup_step[:args])
+ instance.send(setup_step[:method], *evaluate_arguments(instance.configuration, *setup_step[:args]), &setup_step[:block])
+ end
+
+ # Skips steps that contain arguments to be lazily executed (on re-mount time)
+ def skip_immediate_run?(instance, args)
+ instance.base_instance? &&
+ (any_lazy?(args) || args.any? { |arg| arg.is_a?(Hash) && any_lazy?(arg.values) })
+ end
+
+ def any_lazy?(args)
+ args.any? { |argument| argument.respond_to?(:lazy?) && argument.lazy? }
+ end
+
+ def evaluate_arguments(configuration, *args)
+ args.map do |argument|
+ if argument.respond_to?(:lazy?) && argument.lazy?
+ configuration.fetch(argument.access_keys).evaluate
+ elsif argument.is_a?(Hash)
+ argument.map { |key, value| [key, evaluate_arguments(configuration, value).first] }.to_h
+ elsif argument.is_a?(Array)
+ evaluate_arguments(configuration, *argument)
+ else
+ argument
+ end
+ end
end
end
end
end