aws-sdk 1.1.3 → 1.1.4

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 (233) hide show
  1. data/ca-bundle.crt +2 -348
  2. data/lib/aws.rb +24 -49
  3. data/lib/aws/{common.rb → core.rb} +120 -9
  4. data/lib/aws/{api_config.rb → core/api_config.rb} +19 -20
  5. data/lib/aws/core/api_config_transform.rb +36 -0
  6. data/lib/aws/core/async_handle.rb +91 -0
  7. data/lib/aws/core/authorize_v2.rb +39 -0
  8. data/lib/aws/{authorize_v3.rb → core/authorize_v3.rb} +16 -15
  9. data/lib/aws/{api_config_transform.rb → core/authorize_with_session_token.rb} +9 -12
  10. data/lib/aws/core/autoloader.rb +64 -0
  11. data/lib/aws/core/cacheable.rb +78 -0
  12. data/lib/aws/core/client.rb +471 -0
  13. data/lib/aws/core/client_logging.rb +125 -0
  14. data/lib/aws/core/collections.rb +229 -0
  15. data/lib/aws/core/configuration.rb +358 -0
  16. data/lib/aws/core/configured_client_methods.rb +76 -0
  17. data/lib/aws/core/configured_grammars.rb +63 -0
  18. data/lib/aws/{configured_option_grammars.rb → core/configured_option_grammars.rb} +18 -20
  19. data/lib/aws/{configured_xml_grammars.rb → core/configured_xml_grammars.rb} +19 -21
  20. data/lib/aws/core/default_signer.rb +67 -0
  21. data/lib/aws/core/http/curb_handler.rb +129 -0
  22. data/lib/aws/core/http/handler.rb +77 -0
  23. data/lib/aws/core/http/httparty_handler.rb +113 -0
  24. data/lib/aws/core/http/net_http_handler.rb +124 -0
  25. data/lib/aws/core/http/request.rb +207 -0
  26. data/lib/aws/core/http/response.rb +73 -0
  27. data/lib/aws/{ignore_result_element.rb → core/ignore_result_element.rb} +14 -18
  28. data/lib/aws/core/indifferent_hash.rb +88 -0
  29. data/lib/aws/core/inflection.rb +47 -0
  30. data/lib/aws/core/lazy_error_classes.rb +62 -0
  31. data/lib/aws/{uri_escape.rb → core/meta_utils.rb} +24 -23
  32. data/lib/aws/core/model.rb +57 -0
  33. data/lib/aws/{authorize_with_session_token.rb → core/naming.rb} +9 -8
  34. data/lib/aws/core/option_grammar.rb +562 -0
  35. data/lib/aws/core/policy.rb +914 -0
  36. data/lib/aws/core/resource.rb +380 -0
  37. data/lib/aws/core/resource_cache.rb +40 -0
  38. data/lib/aws/core/response.rb +125 -0
  39. data/lib/aws/core/response_cache.rb +50 -0
  40. data/lib/aws/core/service_interface.rb +60 -0
  41. data/lib/aws/core/uri_escape.rb +46 -0
  42. data/lib/aws/core/xml_grammar.rb +926 -0
  43. data/lib/aws/ec2.rb +47 -16
  44. data/lib/aws/ec2/attachment.rb +0 -2
  45. data/lib/aws/ec2/attachment_collection.rb +1 -6
  46. data/lib/aws/ec2/availability_zone.rb +0 -2
  47. data/lib/aws/ec2/availability_zone_collection.rb +0 -3
  48. data/lib/aws/ec2/client.rb +6 -9
  49. data/lib/aws/ec2/client/xml.rb +3 -6
  50. data/lib/aws/ec2/collection.rb +1 -4
  51. data/lib/aws/ec2/config.rb +18 -0
  52. data/lib/aws/ec2/elastic_ip.rb +0 -2
  53. data/lib/aws/ec2/elastic_ip_collection.rb +0 -4
  54. data/lib/aws/ec2/errors.rb +1 -4
  55. data/lib/aws/ec2/has_permissions.rb +0 -2
  56. data/lib/aws/ec2/image.rb +0 -5
  57. data/lib/aws/ec2/image_collection.rb +0 -6
  58. data/lib/aws/ec2/instance.rb +23 -9
  59. data/lib/aws/ec2/instance_collection.rb +85 -22
  60. data/lib/aws/ec2/key_pair.rb +0 -2
  61. data/lib/aws/ec2/key_pair_collection.rb +1 -4
  62. data/lib/aws/ec2/permission_collection.rb +2 -5
  63. data/lib/aws/ec2/region.rb +0 -2
  64. data/lib/aws/ec2/region_collection.rb +0 -4
  65. data/lib/aws/ec2/request.rb +4 -9
  66. data/lib/aws/ec2/reserved_instances.rb +0 -3
  67. data/lib/aws/ec2/reserved_instances_collection.rb +0 -4
  68. data/lib/aws/ec2/reserved_instances_offering.rb +0 -3
  69. data/lib/aws/ec2/reserved_instances_offering_collection.rb +0 -4
  70. data/lib/aws/ec2/resource.rb +3 -5
  71. data/lib/aws/ec2/resource_tag_collection.rb +1 -6
  72. data/lib/aws/ec2/security_group.rb +204 -72
  73. data/lib/aws/ec2/security_group/egress_ip_permission_collection.rb +53 -0
  74. data/lib/aws/ec2/security_group/ip_permission.rb +92 -10
  75. data/lib/aws/ec2/security_group/ip_permission_collection.rb +14 -15
  76. data/lib/aws/ec2/security_group_collection.rb +11 -8
  77. data/lib/aws/ec2/snapshot.rb +0 -4
  78. data/lib/aws/ec2/snapshot_collection.rb +0 -4
  79. data/lib/aws/ec2/tag.rb +0 -3
  80. data/lib/aws/ec2/tag_collection.rb +1 -8
  81. data/lib/aws/ec2/tagged_item.rb +1 -3
  82. data/lib/aws/ec2/volume.rb +0 -6
  83. data/lib/aws/ec2/volume_collection.rb +0 -4
  84. data/lib/aws/errors.rb +0 -3
  85. data/lib/aws/iam.rb +33 -12
  86. data/lib/aws/iam/access_key.rb +0 -3
  87. data/lib/aws/iam/access_key_collection.rb +0 -3
  88. data/lib/aws/iam/account_alias_collection.rb +0 -2
  89. data/lib/aws/iam/client.rb +6 -8
  90. data/lib/aws/iam/client/xml.rb +4 -8
  91. data/lib/aws/iam/collection.rb +2 -5
  92. data/lib/aws/iam/config.rb +18 -0
  93. data/lib/aws/iam/errors.rb +2 -4
  94. data/lib/aws/iam/group.rb +0 -5
  95. data/lib/aws/iam/group_collection.rb +0 -3
  96. data/lib/aws/iam/group_policy_collection.rb +0 -2
  97. data/lib/aws/iam/group_user_collection.rb +1 -4
  98. data/lib/aws/iam/login_profile.rb +0 -2
  99. data/lib/aws/iam/mfa_device.rb +1 -3
  100. data/lib/aws/iam/mfa_device_collection.rb +0 -3
  101. data/lib/aws/iam/policy.rb +2 -4
  102. data/lib/aws/iam/policy_collection.rb +0 -3
  103. data/lib/aws/iam/request.rb +3 -7
  104. data/lib/aws/iam/resource.rb +1 -4
  105. data/lib/aws/iam/server_certificate.rb +0 -2
  106. data/lib/aws/iam/server_certificate_collection.rb +0 -3
  107. data/lib/aws/iam/signing_certificate.rb +0 -2
  108. data/lib/aws/iam/signing_certificate_collection.rb +0 -3
  109. data/lib/aws/iam/user.rb +0 -7
  110. data/lib/aws/iam/user_collection.rb +0 -3
  111. data/lib/aws/iam/user_group_collection.rb +0 -3
  112. data/lib/aws/iam/user_policy.rb +0 -2
  113. data/lib/aws/iam/user_policy_collection.rb +0 -3
  114. data/lib/aws/rails.rb +5 -4
  115. data/lib/aws/record.rb +4 -1
  116. data/lib/aws/record/base.rb +3 -2
  117. data/lib/aws/record/errors.rb +1 -3
  118. data/lib/aws/s3.rb +31 -6
  119. data/lib/aws/s3/access_control_list.rb +0 -2
  120. data/lib/aws/s3/acl_object.rb +10 -12
  121. data/lib/aws/s3/bucket.rb +1 -9
  122. data/lib/aws/s3/bucket_collection.rb +2 -5
  123. data/lib/aws/s3/bucket_version_collection.rb +1 -5
  124. data/lib/aws/s3/client.rb +34 -37
  125. data/lib/aws/s3/client/xml.rb +11 -14
  126. data/lib/aws/{resource_cache.rb → s3/config.rb} +6 -20
  127. data/lib/aws/s3/errors.rb +6 -7
  128. data/lib/aws/s3/multipart_upload.rb +1 -4
  129. data/lib/aws/s3/multipart_upload_collection.rb +1 -6
  130. data/lib/aws/s3/object_collection.rb +1 -5
  131. data/lib/aws/s3/object_metadata.rb +1 -3
  132. data/lib/aws/s3/object_upload_collection.rb +1 -7
  133. data/lib/aws/s3/object_version.rb +1 -4
  134. data/lib/aws/s3/object_version_collection.rb +1 -4
  135. data/lib/aws/s3/policy.rb +3 -5
  136. data/lib/aws/s3/prefix_and_delimiter_collection.rb +0 -2
  137. data/lib/aws/s3/prefixed_collection.rb +0 -2
  138. data/lib/aws/s3/presigned_post.rb +1 -3
  139. data/lib/aws/s3/request.rb +2 -5
  140. data/lib/aws/s3/s3_object.rb +1 -8
  141. data/lib/aws/s3/tree.rb +8 -6
  142. data/lib/aws/s3/tree/branch_node.rb +0 -3
  143. data/lib/aws/s3/tree/child_collection.rb +1 -5
  144. data/lib/aws/s3/tree/leaf_node.rb +0 -5
  145. data/lib/aws/s3/tree/parent.rb +1 -4
  146. data/lib/aws/s3/uploaded_part.rb +1 -3
  147. data/lib/aws/s3/uploaded_part_collection.rb +1 -5
  148. data/lib/aws/simple_db.rb +21 -6
  149. data/lib/aws/simple_db/attribute.rb +1 -6
  150. data/lib/aws/simple_db/attribute_collection.rb +1 -7
  151. data/lib/aws/simple_db/client.rb +7 -9
  152. data/lib/aws/simple_db/client/options.rb +2 -4
  153. data/lib/aws/simple_db/client/xml.rb +5 -10
  154. data/lib/aws/{naming.rb → simple_db/config.rb} +3 -14
  155. data/lib/aws/simple_db/delete_attributes.rb +0 -2
  156. data/lib/aws/simple_db/domain.rb +1 -6
  157. data/lib/aws/simple_db/domain_collection.rb +1 -4
  158. data/lib/aws/simple_db/domain_metadata.rb +1 -3
  159. data/lib/aws/simple_db/errors.rb +1 -4
  160. data/lib/aws/simple_db/item.rb +1 -7
  161. data/lib/aws/simple_db/item_collection.rb +22 -23
  162. data/lib/aws/simple_db/put_attributes.rb +0 -2
  163. data/lib/aws/simple_db/request.rb +3 -7
  164. data/lib/aws/simple_email_service.rb +11 -6
  165. data/lib/aws/simple_email_service/client.rb +7 -9
  166. data/lib/aws/simple_email_service/client/options.rb +3 -6
  167. data/lib/aws/simple_email_service/client/xml.rb +4 -8
  168. data/lib/aws/simple_email_service/config.rb +19 -0
  169. data/lib/aws/simple_email_service/email_address_collection.rb +1 -3
  170. data/lib/aws/simple_email_service/errors.rb +1 -4
  171. data/lib/aws/simple_email_service/quotas.rb +1 -3
  172. data/lib/aws/simple_email_service/request.rb +3 -7
  173. data/lib/aws/sns.rb +15 -8
  174. data/lib/aws/sns/client.rb +7 -8
  175. data/lib/aws/sns/client/options.rb +3 -6
  176. data/lib/aws/sns/client/xml.rb +4 -8
  177. data/lib/aws/sns/config.rb +18 -0
  178. data/lib/aws/sns/errors.rb +1 -4
  179. data/lib/aws/sns/policy.rb +3 -5
  180. data/lib/aws/sns/request.rb +4 -9
  181. data/lib/aws/sns/subscription.rb +1 -5
  182. data/lib/aws/sns/subscription_collection.rb +1 -5
  183. data/lib/aws/sns/topic.rb +1 -6
  184. data/lib/aws/sns/topic_collection.rb +1 -4
  185. data/lib/aws/sns/topic_subscription_collection.rb +1 -4
  186. data/lib/aws/sqs.rb +14 -5
  187. data/lib/aws/sqs/client.rb +6 -9
  188. data/lib/aws/sqs/client/xml.rb +4 -7
  189. data/lib/aws/sqs/config.rb +18 -0
  190. data/lib/aws/sqs/errors.rb +1 -4
  191. data/lib/aws/sqs/policy.rb +3 -5
  192. data/lib/aws/sqs/queue.rb +2 -7
  193. data/lib/aws/sqs/queue_collection.rb +4 -5
  194. data/lib/aws/sqs/received_message.rb +1 -3
  195. data/lib/aws/sqs/received_sns_message.rb +2 -2
  196. data/lib/aws/sqs/request.rb +4 -7
  197. data/lib/aws/sts.rb +12 -6
  198. data/lib/aws/sts/client.rb +6 -8
  199. data/lib/aws/sts/client/xml.rb +4 -8
  200. data/lib/aws/sts/config.rb +18 -0
  201. data/lib/aws/sts/errors.rb +1 -4
  202. data/lib/aws/sts/federated_session.rb +0 -2
  203. data/lib/aws/sts/policy.rb +3 -5
  204. data/lib/aws/sts/request.rb +3 -7
  205. metadata +60 -50
  206. data/lib/aws/async_handle.rb +0 -90
  207. data/lib/aws/authorize_v2.rb +0 -37
  208. data/lib/aws/base_client.rb +0 -488
  209. data/lib/aws/cacheable.rb +0 -79
  210. data/lib/aws/client_logging.rb +0 -122
  211. data/lib/aws/collections.rb +0 -230
  212. data/lib/aws/configuration.rb +0 -357
  213. data/lib/aws/configured_client_methods.rb +0 -81
  214. data/lib/aws/configured_grammars.rb +0 -65
  215. data/lib/aws/default_signer.rb +0 -65
  216. data/lib/aws/http/curb_handler.rb +0 -127
  217. data/lib/aws/http/handler.rb +0 -77
  218. data/lib/aws/http/httparty_handler.rb +0 -103
  219. data/lib/aws/http/request.rb +0 -165
  220. data/lib/aws/http/request_param.rb +0 -64
  221. data/lib/aws/http/response.rb +0 -72
  222. data/lib/aws/indifferent_hash.rb +0 -86
  223. data/lib/aws/inflection.rb +0 -46
  224. data/lib/aws/lazy_error_classes.rb +0 -64
  225. data/lib/aws/meta_utils.rb +0 -43
  226. data/lib/aws/model.rb +0 -57
  227. data/lib/aws/option_grammar.rb +0 -565
  228. data/lib/aws/policy.rb +0 -914
  229. data/lib/aws/resource.rb +0 -381
  230. data/lib/aws/response.rb +0 -125
  231. data/lib/aws/response_cache.rb +0 -50
  232. data/lib/aws/service_interface.rb +0 -60
  233. data/lib/aws/xml_grammar.rb +0 -925
