-
Notifications
You must be signed in to change notification settings - Fork 1.2k
/
Copy pathacl_object.rb
264 lines (227 loc) · 8.34 KB
/
acl_object.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
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
# Copyright 2011-2013 Amazon.com, Inc. or its affiliates. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"). You
# may not use this file except in compliance with the License. A copy of
# the License is located at
#
# http://aws.amazon.com/apache2.0/
#
# or in the "license" file accompanying this file. This file is
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
# ANY KIND, either express or implied. See the License for the specific
# language governing permissions and limitations under the License.
require 'rexml/text'
module AWS
class S3
# Common methods for AccessControlList and related objects.
module ACLObject
# @api private
def initialize(opts = {}); end
# @api private
def body_xml; ""; end
# @api private
def stag
element_name
end
# @api private
def element_name
self.class.name[/::([^:]*)$/, 1]
end
# Returns the XML representation of the object. Generally
# you'll want to call this on an AccessControlList object,
# which will yield an XML representation of the ACL that you
# can send to S3.
def to_s
if body_xml.empty?
"<#{stag}/>"
else
"<#{stag}>#{body_xml}</#{element_name}>"
end
end
# (see #to_s)
def to_xml
to_s
end
# Returns true if and only if this object is valid according
# to S3's published ACL schema. In particular, this will
# check that all required attributes are provided and that
# they are of the correct type.
def valid?
validate!
rescue => e
false
else
true
end
# Raises an exception unless this object is valid according to
# S3's published ACL schema.
# @see #valid?
def validate!; end
# @api private
def validate_input(name, value, context = nil)
send("validate_#{name}_input!", value, context)
end
# @api private
module ClassMethods
def string_attr(element_name, options = {})
method_name = options[:method_name] ||
Core::Inflection.ruby_name(element_name)
attr_accessor(method_name)
setter_option(method_name)
string_input_validator(method_name)
validate_string(method_name) if options[:required]
body_xml_string_content(element_name, method_name)
end
def object_attr(klass, options = {})
base_name = klass.name[/::([^:]*)$/, 1]
method_name = Core::Inflection.ruby_name(base_name)
cast = options[:cast] || Hash
attr_reader(method_name)
setter_option(method_name)
object_setter(klass, method_name, cast)
object_input_validator(klass, base_name, method_name, cast)
validate_object(method_name) if options[:required]
body_xml_content(method_name)
end
def object_list_attr(list_element, klass, options = {})
base_name = klass.name[/::([^:]*)$/, 1]
method_name = Core::Inflection.ruby_name(options[:method_name].to_s || list_element)
default_value = nil
default_value = [] if options[:required]
attr_reader(method_name)
setter_option(method_name) { [] if options[:required] }
object_list_setter(klass, method_name)
object_list_input_validator(klass, base_name, method_name)
validate_list(method_name)
body_xml_list_content(list_element, method_name)
end
def setter_option(method_name)
Core::MetaUtils.class_extend_method(self, :initialize) do |*args|
opts = args.last || {}
instance_variable_set("@#{method_name}", yield) if block_given?
key = method_name.to_sym
if opts.has_key?(key)
value = opts[key]
validate_input(method_name, value, "for #{method_name} option")
self.send("#{method_name}=", value)
end
super(opts)
end
end
def string_input_validator(method_name)
input_validator(method_name) do |value, context|
raise ArgumentError.new("expected string"+context) unless
value.respond_to?(:to_str)
end
end
def object_input_validator(klass, base_name, method_name, cast)
input_validator(method_name) do |value, context|
if value.kind_of?(cast)
klass.new(value).validate!
else
raise ArgumentError.new("expected #{base_name} object or hash"+context) unless
value.nil? or value.kind_of? klass
end
end
end
def object_list_input_validator(klass, base_name, method_name)
input_validator(method_name) do |value, context|
raise ArgumentError.new("expected array"+context) unless value.kind_of?(Array)
value.each do |member|
if member.kind_of?(Hash)
klass.new(member).validate!
else
raise ArgumentError.new("expected array#{context} "+
"to contain #{base_name} objects "+
"or hashes") unless
member.kind_of? klass
end
end
end
end
def input_validator(method_name, &blk)
validator = "__validator__#{blk.object_id}"
Core::MetaUtils.class_extend_method(self, validator, &blk)
Core::MetaUtils.class_extend_method(self, "validate_#{method_name}_input!") do |*args|
(value, context) = args
context = " "+context if context
context ||= ""
send(validator, value, context)
end
end
def object_setter(klass, method_name, cast)
define_method("#{method_name}=") do |value|
validate_input(method_name, value)
if value.kind_of?(cast)
value = klass.new(value)
end
instance_variable_set("@#{method_name}", value)
end
end
def object_list_setter(klass, method_name)
define_method("#{method_name}=") do |value|
validate_input(method_name, value)
list = value.map do |member|
if member.kind_of?(Hash)
klass.new(member)
else
member
end
end
instance_variable_set("@#{method_name}", list)
end
end
def validate_string(method_name)
Core::MetaUtils.class_extend_method(self, :validate!) do
super()
raise "missing #{method_name}" unless send(method_name)
end
end
def validate_object(method_name)
Core::MetaUtils.class_extend_method(self, :validate!) do
super()
raise "missing #{method_name}" unless send(method_name)
send(method_name).validate!
end
end
def validate_list(method_name)
Core::MetaUtils.class_extend_method(self, :validate!) do
super()
raise "missing #{method_name}" unless send(method_name)
send(method_name).each { |member| member.validate! }
end
end
def body_xml_string_content(element_name, method_name)
add_xml_child(method_name) do |value|
normalized = REXML::Text.normalize(value.to_s)
"<#{element_name}>#{normalized}</#{element_name}>"
end
end
def body_xml_content(method_name)
add_xml_child(method_name) { |value| value.to_s }
end
def body_xml_list_content(list_element, method_name)
add_xml_child(method_name) do |list|
list_content = list.map { |member| member.to_s }.join
if list_content.empty?
"<#{list_element}/>"
else
"<#{list_element}>#{list_content}</#{list_element}>"
end
end
end
def add_xml_child(method_name)
Core::MetaUtils.class_extend_method(self, :body_xml) do
xml = super()
value = send(method_name)
xml += yield(value) if value
xml
end
end
end
def self.included(m)
m.extend(ClassMethods)
end
end
end
end