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,245 @@
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 'base64'
14
+ require 'date'
15
+ require 'time'
16
+
17
+ module MSS
18
+ module Core
19
+ module XML
20
+ class Frame
21
+
22
+ TRANSLATE_DIGITS = ['0123456789'.freeze, ('X'*10).freeze]
23
+
24
+ EASY_FORMAT = "XXXX-XX-XXTXX:XX:XX.XXXZ".freeze
25
+
26
+ DATE_PUNCTUATION = ['-:.TZ'.freeze, (' '*5).freeze]
27
+
28
+ def initialize root_frame, parent_frame, element_name, rules
29
+
30
+ @root_frame = root_frame
31
+ @parent_frame = parent_frame
32
+ @element_name = element_name
33
+ @rules = rules
34
+ @rules[:children] ||= {}
35
+
36
+ @data = {}.merge(rules[:defaults] || {})
37
+ @text = nil
38
+
39
+ # initialize values for child frames of special types (e.g.
40
+ # lists, maps, and forced elements)
41
+ known_child_frames.each do |child_frame|
42
+ context = data_context_for(child_frame)
43
+ if child_frame.list?
44
+ context[child_frame.ruby_name] = []
45
+ elsif child_frame.map?
46
+ context[child_frame.ruby_name] = {}
47
+ elsif child_frame.forced?
48
+ context[child_frame.ruby_name] = child_frame.value
49
+ end
50
+ end
51
+
52
+ end
53
+
54
+ attr_reader :root_frame
55
+ attr_reader :parent_frame
56
+ attr_reader :element_name
57
+ attr_reader :rules
58
+
59
+ def data
60
+ ignored? ? parent_frame.data : @data
61
+ end
62
+
63
+ def ruby_name
64
+ rules[:rename] || root_frame.inflect(element_name)
65
+ end
66
+
67
+ def rules_for child_element_name
68
+ rules[:children][child_element_name] || {}
69
+ end
70
+
71
+ # The list of child frames that have customizations (rules), all
72
+ # other children will be parsed using standard rules
73
+ def known_child_frames
74
+ rules[:children].keys.map {|name| build_child_frame(name) }
75
+ end
76
+
77
+ def build_child_frame element_name
78
+ # if element_name should be wrapped
79
+ # build a frame for the wrapper
80
+ # build a child frame from the wrapper
81
+ # else
82
+ Frame.new(root_frame, self, element_name, rules_for(element_name))
83
+ end
84
+
85
+ def consume_child_frame child_frame
86
+
87
+ child_frame.close
88
+
89
+ return if child_frame.ignored?
90
+
91
+ ruby_name = child_frame.ruby_name
92
+ value = child_frame.value
93
+ context = data_context_for(child_frame)
94
+
95
+ if child_frame.list?
96
+ context[ruby_name] << value
97
+ elsif map = child_frame.map?
98
+ context[ruby_name][child_frame.map_key] = child_frame.map_value
99
+ else
100
+ context[ruby_name] = value
101
+ end
102
+ end
103
+
104
+ def close
105
+ # some xml elements should be indexed at the root level
106
+ # The :index rule determines the name of this index
107
+ # and what keys the data should be indexed as (one element
108
+ # can be indexed under multiple keys). The index value
109
+ # is always the element itself.
110
+ if index = @rules[:index]
111
+ index_keys_for(index) do |key|
112
+ root_frame.add_to_index(index[:name], key, data)
113
+ end
114
+ end
115
+ end
116
+
117
+ def index_keys_for index_opts, &block
118
+
119
+ # simple (single) key
120
+ if key = index_opts[:key]
121
+ yield(data[key])
122
+ return
123
+ end
124
+
125
+ # composite key, joined by ":"
126
+ if parts = index_opts[:keys]
127
+ composite_key = parts.map{|part| data[part] }.join(":")
128
+ yield(composite_key)
129
+ return
130
+ end
131
+
132
+ # multiple keys, collected from the given path
133
+ if path = index_opts[:key_path]
134
+ keys_from_path(data, path.dup, &block)
135
+ return
136
+ end
137
+
138
+ raise "missing require index rule option, :key, :keys or :key_path"
139
+
140
+ end
141
+
142
+ def keys_from_path data, path, &block
143
+
144
+ step = path.shift
145
+ value = data[step]
146
+
147
+ if path.empty?
148
+ yield(value)
149
+ return
150
+ end
151
+
152
+ if value.is_a?(Array)
153
+ value.each do |v|
154
+ keys_from_path(v, path.dup, &block)
155
+ end
156
+ else
157
+ keys_from_path(value, path.dup, &block)
158
+ end
159
+
160
+ end
161
+
162
+ def add_text chars
163
+ @text ||= ''
164
+ @text << chars
165
+ end
166
+
167
+ def value
168
+ if !data.empty?
169
+ data[:encoding] == 'base64' ? Base64.decode64(@text.strip) : data
170
+ elsif @text.nil?
171
+ rules[:type] == :boolean ? false : nil
172
+ else
173
+ case rules[:type]
174
+ when nil, :string then @text
175
+ when :datetime then datetime_like_value(DateTime, :civil)
176
+ when :time then datetime_like_value(Time, :utc)
177
+ when :integer then @text.to_i
178
+ when :float then @text.to_f
179
+ when :boolean then @text == 'true'
180
+ when :blob then Base64.decode64(@text)
181
+ when :symbol then Core::Inflection.ruby_name(@text).to_sym
182
+ else raise "unhandled type"
183
+ end
184
+ end
185
+ end
186
+
187
+ def ignored?
188
+ @rules[:ignore]
189
+ end
190
+
191
+ def forced?
192
+ @rules[:force]
193
+ end
194
+
195
+ def list?
196
+ @rules[:list]
197
+ end
198
+
199
+ def map?
200
+ @rules[:map]
201
+ end
202
+
203
+ def wrapped?
204
+ @rules[:wrap]
205
+ end
206
+ alias_method :wrapper, :wrapped?
207
+
208
+ protected
209
+
210
+ def map_key
211
+ data[root_frame.inflect(@rules[:map].first)]
212
+ end
213
+
214
+ def map_value
215
+ data[root_frame.inflect(@rules[:map].last)]
216
+ end
217
+
218
+ def data_context_for child_frame
219
+ if child_frame.wrapped?
220
+ data[child_frame.wrapper] ||= {}
221
+ data[child_frame.wrapper]
222
+ else
223
+ data
224
+ end
225
+ end
226
+
227
+ def datetime_like_value klass, parts_constructor
228
+ # it's way faster to parse this specific format manually
229
+ # vs. DateTime#parse, and this happens to be the format
230
+ # that MSS uses almost (??) everywhere.
231
+ if @text.tr(*TRANSLATE_DIGITS) == EASY_FORMAT
232
+ parts = @text.tr(*DATE_PUNCTUATION).chop.split.map {|p| p.to_i }
233
+ milliseconds = parts.pop
234
+ parts[-1] = parts[-1] + Rational(milliseconds, 1000) #Ruby 1.8.7 compatibility
235
+ klass.send(parts_constructor, *parts)
236
+ else
237
+ # fallback in case we have to handle another date format
238
+ klass.parse(@text)
239
+ end
240
+ end
241
+
242
+ end
243
+ end
244
+ end
245
+ end
@@ -0,0 +1,84 @@
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
+ module MSS
14
+ module Core
15
+ module XML
16
+
17
+ # @api private
18
+ module FrameStack
19
+
20
+ # @param [Hash] rules A hash of parser rules. These
21
+ # rules are typically generated by an {XML::Grammar}.
22
+ def initialize rules
23
+ @frame = RootFrame.new(rules)
24
+ end
25
+
26
+ def sax_parse xml
27
+ raise NotImplementedError
28
+ end
29
+ protected :sax_parse
30
+
31
+ # Parses the xml string and returns a hash with the resutls.
32
+ # @param [String] xml
33
+ # @return [Hash]
34
+ def parse xml
35
+ sax_parse(xml)
36
+ @frame.value
37
+ end
38
+
39
+ # Increase the frame stack level by one.
40
+ # @param [String] element_name The name of the xml opening tag.
41
+ # @param [Hash] attributes A hash of xml element attributes.
42
+ # @return [nil]
43
+ def start_element element_name, attributes = {}
44
+ @frame = @frame.build_child_frame(element_name)
45
+ self.attributes(attributes)
46
+ nil
47
+ end
48
+
49
+ # Increase the frame stack level by one by treating
50
+ # xml element attributes as nested elements.
51
+ # @param [Hash] attributes A hash of attributes names to values.
52
+ # @return [nil]
53
+ def attributes attributes
54
+ attributes.each_pair do |attr_name, attr_value|
55
+ attr_frame = @frame.build_child_frame(attr_name)
56
+ attr_frame.add_text(attr_value)
57
+ @frame.consume_child_frame(attr_frame)
58
+ end
59
+ nil
60
+ end
61
+
62
+ # Pops the top frame off the stack. When closing frames
63
+ # their final value is computed.
64
+ # @overload end_element
65
+ # @return [nil]
66
+ def end_element *ignored
67
+ parent = @frame.parent_frame
68
+ child = @frame
69
+ parent.consume_child_frame(child)
70
+ @frame = @frame.parent_frame
71
+ nil
72
+ end
73
+
74
+ # Adds text to the current frame. Frames that only contain
75
+ # text and no child elements are leaf nodes and have
76
+ # raw string values.
77
+ def set_text text
78
+ @frame.add_text(text) if @frame
79
+ end
80
+
81
+ end
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,306 @@
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
+ module MSS
14
+ module Core
15
+ module XML
16
+
17
+ # A class that simplifies building XML {Parser} rules. This is also
18
+ # a compatability layer between the old and new formats of the api
19
+ # config.
20
+ class Grammar
21
+
22
+ def initialize rules = {}, options = {}
23
+ @rules = rules
24
+ @context = @rules
25
+ @element_name = 'xml'
26
+ @inflect_rename = options.key?(:inflect_rename) ?
27
+ options[:inflect_rename] : true
28
+ end
29
+
30
+ # Parses the XML with the rules provided by the current grammar.
31
+ # This method is meant to provide backwards compatability with
32
+ # the old XmlGrammar class that handled rules and parsing.
33
+ # @param [String] xml
34
+ # @return [Data] Returns a hash-like parsed response.
35
+ def parse xml
36
+ Data.new(Parser.parse(xml, rules))
37
+ end
38
+
39
+ # @return [Hash] Returns a hash of rules defined by this grammar.
40
+ attr_reader :rules
41
+
42
+ # Returns a new grammar (leaving the current one un-modified) with
43
+ # the given customizations applied. Customizations can be given in
44
+ # a hash-form or in a block form.
45
+ #
46
+ # @example Block-form customizations
47
+ #
48
+ # grammar.customize do
49
+ # element "EnumElement" do
50
+ # symbol_value
51
+ # list
52
+ # end
53
+ # end
54
+ #
55
+ # @example Hash-form customizations
56
+ #
57
+ # grammar.customize "EnumElement" => [:symbol_value, :list]
58
+ #
59
+ # @return [Grammar] Returns a grammar with the given customizations
60
+ # applied.
61
+ #
62
+ def customize customizations = nil, &block
63
+ opts = { :inflect_rename => @inflect_rename }
64
+ self.class.customize(customizations, @rules, opts, &block)
65
+ end
66
+
67
+ # Applies customizations to the current grammar, not returning
68
+ # a new grammar.
69
+ def customize! customizations = nil, &block
70
+ apply_customizations(customizations) if customizations
71
+ instance_eval(&block) if block_given?
72
+ self
73
+ end
74
+
75
+ def self.customize customizations = nil, rules = {}, opts = {}, &block
76
+ grammar = self.new(deep_copy(rules), opts)
77
+ grammar.send(:apply_customizations, customizations) if customizations
78
+ grammar.instance_eval(&block) if block_given?
79
+ grammar
80
+ end
81
+
82
+ def self.parse xml
83
+ self.new.parse(xml)
84
+ end
85
+
86
+ protected
87
+
88
+ # Performs a deep copy of the rules hash so that it can be
89
+ # customized without chaning the parent grammar.
90
+ def self.deep_copy rules
91
+ rules.inject({}) do |copy,(key,value)|
92
+ copy[key] = value.is_a?(Hash) ? deep_copy(value) : value
93
+ copy
94
+ end
95
+ end
96
+
97
+ def apply_customizations customizations
98
+ customizations.each do |item|
99
+ (type, identifier, args) = parse_customization_item(item)
100
+ case type
101
+ when :method
102
+ validate_config_method(identifier)
103
+ validate_args(identifier, args)
104
+ send(identifier, *args)
105
+ when :element
106
+ element(identifier) do
107
+ apply_customizations(args)
108
+ end
109
+ end
110
+ end
111
+ end
112
+
113
+ def parse_customization_item item
114
+ case item
115
+ when Symbol
116
+ [:method, item, []]
117
+ when Hash
118
+ (method, arg) = item.to_a.first
119
+ if method.kind_of?(Symbol)
120
+ [:method, method, [arg].flatten]
121
+ else
122
+ [:element, method, arg]
123
+ end
124
+ end
125
+ end
126
+
127
+ def validate_config_method(method)
128
+ allow_methods = %w(
129
+ rename attribute_name boolean integer long float list force string
130
+ ignore collect_values symbol_value timestamp map_entry map blob
131
+ enum position
132
+ )
133
+ unless allow_methods.include?(method.to_s)
134
+ raise "#{method} cannot be used in configuration"
135
+ end
136
+ end
137
+
138
+ def validate_args(identifier, args)
139
+ arity = method(identifier).arity
140
+ if args.length > 0
141
+ raise "#{identifier} does not accept an argument" if
142
+ arity == 0
143
+ else
144
+ raise "#{identifier} requires an argument" unless
145
+ arity == 0 || arity == -1
146
+ end
147
+ end
148
+
149
+ def inflect value
150
+ Inflection.ruby_name(value.to_s).to_sym
151
+ end
152
+
153
+ # customization methods
154
+
155
+ def element element_name, &block
156
+
157
+ parent_context = @context
158
+ parent_element_name = @element_name
159
+
160
+ @context = context_for_child(element_name)
161
+
162
+ @element_name = element_name
163
+
164
+ begin
165
+ if block_given?
166
+ block.arity == 1 ? yield(parent_element_name) : yield
167
+ end
168
+ ensure
169
+ @context = parent_context
170
+ @element_name = parent_element_name
171
+ end
172
+
173
+ end
174
+
175
+ def ignore
176
+ @context[:ignore] = true
177
+ end
178
+
179
+ def rename new_name
180
+ if @inflect_rename
181
+ @context[:rename] = inflect(new_name)
182
+ else
183
+ @context[:rename] = new_name
184
+ end
185
+ end
186
+
187
+ def force
188
+ @context[:force] = true
189
+ end
190
+
191
+ def collect_values
192
+ @context[:list] = true
193
+ end
194
+
195
+ def index index_name, options = {}
196
+ @context[:index] = options.merge(:name => index_name)
197
+ end
198
+
199
+ def default_value name, value
200
+ @context[:defaults] ||= {}
201
+ @context[:defaults][name] = value
202
+ end
203
+
204
+ def list child_element_name = nil, &block
205
+ if child_element_name
206
+ ignore
207
+ element(child_element_name) do |parent_element_name|
208
+ rename(parent_element_name)
209
+ collect_values
210
+ yield if block_given?
211
+ end
212
+ else
213
+ collect_values
214
+ end
215
+ end
216
+
217
+ def map_entry key_element_name, value_element_name
218
+ @context[:map] = [key_element_name, value_element_name]
219
+ end
220
+
221
+ def map map_element_name, key_element_name, value_element_name
222
+ ignore
223
+ element(map_element_name) do |parent_element_name|
224
+ rename(parent_element_name)
225
+ map_entry(key_element_name, value_element_name)
226
+ end
227
+ end
228
+
229
+ def wrapper method_name, options = {}, &block
230
+ options[:for].each do |child|
231
+ context_for_child(child)[:wrap] = method_name
232
+ end
233
+ end
234
+
235
+ def construct_value &block
236
+ raise 'remove the need for this'
237
+ end
238
+
239
+ def boolean_value
240
+ @context[:type] = :boolean
241
+ end
242
+ alias_method :boolean, :boolean_value
243
+
244
+ def blob_value
245
+ @context[:type] = :blob
246
+ end
247
+ alias_method :blob, :blob_value
248
+
249
+ def datetime_value
250
+ @context[:type] = :datetime
251
+ end
252
+ alias_method :datetime, :datetime_value
253
+
254
+ def time_value
255
+ @context[:type] = :time
256
+ end
257
+ alias_method :timestamp, :time_value
258
+ alias_method :time, :time_value
259
+
260
+ def string_value
261
+ @context[:type] = :string
262
+ end
263
+ alias_method :string, :string_value
264
+
265
+ def integer_value
266
+ @context[:type] = :integer
267
+ end
268
+ alias_method :integer, :integer_value
269
+ alias_method :long, :integer_value
270
+
271
+ def float_value
272
+ @context[:type] = :float
273
+ end
274
+ alias_method :float, :float_value
275
+
276
+ def symbol_value
277
+ @context[:type] = :symbol
278
+ end
279
+ alias_method :symbol, :symbol_value
280
+
281
+ def eql? other
282
+ other.is_a?(Grammar) and self.rules == other.rules
283
+ end
284
+ alias_method :==, :eql?
285
+ public :==
286
+
287
+ def enum *args; end
288
+ def position *args; end
289
+ def http_trait *args; end
290
+ alias_method :http_header, :http_trait
291
+ alias_method :http_uri_label, :http_trait
292
+ alias_method :http_payload, :http_trait
293
+ alias_method :http_status, :http_trait
294
+
295
+
296
+ protected
297
+ def context_for_child child_element_name
298
+ @context[:children] ||= {}
299
+ @context[:children][child_element_name] ||= {}
300
+ @context[:children][child_element_name]
301
+ end
302
+
303
+ end
304
+ end
305
+ end
306
+ end
@@ -0,0 +1,69 @@
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
+ module MSS
14
+ module Core
15
+ module XML
16
+ class Parser
17
+
18
+ # @param [Hash] rules A has of xml parsing rules. Generally
19
+ # rules will come from an xml grammar.
20
+ def initialize rules = {}
21
+ @rules = rules
22
+ end
23
+
24
+ # @return [Hash] Returns the rules for this xml parser that define
25
+ # how it should transform the XMl into Ruby.
26
+ attr_reader :rules
27
+
28
+ # @param [String] xml An XML document string to parse.
29
+ # @return [Hash] Returns a hash of parsed xml data.
30
+ def parse xml
31
+ xml = '<xml/>' if xml.nil? or xml.empty?
32
+ sax_handler.parse(xml)
33
+ end
34
+
35
+ # @return [Hash] Returns a hash of mostly empty placeholder data.
36
+ def simulate
37
+ XML::Stub.simulate(rules)
38
+ end
39
+
40
+ # @param [String] xml An XML document string to parse.
41
+ # @param [Hash] rules A has of xml parsing rules. Generally
42
+ # rules will come from an xml grammar.
43
+ # @return [Hash] Returns a hash of parsed xml data.
44
+ def self.parse xml, rules = {}
45
+ self.new(rules).parse(xml)
46
+ end
47
+
48
+ protected
49
+
50
+ # There are three handlers, nokogiri is the fastest, followed
51
+ # by libxml-ruby. Lastly (by a long shot) is REXML. REXML
52
+ # is the only library that does not rely on a native
53
+ # extension.
54
+ #
55
+ # Currently you can not choose your xml sax handler, and the only
56
+ # we express a gem dependency on is nokogiri.
57
+ #
58
+ def sax_handler
59
+ begin
60
+ SaxHandlers::Nokogiri.new(rules)
61
+ rescue NameError, LoadError
62
+ SaxHandlers::REXML.new(rules)
63
+ end
64
+ end
65
+
66
+ end
67
+ end
68
+ end
69
+ end