-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
/
Copy pathsettings.rb
179 lines (146 loc) · 5.55 KB
/
settings.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
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
# frozen_string_literal: true
module Grape
module DSL
# Keeps track of settings (implemented as key-value pairs, grouped by
# types), in two contexts: top-level settings which apply globally no
# matter where they're defined, and inheritable settings which apply only
# in the current scope and scopes nested under it.
module Settings
extend ActiveSupport::Concern
attr_writer :inheritable_setting, :top_level_setting
# Fetch our top-level settings, which apply to all endpoints in the API.
def top_level_setting
@top_level_setting ||= build_top_level_setting
end
# Fetch our current inheritable settings, which are inherited by
# nested scopes but not shared across siblings.
def inheritable_setting
@inheritable_setting ||= Grape::Util::InheritableSetting.new.tap { |new_settings| new_settings.inherit_from top_level_setting }
end
# @param type [Symbol]
# @param key [Symbol]
def unset(type, key)
setting = inheritable_setting.send(type)
setting.delete key
end
# @param type [Symbol]
# @param key [Symbol]
# @param value [Object] will be stored if the value is currently empty
# @return either the old value, if it wasn't nil, or the given value
def get_or_set(type, key, value)
setting = inheritable_setting.send(type)
if value.nil?
setting[key]
else
setting[key] = value
end
end
# @param key [Symbol]
# @param value [Object]
# @return (see #get_or_set)
def global_setting(key, value = nil)
get_or_set :global, key, value
end
# @param key [Symbol]
def unset_global_setting(key)
unset :global, key
end
# (see #global_setting)
def route_setting(key, value = nil)
get_or_set :route, key, value
end
# (see #unset_global_setting)
def unset_route_setting(key)
unset :route, key
end
# (see #global_setting)
def namespace_setting(key, value = nil)
get_or_set :namespace, key, value
end
# (see #unset_global_setting)
def unset_namespace_setting(key)
unset :namespace, key
end
# (see #global_setting)
def namespace_inheritable(key, value = nil)
get_or_set :namespace_inheritable, key, value
end
# (see #unset_global_setting)
def unset_namespace_inheritable(key)
unset :namespace_inheritable, key
end
# @param key [Symbol]
def namespace_inheritable_to_nil(key)
inheritable_setting.namespace_inheritable[key] = nil
end
# (see #global_setting)
def namespace_stackable(key, value = nil)
get_or_set :namespace_stackable, key, value
end
def namespace_reverse_stackable(key, value = nil)
get_or_set :namespace_reverse_stackable, key, value
end
def namespace_stackable_with_hash(key)
settings = get_or_set :namespace_stackable, key, nil
return if settings.blank?
settings.each_with_object({}) { |value, result| result.deep_merge!(value) }
end
def namespace_reverse_stackable_with_hash(key)
settings = get_or_set :namespace_reverse_stackable, key, nil
return if settings.blank?
settings.each_with_object({}) do |setting, result|
result.merge!(setting) { |_k, s1, _s2| s1 }
end
end
# (see #unset_global_setting)
def unset_namespace_stackable(key)
unset :namespace_stackable, key
end
# (see #global_setting)
def api_class_setting(key, value = nil)
get_or_set :api_class, key, value
end
# (see #unset_global_setting)
def unset_api_class_setting(key)
unset :api_class, key
end
# Fork our inheritable settings to a new instance, copied from our
# parent's, but separate so we won't modify it. Every call to this
# method should have an answering call to #namespace_end.
def namespace_start
@inheritable_setting = Grape::Util::InheritableSetting.new.tap { |new_settings| new_settings.inherit_from inheritable_setting }
end
# Set the inheritable settings pointer back up by one level.
def namespace_end
route_end
@inheritable_setting = inheritable_setting.parent
end
# Stop defining settings for the current route and clear them for the
# next, within a namespace.
def route_end
inheritable_setting.route_end
end
# Execute the block within a context where our inheritable settings are forked
# to a new copy (see #namespace_start).
def within_namespace(&block)
namespace_start
result = yield if block
namespace_end
reset_validations!
result
end
private
# Builds the current class :inheritable_setting. If available, it inherits from
# the superclass's :inheritable_setting.
def build_top_level_setting
Grape::Util::InheritableSetting.new.tap do |setting|
# Doesn't try to inherit settings from +Grape::API::Instance+ which also responds to
# +inheritable_setting+, however, it doesn't contain any user-defined settings.
# Otherwise, it would lead to an extra instance of +Grape::Util::InheritableSetting+
# in the chain for every endpoint.
setting.inherit_from superclass.inheritable_setting if defined?(superclass) && superclass.respond_to?(:inheritable_setting) && superclass != Grape::API::Instance
end
end
end
end
end