aws-sdk-code-generator 0.1.0.pre

Sign up to get free protection for your applications and to get access to all the features.
Files changed (78) hide show
  1. checksums.yaml +7 -0
  2. data/lib/aws-sdk-code-generator.rb +91 -0
  3. data/lib/aws-sdk-code-generator/apply_docs.rb +37 -0
  4. data/lib/aws-sdk-code-generator/code_builder.rb +201 -0
  5. data/lib/aws-sdk-code-generator/dsl/access_control_statement.rb +23 -0
  6. data/lib/aws-sdk-code-generator/dsl/attribute_accessor.rb +43 -0
  7. data/lib/aws-sdk-code-generator/dsl/attribute_reader.rb +11 -0
  8. data/lib/aws-sdk-code-generator/dsl/attribute_writer.rb +11 -0
  9. data/lib/aws-sdk-code-generator/dsl/autoload_statement.rb +15 -0
  10. data/lib/aws-sdk-code-generator/dsl/block_param.rb +11 -0
  11. data/lib/aws-sdk-code-generator/dsl/class.rb +27 -0
  12. data/lib/aws-sdk-code-generator/dsl/code_literal.rb +66 -0
  13. data/lib/aws-sdk-code-generator/dsl/code_object.rb +33 -0
  14. data/lib/aws-sdk-code-generator/dsl/docstring.rb +36 -0
  15. data/lib/aws-sdk-code-generator/dsl/eigenclass.rb +15 -0
  16. data/lib/aws-sdk-code-generator/dsl/extend_statement.rb +12 -0
  17. data/lib/aws-sdk-code-generator/dsl/formatter.rb +25 -0
  18. data/lib/aws-sdk-code-generator/dsl/include_statement.rb +17 -0
  19. data/lib/aws-sdk-code-generator/dsl/main.rb +105 -0
  20. data/lib/aws-sdk-code-generator/dsl/method.rb +108 -0
  21. data/lib/aws-sdk-code-generator/dsl/module.rb +167 -0
  22. data/lib/aws-sdk-code-generator/dsl/option_tag.rb +36 -0
  23. data/lib/aws-sdk-code-generator/dsl/param.rb +43 -0
  24. data/lib/aws-sdk-code-generator/dsl/param_list.rb +38 -0
  25. data/lib/aws-sdk-code-generator/dsl/return_tag.rb +19 -0
  26. data/lib/aws-sdk-code-generator/dsl/tag_default.rb +20 -0
  27. data/lib/aws-sdk-code-generator/dsl/tag_docstring.rb +27 -0
  28. data/lib/aws-sdk-code-generator/dsl/tag_type.rb +18 -0
  29. data/lib/aws-sdk-code-generator/errors.rb +30 -0
  30. data/lib/aws-sdk-code-generator/gem_builder.rb +71 -0
  31. data/lib/aws-sdk-code-generator/generators/client_api_module.rb +334 -0
  32. data/lib/aws-sdk-code-generator/generators/client_class.rb +389 -0
  33. data/lib/aws-sdk-code-generator/generators/client_operation_documentation.rb +166 -0
  34. data/lib/aws-sdk-code-generator/generators/errors_module.rb +25 -0
  35. data/lib/aws-sdk-code-generator/generators/resource/action.rb +88 -0
  36. data/lib/aws-sdk-code-generator/generators/resource/batch_builder.rb +211 -0
  37. data/lib/aws-sdk-code-generator/generators/resource/builder.rb +50 -0
  38. data/lib/aws-sdk-code-generator/generators/resource/client_getter.rb +15 -0
  39. data/lib/aws-sdk-code-generator/generators/resource/client_request.rb +49 -0
  40. data/lib/aws-sdk-code-generator/generators/resource/client_request_docs.rb +97 -0
  41. data/lib/aws-sdk-code-generator/generators/resource/client_request_params.rb +88 -0
  42. data/lib/aws-sdk-code-generator/generators/resource/collection_class.rb +180 -0
  43. data/lib/aws-sdk-code-generator/generators/resource/data_attribute_getter.rb +24 -0
  44. data/lib/aws-sdk-code-generator/generators/resource/data_loaded_method.rb +18 -0
  45. data/lib/aws-sdk-code-generator/generators/resource/data_method.rb +49 -0
  46. data/lib/aws-sdk-code-generator/generators/resource/exists_method.rb +29 -0
  47. data/lib/aws-sdk-code-generator/generators/resource/extract_identifier_method.rb +32 -0
  48. data/lib/aws-sdk-code-generator/generators/resource/has_association.rb +101 -0
  49. data/lib/aws-sdk-code-generator/generators/resource/has_many_association.rb +108 -0
  50. data/lib/aws-sdk-code-generator/generators/resource/identifier_getter.rb +26 -0
  51. data/lib/aws-sdk-code-generator/generators/resource/identifiers_method.rb +28 -0
  52. data/lib/aws-sdk-code-generator/generators/resource/initialize_method.rb +67 -0
  53. data/lib/aws-sdk-code-generator/generators/resource/load_method.rb +65 -0
  54. data/lib/aws-sdk-code-generator/generators/resource/value_source.rb +68 -0
  55. data/lib/aws-sdk-code-generator/generators/resource/waiter_method.rb +61 -0
  56. data/lib/aws-sdk-code-generator/generators/resource_class.rb +325 -0
  57. data/lib/aws-sdk-code-generator/generators/response_structure_example.rb +83 -0
  58. data/lib/aws-sdk-code-generator/generators/root_resource_class.rb +42 -0
  59. data/lib/aws-sdk-code-generator/generators/service_documentation.rb +64 -0
  60. data/lib/aws-sdk-code-generator/generators/shared_example.rb +132 -0
  61. data/lib/aws-sdk-code-generator/generators/structure_type_class.rb +95 -0
  62. data/lib/aws-sdk-code-generator/generators/syntax_example.rb +169 -0
  63. data/lib/aws-sdk-code-generator/generators/types_module.rb +52 -0
  64. data/lib/aws-sdk-code-generator/generators/waiter_class.rb +62 -0
  65. data/lib/aws-sdk-code-generator/generators/waiters_module.rb +20 -0
  66. data/lib/aws-sdk-code-generator/hash_formatter.rb +122 -0
  67. data/lib/aws-sdk-code-generator/helper.rb +215 -0
  68. data/lib/aws-sdk-code-generator/service.rb +126 -0
  69. data/lib/aws-sdk-code-generator/underscore.rb +45 -0
  70. data/lib/aws-sdk-code-generator/view.rb +23 -0
  71. data/lib/aws-sdk-code-generator/views.rb +3 -0
  72. data/lib/aws-sdk-code-generator/views/features/env.rb +24 -0
  73. data/lib/aws-sdk-code-generator/views/features/step_definitions.rb +20 -0
  74. data/lib/aws-sdk-code-generator/views/gemspec.rb +41 -0
  75. data/lib/aws-sdk-code-generator/views/service_module.rb +85 -0
  76. data/lib/aws-sdk-code-generator/views/spec/spec_helper.rb +24 -0
  77. data/lib/aws-sdk-code-generator/views/version.rb +16 -0
  78. metadata +120 -0
