aws-sdk-resources 2.0.0.pre

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 (31) hide show
  1. checksums.yaml +7 -0
  2. data/lib/aws-sdk-resources.rb +36 -0
  3. data/lib/aws-sdk-resources/batch.rb +100 -0
  4. data/lib/aws-sdk-resources/builder.rb +86 -0
  5. data/lib/aws-sdk-resources/builder_sources.rb +136 -0
  6. data/lib/aws-sdk-resources/collection.rb +137 -0
  7. data/lib/aws-sdk-resources/definition.rb +363 -0
  8. data/lib/aws-sdk-resources/documenter.rb +18 -0
  9. data/lib/aws-sdk-resources/documenter/base_operation_documenter.rb +269 -0
  10. data/lib/aws-sdk-resources/documenter/data_operation_documenter.rb +47 -0
  11. data/lib/aws-sdk-resources/documenter/enumerate_data_operation_documenter.rb +50 -0
  12. data/lib/aws-sdk-resources/documenter/enumerate_resource_operation_documenter.rb +69 -0
  13. data/lib/aws-sdk-resources/documenter/operation_documenter.rb +43 -0
  14. data/lib/aws-sdk-resources/documenter/reference_operation_documenter.rb +102 -0
  15. data/lib/aws-sdk-resources/documenter/resource_operation_documenter.rb +65 -0
  16. data/lib/aws-sdk-resources/documenter/waiter_operation_documenter.rb +81 -0
  17. data/lib/aws-sdk-resources/errors.rb +15 -0
  18. data/lib/aws-sdk-resources/operation_methods.rb +53 -0
  19. data/lib/aws-sdk-resources/operations.rb +294 -0
  20. data/lib/aws-sdk-resources/options.rb +23 -0
  21. data/lib/aws-sdk-resources/request.rb +39 -0
  22. data/lib/aws-sdk-resources/request_params.rb +225 -0
  23. data/lib/aws-sdk-resources/resource.rb +137 -0
  24. data/lib/aws-sdk-resources/source.rb +39 -0
  25. data/lib/aws-sdk-resources/validator.rb +152 -0
  26. data/lib/aws-sdk-resources/validator/context.rb +60 -0
  27. data/lib/aws-sdk-resources/validator/identifier_validator.rb +107 -0
  28. data/lib/aws-sdk-resources/validator/operation_validator.rb +352 -0
  29. data/lib/aws-sdk-resources/validator/rule.rb +45 -0
  30. data/lib/aws-sdk-resources/validator/shape_validator.rb +47 -0
  31. metadata +87 -0
