aws-sdk-code-generator 0.3.0.pre → 0.5.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 (55) hide show
  1. checksums.yaml +4 -4
  2. data/lib/aws-sdk-code-generator/client_constructor.rb +2 -1
  3. data/lib/aws-sdk-code-generator/code_builder.rb +52 -0
  4. data/lib/aws-sdk-code-generator/eventstream_example.rb +34 -34
  5. data/lib/aws-sdk-code-generator/gem_builder.rb +3 -5
  6. data/lib/aws-sdk-code-generator/plugin_list.rb +2 -1
  7. data/lib/aws-sdk-code-generator/rbs/error_list.rb +38 -0
  8. data/lib/aws-sdk-code-generator/rbs/keyword_argument_builder.rb +159 -0
  9. data/lib/aws-sdk-code-generator/rbs/method_signature.rb +11 -0
  10. data/lib/aws-sdk-code-generator/rbs/resource_action.rb +39 -0
  11. data/lib/aws-sdk-code-generator/rbs/resource_association.rb +50 -0
  12. data/lib/aws-sdk-code-generator/rbs/resource_batch_action.rb +59 -0
  13. data/lib/aws-sdk-code-generator/rbs/resource_client_request.rb +40 -0
  14. data/lib/aws-sdk-code-generator/rbs/waiter.rb +53 -0
  15. data/lib/aws-sdk-code-generator/rbs.rb +40 -0
  16. data/lib/aws-sdk-code-generator/resource_batch_action_code.rb +3 -1
  17. data/lib/aws-sdk-code-generator/resource_client_request.rb +3 -1
  18. data/lib/aws-sdk-code-generator/resource_waiter.rb +6 -5
  19. data/lib/aws-sdk-code-generator/service.rb +21 -0
  20. data/lib/aws-sdk-code-generator/views/async_client_class.rb +5 -1
  21. data/lib/aws-sdk-code-generator/views/client_api_module.rb +29 -4
  22. data/lib/aws-sdk-code-generator/views/client_class.rb +5 -1
  23. data/lib/aws-sdk-code-generator/views/endpoint_provider_class.rb +221 -2
  24. data/lib/aws-sdk-code-generator/views/event_streams_module.rb +7 -1
  25. data/lib/aws-sdk-code-generator/views/features/smoke.rb +99 -23
  26. data/lib/aws-sdk-code-generator/views/features/step_definitions.rb +1 -4
  27. data/lib/aws-sdk-code-generator/views/gemspec.rb +13 -3
  28. data/lib/aws-sdk-code-generator/views/rbs/client_class.rb +172 -0
  29. data/lib/aws-sdk-code-generator/views/rbs/errors_module.rb +28 -0
  30. data/lib/aws-sdk-code-generator/views/rbs/resource_class.rb +95 -0
  31. data/lib/aws-sdk-code-generator/views/rbs/root_resource_class.rb +30 -0
  32. data/lib/aws-sdk-code-generator/views/rbs/types_module.rb +257 -0
  33. data/lib/aws-sdk-code-generator/views/rbs/waiters_module.rb +22 -0
  34. data/lib/aws-sdk-code-generator/views/spec/endpoint_provider_spec_class.rb +5 -1
  35. data/lib/aws-sdk-code-generator/views/types_module.rb +8 -9
  36. data/lib/aws-sdk-code-generator.rb +17 -1
  37. data/templates/client_api_module.mustache +7 -0
  38. data/templates/client_class.mustache +0 -45
  39. data/templates/endpoint_provider_class.mustache +1 -19
  40. data/templates/endpoints_module.mustache +1 -0
  41. data/templates/endpoints_plugin.mustache +4 -2
  42. data/templates/features/smoke.mustache +11 -15
  43. data/templates/features/step_definitions.mustache +0 -5
  44. data/templates/gemspec.mustache +5 -2
  45. data/templates/rbs/client_class.mustache +39 -0
  46. data/templates/rbs/errors_module.mustache +17 -0
  47. data/templates/rbs/resource_class.mustache +71 -0
  48. data/templates/rbs/root_resource_class.mustache +26 -0
  49. data/templates/rbs/types_module.mustache +37 -0
  50. data/templates/rbs/waiters_module.mustache +17 -0
  51. data/templates/resource_class.mustache +3 -1
  52. data/templates/spec/endpoint_provider_spec_class.mustache +10 -0
  53. metadata +24 -5
  54. data/lib/aws-sdk-code-generator/views/features/smoke_step_definitions.rb +0 -26
  55. data/templates/features/smoke_step_definitions.mustache +0 -31
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AwsSdkCodeGenerator
4
+ module RBS
5
+ class ResourceClientRequest
6
+ include Helper
7
+
8
+ attr_reader :method_name
9
+ attr_reader :arguments
10
+ attr_reader :returns
11
+ attr_reader :include_required
12
+
13
+ def initialize(method_name:, api:, request:, returns:, skip: [])
14
+ @method_name = method_name
15
+ @returns = returns
16
+ @include_required = false
17
+
18
+ operation = api["operations"][request["operation"]]
19
+ shape_ref = operation["input"]
20
+ input_shape = AwsSdkCodeGenerator::Api.shape(shape_ref, api)
21
+ skip = Set.new(skip + AwsSdkCodeGenerator::ResourceSkipParams.compute(input_shape, request))
22
+ @arguments = if input_shape
23
+ shape = deep_copy(input_shape)
24
+ shape["members"].select! { |member_name, _| !skip.include?(member_name) }
25
+ KeywordArgumentBuilder.new(api: api, shape: shape, newline: true).format(indent: ' ' * (12 + method_name.length))
26
+ end
27
+ end
28
+
29
+ def build_method_signature
30
+ MethodSignature.new(
31
+ method_name: method_name,
32
+ overloads: [
33
+ "(#{arguments}) -> #{returns}",
34
+ "(#{@include_required ? "" : "?"}Hash[Symbol, untyped]) -> #{returns}"
35
+ ]
36
+ )
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AwsSdkCodeGenerator
4
+ module RBS
5
+ class Waiter < Struct.new(
6
+ :name,
7
+ :class_name,
8
+ :client_overload_keyword_argument,
9
+ :client_overload_positional_argument,
10
+ :waiter_overload_keyword_argument,
11
+ :waiter_overload_positional_argument,
12
+ keyword_init: true
13
+ )
14
+ class << self
15
+ def build_list(api:, waiters:)
16
+ operations = api.fetch("operations")
17
+ waiters =
18
+ if waiters&.first
19
+ waiters["waiters"]
20
+ else
21
+ {}
22
+ end
23
+ waiters.map do |waiter_name, waiter|
24
+ operation = waiter.fetch("operation")
25
+ operation_ref = operations[operation]
26
+ input_shape = operation_ref.dig("input", "shape")
27
+ include_required = api["shapes"][input_shape]&.[]("required")&.empty?&.!
28
+
29
+ name = ":#{Underscore.underscore(waiter_name)}"
30
+ shapes = api.fetch("shapes")
31
+ input_shape_ref = shapes[input_shape]
32
+ params = AwsSdkCodeGenerator::RBS::KeywordArgumentBuilder.new(
33
+ api: api,
34
+ shape: input_shape_ref,
35
+ newline: true,
36
+ ).format(indent: ' ' * 18)
37
+ returns = operation_ref.dig("output", "shape") ? "Client::_#{operation}ResponseSuccess" : "::Seahorse::Client::_ResponseSuccess[::Aws::EmptyStructure]"
38
+ prefix = include_required ? "" : "?"
39
+
40
+ new.tap do |w|
41
+ w.name = name
42
+ w.class_name = waiter_name
43
+ w.client_overload_keyword_argument = "(#{name} waiter_name, #{params}) -> #{returns}"
44
+ w.client_overload_positional_argument = "(#{name} waiter_name, #{prefix}Hash[Symbol, untyped] params, ?Hash[Symbol, untyped] options) -> #{returns}"
45
+ w.waiter_overload_keyword_argument = "(#{params}) -> #{returns}"
46
+ w.waiter_overload_positional_argument = "(#{prefix}Hash[Symbol, untyped]) -> #{returns}"
47
+ end
48
+ end.sort_by(&:name)
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AwsSdkCodeGenerator
4
+ module RBS
5
+ class << self
6
+ def to_type(shape_ref, api)
7
+ _, shape = Api.resolve(shape_ref, api)
8
+ case shape['type']
9
+ when 'blob' then Api.streaming?(shape_ref, api) ? '::IO' : '::String'
10
+ when 'boolean' then 'bool'
11
+ when 'byte' then '::Integer'
12
+ when 'character' then '::String'
13
+ when 'double' then '::Float'
14
+ when 'float' then '::Float'
15
+ when 'integer' then '::Integer'
16
+ when 'list' then "::Array[#{to_type(shape['member'], api)}]"
17
+ when 'long' then '::Integer'
18
+ when 'map' then "::Hash[#{to_type(shape['key'], api)}, #{to_type(shape['value'], api)}]"
19
+ when 'string'
20
+ if shape['enum']
21
+ "(#{shape['enum'].map { |e| "\"#{e}\"" }.join(" | ")})"
22
+ elsif Api.streaming?(shape_ref, api)
23
+ '::IO'
24
+ else
25
+ '::String'
26
+ end
27
+ when 'structure'
28
+ if shape['document']
29
+ 'untyped'
30
+ else
31
+ "Types::#{shape_ref['shape']}"
32
+ end
33
+ when 'timestamp' then '::Time'
34
+ else
35
+ raise "unhandled type #{shape['type'].inspect}"
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -15,7 +15,9 @@ module AwsSdkCodeGenerator
15
15
  parts << 'batch_enum.each do |batch|'