@@ -0,0 +1,83 @@
1
+ require 'set'
2
+
3
+ module AwsSdkCodeGenerator
4
+ module Generators
5
+ class ResponseStructureExample
6
+
7
+ include Helper
8
+
9
+ # @option options [required, Hash] :shape_ref
10
+ # @option options [required, Hash] :api
11
+ def initialize(options = {})
12
+ @shape_ref = options.fetch(:shape_ref)
13
+ @api = options.fetch(:api)
14
+ end
15
+
16
+ def to_str
17
+ "\n@example Response structure\n #{entry(@shape_ref, "resp", Set.new).join("\n ")}"
18
+ end
19
+ alias to_s to_str
20
+
21
+ private
22
+
23
+ def structure(ref, context, visited)
24
+ lines = []
25
+ shape(ref)['members'].each_pair do |member_name, member_ref|
26
+ lines += entry(member_ref, "#{context}.#{underscore(member_name)}", visited)
27
+ end
28
+ lines
29
+ end
30
+
31
+ def list(ref, context, visited)
32
+ lines = []
33
+ lines << "#{context} #=> Array"
34
+ lines += entry(shape(ref)['member'], "#{context}[0]", visited)
35
+ lines
36
+ end
37
+
38
+ def map(ref, context, visited)
39
+ lines = []
40
+ lines << "#{context} #=> Hash"
41
+ lines += entry(shape(ref)['value'], "#{context}[#{map_key(ref)}]", visited)
42
+ lines
43
+ end
44
+
45
+ def map_key(ref)
46
+ shape(ref)['key']['shape'].inspect
47
+ end
48
+
49
+ def entry(ref, context, visited)
50
+ if ref['shape'] == 'AttributeValue'
51
+ return ["#{context} #=> <Hash,Array,String,Numeric,Boolean,IO,Set,nil>"]
52
+ elsif visited.include?(ref['shape'])
53
+ return ["#{context} #=> Types::#{ref['shape']}"]
54
+ else
55
+ visited = visited + [ref['shape']]
56
+ end
57
+ case shape(ref)['type']
58
+ when 'structure' then structure(ref, context, visited)
59
+ when 'list' then list(ref, context, visited)
60
+ when 'map' then map(ref, context, visited)
61
+ else ["#{context} #=> #{type(ref)}"]
62
+ end
63
+ end
64
+
65
+ def type(ref)
66
+ if shape(ref)['type'] == 'string'
67
+ string(ref)
68
+ else
69
+ ruby_type(ref)
70
+ end
71
+ end
72
+
73
+ def string(ref)
74
+ if shape(ref)['enum']
75
+ "String, one of #{shape(ref)['enum'].map(&:inspect).join(', ')}"
76
+ else
77
+ 'String'
78
+ end
79
+ end
80
+
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,42 @@
1
+ module AwsSdkCodeGenerator
2
+ module Generators
3
+ class RootResourceClass < ResourceClass
4
+
5
+ include Helper
6
+
7
+ # @option options [required, Hash] :api
8
+ # @option options [required, String] :var_name
9
+ # @option options [Hash] :resources
10
+ # @option options [Hash] :paginators
11
+ def initialize(options)
12
+ resources = options.fetch(:resources) || {}
13
+ super(
14
+ api: options.fetch(:api),
15
+ name: 'Resource',
16
+ resource: resources.fetch('service', {}),
17
+ paginators: options.fetch(:paginators, nil) || {},
18
+ waiters:nil,
19
+ var_name: options.fetch(:var_name)
20
+ )
21
+ end
22
+
23
+ private
24
+
25
+ def build
26
+ add(initialize_method)
27
+ add(client_getter)
28
+ apply_actions
29
+ apply_associations
30
+ end
31
+
32
+ def initialize_method
33
+ Dsl::Method.new('initialize') do |m|
34
+ m.param('options', default:{})
35
+ m.option(name:'client', type:'Client')
36
+ m.code('@client = options[:client] || Client.new(options)')
37
+ end
38
+ end
39
+
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,64 @@
1
+ require 'erb'
2
+
3
+ module AwsSdkCodeGenerator
4
+ module Generators
5
+ class ServiceDocumentation
6
+
7
+ include Helper
8
+
9
+ # @option options [required, Hash] :api
10
+ # @option options [required, Hash] :product_name
11
+ # @option options [required, Hash] :namespace
12
+ def initialize(options = {})
13
+ @api = options.fetch(:api)
14
+ @product_name = options.fetch(:product_name)
15
+ @namespace = options.fetch(:namespace)
16
+ @var_name = @namespace.split('::').last.downcase
17
+ end
18
+
19
+ def docstring
20
+ <<-MARKDOWN
21
+ @service
22
+ This module provides support for #{@product_name}, which shipped in `aws-sdk-#{@var_name}` gem.
23
+
24
+ # #{@namespace}::Client
25
+
26
+ The {#{@namespace}::Client} class provides one method for each API
27
+ operation. Operation methods each accept a hash of request parameters
28
+ and return a response object.#{example_operation}
29
+
30
+ See {Client} for more information.
31
+
32
+ # #{@namespace}::Errors
33
+
34
+ Errors returned from #{@product_name} all
35
+ extend {Errors::ServiceError}.
36
+
37
+ begin
38
+ # do stuff
39
+ rescue #{@namespace}::Errors::ServiceError
40
+ # rescues all service API errors
41
+ end
42
+
43
+ See {Errors} for more information.
44
+ MARKDOWN
45
+ end
46
+
47
+ def example_operation
48
+ if @api['operations'] && @api['operations'].first
49
+ <<-EXAMPLE
50
+
51
+
52
+ #{@var_name} = #{@namespace}::Client.new
53
+ resp = #{@var_name}.#{example_operation_name}(params)
54
+ EXAMPLE
55
+ end
56
+ end
57
+
58
+ def example_operation_name
59
+ underscore(@api['operations'].keys.first)
60
+ end
61
+
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,132 @@
1
+ module AwsSdkCodeGenerator
2
+ module Generators
3
+ class SharedExample
4
+
5
+ include Helper
6
+
7
+ # @option options [required, String] :operation_name
8
+ # @option options [required, Hash] api
9
+ # @option options [required, Hash] examples
10
+ # @option options [required, Integer] example
11
+ def initialize(options = {})
12
+ @operation_name = options.fetch(:operation_name)
13
+ @operation = options.fetch(:api)['operations'][@operation_name]
14
+ @example = options.fetch(:examples)['examples'][@operation_name][options.fetch(:example)]
15
+ @api = options.fetch(:api)
16
+ @method_name = underscore(@operation_name)
17
+ end
18
+
19
+ def to_s
20
+ lines = []
21
+ lines << ""
22
+ lines << "@example Example: #{@example['description']}"
23
+ lines << ""
24
+ apply_input_example(lines)
25
+ apply_output_example(lines)
26
+ lines.join("\n")
27
+ end
28
+
29
+ private
30
+
31
+ def apply_input_example(lines)
32
+ lines << " resp = client.#{@method_name}(#{input_params})"
33
+ end
34
+
35
+ def input_params
36
+ if @example['input'] && @operation['input']
37
+ entry(
38
+ @example['input'],
39
+ @operation['input'],
40
+ indent = ' ',
41
+ path = [],
42
+ @example['comments']['input']
43
+ ).join("\n")
44
+ else
45
+ ''
46
+ end
47
+ end
48
+
49
+ def apply_output_example(lines)
50
+ if @example['output'] && @operation['output']
51
+ lines << ""
52
+ lines << " # resp.to_h outputs the following:"
53
+ lines << " " + entry(
54
+ @example['output'],
55
+ @operation['output'],
56
+ indent = ' ',
57
+ path = [],
58
+ @example['comments']['output']
59
+ ).join("\n")
60
+ end
61
+ end
62
+
63
+ def entry(json, ref, indent, path, comments)
64
+ case shape(ref)['type']
65
+ when 'structure' then structure(json, ref, indent, path, comments)
66
+ when 'map' then map(json, ref, indent, path, comments)
67
+ when 'list' then list(json, ref, indent, path, comments)
68
+ when 'timestamp' then "Time.parse(#{json.inspect})"
69
+ when 'string', 'blob', 'integer', 'long', 'float', 'double', 'boolean'
70
+ json.inspect
71
+ else
72
+ raise ArgumentError, "unhandled type #{shape(ref)['type'].inspect}"
73
+ end
74
+ end
75
+
76
+ def structure(json, ref, indent, path, comments)
77
+ lines = ["{"]
78
+ json.each_pair do |key, val|
79
+ path << ".#{key}"
80
+ shape_val = entry(val, shape(ref)['members'][key], "#{indent} ", path, comments)
81
+ if shape_val.is_a?(Array)
82
+ shape_val = shape_val.join("\n")
83
+ end
84
+ lines << "#{indent} #{underscore(key)}: #{shape_val},#{comments_for(path, comments)}"
85
+ path.pop
86
+ end
87
+ lines << "#{indent}}"
88
+ lines
89
+ end
90
+
91
+ def map(json, ref, indent, path, comments)
92
+ lines = ["{"]
93
+ json.each do |key, val|
94
+ path << ".#{key}"
95
+ shape_val = entry(val, shape(ref)['value'], "#{indent} ", path, comments)
96
+ if shape_val.is_a?(Array)
97
+ shape_val = shape_val.join("\n")
98
+ end
99
+ lines << "#{indent} \"#{key}\" => #{shape_val},#{comments_for(path, comments)}"
100
+ path.pop
101
+ end
102
+ lines << "#{indent}}"
103
+ lines
104
+ end
105
+
106
+ def list(json, ref, indent, path, comments)
107
+ lines = ["["]
108
+ json.each_with_index do |value, index|
109
+ path << "[#{index}]"
110
+ shape_val = entry(value, shape(ref)['member'], "#{indent} ", path, comments)
111
+ if shape_val.is_a?(Array)
112
+ shape_val = shape_val.join("\n")
113
+ end
114
+ lines << "#{indent} #{shape_val},#{comments_for(path, comments)}"
115
+ path.pop
116
+ end
117
+ lines << "#{indent}]"
118
+ lines
119
+ end
120
+
121
+ def comments_for(path, comments)
122
+ path = path.join().sub(/^\./, '')
123
+ if comments.key?(path)
124
+ " # #{comments[path]}"
125
+ else
126
+ ""
127
+ end
128
+ end
129
+
130
+ end
131
+ end
132
+ end
@@ -0,0 +1,95 @@
1
+ module AwsSdkCodeGenerator
2
+ module Generators
3
+ class StructureTypeClass < Dsl::CodeLiteral
4
+
5
+ include Helper
6
+
7
+ # @option options [required, String] :name
8
+ # @option options [required, Hash] :api
9
+ # @option options [required, Boolean] :used_as_input
10
+ def initialize(options)
11
+ @name = options.fetch(:name)
12
+ @api = options.fetch(:api)
13
+ @shape = @api['shapes'][@name]
14
+ super()
15
+
16
+ apply_class_docs
17
+ apply_input_example if options.fetch(:used_as_input)
18
+ apply_returned_by
19
+ document_members
20
+ if @shape['members'].empty?
21
+ apply_empty_structure
22
+ else
23
+ apply_structure_with_members
24
+ end
25
+ end
26
+
27
+ private
28
+
29
+ def apply_class_docs
30
+ if class_docs = documentation(@shape)
31
+ append(Dsl::Docstring.new(class_docs).to_s)
32
+ end
33
+ end
34
+
35
+ def apply_input_example
36
+ if @shape['members'].empty?
37
+ note = '@api private'
38
+ else
39
+ note = "@note When making an API call, pass #{@name}\n"
40
+ note += " data as a hash:\n\n"
41
+ note += SyntaxExample.new(
42
+ struct_shape: @shape,
43
+ api: @api,
44
+ indent: ' ' * 6
45
+ ).format
46
+ end
47
+ append(Dsl::Docstring.new(note).to_s)
48
+ end
49
+
50
+ def apply_returned_by
51
+ # TODO : implement this
52
+ end
53
+
54
+ def apply_empty_structure
55
+ append("class #{@name} < Aws::EmptyStructure; end")
56
+ end
57
+
58
+ def apply_structure_with_members
59
+ append("class #{@name} < Struct.new(")
60
+ @shape['members'].keys.each.with_index do |member_name, n|
61
+ comma = n == @shape['members'].size - 1 ? ')' : ','
62
+ append(" :#{underscore(member_name)}#{comma}")
63
+ end
64
+ append(" include Aws::Structure")
65
+ append("end")
66
+ end
67
+
68
+ def document_members
69
+ @shape['members'].each.with_index do |(name, ref), n|
70
+ append("#") unless n == 0
71
+ append(Dsl::Docstring.new(attribute_macro(name, ref)).to_s)
72
+ end
73
+ end
74
+
75
+ def attribute_macro(member_name, member_ref)
76
+ docs = documentation(member_ref, line_width:68).lines.to_a.join(" ")
77
+ macro = "@!attribute [rw] #{underscore(member_name)}\n"
78
+ macro << " #{docs}\n" unless docs == ''
79
+ macro << " @return [#{ruby_type(member_ref)}]"
80
+ macro
81
+ end
82
+
83
+ private
84
+
85
+ def needs_defaults?
86
+ @shape['members'].any? do |_, member_ref|
87
+ type = shape(member_ref)['type']
88
+
89
+ type == 'list' || type == 'map'
90
+ end
91
+ end
92
+
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,169 @@
1
+ module AwsSdkCodeGenerator
2
+ module Generators
3
+ class SyntaxExample < Dsl::Docstring
4
+
5
+ include Helper
6
+
7
+ # @option options [required, Hash] :struct_shape
8
+ # @option options [required, Hash] :api
9
+ # @option options [String] :indent ('')
10
+ def initialize(options = {})
11
+ @indent = options.fetch(:indent, '')
12
+ @api = options.fetch(:api)
13
+ @struct_shape = options.fetch(:struct_shape)
14
+ end
15
+
16
+ def format
17
+ if @struct_shape && @struct_shape['members'].length > 0
18
+ @indent + struct(@struct_shape, @indent, [])
19
+ else
20
+ ''
21
+ end
22
+ end
23
+
24
+ private
25
+
26
+ def ref_value(ref, i, visited)
27
+ if visited.include?(ref['shape'])
28
+ return "{\n#{i} # recursive #{ref['shape']}\n#{i}}"
29
+ else
30
+ visited = visited + [ref['shape']]
31
+ end
32
+
33
+ s = shape(ref)
34
+ case s['type']
35
+ when 'structure'
36
+ if ref['shape'] == 'AttributeValue'
37
+ '"value"'
38
+ else
39
+ struct(s, i, visited)
40
+ end
41
+
42
+ when 'blob'
43
+ if ref['streaming']
44
+ 'source_file'
45
+ else
46
+ '"data"'
47
+ end
48
+
49
+ when 'list' then list(s, i, visited)
50
+ when 'map' then map(s, i, visited)
51
+ when 'boolean' then "false"
52
+ when 'integer', 'long' then '1'
53
+ when 'float', 'double' then '1.0'
54
+ when 'byte' then '97'
55
+ when 'character' then '"a"'
56
+ when 'string' then string(ref)
57
+ when 'timestamp' then 'Time.now'
58
+ else raise "unsupported shape #{s['type'].inspect}"
59
+ end
60
+ end
61
+
62
+ def struct(struct_shape, i, visited)
63
+ lines = ['{']
64
+ struct_shape['members'].each_pair do |member_name, member_ref|
65
+ lines << struct_member(struct_shape, member_name, member_ref, i, visited)
66
+ end
67
+ lines << "#{i}}"
68
+ lines.join("\n")
69
+ end
70
+
71
+ def struct_member(struct, member_name, member_ref, i, visited)
72
+ entry = "#{i} #{underscore(member_name)}: #{ref_value(member_ref, i + ' ', visited)},"
73
+ required = (struct['required'] || []).include?(member_name)
74
+ apply_comments(member_ref, entry, required: required)
75
+ end
76
+
77
+ def list(list_shape, i, visited)
78
+ member_ref = list_shape['member']
79
+ if complex?(member_ref)
80
+ complex_list(member_ref, i, visited)
81
+ else
82
+ scalar_list(member_ref, i, visited)
83
+ end
84
+ end
85
+
86
+ def scalar_list(member_ref, i, visited)
87
+ "[#{ref_value(member_ref, i, visited)}]"
88
+ end
89
+
90
+ def complex_list(member_ref, i, visited)
91
+ "[\n#{i} #{ref_value(member_ref, i + ' ', visited)},\n#{i}]"
92
+ end
93
+
94
+ def map(map_shape, i, visited)
95
+ key = string(map_shape['key'])
96
+ value = ref_value(map_shape['value'], i + ' ', visited)
97
+ "{\n#{i} #{key} => #{value},#{comments(map_shape['value'], false)}\n#{i}}"
98
+ end
99
+
100
+ def string(ref)
101
+ string_shape = shape(ref)
102
+ if string_shape['enum']
103
+ string_shape['enum'].first.inspect
104
+ else ref['shape']
105
+ ref['shape'].inspect
106
+ end
107
+ end
108
+
109
+ def apply_comments(ref, text, options = {})
110
+ required = options.fetch(:required)
111
+ lines = text.lines.to_a
112
+ if lines[0].match(/\n$/)
113
+ lines[0] = lines[0].sub(/\n$/, comments(ref, required) + "\n")
114
+ else
115
+ lines[0] += comments(ref, required)
116
+ end
117
+ lines.join
118
+ end
119
+
120
+ def comments(ref, required)
121
+ comments = []
122
+ if ref[:response_target]
123
+ comments << 'where to write response data, file path, or IO object'
124
+ end
125
+ if ref[:streaming]
126
+ comments << 'file/IO object, or string data'
127
+ end
128
+ if required
129
+ comments << 'required'
130
+ end
131
+ if enum = enum_values(ref)
132
+ comments << "accepts #{enum.to_a.join(', ')}"
133
+ end
134
+ if ddb_av?(ref)
135
+ comments << 'value <Hash,Array,String,Numeric,Boolean,IO,Set,nil>'
136
+ end
137
+ comments == [] ? '' : " # #{comments.join(', ')}"
138
+ end
139
+
140
+ def enum_values(ref)
141
+ s = shape(ref)
142
+ case s['type']
143
+ when 'list' then enum_values(s['member'])
144
+ when 'string' then s['enum']
145
+ else nil
146
+ end
147
+ end
148
+
149
+ def complex?(ref)
150
+ s = shape(ref)
151
+ if s['type'] == 'structure'
152
+ !ddb_av?(ref)
153
+ else
154
+ s['type'] == 'list' || s['type'] == 'map'
155
+ end
156
+ end
157
+
158
+ def ddb_av?(ref)
159
+ s = shape(ref)
160
+ case s['type']
161
+ when 'list' then ddb_av?(s['member'])
162
+ when 'structure' then ref['shape'] == 'AttributeValue'
163
+ else false
164
+ end
165
+ end
166
+
167
+ end
168
+ end
169
+ end