1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
|
# frozen_string_literal: true
require 'forwardable'
module Grape
class Entity
class Options
extend Forwardable
attr_reader :opts_hash
def_delegators :opts_hash, :dig, :key?, :fetch, :[], :empty?
def initialize(opts_hash = {})
@opts_hash = opts_hash
@has_only = !opts_hash[:only].nil?
@has_except = !opts_hash[:except].nil?
@for_nesting_cache = {}
@should_return_key_cache = {}
end
def merge(new_opts)
return self if new_opts.empty?
merged = if new_opts.instance_of? Options
@opts_hash.merge(new_opts.opts_hash)
else
@opts_hash.merge(new_opts)
end
Options.new(merged)
end
def reverse_merge(new_opts)
return self if new_opts.empty?
merged = if new_opts.instance_of? Options
new_opts.opts_hash.merge(@opts_hash)
else
new_opts.merge(@opts_hash)
end
Options.new(merged)
end
def ==(other)
other_hash = other.is_a?(Options) ? other.opts_hash : other
@opts_hash == other_hash
end
def should_return_key?(key)
return true unless @has_only || @has_except
only = only_fields.nil? ||
only_fields.key?(key)
except = except_fields&.key?(key) &&
except_fields[key] == true
only && !except
end
def for_nesting(key)
@for_nesting_cache[key] ||= build_for_nesting(key)
end
def only_fields(for_key = nil)
return nil unless @has_only
@only_fields ||= @opts_hash[:only].each_with_object({}) do |attribute, allowed_fields|
build_symbolized_hash(attribute, allowed_fields)
end
only_for_given(for_key, @only_fields)
end
def except_fields(for_key = nil)
return nil unless @has_except
@except_fields ||= @opts_hash[:except].each_with_object({}) do |attribute, allowed_fields|
build_symbolized_hash(attribute, allowed_fields)
end
only_for_given(for_key, @except_fields)
end
def with_attr_path(part)
return yield unless part
stack = (opts_hash[:attr_path] ||= [])
stack.push part
result = yield
stack.pop
result
end
private
def build_for_nesting(key)
Options.new(
opts_hash.dup.reject { |current_key| current_key == :collection }.merge(
root: nil,
only: only_fields(key),
except: except_fields(key),
attr_path: opts_hash[:attr_path]
)
)
end
def build_symbolized_hash(attribute, hash)
case attribute
when Hash
attribute.each do |attr, nested_attrs|
hash[attr.to_sym] = build_symbolized_hash(nested_attrs, {})
end
when Array
return attribute.each { |x| build_symbolized_hash(x, {}) }
else
hash[attribute.to_sym] = true
end
hash
end
def only_for_given(key, fields)
if key && fields[key].is_a?(Array)
fields[key]
elsif key.nil?
fields
end
end
end
end
end
|