16
16
  parts << initialize_params
17
17
  parts << apply_params_per_batch
18
- parts << " batch[0].client.#{client_method}(params)"
18
+ parts << " Aws::Plugins::UserAgent.feature('resource') do"
19
+ parts << " batch[0].client.#{client_method}(params)"
20
+ parts << ' end'
19
21
  parts << 'end'
20
22
  parts << 'nil'
21
23
  parts.join("\n").rstrip
@@ -15,9 +15,11 @@ module AwsSdkCodeGenerator
15
15
  parts = []
16
16
  parts << request_options(params) if merge
17
17
  parts << assignment(options)
18
- parts << "@client."
18
+ parts << "Aws::Plugins::UserAgent.feature('resource') do\n"
19
+ parts << " @client."
19
20
  parts << operation_name(request)
20
21
  parts << arguments(merge, params, streaming)
22
+ parts << "\nend"
21
23
  parts.join
22
24
  end
23
25
 
@@ -52,11 +52,12 @@ module AwsSdkCodeGenerator
52
52
  args = ResourceClientRequestParams.new(
53
53
  params: waiter['params']
54
54
  ).to_s.strip
55
- if waiter['path']
56
- "resp = waiter.wait(params.merge(#{args}))"
57
- else
58
- "waiter.wait(params.merge(#{args}))"
59
- end
55
+ parts = []
56
+ parts << 'resp = ' if waiter['path']
57
+ parts << "Aws::Plugins::UserAgent.feature('resource') do\n"
58
+ parts << " waiter.wait(params.merge(#{args}))"
59
+ parts << "\nend"
60
+ parts.join
60
61
  end
