aws-sdk-core 3.164.0 → 3.165.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +11 -0
  3. data/VERSION +1 -1
  4. data/lib/aws-sdk-core/arn.rb +13 -0
  5. data/lib/aws-sdk-core/binary/encode_handler.rb +12 -1
  6. data/lib/aws-sdk-core/endpoints/condition.rb +36 -0
  7. data/lib/aws-sdk-core/endpoints/endpoint.rb +17 -0
  8. data/lib/aws-sdk-core/endpoints/endpoint_rule.rb +71 -0
  9. data/lib/aws-sdk-core/endpoints/error_rule.rb +37 -0
  10. data/lib/aws-sdk-core/endpoints/function.rb +75 -0
  11. data/lib/aws-sdk-core/endpoints/matchers.rb +127 -0
  12. data/lib/aws-sdk-core/endpoints/reference.rb +26 -0
  13. data/lib/aws-sdk-core/endpoints/rule.rb +20 -0
  14. data/lib/aws-sdk-core/endpoints/rule_set.rb +47 -0
  15. data/lib/aws-sdk-core/endpoints/rules_provider.rb +32 -0
  16. data/lib/aws-sdk-core/endpoints/templater.rb +52 -0
  17. data/lib/aws-sdk-core/endpoints/tree_rule.rb +40 -0
  18. data/lib/aws-sdk-core/endpoints/url.rb +59 -0
  19. data/lib/aws-sdk-core/endpoints.rb +74 -0
  20. data/lib/aws-sdk-core/plugins/credentials_configuration.rb +24 -0
  21. data/lib/aws-sdk-core/plugins/endpoint_discovery.rb +6 -2
  22. data/lib/aws-sdk-core/plugins/regional_endpoint.rb +5 -0
  23. data/lib/aws-sdk-core/plugins/sign.rb +190 -0
  24. data/lib/aws-sdk-core/plugins/signature_v2.rb +1 -0
  25. data/lib/aws-sdk-core/plugins/signature_v4.rb +1 -0
  26. data/lib/aws-sdk-core/rest/request/headers.rb +2 -6
  27. data/lib/aws-sdk-core.rb +3 -0
  28. data/lib/aws-sdk-sso/client.rb +20 -3
  29. data/lib/aws-sdk-sso/endpoint_parameters.rb +66 -0
  30. data/lib/aws-sdk-sso/endpoint_provider.rb +112 -0
  31. data/lib/aws-sdk-sso/endpoints.rb +71 -0
  32. data/lib/aws-sdk-sso/plugins/endpoints.rb +76 -0
  33. data/lib/aws-sdk-sso.rb +5 -1
  34. data/lib/aws-sdk-ssooidc/client.rb +20 -3
  35. data/lib/aws-sdk-ssooidc/endpoint_parameters.rb +66 -0
  36. data/lib/aws-sdk-ssooidc/endpoint_provider.rb +111 -0
  37. data/lib/aws-sdk-ssooidc/endpoints.rb +57 -0
  38. data/lib/aws-sdk-ssooidc/plugins/endpoints.rb +74 -0
  39. data/lib/aws-sdk-ssooidc.rb +5 -1
  40. data/lib/aws-sdk-sts/client.rb +20 -3
  41. data/lib/aws-sdk-sts/endpoint_parameters.rb +78 -0
  42. data/lib/aws-sdk-sts/endpoint_provider.rb +229 -0
  43. data/lib/aws-sdk-sts/endpoints.rb +135 -0
  44. data/lib/aws-sdk-sts/plugins/endpoints.rb +84 -0
  45. data/lib/aws-sdk-sts/presigner.rb +13 -15
  46. data/lib/aws-sdk-sts.rb +5 -1
  47. data/lib/seahorse/client/async_base.rb +0 -1
  48. data/lib/seahorse/client/configuration.rb +2 -2
  49. data/lib/seahorse/util.rb +4 -0
  50. metadata +31 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 482759f78107adf12b6958c01d956f19d65c1c19057df86771f5374f1827ae89
4
- data.tar.gz: 99c3b116e86921582a7de105b0b6231cd6d9404c600ec3ccab8933b6078f1a87
3
+ metadata.gz: df67380b30b1758bb4301b6c2c267866a5e62b068111975c5331ac20fe6290a4
4
+ data.tar.gz: b91374a34d93f7d328f8820a2ba89c6384fbf4dfe6254be974fe4d0b492dbbdf
5
5
  SHA512:
