|
| 1 | +# frozen_string_literal: true |
| 2 | + |
| 3 | +module GrapeSwagger |
| 4 | + class TokenOwnerResolver |
| 5 | + class << self |
| 6 | + SUPPORTED_ARITY_TYPES = %i[req opt rest keyreq key keyrest].freeze |
| 7 | + UNRESOLVED = Object.new.freeze |
| 8 | + private_constant :UNRESOLVED |
| 9 | + |
| 10 | + def resolve(endpoint, method_name) |
| 11 | + return if method_name.nil? |
| 12 | + |
| 13 | + method_name = method_name.to_sym |
| 14 | + return endpoint.public_send(method_name) if endpoint.respond_to?(method_name, true) |
| 15 | + |
| 16 | + helper_value = resolve_from_helpers(endpoint, method_name) |
| 17 | + return helper_value unless helper_value.equal?(UNRESOLVED) |
| 18 | + |
| 19 | + raise Errors::TokenOwnerNotFound, "undefined method `#{method_name}` for #{endpoint.class}" |
| 20 | + end |
| 21 | + |
| 22 | + def evaluate_proc(callable, token_owner) |
| 23 | + return callable.call unless accepts_argument?(callable) |
| 24 | + |
| 25 | + callable.call(token_owner) |
| 26 | + end |
| 27 | + |
| 28 | + private |
| 29 | + |
| 30 | + def resolve_from_helpers(endpoint, method_name) |
| 31 | + helpers = gather_helpers(endpoint) |
| 32 | + return UNRESOLVED if helpers.empty? |
| 33 | + |
| 34 | + helpers.each do |helper| |
| 35 | + resolved = resolve_from_helper(endpoint, helper, method_name) |
| 36 | + return resolved unless resolved.equal?(UNRESOLVED) |
| 37 | + end |
| 38 | + |
| 39 | + UNRESOLVED |
| 40 | + end |
| 41 | + |
| 42 | + def gather_helpers(endpoint) |
| 43 | + return [] if endpoint.nil? |
| 44 | + |
| 45 | + stackable_helpers = fetch_stackable_helpers(endpoint) |
| 46 | + normalize_helpers(stackable_helpers) |
| 47 | + end |
| 48 | + |
| 49 | + def fetch_stackable_helpers(endpoint) |
| 50 | + return unless endpoint.respond_to?(:inheritable_setting) |
| 51 | + |
| 52 | + setting = endpoint.inheritable_setting |
| 53 | + return unless setting.respond_to?(:namespace_stackable) |
| 54 | + |
| 55 | + namespace_stackable = setting.namespace_stackable |
| 56 | + return unless namespace_stackable.respond_to?(:[]) |
| 57 | + |
| 58 | + namespace_stackable[:helpers] |
| 59 | + rescue NameError |
| 60 | + nil |
| 61 | + end |
| 62 | + |
| 63 | + def normalize_helpers(helpers) |
| 64 | + case helpers |
| 65 | + when nil, false |
| 66 | + [] |
| 67 | + when Module |
| 68 | + [helpers] |
| 69 | + when Array |
| 70 | + helpers.compact |
| 71 | + else |
| 72 | + if helpers.respond_to?(:key?) && helpers.respond_to?(:[]) && helpers.key?(:helpers) |
| 73 | + normalize_helpers(helpers[:helpers]) |
| 74 | + elsif helpers.respond_to?(:to_a) |
| 75 | + Array(helpers.to_a).flatten.compact |
| 76 | + else |
| 77 | + Array(helpers).compact |
| 78 | + end |
| 79 | + end |
| 80 | + end |
| 81 | + |
| 82 | + def resolve_from_helper(endpoint, helper, method_name) |
| 83 | + return UNRESOLVED unless helper_method_defined?(helper, method_name) |
| 84 | + |
| 85 | + helper.instance_method(method_name).bind(endpoint).call |
| 86 | + rescue NameError |
| 87 | + UNRESOLVED |
| 88 | + end |
| 89 | + |
| 90 | + def helper_method_defined?(helper, method_name) |
| 91 | + helper.method_defined?(method_name) || helper.private_method_defined?(method_name) |
| 92 | + end |
| 93 | + |
| 94 | + def accepts_argument?(callable) |
| 95 | + return false unless callable.respond_to?(:parameters) |
| 96 | + |
| 97 | + callable.parameters.any? { |type, _| SUPPORTED_ARITY_TYPES.include?(type) } |
| 98 | + end |
| 99 | + end |
| 100 | + end |
| 101 | +end |
0 commit comments