61
62
 
62
63
  def constructor_args(resource, waiter)
@@ -20,6 +20,7 @@ module AwsSdkCodeGenerator
20
20
  # @option options [Hash<gem,version>] :gem_dependencies ({})
21
21
  # @option options [Hash] :add_plugins ({})
22
22
  # @option options [Hash] :remove_plugins ([])
23
+ # @option options [Boolean] :deprecated (false)
23
24
  def initialize(options)
24
25
  @name = options.fetch(:name)
25
26
  @identifier = name.downcase
@@ -57,6 +58,7 @@ module AwsSdkCodeGenerator
57
58
  @require_endpoint_discovery = api.fetch('operations', []).any? do |_, o|
58
59
  o['endpointdiscovery'] && o['endpointdiscovery']['required']
59
60
  end
61
+ @deprecated = options[:deprecated] || false
60
62
  end
61
63
 
62
64
  # @return [String] The service name, e.g. "S3"
@@ -146,6 +148,25 @@ module AwsSdkCodeGenerator
146
148
  # @return [Boolean] true if any operation requires endpoint_discovery
147
149
  attr_reader :require_endpoint_discovery
148
150
 
151
+ # @return [String] the service_id
152
+ def service_id
153
+ metadata = @api['metadata']
154
+ return metadata['serviceId'] if metadata['serviceId']
155
+
156
+ name = metadata['serviceAbbreviation'] || metadata['serviceFullName']
157
+ name = name.gsub(/AWS/, '').gsub(/Amazon/, '')
158
+ name = name.gsub(/[^a-zA-Z0-9 ]+/, '')
159
+ name = name.gsub(/^[0-9]+/, '')
160
+ name = name.strip
161
+
162
+ name
163
+ end
164
+
165
+ # @return [Boolean] true if the service is deprecated
166
+ def deprecated?
167
+ @deprecated
168
+ end
169
+
149
170
  # @api private
