forked from ruby-grape/grape-entity
-
Notifications
You must be signed in to change notification settings - Fork 0
/
base.rb
122 lines (101 loc) · 3.43 KB
/
base.rb
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
module Grape
class Entity
module Exposure
class Base
attr_reader :attribute, :key, :is_safe, :documentation, :conditions
def self.new(attribute, options, conditions, *args, &block)
super(attribute, options, conditions).tap { |e| e.setup(*args, &block) }
end
def initialize(attribute, options, conditions)
@attribute = attribute.try(:to_sym)
@options = options
@key = (options[:as] || attribute).try(:to_sym)
@is_safe = options[:safe]
@attr_path_proc = options[:attr_path]
@documentation = options[:documentation]
@conditions = conditions
end
def dup(&block)
self.class.new(*dup_args, &block)
end
def dup_args
[@attribute, @options, @conditions.map(&:dup)]
end
def ==(other)
self.class == other.class &&
@attribute == other.attribute &&
@options == other.options &&
@conditions == other.conditions
end
def setup
end
def nesting?
false
end
# if we have any nesting exposures with the same name.
def deep_complex_nesting?
false
end
def valid?(entity)
is_delegatable = entity.delegator.delegatable?(@attribute) || entity.respond_to?(@attribute, true)
if @is_safe
is_delegatable
else
is_delegatable || fail(NoMethodError, "#{entity.class.name} missing attribute `#{@attribute}' on #{entity.object}")
end
end
def value(_entity, _options)
fail NotImplementedError
end
def serializable_value(entity, options)
partial_output = valid_value(entity, options)
if partial_output.respond_to?(:serializable_hash)
partial_output.serializable_hash(options)
elsif partial_output.is_a?(Array) && partial_output.all? { |o| o.respond_to?(:serializable_hash) }
if @options[:combine] == :merge
partial_output.reduce({}) { |memo, output| memo.merge(output.serializable_hash) }
else
partial_output.map(&:serializable_hash)
end
elsif partial_output.is_a?(Hash)
partial_output.each do |key, value|
partial_output[key] = value.serializable_hash if value.respond_to?(:serializable_hash)
end
else
partial_output
end
end
def valid_value(entity, options)
valid?(entity) && value(entity, options)
end
def should_return_key?(options)
options.should_return_key?(@key)
end
def conditional?
!@conditions.empty?
end
def conditions_met?(entity, options)
@conditions.all? { |condition| condition.met? entity, options }
end
def should_expose?(entity, options)
should_return_key?(options) && conditions_met?(entity, options)
end
def attr_path(entity, options)
if @attr_path_proc
entity.exec_with_object(options, &@attr_path_proc)
else
@key
end
end
def with_attr_path(entity, options)
path_part = attr_path(entity, options)
options.with_attr_path(path_part) do
yield
end
end
protected
attr_reader :options
end
end
end
end