@@ -0,0 +1,50 @@
1
+ # Copyright 2011 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
+ # http://aws.amazon.com/apache2.0/
8
+ #
9
+ # or in the "license" file accompanying this file. This file is
10
+ # distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
11
+ # ANY KIND, either express or implied. See the License for the specific
12
+ # language governing permissions and limitations under the License.
13
+
14
+ module AWS
15
+ module Core
16
+
17
+ # @private
18
+ class ResponseCache
19
+
20
+ attr_reader :cached_responses
21
+
22
+ attr_reader :resource_cache
23
+
24
+ def initialize
25
+ @cached_responses = []
26
+ @indexed_responses = {}
27
+ @resource_cache = ResourceCache.new
28
+ end
29
+
30
+ def add(resp)
31
+ cached_responses.unshift(resp)
32
+ @indexed_responses[resp.cache_key] = resp if
33
+ resp.respond_to?(:cache_key)
34
+ @resource_cache = ResourceCache.new
35
+ end
36
+
37
+ def select(*types, &block)
38
+ cached_responses.select do |resp|
39
+ types.map{|t| t.to_s }.include?(resp.request_type.to_s) and
40
+ (block.nil? || block.call(resp))
41
+ end
42
+ end
43
+
44
+ def cached(resp)
45
+ @indexed_responses[resp.cache_key]
46
+ end
47
+
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,60 @@
1
+ # Copyright 2011 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
+ # http://aws.amazon.com/apache2.0/
8
+ #
9
+ # or in the "license" file accompanying this file. This file is
10
+ # distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
11
+ # ANY KIND, either express or implied. See the License for the specific
12
+ # language governing permissions and limitations under the License.
13
+
14
+ module AWS
15
+ module Core
16
+
17
+ # @private
18
+ module ServiceInterface
19
+
20
+ def self.included base
21
+
22
+ base.send(:attr_reader, :config)
23
+ base.send(:attr_reader, :client)
24
+
25
+ base.module_eval('module Errors; end')
26
+
27
+ unless base::Errors.include?(Errors)
28
+ base::Errors.module_eval { include Errors }
29
+ end
30
+
31
+ end
32
+
33
+ # Returns a new interface object for this service. You can override
34
+ # any of the global configuration parameters by passing them in as
35
+ # hash options. They are merged with AWS.config or merged
36
+ # with the provided +:config+ object.
37
+ #
38
+ # @ec2 = AWS::EC2.new(:max_retries => 2)
39
+ #
40
+ # @see AWS::Cofiguration
41
+ #
42
+ # @param [Hash] options
43
+ # @option options [Configuration] :config An AWS::Configuration
44
+ # object to initialize this service interface object with. Defaults
45
+ # to AWS.config when not provided.
46
+ def initialize options = {}
47
+ @config = options[:config]
48
+ @config ||= AWS.config
49
+ @config = @config.with(options)
50
+ @client = config.send(Inflection.ruby_name(self.class.to_s) + '_client')
51
+ end
52
+
53
+ # @private
54
+ def inspect
55
+ "<#{self.class}>"
56
+ end
57
+
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,46 @@
1
+ # Copyright 2011 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
+ # http://aws.amazon.com/apache2.0/
8
+ #
9
+ # or in the "license" file accompanying this file. This file is
10
+ # distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
11
+ # ANY KIND, either express or implied. See the License for the specific
12
+ # language governing permissions and limitations under the License.
13
+
14
+ require 'cgi'
15
+
16
+ module AWS
17
+ module Core
18
+
19
+ # @private
20
+ module UriEscape
21
+
22
+ # Does URI escaping the way AWS expects it to be done.
23
+ #
24
+ # @private
25
+ protected
26
+ def escape value
27
+ value = value.encode("UTF-8") if
28
+ value.respond_to?(:encode)
29
+ CGI::escape(value.to_s).gsub('+', '%20')
30
+ end
31
+
32
+ # URI-escapes a path without escaping the separators
33
+ #
34
+ # @private
35
+ protected
36
+ def escape_path value
37
+ escaped = ""
38
+ value.scan(%r{(/?)([^/]+)(/?)}) do |(leading, part, trailing)|
39
+ escaped << leading + escape(part) + trailing
40
+ end
41
+ escaped
42
+ end
43
+
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,926 @@
1
+ # Copyright 2011 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
+ # http://aws.amazon.com/apache2.0/
8
+ #
9
+ # or in the "license" file accompanying this file. This file is
10
+ # distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
11
+ # ANY KIND, either express or implied. See the License for the specific
12
+ # language governing permissions and limitations under the License.
13
+
14
+ require 'rexml/document'
15
+ require 'rexml/streamlistener'
16
+ require 'base64'
17
+
18
+ begin
19
+ require 'nokogiri'
20
+ rescue LoadError => e
21
+ end
22
+
23
+ module AWS
24
+ module Core
25
+
26
+ # @private
27
+ class XmlGrammar
28
+
29
+ # @private
30
+ class Context
31
+
32
+ def initialize
33
+ @data = {}
34
+ end
35
+
36
+ def id
37
+ @data[:id]
38
+ end
39
+
40
+ def method_missing(m, *args)
41
+ key = m.to_sym
42
+
43
+ return super unless @data.key?(key)
44
+ @data[key]
45
+ end
46
+
47
+ def respond_to?(m)
48
+ @data.key?(m.to_sym) or super
49
+ end
50
+
51
+ def inspect
52
+ methods = @data.keys
53
+ "<Object #{methods.reject{|m| m =~ /=$/ }.join(', ')}>"
54
+ end
55
+
56
+ # this gets called a LOT during response parsing, and having
57
+ # it be a public method is the fastest way to call it.
58
+ # Strictly speaking it should be private.
59
+ # @private
60
+ def __set_data__(getter, value)
61
+ @data[getter.to_sym] = value
62
+ end
63
+
64
+ end
65
+
66
+ # @private
67
+ class CustomizationContext < Hash
68
+
69
+ def initialize(element_name = nil)
70
+ original_store(:children, {})
71
+
72
+ if element_name
73
+ original_store(:name, element_name)
74
+ recompute_accessors
75
+ end
76
+ end
77
+
78
+ alias_method :original_store, :[]=
79
+
80
+ def []=(name, value)
81
+ super
82
+ if respond_to?("changed_#{name}")
83
+ send("changed_#{name}", value)
84
+ end
85
+ end
86
+
87
+ def changed_boolean(value)
88
+ recompute_accessors
89
+ end
90
+
91
+ def changed_renamed(value)
92
+ recompute_accessors
93
+ end
94
+
95
+ def deep_copy(hash = self)
96
+ fields = hash.inject({}) do |copy,(key,value)|
97
+ if value.is_a?(CustomizationContext)
98
+ value = value.deep_copy
99
+ elsif value.is_a?(Hash)
100
+ value = deep_copy(value)
101
+ end
102
+ copy[key] = value
103
+ copy
104
+ end
105
+ hash.merge(fields)
106
+ end
107
+
108
+ private
109
+ def recompute_accessors
110
+ ruby_name = Inflection.ruby_name((self[:renamed] ||
111
+ self[:name]).to_s)
112
+ self[:getter] =
113
+ if self[:boolean] && ruby_name != "value"
114
+ "#{ruby_name}?"
115
+ else
116
+ ruby_name
117
+ end
118
+ self[:setter] = "#{ruby_name}="
119
+ end
120
+
121
+ end
122
+
123
+ # @private
124
+ class << self
125
+
126
+ def parse xml, options = {}
127
+
128
+ context = options[:context] || Context.new
129
+
130
+ if defined? Nokogiri
131
+ parser = Parser.new(context, customizations)
132
+ parser.extend(NokogiriAdapter)
133
+ xml = "<foo/>" if xml.empty?
134
+ Nokogiri::XML::SAX::Parser.new(parser).parse(xml.strip)
135
+ else
136
+ parser = Parser.new(context, customizations)
137
+ parser.extend(REXMLSaxParserAdapter)
138
+ REXML::Parsers::StreamParser.new(REXML::Source.new(xml), parser).parse
139
+ end
140
+
141
+ context
142
+
143
+ end
144
+
145
+ def simulate context = nil
146
+ StubResponse.new(customizations, context)
147
+ end
148
+
149
+ def customize config = nil, &block
150
+ grammar = Class.new(self)
151
+ grammar.customizations = customizations.deep_copy
152
+ grammar.config_eval(config) if config
153
+ grammar.module_eval(&block) if block_given?
154
+ grammar
155
+ end
156
+
157
+ def element element_name, &block
158
+ eval_customization_context(element_name, &block)
159
+ end
160
+
161
+ def add_method method_name, &block
162
+ format_value do |value|
163
+ MetaUtils.extend_method(value = super(value), method_name, &block)
164
+ value
165
+ end
166
+ # different strategey, slightly different behavior
167
+ # element(method_name.to_s) do
168
+ # format_value(&block)
169
+ # force
170
+ # end
171
+ end
172
+
173
+ def ignore
174
+ @current[:ignored] = true
175
+ end
176
+
177
+ def rename new_name
178
+ @current[:renamed] = new_name.to_s
179
+ end
180
+
181
+ def force
182
+ @current[:forced] = true
183
+ end
184
+
185
+ def collect_values
186
+ @current[:collected] = true
187
+ @current[:initial_collection] = lambda { [] }
188
+ @current[:add_to_collection] =
189
+ lambda { |ary, val| ary << val }
190
+ force
191
+ end
192
+
193
+ def index(name, &block)
194
+ (@customizations[:index_names] ||= []) << name
195
+ @current[:indexed] = [name, block]
196
+ end
197
+
198
+ def boolean_value
199
+ @current[:boolean] = true
200
+ format_value {|value| super(value) == 'true' }
201
+ end
202
+ # required by the hash configuration method
203
+ alias_method :boolean, :boolean_value
204
+
205
+ TRANSLATE_DIGITS = ['0123456789'.freeze, ('X'*10).freeze]
206
+ EASY_FORMAT = "XXXX-XX-XXTXX:XX:XX.XXXZ".freeze
207
+ DATE_PUNCTUATION = ['-:.TZ'.freeze, (' '*5).freeze]
208
+
209
+ def datetime_value
210
+ datetime_like_value(DateTime, :civil)
211
+ end
212
+
213
+ def time_value
214
+ datetime_like_value(Time, :utc)
215
+ end
216
+ alias_method :timestamp, :time_value
217
+
218
+ def datetime_like_value(klass, parts_constructor)
219
+ format_value do |value|
220
+ value = super(value)
221
+ if value and value.tr(*TRANSLATE_DIGITS) == EASY_FORMAT
222
+
223
+ # it's way faster to parse this specific format manually
224
+ # vs. DateTime#parse, and this happens to be the format
225
+ # that AWS uses almost (??) everywhere.
226
+
227
+ parts = value.tr(*DATE_PUNCTUATION).
228
+ chop.split.map { |elem| elem.to_i }
229
+ klass.send(parts_constructor, *parts)
230
+ elsif value
231
+ # fallback in case we have to handle another date format
232
+ klass.parse(value)
233
+ else
234
+ nil
235
+ end
236
+ end
237
+ end
238
+
239
+ def integer_value
240
+ format_value do |value|
241
+ value = super(value)
242
+ value.nil? ? nil : value.to_i
243
+ end
244
+ end
245
+ # required by the hash configuration method
246
+ alias_method :integer, :integer_value
247
+ alias_method :long, :integer_value
248
+
249
+ def float_value
250
+ format_value do |value|
251
+ value = super(value)
252
+ value.nil? ? nil : value.to_f
253
+ end
254
+ end
255
+
256
+ alias_method :float, :float_value
257
+
258
+ def symbol_value
259
+ format_value do |value|
260
+ value = super(value)
261
+ ['', nil].include?(value) ? nil : Inflection.ruby_name(value).to_sym
262
+ end
263
+ end
264
+
265
+ def format_value &block
266
+ @current[:value_formatter] ||= ValueFormatter.new
267
+ @current[:value_formatter].extend_format_value(&block)
268
+ end
269
+
270
+ def list child_element_name = nil, &block
271
+ if child_element_name
272
+ ignore
273
+ parent_element_name = @current_name
274
+ element(child_element_name) do
275
+ rename(parent_element_name)
276
+ collect_values
277
+ yield if block_given?
278
+ end
279
+ else
280
+ collect_values
281
+ end
282
+ end
283
+
284
+ def map_entry(key, value)
285
+ collect_values
286
+ element(key) { rename :key }
287
+ element(value) { rename :value }
288
+ @current[:initial_collection] = lambda { {} }
289
+ @current[:add_to_collection] = lambda do |hash, entry|
290
+ hash[entry.key] = entry.value
291
+ end
292
+ end
293
+
294
+ def map entry_name, key, value
295
+ parent_element_name = @current_name
296
+ ignore
297
+ element(entry_name) do
298
+ rename(parent_element_name)
299
+ map_entry(key, value)
300
+ end
301
+ end
302
+
303
+ def wrapper method_name, options = {}, &blk
304
+ if block_given?
305
+ customizations =
306
+ eval_customization_context(method_name,
307
+ CustomizationContext.new(method_name),
308
+ &blk)
309
+ raise NotImplementedError.new("can't customize wrapped " +
310
+ "elements within the wrapper") unless
311
+ customizations[:children].empty?
312
+ @current[:wrapper_frames] ||= {}
313
+ @current[:wrapper_frames][method_name] = customizations
314
+ end
315
+
316
+ (options[:for] || []).each do |element_name|
317
+ element element_name do
318
+ @current[:wrapper] ||= []
319
+ @current[:wrapper] << method_name
320
+ end
321
+ end
322
+ end
323
+
324
+ def construct_value &block
325
+ @current[:construct_value] = block
326
+ end
327
+
328
+ def eql? other
329
+ self.customizations == other.customizations
330
+ end
331
+
332
+ protected
333
+ def initial_customizations(element_name = nil)
334
+ CustomizationContext.new(element_name)
335
+ end
336
+
337
+ protected
338
+ def eval_customization_context name, initial = nil, &block
339
+ current_name = @current_name
340
+ current = @current
341
+ parent = @parent
342
+ begin
343
+ @current_name = name
344
+ @parent = @current
345
+ initial ||= customizations_for(name)
346
+ @current = initial
347
+ yield if block_given?
348
+ ensure
349
+ @current_name = current_name
350
+ @current = current
351
+ @parent = parent
352
+ end
353
+
354
+ # will be modified to include the customizations defined in
355
+ # the block
356
+ initial
357
+ end
358
+
359
+ protected
360
+ def config_eval(config)
361
+ config.each do |item|
362
+ (type, identifier, args) = parse_config_item(item)
363
+ case type
364
+ when :method
365
+ validate_config_method(identifier)
366
+ validate_args(identifier, args)
367
+ send(identifier, *args)
368
+ when :element
369
+ element(identifier) do
370
+ config_eval(args)
371
+ end
372
+ end
373
+ end
374
+ end
375
+
376
+ protected
377
+ def validate_args(identifier, args)
378
+ arity = method(identifier).arity
379
+ if args.length > 0
380
+ raise "#{identifier} does not accept an argument" if
381
+ arity == 0
382
+ else
383
+ raise "#{identifier} requires an argument" unless
384
+ arity == 0 || arity == -1
385
+ end
386
+ end
387
+
388
+ protected
389
+ def parse_config_item(item)
390
+ case item
391
+ when Symbol
392
+ [:method, item, []]
393
+ when Hash
394
+ (method, arg) = item.to_a.first
395
+ if method.kind_of?(Symbol)
396
+ [:method, method, [arg].flatten]
397
+ else
398
+ [:element, method, arg]
399
+ end
400
+ end
401
+ end
402
+
403
+ protected
404
+ def validate_config_method(method)
405
+ allow_methods = %w(
406
+ rename attribute_name boolean integer long float list force
407
+ ignore collect_values symbol_value timestamp map_entry map
408
+ )
409
+ unless allow_methods.include?(method.to_s)
410
+ raise "#{method} cannot be used in configuration"
411
+ end
412
+ end
413
+
414
+ protected
415
+ def customizations
416
+ @customizations ||= CustomizationContext.new
417
+ end
418
+
419
+ protected
420
+ def customizations_for element_name
421
+ if @parent
422
+ @parent[:children][element_name] ||=
423
+ CustomizationContext.new(element_name)
424
+ else
425
+ customizations[:children][element_name] ||=
426
+ CustomizationContext.new(element_name)
427
+ end
428
+ end
429
+
430
+ protected
431
+ def customizations= customizations
432
+ @customizations = customizations
433
+ @current = customizations
434
+ end
435
+
436
+ end
437
+
438
+ # @private
439
+ class ValueFormatter
440
+
441
+ def extend_format_value &block
442
+ MetaUtils.extend_method(self, :format_value, &block)
443
+ end
444
+
445
+ def format_value value
446
+ value
447
+ end
448
+
449
+ end
450
+
451
+ # @private
452
+ class Parser
453
+
454
+ def initialize context, customizations
455
+ @context = context
456
+ @customizations = customizations
457
+ end
458
+
459
+ def start_element element_name, attrs
460
+
461
+ if @frame
462
+ @frame = @frame.build_child_frame(element_name)
463
+ else
464
+ @frame = RootFrame.new(@context, @customizations)
465
+ end
466
+
467
+ # consume attributes the same way we consume nested xml elements
468
+ attrs.each do |(attr_name, attr_value)|
469
+ attr_frame = @frame.build_child_frame(attr_name)
470
+ attr_frame.add_text(attr_value)
471
+ @frame.consume_child_frame(attr_frame)
472
+ end
473
+
474
+ end
475
+
476
+ def end_element name
477
+ @frame.close
478
+ if @frame.parent_frame
479
+ child_frame = @frame
480
+ parent_frame = @frame.parent_frame
481
+ parent_frame.consume_child_frame(child_frame)
482
+ end
483
+ @frame = @frame.parent_frame
484
+ end
485
+
486
+ def characters chars
487
+ @frame.add_text(chars) if @frame
488
+ end
489
+
490
+ end
491
+
492
+ module REXMLSaxParserAdapter
493
+
494
+ include REXML::StreamListener
495
+
496
+ def tag_start(name, attrs)
497
+ start_element(name, attrs)
498
+ end
499
+
500
+ def tag_end(name)
501
+ end_element(name)
502
+ end
503
+
504
+ def text(chars)
505
+ characters(chars)
506
+ end
507
+
508
+ end
509
+
510
+ module NokogiriAdapter
511
+
512
+ def xmldecl(*args); end
513
+ def start_document; end
514
+ def end_document; end
515
+ def start_element_namespace(name, attrs = [], prefix = nil, uri = nil, ns = [])
516
+ start_element(name, attrs.map { |att| [att.localname, att.value] })
517
+ end
518
+ def end_element_namespace(name, prefix = nil, uri = nil)
519
+ end_element(name)
520
+ end
521
+ def error(*args); end
522
+
523
+ end
524
+
525
+ # @private
526
+ class Frame
527
+
528
+ attr_reader :parent_frame
529
+
530
+ attr_reader :root_frame
531
+
532
+ attr_reader :element_name
533
+
534
+ attr_accessor :customizations
535
+
536
+ def initialize element_name, options = {}
537
+
538
+ @element_name = element_name
539
+ @context = options[:context]
540
+ @parent_frame = options[:parent_frame]
541
+ @root_frame = options[:root_frame]
542
+ @wrapper_frames = {}
543
+
544
+ if @parent_frame
545
+ @customizations = @parent_frame.customizations_for_child(element_name)
546
+ else
547
+ @customizations = options[:customizations]
548
+ @root_frame ||= self
549
+ end
550
+
551
+ if @root_frame == self and
552
+ indexes = @customizations[:index_names]
553
+ indexes.each do |name|
554
+ if context.kind_of?(Context)
555
+ context.__set_data__(name, {})
556
+ else
557
+ add_mutators(name)
558
+ context.send("#{name}=", {})
559
+ end
560
+ end
561
+ end
562
+
563
+ # we build and discard child frames here so we can know
564
+ # which children should always add a method to this
565
+ # frame's context (forced elements, like collected arrays)
566
+ @customizations[:children].keys.each do |child_element_name|
567
+ consume_initial_frame(build_child_frame(child_element_name))
568
+ end
569
+
570
+ if @customizations[:wrapper_frames]
571
+ @customizations[:wrapper_frames].keys.each do |method_name|
572
+ consume_initial_frame(wrapper_frame_for(method_name))
573
+ end
574
+ end
575
+
576
+ end
577
+
578
+ def build_child_frame(child_element_name)
579
+ Frame.new(child_element_name,
580
+ :parent_frame => self,
581
+ :root_frame => root_frame)
582
+ end
583
+
584
+ def consume_child_frame child_frame
585
+
586
+ return if child_frame.ignored?
587
+
588
+ if child_frame.wrapped?
589
+ child_frame.wrapper_methods.each do |method_name|
590
+ consume_in_wrapper(method_name, child_frame)
591
+ end
592
+ else
593
+ # forced child frames have already added mutators to this context
594
+ add_mutators_for(child_frame) unless child_frame.forced?
595
+
596
+ if child_frame.collected?
597
+ child_frame.add_to_collection(context.send(child_frame.getter),
598
+ child_frame.value)
599
+ else
600
+ invoke_setter(child_frame, child_frame.value)
601
+ end
602
+ end
603
+
604
+ end
605
+
606
+ def close
607
+ if indexed = @customizations[:indexed]
608
+ (name, block) = indexed
609
+ key = block.call(context)
610
+ [key].flatten.each do |k|
611
+ index(name)[k] = context
612
+ end
613
+ end
614
+ end
615
+
616
+ def add_text text
617
+ @text ||= ''
618
+ @text << text
619
+ end
620
+
621
+ def value
622
+ @customizations[:value_formatter] ?
623
+ @customizations[:value_formatter].format_value(default_value) :
624
+ default_value
625
+ end
626
+
627
+ def context
628
+ @context ||= (self.ignored? ? parent_frame.context : construct_context)
629
+ end
630
+
631
+ def setter
632
+ @customizations[:setter]
633
+ end
634
+
635
+ def getter
636
+ @customizations[:getter]
637
+ end
638
+
639
+ def initial_collection
640
+ @customizations[:initial_collection].call
641
+ end
642
+
643
+ def add_to_collection(collection, value)
644
+ @customizations[:add_to_collection].call(collection, value)
645
+ end
646
+
647
+ def index(name)
648
+ return root_frame.index(name) unless root_frame == self
649
+ context.send(name)
650
+ end
651
+
652
+ protected
653
+ def consume_initial_frame(child_frame)
654
+ if child_frame.forced?
655
+ add_mutators_for(child_frame)
656
+ if child_frame.collected?
657
+ invoke_setter(child_frame, child_frame.initial_collection)
658
+ else
659
+ # this allows nested forced elements to appear
660
+ invoke_setter(child_frame, child_frame.value)
661
+ end
662
+ end
663
+ end
664
+
665
+ protected
666
+ def construct_context
667
+ if @customizations[:construct_value]
668
+ instance_eval(&@customizations[:construct_value])
669
+ else
670
+ Context.new
671
+ end
672
+ end
673
+
674
+ protected
675
+ def consume_in_wrapper method_name, child_frame
676
+ wrapper_frame = wrapper_frame_for(method_name)
677
+ add_mutators(method_name)
678
+
679
+ # the wrapper consumes the unwrapped child
680
+ customizations = child_frame.customizations.merge(:wrapper => nil)
681
+ child_frame = child_frame.dup
682
+ child_frame.customizations = customizations
683
+
684
+ wrapper_frame.consume_child_frame(child_frame)
685
+ consume_child_frame(wrapper_frame)
686
+ end
687
+
688
+ protected
689
+ def wrapper_frame_for(method_name)
690
+ @wrapper_frames[method_name] ||=
691
+ Frame.new(method_name.to_s,
692
+ :customizations => wrapper_customizations(method_name))
693
+ end
694
+
695
+ protected
696
+ def wrapper_customizations(method_name)
697
+ customizations = CustomizationContext.new(method_name)
698
+ customizations[:children] = @customizations[:children]
699
+ if wrapper_frames = @customizations[:wrapper_frames] and
700
+ additional = wrapper_frames[method_name]
701
+ additional[:children] = @customizations[:children].merge(additional[:children]) if
702
+ additional[:children]
703
+ customizations.merge!(additional)
704
+ end
705
+ customizations
706
+ end
707
+
708
+ protected
709
+ def invoke_setter(child_frame, value)
710
+ if context.kind_of?(Context)
711
+ context.__set_data__(child_frame.getter, value)
712
+ else
713
+ context.send(child_frame.setter, value)
714
+ end
715
+ end
716
+
717
+ protected
718
+ def add_mutators_for child_frame
719
+ return if context.kind_of?(Context)
720
+ add_mutators(child_frame.ruby_name,
721
+ child_frame.setter,
722
+ child_frame.getter)
723
+ end
724
+
725
+ protected
726
+ def add_mutators(variable_name,
727
+ setter = nil,
728
+ getter = nil)
729
+ return if context.kind_of?(Context)
730
+ variable_name = variable_name.to_s.gsub(/\?$/, '')
731
+ setter ||= "#{variable_name}="
732
+ getter ||= variable_name
733
+ return if context.respond_to?(getter) && context.respond_to?(setter)
734
+ MetaUtils.extend_method(context, setter) do |val|
735
+ instance_variable_set("@#{variable_name}", val)
736
+ end
737
+ MetaUtils.extend_method(context, getter) do
738
+ instance_variable_get("@#{variable_name}")
739
+ end
740
+ end
741
+
742
+ protected
743
+ def forced?
744
+ @customizations[:forced]
745
+ end
746
+
747
+ protected
748
+ def ignored?
749
+ @customizations[:ignored]
750
+ end
751
+
752
+ protected
753
+ def collected?
754
+ @customizations[:collected]
755
+ end
756
+
757
+ protected
758
+ def wrapped?
759
+ @customizations[:wrapper]
760
+ end
761
+
762
+ protected
763
+ def wrapper_methods
764
+ @customizations[:wrapper]
765
+ end
766
+
767
+ protected
768
+ def default_value
769
+ if
770
+ # TODO : move this out of the default value method
771
+ @context and
772
+ @context.respond_to?(:encoding) and
773
+ @context.encoding == 'base64'
774
+ then
775
+ Base64.decode64(@text.strip)
776
+ else
777
+ @context || @text
778
+ end
779
+ end
780
+
781
+ protected
782
+ def ruby_name
783
+ Inflection.ruby_name(@customizations[:renamed] || element_name)
784
+ end
785
+
786
+ protected
787
+ def customizations_for_child child_element_name
788
+ @customizations[:children][child_element_name] ||
789
+ CustomizationContext.new(child_element_name)
790
+ end
791
+
792
+ protected
793
+ def initial_customizations(element_name = nil)
794
+ end
795
+
796
+ end
797
+
798
+ # @private
799
+ class RootFrame < Frame
800
+
801
+ def initialize context, customizations
802
+ super('ROOT', :context => context, :customizations => customizations)
803
+ end
804
+
805
+ end
806
+
807
+ # @private
808
+ class StubResponse
809
+
810
+ def initialize customizations, context = nil
811
+ @customizations = customizations
812
+ stub_methods(customizations, context || self)
813
+ end
814
+
815
+ def inspect
816
+ methods = public_methods - Object.public_methods
817
+ "<Stub #{methods.collect{|m| ":#{m}" }.sort.join(', ')}>"
818
+ end
819
+
820
+ # @private
821
+ private
822
+ def stub_methods customizations, context
823
+ add_wrappers_to_context(customizations, context)
824
+ add_child_elements_to_context(customizations, context)
825
+ add_indexes_to_context(customizations, context)
826
+ end
827
+
828
+ # @private
829
+ private
830
+ def add_wrappers_to_context customizations, context
831
+ wrappers(customizations) do |wrapper_name,wrapper_customizations|
832
+ MetaUtils.extend_method(context, wrapper_name) do
833
+ StubResponse.new(wrapper_customizations)
834
+ end
835
+ end
836
+ end
837
+
838
+ # @private
839
+ private
840
+ def add_child_elements_to_context customizations, context
841
+ without_wrapper(customizations) do |child_name,child_rules|
842
+
843
+ ruby_name = Inflection.ruby_name(child_rules[:renamed] || child_name)
844
+
845
+ # we stop at any collected elements
846
+ if child_rules[:collected]
847
+ MetaUtils.extend_method(context, ruby_name) { [] }
848
+ next
849
+ end
850
+
851
+ if child_rules[:construct_value]
852
+
853
+ MetaUtils.extend_method(context, ruby_name) do
854
+ child_rules[:construct_value].call
855
+ end
856
+
857
+ elsif child_rules[:children].empty? # has no child elements
858
+
859
+ unless child_rules[:ignored]
860
+
861
+ method_name = child_rules[:boolean] ? "#{ruby_name}?" : ruby_name
862
+
863
+ MetaUtils.extend_method(context, method_name) do
864
+ if child_rules[:value_formatter]
865
+ child_rules[:value_formatter].format_value('')
866
+ else
867
+ nil
868
+ end
869
+ end
870
+ end
871
+
872
+ else # it has one or more child elements
873
+
874
+ if child_rules[:ignored]
875
+ stub_methods(child_rules, context)
876
+ else
877
+ MetaUtils.extend_method(context, ruby_name) do
878
+ StubResponse.new(child_rules)
879
+ end
880
+ end
881
+
882
+ end
883
+
884
+ end
885
+ end
886
+
887
+ # @private
888
+ def add_indexes_to_context(customizations, context)
889
+ if indexes = customizations[:index_names]
890
+ indexes.each do |index|
891
+ MetaUtils.extend_method(context, index) { {} }
892
+ end
893
+ end
894
+ end
895
+
896
+ # @private
897
+ def wrappers customizations, &block
898
+ wrappers = {}
899
+ customizations[:children].each_pair do |child_name,child_rules|
900
+ if child_rules[:wrapper]
901
+ wrapper_name = child_rules[:wrapper].first
902
+ wrappers[wrapper_name] ||= { :children => {} }
903
+ wrappers[wrapper_name][:children][child_name] = child_rules.merge(:wrapper => nil)
904
+ end
905
+ end
906
+
907
+ wrappers.each_pair do |wrapper_name, wrapper_customizations|
908
+ yield(wrapper_name, wrapper_customizations)
909
+ end
910
+ end
911
+
912
+ # @private
913
+ private
914
+ def without_wrapper customizations, &block
915
+ customizations[:children].each_pair do |child_name,child_rules|
916
+ unless child_rules[:wrapper]
917
+ yield(child_name, child_rules)
918
+ end
919
+ end
920
+ end
921
+
922
+ end
923
+
924
+ end
925
+ end
926
+ end