mss-sdk 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.yardopts +9 -0
- data/LICENSE.txt +0 -0
- data/README.md +192 -0
- data/bin/mss-rb +178 -0
- data/ca-bundle.crt +3554 -0
- data/lib/mss/core/async_handle.rb +89 -0
- data/lib/mss/core/cacheable.rb +76 -0
- data/lib/mss/core/client.rb +786 -0
- data/lib/mss/core/collection/simple.rb +81 -0
- data/lib/mss/core/collection/with_limit_and_next_token.rb +70 -0
- data/lib/mss/core/collection/with_next_token.rb +96 -0
- data/lib/mss/core/collection.rb +262 -0
- data/lib/mss/core/configuration.rb +527 -0
- data/lib/mss/core/credential_providers.rb +653 -0
- data/lib/mss/core/data.rb +251 -0
- data/lib/mss/core/deprecations.rb +83 -0
- data/lib/mss/core/endpoints.rb +36 -0
- data/lib/mss/core/http/connection_pool.rb +374 -0
- data/lib/mss/core/http/curb_handler.rb +150 -0
- data/lib/mss/core/http/handler.rb +88 -0
- data/lib/mss/core/http/net_http_handler.rb +144 -0
- data/lib/mss/core/http/patch.rb +98 -0
- data/lib/mss/core/http/request.rb +258 -0
- data/lib/mss/core/http/response.rb +80 -0
- data/lib/mss/core/indifferent_hash.rb +87 -0
- data/lib/mss/core/inflection.rb +55 -0
- data/lib/mss/core/ini_parser.rb +41 -0
- data/lib/mss/core/json_client.rb +46 -0
- data/lib/mss/core/json_parser.rb +75 -0
- data/lib/mss/core/json_request_builder.rb +34 -0
- data/lib/mss/core/json_response_parser.rb +78 -0
- data/lib/mss/core/lazy_error_classes.rb +107 -0
- data/lib/mss/core/log_formatter.rb +426 -0
- data/lib/mss/core/managed_file.rb +31 -0
- data/lib/mss/core/meta_utils.rb +44 -0
- data/lib/mss/core/model.rb +61 -0
- data/lib/mss/core/naming.rb +29 -0
- data/lib/mss/core/option_grammar.rb +737 -0
- data/lib/mss/core/options/json_serializer.rb +81 -0
- data/lib/mss/core/options/validator.rb +154 -0
- data/lib/mss/core/options/xml_serializer.rb +117 -0
- data/lib/mss/core/page_result.rb +74 -0
- data/lib/mss/core/policy.rb +938 -0
- data/lib/mss/core/query_client.rb +40 -0
- data/lib/mss/core/query_error_parser.rb +23 -0
- data/lib/mss/core/query_request_builder.rb +46 -0
- data/lib/mss/core/query_response_parser.rb +34 -0
- data/lib/mss/core/region.rb +84 -0
- data/lib/mss/core/region_collection.rb +79 -0
- data/lib/mss/core/resource.rb +412 -0
- data/lib/mss/core/resource_cache.rb +39 -0
- data/lib/mss/core/response.rb +214 -0
- data/lib/mss/core/response_cache.rb +49 -0
- data/lib/mss/core/rest_error_parser.rb +23 -0
- data/lib/mss/core/rest_json_client.rb +39 -0
- data/lib/mss/core/rest_request_builder.rb +153 -0
- data/lib/mss/core/rest_response_parser.rb +65 -0
- data/lib/mss/core/rest_xml_client.rb +46 -0
- data/lib/mss/core/service_interface.rb +82 -0
- data/lib/mss/core/signers/base.rb +45 -0
- data/lib/mss/core/signers/cloud_front.rb +55 -0
- data/lib/mss/core/signers/s3.rb +158 -0
- data/lib/mss/core/signers/version_2.rb +71 -0
- data/lib/mss/core/signers/version_3.rb +85 -0
- data/lib/mss/core/signers/version_3_https.rb +60 -0
- data/lib/mss/core/signers/version_4/chunk_signed_stream.rb +190 -0
- data/lib/mss/core/signers/version_4.rb +227 -0
- data/lib/mss/core/uri_escape.rb +43 -0
- data/lib/mss/core/xml/frame.rb +245 -0
- data/lib/mss/core/xml/frame_stack.rb +84 -0
- data/lib/mss/core/xml/grammar.rb +306 -0
- data/lib/mss/core/xml/parser.rb +69 -0
- data/lib/mss/core/xml/root_frame.rb +64 -0
- data/lib/mss/core/xml/sax_handlers/libxml.rb +46 -0
- data/lib/mss/core/xml/sax_handlers/nokogiri.rb +55 -0
- data/lib/mss/core/xml/sax_handlers/ox.rb +40 -0
- data/lib/mss/core/xml/sax_handlers/rexml.rb +46 -0
- data/lib/mss/core/xml/stub.rb +122 -0
- data/lib/mss/core.rb +602 -0
- data/lib/mss/errors.rb +161 -0
- data/lib/mss/rails.rb +194 -0
- data/lib/mss/s3/access_control_list.rb +262 -0
- data/lib/mss/s3/acl_object.rb +263 -0
- data/lib/mss/s3/acl_options.rb +200 -0
- data/lib/mss/s3/bucket.rb +757 -0
- data/lib/mss/s3/bucket_collection.rb +161 -0
- data/lib/mss/s3/bucket_lifecycle_configuration.rb +472 -0
- data/lib/mss/s3/bucket_region_cache.rb +51 -0
- data/lib/mss/s3/bucket_tag_collection.rb +110 -0
- data/lib/mss/s3/bucket_version_collection.rb +78 -0
- data/lib/mss/s3/cipher_io.rb +119 -0
- data/lib/mss/s3/client/xml.rb +265 -0
- data/lib/mss/s3/client.rb +2076 -0
- data/lib/mss/s3/config.rb +60 -0
- data/lib/mss/s3/cors_rule.rb +107 -0
- data/lib/mss/s3/cors_rule_collection.rb +193 -0
- data/lib/mss/s3/data_options.rb +190 -0
- data/lib/mss/s3/encryption_utils.rb +145 -0
- data/lib/mss/s3/errors.rb +93 -0
- data/lib/mss/s3/multipart_upload.rb +353 -0
- data/lib/mss/s3/multipart_upload_collection.rb +75 -0
- data/lib/mss/s3/object_collection.rb +355 -0
- data/lib/mss/s3/object_metadata.rb +102 -0
- data/lib/mss/s3/object_upload_collection.rb +76 -0
- data/lib/mss/s3/object_version.rb +153 -0
- data/lib/mss/s3/object_version_collection.rb +88 -0
- data/lib/mss/s3/paginated_collection.rb +74 -0
- data/lib/mss/s3/policy.rb +73 -0
- data/lib/mss/s3/prefix_and_delimiter_collection.rb +46 -0
- data/lib/mss/s3/prefixed_collection.rb +84 -0
- data/lib/mss/s3/presign_v4.rb +135 -0
- data/lib/mss/s3/presigned_post.rb +574 -0
- data/lib/mss/s3/region_detection.rb +75 -0
- data/lib/mss/s3/request.rb +61 -0
- data/lib/mss/s3/s3_object.rb +1795 -0
- data/lib/mss/s3/tree/branch_node.rb +67 -0
- data/lib/mss/s3/tree/child_collection.rb +103 -0
- data/lib/mss/s3/tree/leaf_node.rb +93 -0
- data/lib/mss/s3/tree/node.rb +21 -0
- data/lib/mss/s3/tree/parent.rb +86 -0
- data/lib/mss/s3/tree.rb +115 -0
- data/lib/mss/s3/uploaded_part.rb +81 -0
- data/lib/mss/s3/uploaded_part_collection.rb +83 -0
- data/lib/mss/s3/website_configuration.rb +101 -0
- data/lib/mss/s3.rb +161 -0
- data/lib/mss/version.rb +16 -0
- data/lib/mss-sdk.rb +2 -0
- data/lib/mss.rb +14 -0
- data/rails/init.rb +14 -0
- metadata +201 -0
@@ -0,0 +1,737 @@
|
|
1
|
+
# Copyright 2011-2013 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License"). You
|
4
|
+
# may not use this file except in compliance with the License. A copy of
|
5
|
+
# the License is located at
|
6
|
+
#
|
7
|
+
#
|
8
|
+
# or in the "license" file accompanying this file. This file is
|
9
|
+
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
|
10
|
+
# ANY KIND, either express or implied. See the License for the specific
|
11
|
+
# language governing permissions and limitations under the License.
|
12
|
+
|
13
|
+
require 'bigdecimal'
|
14
|
+
require 'json'
|
15
|
+
|
16
|
+
module MSS
|
17
|
+
module Core
|
18
|
+
|
19
|
+
# @api private
|
20
|
+
class OptionGrammar
|
21
|
+
|
22
|
+
# @api private
|
23
|
+
class DefaultOption; end
|
24
|
+
|
25
|
+
# @api private
|
26
|
+
class FormatError < ArgumentError
|
27
|
+
attr_accessor :expectation
|
28
|
+
attr_accessor :context_description
|
29
|
+
|
30
|
+
def initialize(expectation, context)
|
31
|
+
@expectation = expectation
|
32
|
+
@context_description = context
|
33
|
+
end
|
34
|
+
|
35
|
+
def to_s
|
36
|
+
"expected #{expectation} for #{context_description}"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# @api private
|
41
|
+
module Descriptors
|
42
|
+
|
43
|
+
# @api private
|
44
|
+
module NoArgs
|
45
|
+
def apply(option)
|
46
|
+
option.extend self
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
module Timestamp
|
51
|
+
|
52
|
+
extend NoArgs
|
53
|
+
|
54
|
+
def validate(value, context = nil)
|
55
|
+
true
|
56
|
+
# raise format_error("timestamp value", context) unless
|
57
|
+
# case value
|
58
|
+
# when String
|
59
|
+
# value =~ /^\d+$/ or value =~ /^\d{4}-\d{2}-d{2}T\d{2}:\d{2}:\d{2}Z$/
|
60
|
+
# when String then value =~ /^2009-12-04T20:56:05.000Z\d+$/
|
61
|
+
# when Integer then true
|
62
|
+
# when DateTime then true
|
63
|
+
# when Timestamp then true
|
64
|
+
# when Date then true
|
65
|
+
# else false
|
66
|
+
# end
|
67
|
+
# end
|
68
|
+
# value.respond_to? :to_str
|
69
|
+
end
|
70
|
+
|
71
|
+
def encode_value(value)
|
72
|
+
value.to_s
|
73
|
+
# value.to_s
|
74
|
+
# case value
|
75
|
+
# when Integer
|
76
|
+
# when
|
77
|
+
# case value
|
78
|
+
# when nil, '' then nil
|
79
|
+
# when DateTime then raw
|
80
|
+
# when Integer then DateTime.parse(Time.at(raw).to_s) # timestamp
|
81
|
+
# else DateTime.parse(raw.to_s) # work with Time, Date and String objects
|
82
|
+
# end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
# @api private
|
87
|
+
module String
|
88
|
+
|
89
|
+
extend NoArgs
|
90
|
+
|
91
|
+
def validate(value, context = nil)
|
92
|
+
raise format_error("string value", context) unless
|
93
|
+
value.respond_to? :to_str
|
94
|
+
end
|
95
|
+
|
96
|
+
def encode_value(value)
|
97
|
+
value.to_s
|
98
|
+
end
|
99
|
+
|
100
|
+
end
|
101
|
+
|
102
|
+
# @api private
|
103
|
+
module Blob
|
104
|
+
|
105
|
+
extend NoArgs
|
106
|
+
|
107
|
+
def validate(value, context = nil)
|
108
|
+
raise format_error("string value", context) unless
|
109
|
+
value.respond_to? :to_str
|
110
|
+
end
|
111
|
+
|
112
|
+
def encode_value(value)
|
113
|
+
[value.to_s].pack("m0").gsub("\n", '')
|
114
|
+
end
|
115
|
+
|
116
|
+
def hash_format(value)
|
117
|
+
[value.to_s].pack("m0").gsub("\n", '')
|
118
|
+
end
|
119
|
+
|
120
|
+
end
|
121
|
+
|
122
|
+
# @api private
|
123
|
+
module Integer
|
124
|
+
|
125
|
+
extend NoArgs
|
126
|
+
|
127
|
+
def validate(value, context = nil)
|
128
|
+
raise format_error("integer value", context) unless
|
129
|
+
value.respond_to? :to_int
|
130
|
+
end
|
131
|
+
|
132
|
+
def encode_value(value)
|
133
|
+
value.to_s
|
134
|
+
end
|
135
|
+
|
136
|
+
end
|
137
|
+
|
138
|
+
Long = Integer
|
139
|
+
|
140
|
+
# @api private
|
141
|
+
module Boolean
|
142
|
+
|
143
|
+
extend NoArgs
|
144
|
+
|
145
|
+
def validate(value, context = nil)
|
146
|
+
raise format_error("boolean value", context) unless
|
147
|
+
value == true || value == false
|
148
|
+
end
|
149
|
+
|
150
|
+
def encode_value(value)
|
151
|
+
value.to_s
|
152
|
+
end
|
153
|
+
|
154
|
+
end
|
155
|
+
|
156
|
+
# @api private
|
157
|
+
module Required
|
158
|
+
extend NoArgs
|
159
|
+
def required?; true; end
|
160
|
+
end
|
161
|
+
|
162
|
+
module Position
|
163
|
+
def self.apply *args; end
|
164
|
+
end
|
165
|
+
|
166
|
+
# @api private
|
167
|
+
module Float
|
168
|
+
|
169
|
+
extend NoArgs
|
170
|
+
|
171
|
+
def validate(value, context = nil)
|
172
|
+
raise format_error("float value", context) unless
|
173
|
+
value.kind_of?(Numeric) or
|
174
|
+
value.respond_to? :to_f
|
175
|
+
end
|
176
|
+
|
177
|
+
def encode_value(value)
|
178
|
+
value.to_f.to_s
|
179
|
+
end
|
180
|
+
|
181
|
+
end
|
182
|
+
|
183
|
+
Double = Float
|
184
|
+
|
185
|
+
# @api private
|
186
|
+
module Rename
|
187
|
+
def self.apply(option, new_name)
|
188
|
+
new_name = Inflection.ruby_name(new_name)
|
189
|
+
MetaUtils.extend_method(option, :ruby_name) { new_name }
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
# @api private
|
194
|
+
module Pattern
|
195
|
+
|
196
|
+
# def validate value, context = nil
|
197
|
+
# unless value =~ regex
|
198
|
+
# raise format_error("value to match #{regex}", context)
|
199
|
+
# end
|
200
|
+
# end
|
201
|
+
#
|
202
|
+
# def self.apply option, regex
|
203
|
+
# option.extend(self)
|
204
|
+
# MetaUtils.extend_method(option, :regex) { regex }
|
205
|
+
# end
|
206
|
+
|
207
|
+
def self.apply *args
|
208
|
+
end
|
209
|
+
|
210
|
+
end
|
211
|
+
|
212
|
+
# @api private
|
213
|
+
module ListMethods
|
214
|
+
|
215
|
+
module ClassMethods
|
216
|
+
|
217
|
+
def apply(option, member_descriptors)
|
218
|
+
super(option)
|
219
|
+
member_option = option.member_option if option.respond_to?(:member_option)
|
220
|
+
|
221
|
+
# ignoring member name descriptors for lists, only useful for rest
|
222
|
+
descriptors = []
|
223
|
+
member_descriptors.each do |descriptor|
|
224
|
+
unless descriptor.is_a?(Hash) and descriptor[:member_name]
|
225
|
+
descriptors << descriptor
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
member_option ||= ListMember.new
|
230
|
+
member_option = member_option.extend_with_config(*descriptors)
|
231
|
+
MetaUtils.extend_method(option, :member_option) { member_option }
|
232
|
+
end
|
233
|
+
|
234
|
+
end
|
235
|
+
|
236
|
+
module InstanceMethods
|
237
|
+
|
238
|
+
def validate(value, context = nil)
|
239
|
+
raise format_error("enumerable value", context) unless
|
240
|
+
value.respond_to? :each
|
241
|
+
i = 0
|
242
|
+
value.each do |member|
|
243
|
+
i += 1
|
244
|
+
member_option.validate(member,
|
245
|
+
"member #{i} of #{context_description(context)}")
|
246
|
+
end
|
247
|
+
end
|
248
|
+
|
249
|
+
def request_params(value, prefix = nil)
|
250
|
+
params = []
|
251
|
+
value.each do |v|
|
252
|
+
name = prefixed_name(prefix) + join + (params.size + 1).to_s
|
253
|
+
params << member_option.request_params(v, name)
|
254
|
+
end
|
255
|
+
return [Http::Request::Param.new(prefixed_name(prefix), "")] if params.empty?
|
256
|
+
params
|
257
|
+
end
|
258
|
+
|
259
|
+
def hash_format(value)
|
260
|
+
value.map do |v|
|
261
|
+
member_option.hash_format(v)
|
262
|
+
end
|
263
|
+
end
|
264
|
+
|
265
|
+
def join
|
266
|
+
'.'
|
267
|
+
end
|
268
|
+
|
269
|
+
end
|
270
|
+
|
271
|
+
end
|
272
|
+
|
273
|
+
module List
|
274
|
+
|
275
|
+
extend NoArgs
|
276
|
+
extend ListMethods::ClassMethods
|
277
|
+
include ListMethods::InstanceMethods
|
278
|
+
|
279
|
+
end
|
280
|
+
|
281
|
+
module MemberedList
|
282
|
+
|
283
|
+
extend NoArgs
|
284
|
+
extend ListMethods::ClassMethods
|
285
|
+
include ListMethods::InstanceMethods
|
286
|
+
|
287
|
+
def join
|
288
|
+
'.member.'
|
289
|
+
end
|
290
|
+
|
291
|
+
end
|
292
|
+
|
293
|
+
class ListMember < DefaultOption
|
294
|
+
|
295
|
+
def initialize options = {}
|
296
|
+
super("##list-member##")
|
297
|
+
@prefix = options[:prefix] || ''
|
298
|
+
end
|
299
|
+
|
300
|
+
def prefixed_name(prefix)
|
301
|
+
"#{prefix}#{@prefix}"
|
302
|
+
end
|
303
|
+
|
304
|
+
end
|
305
|
+
|
306
|
+
# @api private
|
307
|
+
module Structure
|
308
|
+
|
309
|
+
extend NoArgs
|
310
|
+
|
311
|
+
def self.apply(option, members)
|
312
|
+
options = {}
|
313
|
+
options = option.member_options.inject({}) do |memo, member_option|
|
314
|
+
memo[member_option.name] = member_option
|
315
|
+
memo
|
316
|
+
end if option.respond_to?(:member_options)
|
317
|
+
|
318
|
+
super(option)
|
319
|
+
|
320
|
+
members.each do |(name, descriptors)|
|
321
|
+
member_option = options[name] || DefaultOption.new(name)
|
322
|
+
member_option = member_option.extend_with_config(*descriptors)
|
323
|
+
options[name] = member_option
|
324
|
+
end
|
325
|
+
|
326
|
+
MetaUtils.extend_method(option, :member_options) { options.values }
|
327
|
+
by_ruby_name = options.values.inject({}) do |memo, member_option|
|
328
|
+
memo[member_option.ruby_name] = member_option
|
329
|
+
memo[member_option.name] = member_option
|
330
|
+
memo
|
331
|
+
end
|
332
|
+
MetaUtils.extend_method(option, :member_option) { |n| by_ruby_name[n] }
|
333
|
+
end
|
334
|
+
|
335
|
+
def validate(value, context = nil)
|
336
|
+
raise format_error("hash value", context) unless
|
337
|
+
value.respond_to?(:to_hash)
|
338
|
+
|
339
|
+
context = context_description(context)
|
340
|
+
|
341
|
+
value.each do |name, v|
|
342
|
+
name = name.to_s
|
343
|
+
raise ArgumentError.new("unexpected key #{name} for #{context}") unless
|
344
|
+
member_option(name)
|
345
|
+
member_option(name).validate(v, "key #{name} of #{context}")
|
346
|
+
end
|
347
|
+
|
348
|
+
member_options.each do |option|
|
349
|
+
raise ArgumentError.new("missing required key #{option.ruby_name} for #{context}") if
|
350
|
+
option.required? and
|
351
|
+
!value.has_key?(option.ruby_name) and
|
352
|
+
!value.has_key?(option.ruby_name.to_sym) and
|
353
|
+
!value.has_key?(option.name)
|
354
|
+
end
|
355
|
+
end
|
356
|
+
|
357
|
+
def request_params(values, prefix = nil)
|
358
|
+
values.map do |name, value|
|
359
|
+
name = name.to_s
|
360
|
+
member_option(name).request_params(value, prefixed_name(prefix))
|
361
|
+
end.flatten
|
362
|
+
end
|
363
|
+
|
364
|
+
def hash_format(hash)
|
365
|
+
hash.inject({}) do |hash, (name, value)|
|
366
|
+
option = member_option(name.to_s)
|
367
|
+
hash[option.name] = option.hash_format(value)
|
368
|
+
hash
|
369
|
+
end
|
370
|
+
end
|
371
|
+
|
372
|
+
end
|
373
|
+
|
374
|
+
module Map
|
375
|
+
|
376
|
+
def self.apply option, members = {}
|
377
|
+
|
378
|
+
option.extend self
|
379
|
+
|
380
|
+
key_option = option.key_option(members)
|
381
|
+
if key_descriptors = members[:key]
|
382
|
+
key_option = key_option.extend_with_config(*key_descriptors)
|
383
|
+
MetaUtils.extend_method(option, :key_option) { key_option }
|
384
|
+
end
|
385
|
+
|
386
|
+
value_option = option.value_option(members)
|
387
|
+
if value_descriptors = members[:value]
|
388
|
+
value_option = value_option.extend_with_config(*value_descriptors)
|
389
|
+
MetaUtils.extend_method(option, :value_option) { value_option }
|
390
|
+
end
|
391
|
+
|
392
|
+
key_option.param_name = members[:key_param] if members[:key_param]
|
393
|
+
value_option.param_name = members[:value_param] if members[:value_param]
|
394
|
+
|
395
|
+
separator = members[:flattened] ? '.' : '.entry.'
|
396
|
+
MetaUtils.extend_method(option, :separator) { separator }
|
397
|
+
|
398
|
+
end
|
399
|
+
|
400
|
+
def validate(value, context = nil)
|
401
|
+
|
402
|
+
raise format_error("hash value", context) unless
|
403
|
+
value.respond_to?(:to_hash)
|
404
|
+
|
405
|
+
context = context_description(context)
|
406
|
+
|
407
|
+
value.each do |key, value|
|
408
|
+
key_option.validate(key, "key of #{context}")
|
409
|
+
value_option.validate(value, "value at key #{key} of #{context}")
|
410
|
+
end
|
411
|
+
|
412
|
+
end
|
413
|
+
|
414
|
+
def request_params values, prefix = nil
|
415
|
+
index = 0
|
416
|
+
values.inject([]) do |params, (key,value)|
|
417
|
+
index += 1
|
418
|
+
common_prefix = "#{prefixed_name(prefix)}#{separator}#{index}"
|
419
|
+
|
420
|
+
key_name = common_prefix + key_option.param_name
|
421
|
+
value_name = common_prefix + value_option.param_name
|
422
|
+
|
423
|
+
params += key_option.request_params(key, common_prefix)
|
424
|
+
params += value_option.request_params(value, common_prefix)
|
425
|
+
|
426
|
+
end
|
427
|
+
end
|
428
|
+
|
429
|
+
|
430
|
+
def hash_format(value)
|
431
|
+
value.inject({}) do |hash, (key, value)|
|
432
|
+
hash[key_option.hash_format(key)] =
|
433
|
+
value_option.hash_format(value)
|
434
|
+
hash
|
435
|
+
end
|
436
|
+
end
|
437
|
+
|
438
|
+
def key_option(options)
|
439
|
+
@_key_option ||= MapOption.new(options[:key_param] || "key")
|
440
|
+
end
|
441
|
+
|
442
|
+
def value_option(options)
|
443
|
+
@_value_option ||= MapOption.new(options[:value_param] || "value")
|
444
|
+
end
|
445
|
+
|
446
|
+
end
|
447
|
+
|
448
|
+
module Bigdecimal
|
449
|
+
|
450
|
+
extend NoArgs
|
451
|
+
|
452
|
+
def validate(value, context = nil)
|
453
|
+
raise format_error("decimal value", context) unless
|
454
|
+
value.kind_of?(Numeric) or
|
455
|
+
value.respond_to?(:to_int)
|
456
|
+
end
|
457
|
+
|
458
|
+
def hash_format(value)
|
459
|
+
BigDecimal(value.to_s)
|
460
|
+
end
|
461
|
+
|
462
|
+
end
|
463
|
+
|
464
|
+
# @api private
|
465
|
+
module Boolean
|
466
|
+
extend NoArgs
|
467
|
+
end
|
468
|
+
|
469
|
+
end
|
470
|
+
|
471
|
+
class DefaultOption
|
472
|
+
|
473
|
+
attr_reader :name
|
474
|
+
|
475
|
+
def initialize(name)
|
476
|
+
@name = name
|
477
|
+
end
|
478
|
+
|
479
|
+
def ruby_name
|
480
|
+
Inflection.ruby_name(name)
|
481
|
+
end
|
482
|
+
|
483
|
+
def request_params(value, prefix = nil)
|
484
|
+
[Http::Request::Param.new(prefixed_name(prefix), encode_value(value))]
|
485
|
+
end
|
486
|
+
|
487
|
+
def hash_format(value)
|
488
|
+
value
|
489
|
+
end
|
490
|
+
|
491
|
+
def prefixed_name(prefix)
|
492
|
+
return "#{prefix}.#{name}" if prefix
|
493
|
+
name
|
494
|
+
end
|
495
|
+
|
496
|
+
def encode_value(value)
|
497
|
+
value
|
498
|
+
end
|
499
|
+
|
500
|
+
def required?
|
501
|
+
false
|
502
|
+
end
|
503
|
+
|
504
|
+
def format_error(expected, context = nil)
|
505
|
+
context = context_description(context)
|
506
|
+
FormatError.new(expected, context)
|
507
|
+
end
|
508
|
+
|
509
|
+
def context_description(context)
|
510
|
+
context or "option #{ruby_name}"
|
511
|
+
end
|
512
|
+
|
513
|
+
def extend_with_config(*descriptors)
|
514
|
+
option = clone
|
515
|
+
descriptors.each do |desc|
|
516
|
+
if desc.kind_of?(Hash)
|
517
|
+
(name, arg) = desc.to_a.first
|
518
|
+
next if name == :documentation
|
519
|
+
else
|
520
|
+
name = desc
|
521
|
+
arg = nil
|
522
|
+
end
|
523
|
+
class_name = Inflection.class_name(name.to_s)
|
524
|
+
mod = Descriptors::const_get(class_name)
|
525
|
+
if arg
|
526
|
+
mod.apply(option, arg)
|
527
|
+
else
|
528
|
+
mod.apply(option)
|
529
|
+
end
|
530
|
+
end
|
531
|
+
option
|
532
|
+
end
|
533
|
+
|
534
|
+
include Descriptors::String
|
535
|
+
|
536
|
+
end
|
537
|
+
|
538
|
+
# @api private
|
539
|
+
module ModuleMethods
|
540
|
+
|
541
|
+
include Inflection
|
542
|
+
|
543
|
+
def customize(config = [])
|
544
|
+
m = Class.new(self)
|
545
|
+
supported_options = m.supported_options.inject({}) do |memo, opt|
|
546
|
+
memo[opt.name] = opt
|
547
|
+
memo
|
548
|
+
end
|
549
|
+
config.each do |option_config|
|
550
|
+
if config.kind_of?(Hash)
|
551
|
+
(name, value_desc) = option_config
|
552
|
+
else
|
553
|
+
(name, value_desc) = parse_option(option_config)
|
554
|
+
end
|
555
|
+
option = supported_options[name] || DefaultOption.new(name)
|
556
|
+
option = option.extend_with_config(*value_desc)
|
557
|
+
supported_options[option.name] = option
|
558
|
+
end
|
559
|
+
|
560
|
+
supported_ary = supported_options.values
|
561
|
+
MetaUtils.extend_method(m, :supported_options) { supported_ary }
|
562
|
+
supported_ruby_names = supported_ary.inject({}) do |memo, opt|
|
563
|
+
memo[opt.ruby_name] = opt
|
564
|
+
memo
|
565
|
+
end
|
566
|
+
MetaUtils.extend_method(m, :option) { |n| supported_ruby_names[n] }
|
567
|
+
supported_ary.each do |opt|
|
568
|
+
MetaUtils.extend_method(m, "validate_#{opt.ruby_name}") do |value|
|
569
|
+
opt.validate(value)
|
570
|
+
end
|
571
|
+
end
|
572
|
+
|
573
|
+
m
|
574
|
+
end
|
575
|
+
|
576
|
+
def option(name)
|
577
|
+
nil
|
578
|
+
end
|
579
|
+
|
580
|
+
def supported_options
|
581
|
+
[]
|
582
|
+
end
|
583
|
+
|
584
|
+
def validate(options)
|
585
|
+
options.each do |name, value|
|
586
|
+
name = name.to_s
|
587
|
+
raise ArgumentError.new("unexpected option #{name}") unless
|
588
|
+
option(name)
|
589
|
+
option(name).validate(value)
|
590
|
+
end
|
591
|
+
supported_options.each do |option|
|
592
|
+
raise ArgumentError.new("missing required option #{option.ruby_name}") unless
|
593
|
+
!option.required? ||
|
594
|
+
options.has_key?(option.ruby_name) || options.has_key?(option.ruby_name.to_sym)
|
595
|
+
end
|
596
|
+
end
|
597
|
+
|
598
|
+
# Returns the options in MSS/Query format
|
599
|
+
def request_params(options)
|
600
|
+
validate(options)
|
601
|
+
options.map do |(name, value)|
|
602
|
+
name = name.to_s
|
603
|
+
option(name).request_params(value)
|
604
|
+
end.flatten
|
605
|
+
end
|
606
|
+
|
607
|
+
# Returns the options as a hash (which is used to generate JSON
|
608
|
+
# in to_json).
|
609
|
+
def to_h(options)
|
610
|
+
validate(options)
|
611
|
+
options.inject({}) do |hash, (name, value)|
|
612
|
+
option = self.option(name.to_s)
|
613
|
+
hash[option.name] = option.hash_format(value)
|
614
|
+
hash
|
615
|
+
end
|
616
|
+
end
|
617
|
+
|
618
|
+
# Returns the options in JSON format
|
619
|
+
def to_json(options)
|
620
|
+
to_h(options).to_json
|
621
|
+
end
|
622
|
+
|
623
|
+
def included(m)
|
624
|
+
m.extend(self::ModuleMethods)
|
625
|
+
end
|
626
|
+
|
627
|
+
protected
|
628
|
+
def parse_option(option)
|
629
|
+
value_desc = nil
|
630
|
+
if option.kind_of? Hash
|
631
|
+
raise ArgumentError.new("passed empty hash where an option was expected") if
|
632
|
+
option.empty?
|
633
|
+
|
634
|
+
raise ArgumentError.new("too many entries in option description") if
|
635
|
+
option.size > 1
|
636
|
+
|
637
|
+
(name, value_desc) = option.to_a.first
|
638
|
+
name = name.to_s
|
639
|
+
|
640
|
+
raise ArgumentError.new("expected an array for "+
|
641
|
+
"value description of option #{name},"+
|
642
|
+
"got #{value_desc.inspect}") unless
|
643
|
+
value_desc.nil? or value_desc.kind_of?(Array)
|
644
|
+
else
|
645
|
+
name = option
|
646
|
+
end
|
647
|
+
|
648
|
+
value_desc ||= []
|
649
|
+
|
650
|
+
[name, value_desc]
|
651
|
+
end
|
652
|
+
|
653
|
+
protected
|
654
|
+
def apply_required_descriptor(m, name)
|
655
|
+
name = ruby_name(name)
|
656
|
+
MetaUtils.extend_method(m, :validate) do |opts|
|
657
|
+
raise ArgumentError.new("missing required option #{name}") unless
|
658
|
+
opts.key? name or opts.key? name.to_sym
|
659
|
+
end
|
660
|
+
end
|
661
|
+
|
662
|
+
protected
|
663
|
+
def apply_integer_descriptor(m, name)
|
664
|
+
MetaUtils.extend_method(m, "validate_#{ruby_name(name)}") do |value|
|
665
|
+
raise ArgumentError.new("expected integer value for option #{ruby_name(name)}") unless
|
666
|
+
value.respond_to? :to_int
|
667
|
+
end
|
668
|
+
end
|
669
|
+
|
670
|
+
protected
|
671
|
+
def apply_string_descriptor(m, name)
|
672
|
+
MetaUtils.extend_method(m, "validate_#{ruby_name(name)}") do |value|
|
673
|
+
raise ArgumentError.new("expected string value for option #{ruby_name(name)}") unless
|
674
|
+
value.respond_to? :to_str
|
675
|
+
end
|
676
|
+
end
|
677
|
+
|
678
|
+
protected
|
679
|
+
def apply_list_descriptor(m, name, arg)
|
680
|
+
MetaUtils.extend_method(m, "validate_#{ruby_name(name)}") do |value|
|
681
|
+
raise ArgumentError.new("expected value for option #{ruby_name(name)} "+
|
682
|
+
"to respond to #each") unless
|
683
|
+
value.respond_to? :each
|
684
|
+
end
|
685
|
+
MetaUtils.extend_method(m, "params_for_#{ruby_name(name)}") do |value|
|
686
|
+
i = 0
|
687
|
+
values = []
|
688
|
+
value.each do |member|
|
689
|
+
i += 1
|
690
|
+
values << Http::Request::Param.new(name+"."+i.to_s, member.to_s)
|
691
|
+
end
|
692
|
+
if i > 0
|
693
|
+
values
|
694
|
+
else
|
695
|
+
Http::Request::Param.new(name, "")
|
696
|
+
end
|
697
|
+
end
|
698
|
+
end
|
699
|
+
|
700
|
+
protected
|
701
|
+
def apply_rename_descriptor(m, name, new_name)
|
702
|
+
name = ruby_name(name)
|
703
|
+
MetaUtils.extend_method(m, :validate) do |opts|
|
704
|
+
raise ArgumentError.new("unexpected option foo") if
|
705
|
+
opts.key?(name) or opts.key?(name.to_sym)
|
706
|
+
|
707
|
+
opts = opts.dup
|
708
|
+
opts[name] = opts[new_name] if opts.key?(new_name)
|
709
|
+
opts[name.to_sym] = opts[new_name.to_sym] if opts.key?(new_name.to_sym)
|
710
|
+
opts.delete(new_name)
|
711
|
+
opts.delete(new_name.to_sym)
|
712
|
+
super(opts)
|
713
|
+
end
|
714
|
+
|
715
|
+
# couldn't find a better way to alias a class method
|
716
|
+
method = m.method("params_for_#{name}")
|
717
|
+
MetaUtils.extend_method(m, "params_for_#{new_name}") do |value|
|
718
|
+
method.call(value)
|
719
|
+
end
|
720
|
+
end
|
721
|
+
|
722
|
+
end
|
723
|
+
|
724
|
+
class MapOption < DefaultOption
|
725
|
+
def param_name
|
726
|
+
@param_name || name
|
727
|
+
end
|
728
|
+
def param_name= name
|
729
|
+
@param_name = name
|
730
|
+
end
|
731
|
+
end
|
732
|
+
|
733
|
+
extend ModuleMethods
|
734
|
+
|
735
|
+
end
|
736
|
+
end
|
737
|
+
end
|