150
171
  def inspect
151
172
  "#<#{self.class.name}>"
@@ -24,10 +24,14 @@ module AwsSdkCodeGenerator
24
24
  @gem_version = options.fetch(:gem_version)
25
25
  @plugins = PluginList.new(options)
26
26
  @codegenerated_plugins = options.fetch(:codegenerated_plugins, [])
27
+ @default_plugins = Seahorse::Client::AsyncBase.plugins.map do |plugin|
28
+ PluginList::Plugin.new(class_name: plugin.name, options: plugin.options, path: '')
29
+ end
27
30
  @client_constructor = ClientConstructor.new(
28
31
  options.merge(
29
32
  plugins: @plugins,
30
- codegenerated_plugins: @codegenerated_plugins))
33
+ codegenerated_plugins: @codegenerated_plugins,
34
+ default_plugins: @default_plugins))
31
35
  @operations = ClientOperationList.new(options).to_a
32
36
  end
33
37
 
@@ -34,6 +34,8 @@ module AwsSdkCodeGenerator
34
34
  'union' => false, # should remain false
35
35
  'document' => true,
36
36
  'jsonvalue' => true,
37
+ 'error' => true, # parsing customized error code in query protocol
38
+ 'locationName' => true, # to recognize xmlName defined on shape
37
39
  # event stream modeling
38
40
  'event' => false,
39
41
  'eventstream' => false,
@@ -43,7 +45,7 @@ module AwsSdkCodeGenerator
43
45
  'synthetic' => false,
44
46
  'box' => false,
45
47
  'fault' => false,
46
- 'error' => false,
48
+ 'exception_event' => false, # internal, exceptions cannot be events
47
49
  'deprecated' => false,
48
50
  'deprecatedMessage' => false,
49
51
  'type' => false,
@@ -51,7 +53,6 @@ module AwsSdkCodeGenerator
51
53
  'members' => false,
52
54
  'member' => false,
53
55
  'key' => false,
54
- 'locationName' => false,
55
56
  'value' => false,
56
57
  'required' => false,
57
58
  'enum' => false,
@@ -70,9 +71,11 @@ module AwsSdkCodeGenerator
70
71
  # keep all
71
72
  'endpointPrefix' => true,
72
73
  'signatureVersion' => true,
74
+ 'auth' => true,
73
75
  'signingName' => true,
74
76
  'serviceFullName' => true,
75
77
  'protocol' => true,
78
+ 'protocols' => true,
76
79
  'targetPrefix' => true,
77
80
  'jsonVersion' => true,
78
81
  'errorPrefix' => true,
@@ -98,6 +101,7 @@ module AwsSdkCodeGenerator
98
101
  # @return [String|nil]
99
102
  def generated_src_warning
100
103
  return if @service.protocol == 'api-gateway'
104
+
101
105
  GENERATED_SRC_WARNING
102
106
  end
103
107
 
@@ -204,12 +208,18 @@ module AwsSdkCodeGenerator
204
208
  if operation.key?('httpChecksum')
205
209
  operation['httpChecksum']['requestAlgorithmMember'] = underscore(operation['httpChecksum']['requestAlgorithmMember']) if operation['httpChecksum']['requestAlgorithmMember']
