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.
Files changed (131) hide show
  1. checksums.yaml +7 -0
  2. data/.yardopts +9 -0
  3. data/LICENSE.txt +0 -0
  4. data/README.md +192 -0
  5. data/bin/mss-rb +178 -0
  6. data/ca-bundle.crt +3554 -0
  7. data/lib/mss/core/async_handle.rb +89 -0
  8. data/lib/mss/core/cacheable.rb +76 -0
  9. data/lib/mss/core/client.rb +786 -0
  10. data/lib/mss/core/collection/simple.rb +81 -0
  11. data/lib/mss/core/collection/with_limit_and_next_token.rb +70 -0
  12. data/lib/mss/core/collection/with_next_token.rb +96 -0
  13. data/lib/mss/core/collection.rb +262 -0
  14. data/lib/mss/core/configuration.rb +527 -0
  15. data/lib/mss/core/credential_providers.rb +653 -0
  16. data/lib/mss/core/data.rb +251 -0
  17. data/lib/mss/core/deprecations.rb +83 -0
  18. data/lib/mss/core/endpoints.rb +36 -0
  19. data/lib/mss/core/http/connection_pool.rb +374 -0
  20. data/lib/mss/core/http/curb_handler.rb +150 -0
  21. data/lib/mss/core/http/handler.rb +88 -0
  22. data/lib/mss/core/http/net_http_handler.rb +144 -0
  23. data/lib/mss/core/http/patch.rb +98 -0
  24. data/lib/mss/core/http/request.rb +258 -0
  25. data/lib/mss/core/http/response.rb +80 -0
  26. data/lib/mss/core/indifferent_hash.rb +87 -0
  27. data/lib/mss/core/inflection.rb +55 -0
  28. data/lib/mss/core/ini_parser.rb +41 -0
  29. data/lib/mss/core/json_client.rb +46 -0
  30. data/lib/mss/core/json_parser.rb +75 -0
  31. data/lib/mss/core/json_request_builder.rb +34 -0
  32. data/lib/mss/core/json_response_parser.rb +78 -0
  33. data/lib/mss/core/lazy_error_classes.rb +107 -0
  34. data/lib/mss/core/log_formatter.rb +426 -0
  35. data/lib/mss/core/managed_file.rb +31 -0
  36. data/lib/mss/core/meta_utils.rb +44 -0
  37. data/lib/mss/core/model.rb +61 -0
  38. data/lib/mss/core/naming.rb +29 -0
  39. data/lib/mss/core/option_grammar.rb +737 -0
  40. data/lib/mss/core/options/json_serializer.rb +81 -0
  41. data/lib/mss/core/options/validator.rb +154 -0
  42. data/lib/mss/core/options/xml_serializer.rb +117 -0
  43. data/lib/mss/core/page_result.rb +74 -0
  44. data/lib/mss/core/policy.rb +938 -0
  45. data/lib/mss/core/query_client.rb +40 -0
  46. data/lib/mss/core/query_error_parser.rb +23 -0
  47. data/lib/mss/core/query_request_builder.rb +46 -0
  48. data/lib/mss/core/query_response_parser.rb +34 -0
  49. data/lib/mss/core/region.rb +84 -0
  50. data/lib/mss/core/region_collection.rb +79 -0
  51. data/lib/mss/core/resource.rb +412 -0
  52. data/lib/mss/core/resource_cache.rb +39 -0
  53. data/lib/mss/core/response.rb +214 -0
  54. data/lib/mss/core/response_cache.rb +49 -0
  55. data/lib/mss/core/rest_error_parser.rb +23 -0
  56. data/lib/mss/core/rest_json_client.rb +39 -0
  57. data/lib/mss/core/rest_request_builder.rb +153 -0
  58. data/lib/mss/core/rest_response_parser.rb +65 -0
  59. data/lib/mss/core/rest_xml_client.rb +46 -0
  60. data/lib/mss/core/service_interface.rb +82 -0
  61. data/lib/mss/core/signers/base.rb +45 -0
  62. data/lib/mss/core/signers/cloud_front.rb +55 -0
  63. data/lib/mss/core/signers/s3.rb +158 -0
  64. data/lib/mss/core/signers/version_2.rb +71 -0
  65. data/lib/mss/core/signers/version_3.rb +85 -0
  66. data/lib/mss/core/signers/version_3_https.rb +60 -0
  67. data/lib/mss/core/signers/version_4/chunk_signed_stream.rb +190 -0
  68. data/lib/mss/core/signers/version_4.rb +227 -0
  69. data/lib/mss/core/uri_escape.rb +43 -0
  70. data/lib/mss/core/xml/frame.rb +245 -0
  71. data/lib/mss/core/xml/frame_stack.rb +84 -0
  72. data/lib/mss/core/xml/grammar.rb +306 -0
  73. data/lib/mss/core/xml/parser.rb +69 -0
  74. data/lib/mss/core/xml/root_frame.rb +64 -0
  75. data/lib/mss/core/xml/sax_handlers/libxml.rb +46 -0
  76. data/lib/mss/core/xml/sax_handlers/nokogiri.rb +55 -0
  77. data/lib/mss/core/xml/sax_handlers/ox.rb +40 -0
  78. data/lib/mss/core/xml/sax_handlers/rexml.rb +46 -0
  79. data/lib/mss/core/xml/stub.rb +122 -0
  80. data/lib/mss/core.rb +602 -0
  81. data/lib/mss/errors.rb +161 -0
  82. data/lib/mss/rails.rb +194 -0
  83. data/lib/mss/s3/access_control_list.rb +262 -0
  84. data/lib/mss/s3/acl_object.rb +263 -0
  85. data/lib/mss/s3/acl_options.rb +200 -0
  86. data/lib/mss/s3/bucket.rb +757 -0
  87. data/lib/mss/s3/bucket_collection.rb +161 -0
  88. data/lib/mss/s3/bucket_lifecycle_configuration.rb +472 -0
  89. data/lib/mss/s3/bucket_region_cache.rb +51 -0
  90. data/lib/mss/s3/bucket_tag_collection.rb +110 -0
  91. data/lib/mss/s3/bucket_version_collection.rb +78 -0
  92. data/lib/mss/s3/cipher_io.rb +119 -0
  93. data/lib/mss/s3/client/xml.rb +265 -0
  94. data/lib/mss/s3/client.rb +2076 -0
  95. data/lib/mss/s3/config.rb +60 -0
  96. data/lib/mss/s3/cors_rule.rb +107 -0
  97. data/lib/mss/s3/cors_rule_collection.rb +193 -0
  98. data/lib/mss/s3/data_options.rb +190 -0
  99. data/lib/mss/s3/encryption_utils.rb +145 -0
  100. data/lib/mss/s3/errors.rb +93 -0
  101. data/lib/mss/s3/multipart_upload.rb +353 -0
  102. data/lib/mss/s3/multipart_upload_collection.rb +75 -0
  103. data/lib/mss/s3/object_collection.rb +355 -0
  104. data/lib/mss/s3/object_metadata.rb +102 -0
  105. data/lib/mss/s3/object_upload_collection.rb +76 -0
  106. data/lib/mss/s3/object_version.rb +153 -0
  107. data/lib/mss/s3/object_version_collection.rb +88 -0
  108. data/lib/mss/s3/paginated_collection.rb +74 -0
  109. data/lib/mss/s3/policy.rb +73 -0
  110. data/lib/mss/s3/prefix_and_delimiter_collection.rb +46 -0
  111. data/lib/mss/s3/prefixed_collection.rb +84 -0
  112. data/lib/mss/s3/presign_v4.rb +135 -0
  113. data/lib/mss/s3/presigned_post.rb +574 -0
  114. data/lib/mss/s3/region_detection.rb +75 -0
  115. data/lib/mss/s3/request.rb +61 -0
  116. data/lib/mss/s3/s3_object.rb +1795 -0
  117. data/lib/mss/s3/tree/branch_node.rb +67 -0
  118. data/lib/mss/s3/tree/child_collection.rb +103 -0
  119. data/lib/mss/s3/tree/leaf_node.rb +93 -0
  120. data/lib/mss/s3/tree/node.rb +21 -0
  121. data/lib/mss/s3/tree/parent.rb +86 -0
  122. data/lib/mss/s3/tree.rb +115 -0
  123. data/lib/mss/s3/uploaded_part.rb +81 -0
  124. data/lib/mss/s3/uploaded_part_collection.rb +83 -0
  125. data/lib/mss/s3/website_configuration.rb +101 -0
  126. data/lib/mss/s3.rb +161 -0
  127. data/lib/mss/version.rb +16 -0
  128. data/lib/mss-sdk.rb +2 -0
  129. data/lib/mss.rb +14 -0
  130. data/rails/init.rb +14 -0
  131. 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