6
- metadata.gz: 01dad2b5e6a1d7dd5995b297120a599ab3e2f707cf3616eb08feefb44ff9d1f3c878586a4b9b31ee0263a7780a23224093f78062125c58daffb1a3a3fd742dad
7
- data.tar.gz: 91c47a9849417a1a3848cd477f74b11bf232248f208d0b709a948cbb32735dfb583f58c66c12853d3933866db92325e7548ee5fd397e24260685bfe22ae8a6a9
6
+ metadata.gz: '0927312f09c93e40c158b18ac109c8bdee223aef6972868203d63cbd2120522367bc9448dc61f27cf445757ba9f5c00760122be8c469997b5b48fff19e2d9eeb'
7
+ data.tar.gz: 1a65436045eb469c4b1a18b3d7caa36be6659affb6e1dfd24dacf15587025585336bf0f8297f258f999471b2d1ed2f933e599230404fbd12ee6bc69bdc475ad7
data/CHANGELOG.md CHANGED
@@ -1,6 +1,15 @@
1
1
  Unreleased Changes
2
2
  ------------------
3
3
 
4
+ 3.165.0 (2022-10-25)
5
+ ------------------
6
+
7
+ * Feature - Updated Aws::SSOOIDC::Client with the latest API changes.
8
+
9
+ * Feature - Updated Aws::SSO::Client with the latest API changes.
10
+
11
+ * Feature - Add support for service gems to dynamically determine their own endpoints via modeling. Service gems now generate a plugin called "Endpoints" that defines configuration for EndpointProvider, a new public type, and any client config related to endpoints. Endpoint providers will resolve values using another new public type, Endpoint Parameters, generated for each service. The plugin will use the endpoint provider to resolve an endpoint and then apply it to the request prior to serialization. Endpoint providers can be composed to change endpoint resolution logic, i.e. for testing. In addition to endpoints, the endpoint provider may also override the authentication scheme (auth scheme) which details how the request should be signed for the endpoint. A new "Sign" plugin in core replaces the SignatureV4 plugin that will generically sign any type of auth scheme that a service might have.
12
+
4
13
  3.164.0 (2022-10-21)
5
14
  ------------------
6
15
 
@@ -153,6 +162,8 @@ Unreleased Changes
153
162
 
154
163
  * Feature - Updated Aws::SSO::Client with the latest API changes.
155
164
 
165
+ * Feature - Updated Aws::SSOOIDC::Client with the latest API changes.
166
+
156
167
  3.135.0 (2022-08-24)
157
168
  ------------------
158
169
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 3.164.0
1
+ 3.165.0
@@ -88,5 +88,18 @@ module Aws
88
88
  resource: @resource
89
89
  }
90
90
  end
91
+
92
+ # Return the ARN as JSON
93
+ #
94
+ # @return [Hash]
95
+ def as_json(_options = nil)
96
+ {
97
+ 'partition' => @partition,
98
+ 'service' => @service,
99
+ 'region' => @region,
100
+ 'accountId' => @account_id,
101
+ 'resource' => @resource
102
+ }
103
+ end
91
104
  end
92
105
  end
@@ -13,7 +13,7 @@ module Aws
13
13
  context.config.api.metadata['protocol'],
14
14
  eventstream_member,
15
15
  context.operation.input,
16
- context.config.sigv4_signer
16
+ signer_for(context)
17
17
  )
18
18
  context[:input_event_emitter] = input_es_handler.event_emitter
19
19
  end
@@ -22,6 +22,17 @@ module Aws
22
22
 
23
23
  private
24
24
 
25
+ def signer_for(context)
26
+ # New endpoint/signing logic, use the auth scheme to make a signer
27
+ if context[:auth_scheme]
28
+ Aws::Plugins::Sign.signer_for(context[:auth_scheme], context.config)
29
+ else
30
+ # Previous implementation always assumed sigv4_signer from config.
31
+ # Relies only on sigv4 signing (and plugin) for event stream services
32
+ context.config.sigv4_signer
33
+ end
34
+ end
35
+
25
36
  def eventstream_input?(ctx)
26
37
  ctx.operation.input.shape.members.each do |_, ref|