206
210
  operation['httpChecksum']['requestValidationModeMember'] = underscore(operation['httpChecksum']['requestValidationModeMember']) if operation['httpChecksum']['requestValidationModeMember']
207
-
208
211
  o.http_checksum = operation['httpChecksum'].inject([]) do |a, (k, v)|
209
212
  a << { key: k.inspect, value: v.inspect }
210
213
  a
211
214
  end
212
215
  end
216
+
217
+ if operation.key?('requestcompression')
218
+ o.request_compression = operation['requestcompression'].each_with_object([]) do |(k, v), arr|
219
+ arr << { key: k.inspect, value: v.inspect }
220
+ end
221
+ end
222
+
213
223
  %w(input output).each do |key|
214
224
  if operation[key]
215
225
  o.shape_references << "o.#{key} = #{operation_ref(operation[key])}"
@@ -250,6 +260,7 @@ module AwsSdkCodeGenerator
250
260
 
251
261
  def apig_authorizer
252
262
  return nil unless @service.api.key? 'authorizers'
263
+
253
264
  @service.api['authorizers'].map do |name, authorizer|
254
265
  Authorizer.new.tap do |a|
255
266
  a.name = name
@@ -298,6 +309,9 @@ module AwsSdkCodeGenerator
298
309
  args << "name: '#{shape_name}'"
299
310
  shape.each_pair do |key, value|
300
311
  if SHAPE_KEYS[key]
312
+ # only query protocols have custom error code
313
+ next if @service.protocol != 'query' && key == 'error'
314
+
301
315
  args << "#{key}: #{value.inspect}"
302
316
  elsif SHAPE_KEYS[key].nil?
303
317
  raise "unhandled shape key #{key.inspect}"
@@ -491,8 +505,16 @@ module AwsSdkCodeGenerator
491
505
  options = {}
492
506
  metadata.each_pair do |key, value|
493
507
  next if key == 'resultWrapper'
508
+
494
509
  if key == 'locationName'
495
- options[:location_name] = value.inspect
510
+ options[:location_name] =
511
+ # use the xmlName on shape if defined
512
+ if (@service.protocol == 'rest-xml') &&
513
+ (shape_location_name = @service.api['shapes'][shape_name]['locationName'])
514
+ shape_location_name.inspect
515
+ else
516
+ value.inspect
517
+ end
496
518
  else
497
519
  options[:metadata] ||= {}
498
520
  options[:metadata][key] = value.inspect
@@ -551,6 +573,9 @@ module AwsSdkCodeGenerator
551
573
  # @return [Hash]
552
574
  attr_accessor :http_checksum
553
575
 
576
+ # @return [Hash]
577
+ attr_accessor :request_compression
578
+
554
579
  # @return [Array<String>]
555
580
  attr_accessor :shape_references
556
581
 
@@ -27,10 +27,14 @@ module AwsSdkCodeGenerator
27
27
  @gem_version = options.fetch(:gem_version)
28
28
  @plugins = PluginList.new(options)
29
29
  @codegenerated_plugins = options.fetch(:codegenerated_plugins, [])
30
+ @default_plugins = Seahorse::Client::Base.plugins.map do |plugin|
31
+ PluginList::Plugin.new(class_name: plugin.name, options: plugin.options, path: '')
32
+ end
30
33
  @client_constructor = ClientConstructor.new(
31
34
  options.merge(
32
35
  plugins: @plugins,
33
- codegenerated_plugins: @codegenerated_plugins))
36
+ codegenerated_plugins: @codegenerated_plugins,
37
+ default_plugins: @default_plugins))
34
38
  @operations = ClientOperationList.new(options).to_a
35
39
  @waiters = Waiter.build_list(options[:waiters])
36
40
  @custom = options.fetch(:custom)
@@ -26,8 +26,227 @@ module AwsSdkCodeGenerator
26
26
  @service.module_name
27
27
  end
28
28
 