@@ -0,0 +1,363 @@
1
+ require 'set'
2
+
3
+ module Aws
4
+ module Resources
5
+
6
+ # Given a resource definition document, a {Definition} can build a set
7
+ # of related resource classes.
8
+ class Definition
9
+
10
+ # @param [Hash] definition
11
+ # @option options [String] :source_path
12
+ def initialize(definition = {}, options = {})
13
+ @source = definition
14
+ @source_path = options[:source_path]
15
+ end
16
+
17
+ # @param [Module<Service>] namespace
18
+ # @return [void]
19
+ def apply(namespace)
20
+ build_resource_classes(namespace)
21
+ each_resource_class(namespace) do |resource, definition|
22
+ define_load(namespace, resource, definition['load'])
23
+ define_actions(namespace, resource, definition['actions'] || {})
24
+ define_batch_actions(namespace, resource, definition['batchActions'] || {})
25
+ define_waiters(namespace, resource, definition['waiters'] || {})
26
+ define_has_many(namespace, resource, definition['hasMany'] || {})
27
+ define_has_some(namespace, resource, definition['hasSome'] || {})
28
+ define_has_one(namespace, resource, definition['hasOne'] || {})
29
+ define_data_attributes(namespace, resource, definition['shape'])
30
+ define_subresources(namespace, resource, definition['subResources'] || {})
31
+ end
32
+ define_top_level_references(namespace)
33
+ end
34
+
35
+ private
36
+
37
+ def build_resource_classes(namespace)
38
+ each_definition do |name, definition|
39
+ resource_class = Class.new(Resource)
40
+ resource_class.client_class = namespace::Client
41
+ resource_class.resource_name = name
42
+ (definition['identifiers'] || []).each do |identifier|
43
+ resource_class.add_identifier(underscore(identifier['name']))
44
+ end
45
+ namespace.const_set(name, resource_class)
46
+ unless name == 'Resource'
47
+ resource_class.const_set(:Batch, Class.new(Batch))
48
+ end
49
+ end
50
+ end
51
+
52
+ def each_resource_class(namespace, &block)
53
+ each_definition do |name, definition|
54
+ yield(namespace.const_get(name), definition)
55
+ end
56
+ end
57
+
58
+ def define_subresources(namespace, parent, definition)
59
+ parent_name = parent.resource_name
60
+ identifiers = definition['identifiers'] || {}
61
+ (definition['resources'] || []).each do |child_name|
62
+
63
+ method_name = underscore(child_name.sub(/^#{parent_name}/, ''))
64
+ operation = subresource(namespace, child_name, identifiers)
65
+ parent.add_operation(method_name, operation)
66
+
67
+ method_name = underscore(parent_name)
68
+ operation = subresource(namespace, parent_name, identifiers.invert)
69
+ namespace.const_get(child_name).add_operation(method_name, operation)
70
+
71
+ end
72
+ end
73
+
74
+ def subresource(namespace, type, identifiers)
75
+ Operations::ReferenceOperation.new(builder: define_builder(namespace, {
76
+ 'type' => type,
77
+ 'identifiers' => identifiers.map { |source, target|
78
+ {
79
+ 'target' => target,
80
+ 'sourceType' => 'identifier',
81
+ 'source' => source,
82
+ }
83
+ }
84
+ }))
85
+ end
86
+
87
+ def define_top_level_references(namespace)
88
+ top_level = Set.new(resource_definitions.keys)
89
+ each_resource_class(namespace) do |resource, definition|
90
+ unless resource.identifiers.count == 1
91
+ top_level.delete(resource.resource_name)
92
+ end
93
+ ((definition['subResources'] || {})['resources'] || {}).each do |child|
94
+ top_level.delete(child)
95
+ end
96
+ end
97
+ top_level.each do |resource_name|
98
+ method_name = underscore(resource_name)
99
+ operation = subresource(namespace, resource_name, {})
100
+ namespace::Resource.add_operation(method_name, operation)
101
+ end
102
+ end
103
+
104
+ def define_batch_actions(namespace, resource, batch_actions)
105
+ batch_actions.each do |name, definition|
106
+ method_name = underscore(name)
107
+ operation = build_operation(namespace, resource, definition)
108
+ resource::Batch.add_operation(method_name, operation)
109
+ end
110
+ end
111
+
112
+ def define_data_attributes(namespace, resource, shape_name)
113
+ return unless shape_name
114
+ shape = resource.client_class.api.shape_map.shape('shape' => shape_name)
115
+ shape.member_names.each do |member_name|
116
+ if
117
+ resource.identifiers.include?(member_name) ||
118
+ resource.instance_methods.include?(member_name)
119
+ then
120
+ next # some data attributes are duplicates to identifiers
121
+ else
122
+ resource.add_data_attribute(member_name)
123
+ end
124
+ end
125
+ end
126
+
127
+ def define_load(namespace, resource, definition)
128
+ return unless definition
129
+ resource.load_operation = Operations::DataOperation.new(
130
+ request: define_request(definition['request']),
131
+ path: underscore(definition['path']),
132
+ source: source(definition),
133
+ )
134
+ end
135
+
136
+ def define_actions(namespace, resource, actions)
137
+ actions.each do |name, action|
138
+ operation = build_operation(namespace, resource, action)
139
+ resource.add_operation(underscore(name), operation)
140
+ end
141
+ end
142
+
143
+ def define_waiters(namespace, resource, waiters)
144
+ waiters.each do |name, definition|
145
+ operation = build_waiter_operation(namespace, resource, definition)
146
+ resource.add_operation("wait_until_#{underscore(name)}", operation)
147
+ end
148
+ end
149
+
150
+ def build_operation(namespace, resource, definition)
151
+ type = operation_type(definition)
152
+ send("build_#{type}_operation", namespace, resource, definition)
153
+ end
154
+
155
+ def build_basic_operation(namespace, resource, definition)
156
+ Operations::Operation.new(
157
+ request: define_request(definition['request']),
158
+ source: source(definition)
159
+ )
160
+ end
161
+
162
+ def build_data_operation(namespace, resource, definition)
163
+ plural = definition['path'].include?('[')
164
+ source = source(definition)
165
+ if plural
166
+ Operations::EnumerateDataOperation.new(
167
+ request: define_request(definition['request']),
168
+ path: underscore(definition['path']),
169
+ source: source,
170
+ limit_key: limit_key(resource, definition)
171
+ )
172
+ else
173
+ Operations::DataOperation.new(
174
+ request: define_request(definition['request']),
175
+ path: underscore(definition['path']),
176
+ source: source
177
+ )
178
+ end
179
+ end
180
+
181
+ def build_resource_operation(namespace, resource, definition)
182
+ builder = define_builder(namespace, definition['resource'])
183
+ if path = definition['path']
184
+ source = underscore(path)
185
+ builder.sources << BuilderSources::ResponsePath.new(source, :data)
186
+ end
187
+ Operations::ResourceOperation.new(
188
+ request: define_request(definition['request']),
189
+ builder: builder,
190
+ source: source(definition)
191
+ )
192
+ end
193
+
194
+ def build_enumerate_resource_operation(namespace, resource, definition)
195
+ builder = define_builder(namespace, definition['resource'])
196
+ if path = definition['path']
197
+ source = underscore(path)
198
+ builder.sources << BuilderSources::ResponsePath.new(source, :data)
199
+ end
200
+ Operations::EnumerateResourceOperation.new(
201
+ request: define_request(definition['request']),
202
+ builder: builder,
203
+ source: source(definition),
204
+ limit_key: limit_key(resource, definition))
205
+ end
206
+
207
+ def build_waiter_operation(namespace, resource, definition)
208
+ Operations::WaiterOperation.new(
209
+ waiter_name: underscore(definition['waiterName']).to_sym,
210
+ waiter_params: request_params(definition['params']),
211
+ path: underscore(definition['path'])
212
+ )
213
+ end
214
+
215
+ def limit_key(resource, definition)
216
+ operation_name = definition['request']['operation']
217
+ paginators = resource.client_class.paginators
218
+ paginators.pager(operation_name).limit_key
219
+ end
220
+
221
+ def define_request(definition)
222
+ Request.new(
223
+ method_name: underscore(definition['operation']),
224
+ params: request_params(definition['params'] || [])
225
+ )
226
+ end
227
+
228
+ def request_params(params)
229
+ params.map do |definition|
230
+ param_class =
231
+ case definition['sourceType']
232
+ when 'identifier' then RequestParams::Identifier
233
+ when 'dataMember' then RequestParams::DataMember
234
+ when 'string' then RequestParams::String
235
+ when 'integer' then RequestParams::Integer
236
+ when 'boolean' then RequestParams::Boolean
237
+ else
238
+ msg = "unhandled param source type `#{definition['sourceType']}'"
239
+ raise ArgumentError, msg
240
+ end
241
+ source = definition['source']
242
+ param_class.new(
243
+ param_class.literal? ? source : underscore(source),
244
+ underscore(definition['target'])
245
+ )
246
+ end
247
+ end
248
+
249
+ def define_has_many(namespace, resource, has_many)
250
+ has_many.each do |name, definition|
251
+ operation = build_enumerate_resource_operation(namespace, resource, definition)
252
+ resource.add_operation(underscore(name), operation)
253
+ end
254
+ end
255
+
256
+ def define_has_some(namespace, resource, has_some)
257
+ has_some.each do |name, definition|
258
+ define_reference(namespace, resource, name, definition)
259
+ end
260
+ end
261
+
262
+ def define_has_one(namespace, resource, has_one)
263
+ has_one.each do |name, definition|
264
+ define_reference(namespace, resource, name, definition)
265
+ end
266
+ end
267
+
268
+ def define_reference(namespace, resource, name, definition)
269
+ builder = define_builder(namespace, definition['resource'])
270
+ if path = definition['path']
271
+ source = underscore(path)
272
+ builder.sources << BuilderSources::DataMember.new(source, :data)
273
+ end
274
+ operation = Operations::ReferenceOperation.new(
275
+ builder: builder,
276
+ source: source(definition))
277
+ resource.add_operation(underscore(name), operation)
278
+ end
279
+
280
+ def define_builder(namespace, definition)
281
+ builder = Builder.new(
282
+ resource_class: namespace.const_get(definition['type']),
283
+ sources: builder_sources(definition['identifiers'] || [])
284
+ )
285
+ delta = builder.resource_class.identifiers - builder.sources.map(&:target)
286
+ if delta.size == 0
287
+ # all identifiers provided
288
+ elsif delta.size == 1
289
+ # all but one provided, adding an Argument source
290
+ target = delta.first
291
+ builder.sources << BuilderSources::Argument.new(target)
292
+ else
293
+ msg = "too many unsourced identifiers: #{definition.inspect}"
294
+ raise Errors::DefinitionError, msg
295
+ end
296
+ builder
297
+ end
298
+
299
+ def builder_sources(sources)
300
+ sources.map do |definition|
301
+ source_class =
302
+ case definition['sourceType']
303
+ when 'identifier' then BuilderSources::Identifier
304
+ when 'dataMember' then BuilderSources::DataMember
305
+ when 'requestParameter' then BuilderSources::RequestParameter
306
+ when 'responsePath' then BuilderSources::ResponsePath
307
+ else
308
+ msg = "unhandled identifier source type `#{definition['sourceType']}'"
309
+ raise ArgumentError, msg
310
+ end
311
+ source_class.new(
312
+ underscore(definition['source']),
313
+ underscore(definition['target'])
314
+ )
315
+ end
316
+ end
317
+
318
+ def operation_type(action)
319
+ case action.keys.sort
320
+ when %w(request) then :basic
321
+ when %w(path request) then :data
322
+ when %w(request resource) then :resource
323
+ when %w(path request resource) then :resource
324
+ else
325
+ msg = "unhandled action: #{action.keys.inspect}"
326
+ raise Errors::DefinitionError, msg
327
+ end
328
+ end
329
+
330
+ def svc_definition
331
+ @source['service'] || {}
332
+ end
333
+
334
+ def resource_definitions
335
+ @source['resources'] || {}
336
+ end
337
+
338
+ def each_definition(&block)
339
+ yield('Resource', svc_definition)
340
+ resource_definitions.each(&block)
341
+ end
342
+
343
+ def underscore(str)
344
+ if str
345
+ str.gsub(/\w+/) { |part| Seahorse::Util.underscore(part) }
346
+ end
347
+ end
348
+
349
+ def pluralize(str)
350
+ underscore(str) + 's'
351
+ end
352
+
353
+ def source(definition)
354
+ if ENV['SOURCE']
355
+ Source.new(definition, @source_path)
356
+ else
357
+ nil
358
+ end
359
+ end
360
+
361
+ end
362
+ end
363
+ end
@@ -0,0 +1,18 @@
1
+ require 'json'
2
+
3
+ module Aws
4
+ module Resources
5
+ class Documenter
6
+
7
+ autoload :BaseOperationDocumenter, 'aws-sdk-resources/documenter/base_operation_documenter'
8
+ autoload :DataOperationDocumenter, 'aws-sdk-resources/documenter/data_operation_documenter'
9
+ autoload :EnumerateDataOperationDocumenter, 'aws-sdk-resources/documenter/enumerate_data_operation_documenter'
10
+ autoload :EnumerateResourceOperationDocumenter, 'aws-sdk-resources/documenter/enumerate_resource_operation_documenter'
11
+ autoload :OperationDocumenter, 'aws-sdk-resources/documenter/operation_documenter'
12
+ autoload :ReferenceOperationDocumenter, 'aws-sdk-resources/documenter/reference_operation_documenter'
13
+ autoload :ResourceOperationDocumenter, 'aws-sdk-resources/documenter/resource_operation_documenter'
14
+ autoload :WaiterOperationDocumenter, 'aws-sdk-resources/documenter/waiter_operation_documenter'
15
+
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,269 @@
1
+ module Aws
2
+ module Resources
3
+ class Documenter
4
+ class BaseOperationDocumenter
5
+
6
+ def initialize(yard_class, resource_class, operation_name, operation)
7
+ @yard_class = yard_class
8
+ @resource_class = resource_class
9
+ @resource_class_name = @resource_class.name.split('::').last
10
+ @operation_name = operation_name.to_s
11
+ @operation = operation
12
+ @source = @operation.source
13
+ if @operation.respond_to?(:request)
14
+ @api_request_name = @operation.request.method_name
15
+ @api_request = @resource_class.client_class.api.operation(@api_request_name)
16
+ @api_request_params = @operation.request.params
17
+ @request_operation_name = @operation.request.method_name.to_s
18
+ @called_operation = "Client##{@api_request_name}"
19
+ end
20
+ if @operation.respond_to?(:builder)
21
+ @builder = @operation.builder
22
+ @target_resource_class = @builder.resource_class
23
+ @target_resource_class_name = @target_resource_class.name.split('::').last
24
+ end
25
+ end
26
+
27
+ # @return [YARD::CodeObject::ClassObject]
28
+ attr_reader :yard_class
29
+
30
+ # @return [Class<Resource>] Returns the resource class this
31
+ # operation belongs to.
32
+ attr_reader :resource_class
33
+
34
+ # @return [String] The name of this resource operation.
35
+ attr_reader :operation_name
36
+
37
+ # @return [String] Returns the name of the resource class being
38
+ # documented without the namespace prefix. Example:
39
+ #
40
+ # * Aws::S3::Resource => 'Resource'
41
+ # * Aws::S3::Bucket => 'Bucket'
42
+ #
43
+ attr_reader :resource_class_name
44
+
45
+ # @return [Class<Resource>,nil] Returns the class of the resource
46
+ # returned by invoking this operation. Returns `nil` if this operation
47
+ # does not return any resource objects.
48
+ attr_reader :target_resource_class
49
+
50
+ # @return [String,nil] Returns the name of the resource class
51
+ # returned by this operation. This is the base name of
52
+ # the class without a namespace prefix. Returns `nil` if this
53
+ # operation does not return any resource objects.
54
+ attr_reader :target_resource_class_name
55
+
56
+ # @return [String,nil] Returns the name of the API operation called
57
+ # on the client. Returns `nil` if this operation does not make
58
+ # any API requests.
59
+ attr_reader :api_request_name
60
+
61
+ # @return [Seahorse::Model::Operation,nil] Returns the model of the
62
+ # API operation called. Returns `nil` if this operation does not make
63
+ # any API requests.
64
+ attr_reader :api_request
65
+
66
+ # @return [Array<Resources::RequestParams::Base>, nil] Returns the
67
+ # parameters this operation binds to the made request. Returns `nil`
68
+ # if this operation does not make a request.
69
+ attr_reader :api_request_params
70
+
71
+ # @return [String,nil] Returns the `Client#operation_name` reference.
72
+ # This is useful for generating `@see` tags and `{links}`.
73
+ attr_reader :called_operation
74
+
75
+ # @return [Builder,nil] Returns the resource builder for
76
+ # this operation. Returns `nil` if this operation does not build
77
+ # and return resource objects.
78
+ attr_reader :builder
79
+
80
+ # @return [Source]
81
+ attr_reader :source
82
+
83
+ # Constructs and returns a new YARD method object for this operation.
84
+ # @return [YARD::CodeObject::MethodObject]
85
+ def method_object
86
+ m = YARD::CodeObjects::MethodObject.new(yard_class, operation_name)
87
+ m.scope = :instance
88
+ m.parameters = parameters
89
+ m.docstring = docstring
90
+ if source
91
+ m.source_type = :json
92
+ m.source = source.format
93
+ filename = source.file
94
+ filename = filename.match('(aws-sdk-core/apis/.+\.resources\.json)')[1]
95
+ m.add_file(filename, nil, true)
96
+ end
97
+ tags.each do |tag|
98
+ m.add_tag(tag)
99
+ end
100
+ m
101
+ end
102
+
103
+ private
104
+
105
+ def parameters
106
+ if option_tags.empty?
107
+ []
108
+ else
109
+ [['params', '{}']]
110
+ end
111
+ end
112
+
113
+ def docstring
114
+ ''
115
+ end
116
+
117
+ def tags
118
+ (option_tags + example_tags + [return_tag] + see_also_tags).compact
119
+ end
120
+
121
+ # This method should be overridden in sub-classes to add YARD tags
122
+ # to the method code object.
123
+ # @return [Array<YARD::Tag>]
124
+ def example_tags
125
+ []
126
+ end
127
+
128
+ def option_tags
129
+ if api_request && api_request.input
130
+ tags = []
131
+ required = api_request.input.required
132
+ members = api_request.input.members
133
+ members = members.sort_by { |name,_| required.include?(name) ? 0 : 1 }
134
+ members.each do |member_name, member_shape|
135
+ if api_request_params.any? { |p| p.target.match(/^#{member_name}\b/) }
136
+ next
137
+ end
138
+ docstring = member_shape.documentation
139
+ req = ' **`required`** &mdash; ' if required.include?(member_name)
140
+ tags << "@option params [#{param_type(member_shape)}] :#{member_name} #{req}#{docstring}"
141
+ end
142
+ tags = tags.join("\n")
143
+ YARD::DocstringParser.new.parse(tags).to_docstring.tags
144
+ else
145
+ []
146
+ end
147
+ end
148
+
149
+ # If this operation makes an API request, then a `@see` tag is
150
+ # returned that references the client API operation.
151
+ # @return [Array<YARD::Tag>]
152
+ def see_also_tags
153
+ tags = []
154
+ tags += related_resource_operation_tags if target_resource_class
155
+ tags += called_operation_tag if called_operation
156
+ tags
157
+ end
158
+
159
+ def called_operation_tag
160
+ tag = "@see #{called_operation}"
161
+ YARD::DocstringParser.new.parse(tag).to_docstring.tags
162
+ end
163
+
164
+ def related_resource_operation_tags
165
+ tags = []
166
+ resource_class.operations.each do |name,op|
167
+ if
168
+ name.to_s != self.operation_name &&
169
+ op.respond_to?(:builder) &&
170
+ op.builder.resource_class == target_resource_class
171
+ then
172
+ tags << "@see ##{name}"
173
+ end
174
+ end
175
+ YARD::DocstringParser.new.parse(tags.sort.join("\n")).to_docstring.tags
176
+ end
177
+
178
+ def return_tag
179
+ if return_type == ['void'] && return_message.strip.empty?
180
+ nil
181
+ else
182
+ YARD::Tags::Tag.new(:return, return_message, return_type)
183
+ end
184
+ end
185
+
186
+ # The response object type for the @return tag. This must be overridden
187
+ # in sub-classes.
188
+ def return_type
189
+ raise NotImplementedError
190
+ end
191
+
192
+ # The message portion of the @return tag for this operation. This must
193
+ # be overidden in sub-classes.
194
+ def return_message
195
+ raise NotImplementedError
196
+ end
197
+
198
+ # Returns a suitable variable name for the resource class being
199
+ # documented:
200
+ #
201
+ # Aws::S3::Resource => 's3'
202
+ # Aws::S3::Bucket => 'bucket'
203
+ #
204
+ def variable_name
205
+ parts = resource_class.name.split('::')
206
+ (parts.last == 'Resource' ? parts[-2] : parts[-1]).downcase
207
+ end
208
+
209
+ def path_type
210
+ case path_shape
211
+ when Seahorse::Model::Shapes::Structure then 'Structure'
212
+ when Seahorse::Model::Shapes::List then 'Array'
213
+ when Seahorse::Model::Shapes::Map then 'Hash'
214
+ when Seahorse::Model::Shapes::String then 'String'
215
+ when Seahorse::Model::Shapes::Integer then 'Integer'
216
+ when Seahorse::Model::Shapes::Float then 'Float'
217
+ when Seahorse::Model::Shapes::Boolean then 'Boolean'
218
+ when Seahorse::Model::Shapes::Timestamp then 'Time'
219
+ when Seahorse::Model::Shapes::Blob then 'IO'
220
+ else
221
+ raise "unhandled shape class `#{path_shape.class.name}'"
222
+ end
223
+ end
224
+
225
+ def path_shape
226
+ resolve_shape(response_shape, @operation.path)
227
+ end
228
+
229
+ # Returns the output shape for the called operation.
230
+ def response_shape
231
+ api = resource_class.client_class.api
232
+ api.operation(@operation.request.method_name).output
233
+ end
234
+
235
+ def resolve_shape(shape, path)
236
+ if path != '$'
237
+ shape = path.scan(/\w+|\[.*?\]/).inject(shape) do |shape, part|
238
+ if part[0] == '['
239
+ shape.member
240
+ else
241
+ shape.member(part)
242
+ end
243
+ end
244
+ end
245
+ end
246
+
247
+ def param_type(shape)
248
+ case shape
249
+ when Seahorse::Model::Shapes::Blob then 'IO'
250
+ when Seahorse::Model::Shapes::Byte then 'String'
251
+ when Seahorse::Model::Shapes::Boolean then 'Boolean'
252
+ when Seahorse::Model::Shapes::Character then 'String'
253
+ when Seahorse::Model::Shapes::Double then 'Float'
254
+ when Seahorse::Model::Shapes::Float then 'Float'
255
+ when Seahorse::Model::Shapes::Integer then 'Integer'
256
+ when Seahorse::Model::Shapes::List then 'Array'
257
+ when Seahorse::Model::Shapes::Long then 'Integer'
258
+ when Seahorse::Model::Shapes::Map then 'Hash'
259
+ when Seahorse::Model::Shapes::String then 'String'
260
+ when Seahorse::Model::Shapes::Structure then 'Hash'
261
+ when Seahorse::Model::Shapes::Timestamp then 'Time'
262
+ else raise 'unhandled type'
263
+ end
264
+ end
265
+
266
+ end
267
+ end
268
+ end
269
+ end