27
38
  return ref if ref.eventstream
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Aws
4
+ module Endpoints
5
+ # @api private
6
+ class Condition
7
+ def initialize(fn:, argv:, assign: nil)
8
+ @fn = Function.new(fn: fn, argv: argv)
9
+ @assign = assign
10
+ @assigned = {}
11
+ end
12
+
13
+ attr_reader :fn
14
+ attr_reader :argv
15
+ attr_reader :assign
16
+
17
+ attr_reader :assigned
18
+
19
+ def match?(parameters, assigns)
20
+ output = @fn.call(parameters, assigns)
21
+ @assigned = @assigned.merge({ @assign => output }) if @assign
22
+ output
23
+ end
24
+
25
+ def self.from_json(conditions_json)
26
+ conditions_json.each.with_object([]) do |condition, conditions|
27
+ conditions << new(
28
+ fn: condition['fn'],
29
+ argv: condition['argv'],
30
+ assign: condition['assign']
31
+ )
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Aws
4
+ module Endpoints
5
+ class Endpoint
6
+ def initialize(url:, properties: {}, headers: {})
7
+ @url = url
8
+ @properties = properties
9
+ @headers = headers
10
+ end
11
+
12
+ attr_reader :url
13
+ attr_reader :properties
14
+ attr_reader :headers
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,71 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Aws
4
+ module Endpoints
5
+ # @api private
6
+ class EndpointRule < Rule
7
+ def initialize(type: 'endpoint', conditions:, endpoint:,
8
+ documentation: nil)
9
+ @type = type
10
+ @conditions = Condition.from_json(conditions)
11
+ @endpoint = endpoint
12
+ @documentation = documentation
13
+ end
14
+
15
+ attr_reader :type
16
+ attr_reader :conditions
17
+ attr_reader :endpoint
18
+ attr_reader :documentation
19
+
20
+ def match(parameters, assigned = {})
21
+ assigns = assigned.dup
22
+ matched = conditions.all? do |condition|
23
+ output = condition.match?(parameters, assigns)
24
+ assigns = assigns.merge(condition.assigned) if condition.assign
25
+ output
26
+ end
27
+ resolved_endpoint(parameters, assigns) if matched
28
+ end
29
+
30
+ def resolved_endpoint(parameters, assigns)
31
+ Endpoint.new(
32
+ url: resolve_value(@endpoint['url'], parameters, assigns),
33
+ properties: resolve_properties(
34
+ @endpoint['properties'] || {},
35
+ parameters,
36
+ assigns
37
+ ),
38
+ headers: resolve_headers(parameters, assigns)
39
+ )
40
+ end
41
+
42
+ private
43
+
44
+ def resolve_headers(parameters, assigns)
45
+ (@endpoint['headers'] || {}).each.with_object({}) do |(key, arr), headers|
46
+ headers[key] = []
47
+ arr.each do |value|
48
+ headers[key] << resolve_value(value, parameters, assigns)
49
+ end
50
+ end
51
+ end
52
+
53
+ def resolve_properties(obj, parameters, assigns)
54
+ case obj
55
+ when Hash
56
+ obj.each.with_object({}) do |(key, value), hash|
57
+ hash[key] = resolve_properties(value, parameters, assigns)
58
+ end
59
+ when Array
60
+ obj.collect { |value| resolve_properties(value, parameters, assigns) }
61
+ else
62
+ if obj.is_a?(String)
63
+ Templater.resolve(obj, parameters, assigns)
64
+ else
65
+ obj
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Aws
4
+ module Endpoints
5
+ # @api private
6
+ class ErrorRule < Rule
7
+ def initialize(type: 'error', conditions:, error: nil, documentation: nil)
8
+ @type = type
9
+ @conditions = Condition.from_json(conditions)
10
+ @error = error
11
+ @documentation = documentation
12
+ end
13
+
14
+ attr_reader :type
15
+ attr_reader :conditions
16
+ attr_reader :error
17
+ attr_reader :documentation
18
+
19
+ def match(parameters, assigned = {})
20
+ assigns = assigned.dup
21
+ matched = conditions.all? do |condition|
22
+ output = condition.match?(parameters, assigns)
23
+ assigns = assigns.merge(condition.assigned) if condition.assign
24
+ output
25
+ end
26
+ resolved_error(parameters, assigns) if matched
27
+ end
28
+
29
+ private
30
+
31
+ def resolved_error(parameters, assigns)
32
+ error = resolve_value(@error, parameters, assigns)
33
+ ArgumentError.new(error)
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,75 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Aws
4
+ module Endpoints
5
+ # @api private
6
+ class Function
7
+ def initialize(fn:, argv:)
8
+ @fn = fn
9
+ @argv = build_argv(argv)
10
+ end
11
+
12
+ attr_reader :fn
13
+ attr_reader :argv
14
+
15
+ def call(parameters, assigns)
16
+ args = []
17
+ @argv.each do |arg|
18
+ if arg.is_a?(Reference)
19
+ args << arg.resolve(parameters, assigns)
20
+ elsif arg.is_a?(Function)
21
+ args << arg.call(parameters, assigns)
22
+ else
23
+ if arg.is_a?(String)
24
+ arg = Templater.resolve(arg, parameters, assigns)
25
+ end
26
+ args << arg
27
+ end
28
+ end
29
+
30
+ case @fn
31
+ when 'isSet'
32
+ Matchers.set?(*args)
33
+ when 'not'
34
+ Matchers.not(*args)
35
+ when 'getAttr'
36
+ Matchers.attr(*args)
37
+ when 'substring'
38
+ Matchers.substring(*args)
39
+ when 'stringEquals'
40
+ Matchers.string_equals?(*args)
41
+ when 'booleanEquals'
42
+ Matchers.boolean_equals?(*args)
43
+ when 'uriEncode'
44
+ Matchers.uri_encode(*args)
45
+ when 'parseURL'
46
+ Matchers.parse_url(*args)
47
+ when 'isValidHostLabel'
48
+ Matchers.valid_host_label?(*args)
49
+ when 'aws.partition'
50
+ Matchers.aws_partition(*args)
51
+ when 'aws.parseArn'
52
+ Matchers.aws_parse_arn(*args)
53
+ when 'aws.isVirtualHostableS3Bucket'
54
+ Matchers.aws_virtual_hostable_s3_bucket?(*args)
55
+ else
56
+ raise "Function not found: #{@fn}"
57
+ end
58
+ end
59
+
60
+ private
61
+
62
+ def build_argv(argv_json)
63
+ argv_json.each.with_object([]) do |arg, argv|
64
+ argv << if arg.is_a?(Hash) && arg['ref']
65
+ Reference.new(ref: arg['ref'])
66
+ elsif arg.is_a?(Hash) && arg['fn']
67
+ Function.new(fn: arg['fn'], argv: arg['argv'])
68
+ else
69
+ arg
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,127 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'cgi'
4
+
5
+ module Aws
6
+ module Endpoints
7
+ # generic matcher functions for service endpoints
8
+ # @api private
9
+ module Matchers
10
+ # Regex that extracts anything in square brackets
11
+ BRACKET_REGEX = /\[(.*?)\]/.freeze
12
+
13
+ # CORE
14
+
15
+ # isSet(value: Option<T>) bool
16
+ def self.set?(value)
17
+ !value.nil?
18
+ end
19
+
20
+ # not(value: bool) bool
21
+ def self.not(bool)
22
+ !bool
23
+ end
24
+
25
+ # getAttr(value: Object | Array, path: string) Document
26
+ def self.attr(value, path)
27
+ parts = path.split('.')
28
+
29
+ val = if (index = parts.first[BRACKET_REGEX, 1])
30
+ # remove brackets and index from part before indexing
31
+ value[parts.first.gsub(BRACKET_REGEX, '')][index.to_i]
32
+ else
33
+ value[parts.first]
34
+ end
35
+
36
+ if parts.size == 1
37
+ val
38
+ else
39
+ attr(val, parts.slice(1..-1).join('.'))
40
+ end
41
+ end
42
+
43
+ def self.substring(input, start, stop, reverse)
44
+ return nil if start >= stop || input.size < stop
45
+
46
+ return nil if input.chars.any? { |c| c.ord > 127 }
47
+
48
+ return input[start...stop] unless reverse
49
+
50
+ r_start = input.size - stop
51
+ r_stop = input.size - start
52
+ input[r_start...r_stop]
53
+ end
54
+
55
+ # stringEquals(value1: string, value2: string) bool
56
+ def self.string_equals?(value1, value2)
57
+ value1 == value2
58
+ end
59
+
60
+ # booleanEquals(value1: bool, value2: bool) bool
61
+ def self.boolean_equals?(value1, value2)
62
+ value1 == value2
63
+ end
64
+
65
+ # uriEncode(value: string) string
66
+ def self.uri_encode(value)
67
+ CGI.escape(value.encode('UTF-8')).gsub('+', '%20').gsub('%7E', '~')
68
+ end
69
+
70
+ # parseUrl(value: string) Option<URL>
71
+ def self.parse_url(value)
72
+ URL.new(value).as_json
73
+ rescue ArgumentError, URI::InvalidURIError
74
+ nil
75
+ end
76
+
77
+ # isValidHostLabel(value: string, allowSubDomains: bool) bool
78
+ def self.valid_host_label?(value, allow_sub_domains = false)
79
+ return false if value.empty?
80
+
81
+ if allow_sub_domains
82
+ labels = value.split('.')
83
+ return labels.all? { |l| valid_host_label?(l) }
84
+ end
85
+
86
+ value =~ /\A(?!-)[a-zA-Z0-9-]{1,63}(?<!-)\z/
87
+ end
88
+
89
+ # AWS
90
+
91
+ # aws.partition(value: string) Option<Partition>
92
+ def self.aws_partition(value)
93
+ partition =
94
+ Aws::Partitions.find { |p| p.region?(value) } ||
95
+ Aws::Partitions.find { |p| value.match(p.region_regex) } ||
96
+ Aws::Partitions.find { |p| p.name == 'aws' }
97
+
98
+ return nil unless partition
99
+
100
+ partition.metadata
101
+ end
102
+
103
+ # aws.parseArn(value: string) Option<ARN>
104
+ def self.aws_parse_arn(value)
105
+ arn = Aws::ARNParser.parse(value)
106
+ json = arn.as_json
107
+ # HACK: because of poor naming and also requirement of splitting
108
+ resource = json.delete('resource')
109
+ json['resourceId'] = resource.split(%r{[:\/]}, -1)
110
+ json
111
+ rescue Aws::Errors::InvalidARNError
112
+ nil
113
+ end
114
+
115
+ # aws.isVirtualHostableS3Bucket(value: string, allowSubDomains: bool) bool
116
+ def self.aws_virtual_hostable_s3_bucket?(value, allow_sub_domains = false)
117
+ !!(value.size < 64 &&
118
+ # regular naming rules
119
+ value =~ /^[a-z0-9][a-z0-9\-#{'.' if allow_sub_domains}]+[a-z0-9]$/ &&
120
+ # not IP address
121
+ value !~ /(\d+\.){3}\d+/ &&
122
+ # no dash and hyphen together
123
+ value !~ /[.-]{2}/)
124
+ end
125
+ end
126
+ end
127
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Aws
4
+ module Endpoints
5
+ # @api private
6
+ class Reference
7
+ def initialize(ref:)
8
+ @ref = ref
9
+ end
10
+
11
+ attr_reader :ref
12
+
13
+ def resolve(parameters, assigns)
14
+ if parameters.class.singleton_class::PARAM_MAP.key?(@ref)
15
+ member_name = parameters.class.singleton_class::PARAM_MAP[@ref]
16
+ parameters[member_name]
17
+ elsif assigns.key?(@ref)
18
+ assigns[@ref]
19
+ else
20
+ raise ArgumentError,
21
+ "Reference #{@ref} is not a param or an assigned value."
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Aws
4
+ module Endpoints
5
+ # @api private
6
+ class Rule
7
+ # Resolves a value that is a function, reference, or template string.
8
+ def resolve_value(value, parameters, assigns)
9
+ if value.is_a?(Hash) && value['fn']
10
+ Function.new(fn: value['fn'], argv: value['argv'])
11
+ .call(parameters, assigns)
12
+ elsif value.is_a?(Hash) && value['ref']
13
+ Reference.new(ref: value['ref']).resolve(parameters, assigns)
14
+ else
15
+ Templater.resolve(value, parameters, assigns)
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Aws
4
+ module Endpoints
5
+ # @api private
6
+ class RuleSet
7
+ def initialize(version:, service_id:, parameters:, rules:)
8
+ @version = version
9
+ @service_id = service_id
10
+ @parameters = parameters
11
+ @rules = RuleSet.rules_from_json(rules || [])
12
+ end
13
+
14
+ attr_reader :version
15
+ attr_reader :service_id
16
+ attr_reader :parameters
17
+ attr_reader :rules
18
+
19
+ def self.rules_from_json(rules_json)
20
+ rules_json.each.with_object([]) do |rule, rules|
21
+ if rule['type'] == 'endpoint'
22
+ rules << EndpointRule.new(
23
+ conditions: rule['conditions'],
24
+ endpoint: rule['endpoint'],
25
+ documentation: rule['documentation']
26
+ )
27
+ elsif rule['type'] == 'error'
28
+ rules << ErrorRule.new(
29
+ conditions: rule['conditions'],
30
+ error: rule['error'],
31
+ documentation: rule['documentation']
32
+ )
33
+ elsif rule['type'] == 'tree'
34
+ rules << TreeRule.new(
35
+ conditions: rule['conditions'],
36
+ rules: rule['rules'],
37
+ documentation: rule['documentation']
38
+ )
39
+ else
40
+ # should not happen
41
+ raise "Unknown endpoint rule type: #{rule}"
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,32 @@
1
+ module Aws
2
+ module Endpoints
3
+ # @api private
4
+ class RulesProvider
5
+ def initialize(rule_set)
6
+ @rule_set = rule_set
7
+ end
8
+
9
+ def resolve_endpoint(parameters)
10
+ obj = resolve_rules(parameters)
11
+ case obj
12
+ when Endpoint
13
+ obj
14
+ when ArgumentError
15
+ raise obj
16
+ else
17
+ raise ArgumentError, 'No endpoint could be resolved'
18
+ end
19
+ end
20
+
21
+ private
22
+
23
+ def resolve_rules(parameters)
24
+ @rule_set.rules.each do |rule|
25
+ output = rule.match(parameters)
26
+ return output if output
27
+ end
28
+ nil
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Aws
4
+ module Endpoints
5
+ # Does substitutions for templated endpoint strings
6
+ # @api private
7
+ module Templater
8
+ class << self
9
+ def resolve(string, parameters, assigns)
10
+ # scans for strings in curly brackets {}
11
+ string.scan(/\{.+?\}/).each do |capture|
12
+ value = capture[1..-2] # strips curly brackets
13
+ string = string.gsub(capture, replace(value, parameters, assigns))
14
+ end
15
+ string
16
+ end
17
+
18
+ private
19
+
20
+ # Replaces the captured value with values from parameters or assign
21
+ def replace(capture, parameters, assigns)
22
+ # Pound sigil is used for getAttr calls
23
+ indexes = capture.split('#')
24
+
25
+ # no sigil found, just do substitution
26
+ if indexes.size == 1
27
+ extract_value(capture, parameters, assigns)
28
+ # sigil was found, need to call getAttr
29
+ elsif indexes.size == 2
30
+ ref, property = indexes
31
+ param = extract_value(ref, parameters, assigns)
32
+ Matchers.attr(param, property)
33
+ else
34
+ raise "Invalid templatable value: #{capture}"
35
+ end
36
+ end
37
+
38
+ # Checks both parameters and assigns hash for the referenced value
39
+ def extract_value(key, parameters, assigns)
40
+ if assigns.key?(key)
41
+ assigns[key]
42
+ elsif parameters.class.singleton_class::PARAM_MAP.key?(key)
43
+ member_name = parameters.class.singleton_class::PARAM_MAP[key]
44
+ parameters[member_name]
45
+ else
46
+ raise "Templatable value not found: #{key}"
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Aws
4
+ module Endpoints
5
+ # @api private
6
+ class TreeRule
7
+ def initialize(type: 'tree', conditions:, rules:, documentation: nil)
8
+ @type = type
9
+ @conditions = Condition.from_json(conditions)
10
+ @rules = RuleSet.rules_from_json(rules)
11
+ @documentation = documentation
12
+ end
13
+
14
+ attr_reader :type
15
+ attr_reader :conditions
16
+ attr_reader :error
17
+ attr_reader :documentation
18
+
19
+ def match(parameters, assigned = {})
20
+ assigns = assigned.dup
21
+ matched = conditions.all? do |condition|
22
+ output = condition.match?(parameters, assigns)
23
+ assigns = assigns.merge(condition.assigned) if condition.assign
24
+ output
25
+ end
26
+ resolve_rules(parameters, assigns) if matched
27
+ end
28
+
29
+ private
30
+
31
+ def resolve_rules(parameters, assigns)
32
+ @rules.each do |rule|
33
+ output = rule.match(parameters, assigns)
34
+ return output if output
35
+ end
36
+ nil
37
+ end
38
+ end
39
+ end
40
+ end