29
- def endpoint_rules_encoded
30
- Base64.encode64(JSON.dump(@endpoint_rules))
29
+ def endpoint_rules_code
30
+ res = StringIO.new
31
+ # map parameters first
32
+ @endpoint_rules["parameters"].each do |k,_v|
33
+ res << indent("#{underscore(k)} = parameters.#{underscore(k)}\n", 3)
34
+ end
35
+
36
+ # map rules
37
+ @endpoint_rules["rules"].each do |rule|
38
+ case rule["type"]
39
+ when "endpoint"
40
+ res << endpoint_rule(rule, 3)
41
+ when "error"
42
+ res << error_rule(rule, 3)
43
+ when "tree"
44
+ res << tree_rule(rule, 3)
45
+ else
46
+ raise "Unknown rule type: #{rule['type']}"
47
+ end
48
+ end
49
+
50
+ # if no rules match, raise an error
51
+ res << indent("raise ArgumentError, 'No endpoint could be resolved'\n", 3)
52
+
53
+ res.string
54
+ end
55
+
56
+ private
57
+
58
+ def endpoint_rule(rule, levels=3)
59
+ res = StringIO.new
60
+ if rule['conditions'] && !rule['conditions'].empty?
61
+ res << conditions(rule['conditions'], levels)
62
+ res << endpoint(rule['endpoint'], levels+1)
63
+ res << indent("end\n", levels)
64
+ else
65
+ res << endpoint(rule['endpoint'], levels)
66
+ end
67
+ res.string
68
+ end
69
+
70
+ def endpoint(endpoint, levels)
71
+ res = StringIO.new
72
+ res << "return Aws::Endpoints::Endpoint.new(url: #{str(endpoint['url'])}"
73
+ if endpoint['headers']
74
+ res << ", headers: #{templated_hash_to_s(endpoint['headers'])}"
75
+ end
76
+ if endpoint['properties']
77
+ res << ", properties: #{templated_hash_to_s(endpoint['properties'])}"
78
+ end
79
+ res << ")\n"
80
+ indent(res.string, levels)
81
+ end
82
+
83
+ def templated_hash_to_s(hash)
84
+ template_hash_values(hash).to_s.gsub('\#{', '#{') # unescape references
85
+ end
86
+
87
+ def template_hash_values(hash)
88
+ hash.inject({}) { |h, (k, v)| h[k] = template_hash_value(v); h }
89
+ end
90
+
91
+ def template_hash_value(value)
92
+ case value
93
+ when Hash
94
+ template_hash_values(value)
95
+ when Array
96
+ value.map { |v| template_hash_value(v) }
97
+ when String
98
+ template_str(value, false)
99
+ else
100
+ value
101
+ end
102
+ end
103
+
104
+ def error_rule(rule, levels=3)
105
+ res = StringIO.new
106
+ if rule['conditions'] && !rule['conditions'].empty?
107
+ res << conditions(rule['conditions'], levels)
108
+ res << error(rule['error'], levels+1)
109
+ res << indent("end\n", levels)
110
+ else
111
+ res << error(rule['error'], levels)
112
+ end
113
+ res.string
114
+ end
115
+
116
+ def error(error, levels)
117
+ indent("raise ArgumentError, #{str(error)}\n", levels)
118
+ end
119
+
120
+ def tree_rule(rule, levels=3)
121
+ res = StringIO.new
122
+ if rule['conditions'] && !rule['conditions'].empty?
123
+ res << conditions(rule['conditions'], levels)
124
+ res << tree_rules(rule['rules'], levels+1)
125
+ res << indent("end\n", levels)
126
+ else
127
+ res << tree_rules(rule['rules'], levels)
128
+ end
129
+ res.string
130
+ end
131
+
132
+ def tree_rules(rules, levels)
133
+ res = StringIO.new
134
+ rules.each do |rule|
135
+ case rule["type"]
136
+ when "endpoint"
137
+ res << endpoint_rule(rule, levels)
138
+ when "error"
139
+ res << error_rule(rule, levels)
140
+ when "tree"
141
+ res << tree_rule(rule, levels)
142
+ else
143
+ raise "Unknown rule type: #{rule['type']}"
144
+ end
145
+ end
146
+ res.string
147
+ end
148
+
149
+ def conditions(conditions, level)
150
+ res = StringIO.new
151
+ cnd_str = conditions.map { |c| condition(c) }.join(" && ")
152
+ res << indent("if #{cnd_str}\n", level)
153
+ res.string
154
+ end
155
+
156
+ def condition(condition)
157
+ if condition['assign']
158
+ "(#{underscore(condition['assign'])} = #{fn(condition)})"
159
+ else
160
+ fn(condition)
161
+ end
162
+ end
163
+
164
+ def str(s)
165
+ if s.is_a?(Hash)
166
+ if s['ref']
167
+ underscore(s['ref'])
168
+ elsif s['fn']
169
+ fn(s)
170
+ else
171
+ raise "Unknown string type: #{s}"
172
+ end
173
+ else
174
+ template_str(s)
175
+ end
176
+ end
177
+
178
+ def template_str(string, wrap=true)
179
+ string.scan(/\{.+?\}/).each do |capture|
180
+ value = capture[1..-2] # strips curly brackets
181
+ string = string.gsub(capture, '#{' + template_replace(value) + '}')
182
+ end
183
+ string = string.gsub('"', '\"')
184
+ wrap ? "\"#{string}\"" : string
185
+ end
186
+
187
+ def template_replace(value)
188
+ indexes = value.split("#")
189
+ res = underscore(indexes.shift)
190
+ res += indexes.map do |index|
191
+ "['#{index}']"
192
+ end.join("")
193
+ res
194
+ end
195
+
196
+ def fn(fn)
197
+ args = fn['argv'].map {|arg| fn_arg(arg)}.join(", ")
198
+ "#{fn_name(fn['fn'])}(#{args})"
199
+ end
200
+
201
+ def fn_arg(arg)
202
+ if arg.is_a?(Hash)
203
+ if arg['ref']
204
+ underscore(arg['ref'])
205
+ elsif arg['fn']
206
+ fn(arg)
207
+ else
208
+ raise "Unexpected argument type: #{arg}"
209
+ end
210
+ elsif arg.is_a?(String)
211
+ template_str(arg)
212
+ else
213
+ arg
214
+ end
215
+ end
216
+
217
+ def fn_name(fn)
218
+ case fn
219
+ when 'isSet'
220
+ "Aws::Endpoints::Matchers.set?"
221
+ when 'not'
222
+ "Aws::Endpoints::Matchers.not"
223
+ when 'getAttr'
224
+ "Aws::Endpoints::Matchers.attr"
225
+ when 'substring'
226
+ "Aws::Endpoints::Matchers.substring"
227
+ when 'stringEquals'
228
+ "Aws::Endpoints::Matchers.string_equals?"
229
+ when 'booleanEquals'
230
+ "Aws::Endpoints::Matchers.boolean_equals?"
231
+ when 'uriEncode'
232
+ "Aws::Endpoints::Matchers.uri_encode"
233
+ when 'parseURL'
234
+ "Aws::Endpoints::Matchers.parse_url"
235
+ when 'isValidHostLabel'
236
+ "Aws::Endpoints::Matchers.valid_host_label?"
237
+ when 'aws.partition'
238
+ "Aws::Endpoints::Matchers.aws_partition"
239
+ when 'aws.parseArn'
240
+ "Aws::Endpoints::Matchers.aws_parse_arn"
241
+ when 'aws.isVirtualHostableS3Bucket'
242
+ "Aws::Endpoints::Matchers.aws_virtual_hostable_s3_bucket?"
243
+ else
244
+ raise "Function not found: #{@fn}"
245
+ end
246
+ end
247
+
248
+ def indent(s, levels=3)
249
+ (" " * levels) + s
31
250
  end
32
251
  end
33
252
  end
@@ -99,9 +99,15 @@ module AwsSdkCodeGenerator
99
99
  ).to_s
100
100
  end
101
101
  param_hash_str = Docstring.join_docstrings([option_tags], block_comment: false)
102
+ param_hash =
103
+ if param_hash_str.nil?
104
+ '# This event has no members'
105
+ else
106
+ Docstring.indent(param_hash_str, ' ')
107
+ end
102
108
  m << EventEntry.new(
103
109
  name: underscore(n),
104
- param_hash: Docstring.indent(param_hash_str, ' ')
110
+ param_hash: param_hash
105
111
  )
106
112
  m
107
113
  end