aws-sdk-resources 2.0.0.pre

Sign up to get free protection for your applications and to get access to all the features.
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,15 @@
1
+ module Aws
2
+ module Resources
3
+ module Errors
4
+
5
+ class UnknownOperationError < ArgumentError
6
+ def initialize(name)
7
+ super("operation `#{name}' not defined")
8
+ end
9
+ end
10
+
11
+ class DefinitionError < ArgumentError; end
12
+
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,53 @@
1
+ module Aws
2
+ module Resources
3
+ module OperationMethods
4
+
5
+ # @param [Symbol] name
6
+ # @return [Operation] Returns the named operation.
7
+ # @raise [Errors::UnknownOperationError]
8
+ def operation(name)
9
+ @operations[name.to_sym] or
10
+ raise Errors::UnknownOperationError.new(name)
11
+ end
12
+
13
+ # @param [Symbol] method_name
14
+ # @param [Operation] operation
15
+ # @return [void]
16
+ def add_operation(method_name, operation = nil, &definition)
17
+ operation = definition if block_given?
18
+ safe_define_method(method_name) do |*args, &block|
19
+ operation.call(resource:self, args:args, block:block)
20
+ end
21
+ @operations[method_name.to_sym] = operation
22
+ end
23
+
24
+ # @return [Hash]
25
+ def operations(&block)
26
+ @operations.dup
27
+ end
28
+
29
+ # @return [Array<Symbol>]
30
+ def operation_names
31
+ @operations.keys
32
+ end
33
+
34
+ # @api private
35
+ def inherited(subclass)
36
+ subclass.send(:instance_variable_set, "@operations", {})
37
+ end
38
+
39
+ private
40
+
41
+ def safe_define_method(method_name, &block)
42
+ if instance_methods.include?(method_name.to_sym)
43
+ msg = "unable to define method #{name}##{method_name}, "
44
+ msg << "method already exists"
45
+ raise Errors::DefinitionError, msg
46
+ else
47
+ define_method(method_name, &block)
48
+ end
49
+ end
50
+
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,294 @@
1
+ require 'jamespath'
2
+
3
+ module Aws
4
+ module Resources
5
+ module Operations
6
+
7
+ # Base class for operations. An operation is any object that responds
8
+ # to {#call} receiving a hash of options including:
9
+ #
10
+ # * `:resource` - The resource object the operation is invoked against.
11
+ # * `:args` - An array of arguments given by the caller
12
+ # * `:block` - An optional block argument
13
+ #
14
+ class Base
15
+
16
+ include Options
17
+
18
+ def initialize(options = {})
19
+ @source = options[:source]
20
+ end
21
+
22
+ # @return [Source, nil]
23
+ attr_reader :source
24
+
25
+ # @option options[required,Resource] :resource
26
+ # @option options[required,Array<Mixed>] :args
27
+ # @option options[Proc] :block
28
+ # @return [Mixed]
29
+ def call(options = {})
30
+ raise NotImplementedError
31
+ end
32
+
33
+ end
34
+
35
+ # Makes an API request using the resource client, returning the client
36
+ # response. Most operation classes extend this basic operation.
37
+ class Operation < Base
38
+
39
+ # @option options [required, Request] :request
40
+ def initialize(options = {})
41
+ @request = option(:request, options)
42
+ super
43
+ end
44
+
45
+ # @return [Request]
46
+ attr_reader :request
47
+
48
+ # @option (see Base#call)
49
+ # @return [Seahorse::Client::Response]
50
+ def call(options)
51
+ @request.call(options)
52
+ end
53
+
54
+ end
55
+
56
+ class DataOperation < Operation
57
+
58
+ # @option options [required, Request] :request
59
+ # @option options [required, String<JMESPath>] :path
60
+ def initialize(options = {})
61
+ @path = option(:path, options)
62
+ super
63
+ end
64
+
65
+ # @return [String<JMESPath>]
66
+ attr_reader :path
67
+
68
+ # @option (see Base#call)
69
+ # @return [Object] Returns the value resolved to by {#path}.
70
+ def call(options)
71
+ extract(super)
72
+ end
73
+
74
+ private
75
+
76
+ def extract(resp)
77
+ @path == '$' ? resp.data : Jamespath.search(@path, resp.data)
78
+ end
79
+
80
+ end
81
+
82
+ class EnumerateDataOperation < DataOperation
83
+
84
+ # @option options [required, Request] :request
85
+ # @option options [required, String<JMESPath>] :path
86
+ # @option options [Symbol] :limit_key
87
+ def initialize(options = {})
88
+ @limit_key = options[:limit_key]
89
+ super
90
+ end
91
+
92
+ # @option (see Base#call)
93
+ # @option options [Integer] :limit (nil)
94
+ # @return [Enumerator]
95
+ def call(options)
96
+ if options[:limit]
97
+ enum_for(:limited_each, options[:limit], options)
98
+ else
99
+ enum_for(:each, options)
100
+ end
101
+ end
102
+
103
+ private
104
+
105
+ def each(options, &block)
106
+ @request.call(options).each do |response|
107
+ extract(response).each(&block)
108
+ end
109
+ end
110
+
111
+ def limited_each(limit, options, &block)
112
+ yielded = 0
113
+ each(options) do |value|
114
+ yield(value)
115
+ yielded += 1
116
+ break if yielded == limit
117
+ end
118
+ end
119
+
120
+ end
121
+
122
+ class ResourceOperation < Operation
123
+
124
+ # @option options [required, Request] :request
125
+ # @option options [required, Builder] :builder
126
+ def initialize(options = {})
127
+ @builder = option(:builder, options)
128
+ super
129
+ end
130
+
131
+ # @return [Builder]
132
+ attr_reader :builder
133
+
134
+ # @option (see Base#call)
135
+ # @return [Resource, Array<Resource>]
136
+ def call(options)
137
+ @builder.build(options.merge(response:super))
138
+ end
139
+
140
+ end
141
+
142
+ class EnumerateResourceOperation < ResourceOperation
143
+
144
+ # @option options [required, Request] :request
145
+ # @option options [required, Builder] :builder
146
+ # @option options [Symbol] :limit_key
147
+ def initialize(options)
148
+ @limit_key = options[:limit_key]
149
+ super
150
+ end
151
+
152
+ # @return [Builder]
153
+ attr_reader :builder
154
+
155
+ # @return [Symbol, nil]
156
+ attr_reader :limit_key
157
+
158
+ # @option (see Base#call)
159
+ # @return [Collection]
160
+ def call(options)
161
+ Collection.new(self, options)
162
+ end
163
+
164
+ # @api private
165
+ # @return [Enumerator<Batch>]
166
+ def batches(options, &block)
167
+ if options[:limit]
168
+ enum_for(:limited_batches, options[:limit], options, &block)
169
+ else
170
+ enum_for(:all_batches, options, &block)
171
+ end
172
+ end
173
+
174
+ private
175
+
176
+ def all_batches(options, &block)
177
+ options = apply_batch_size(options)
178
+ @request.call(options).each do |response|
179
+ yield(@builder.build(options.merge(response:response)))
180
+ end
181
+ end
182
+
183
+ def limited_batches(limit, options, &block)
184
+ remaining = limit
185
+ all_batches(options) do |batch|
186
+ if batch.size < remaining
187
+ yield(batch)
188
+ remaining -= batch.size
189
+ else
190
+ yield(batch.first(remaining))
191
+ break
192
+ end
193
+ end
194
+ end
195
+
196
+ def apply_batch_size(options)
197
+ if batch_size = options[:batch_size]
198
+ params = (options[:params] || {}).merge(limit_key => batch_size)
199
+ options.merge(params: params)
200
+ else
201
+ options
202
+ end
203
+ end
204
+
205
+ end
206
+
207
+ class ReferenceOperation < Base
208
+
209
+ # @option options [required, Builder] :builder
210
+ def initialize(options = {})
211
+ @builder = option(:builder, options)
212
+ super
213
+ end
214
+
215
+ # @return [Builder]
216
+ attr_reader :builder
217
+
218
+ # @option (see Base#call)
219
+ # @return [Resource]
220
+ def call(options)
221
+ if argc(options) == arity
222
+ @builder.build(options)
223
+ else
224
+ msg = "wrong number of arguments (#{argc(options)} for #{arity})"
225
+ raise ArgumentError, msg
226
+ end
227
+ end
228
+
229
+ def arity
230
+ @builder.sources.count { |s| BuilderSources::Argument === s }
231
+ end
232
+
233
+ private
234
+
235
+ def argc(options)
236
+ (options[:args] || []).count
237
+ end
238
+
239
+ end
240
+
241
+ class WaiterOperation < Base
242
+
243
+ include Options
244
+
245
+ def initialize(options = {})
246
+ @waiter_name = option(:waiter_name, options)
247
+ @waiter_params = option(:waiter_params, options)
248
+ @path = options[:path]
249
+ super
250
+ end
251
+
252
+ # @return [Symbol]
253
+ attr_reader :waiter_name
254
+
255
+ # @return [Array<RequestParams::Base>]
256
+ attr_reader :waiter_params
257
+
258
+ # @return [String<JMESPathExpression>, nil]
259
+ attr_reader :path
260
+
261
+ # @option options [required,Resource] :resource
262
+ # @option options [required,Array<Mixed>] :args
263
+ def call(options, &block)
264
+
265
+ resource = options[:resource]
266
+
267
+ params_hash = {}
268
+ @waiter_params.each do |param|
269
+ param.apply(params_hash, options)
270
+ end
271
+
272
+ user_params = options[:params] || {}
273
+ params = deep_merge(user_params, params_hash)
274
+ resp = resource.client.wait_until(@waiter_name, params)
275
+
276
+ resource_opts = resource.identifiers.dup
277
+ resource_opts[:data] = Jamespath.search(@path, resp.data) if @path
278
+ resource_opts[:client] = resource.client
279
+ resource.class.new(resource_opts)
280
+ end
281
+
282
+ def deep_merge(obj1, obj2)
283
+ case obj1
284
+ when Hash then obj1.merge(obj2) { |key, v1, v2| deep_merge(v1, v2) }
285
+ when Array then obj2 + obj1
286
+ else obj2
287
+ end
288
+ end
289
+
290
+ end
291
+
292
+ end
293
+ end
294
+ end
@@ -0,0 +1,23 @@
1
+ module Aws
2
+ module Resources
3
+ module Options
4
+
5
+ private
6
+
7
+ def expect_hash(key, options)
8
+ if options.key?(key) && !(Hash === options[key])
9
+ raise ArgumentError, "expected #{key.inspect} to be a Hash"
10
+ end
11
+ end
12
+
13
+ def option(key, options)
14
+ if options[key].nil?
15
+ raise Errors::DefinitionError, "missing required option #{key.inspect}"
16
+ else
17
+ options[key]
18
+ end
19
+ end
20
+
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,39 @@
1
+ module Aws
2
+ module Resources
3
+ class Request
4
+
5
+ # @option opitons [requried, String] :method_name
6
+ # @option options [Array<RequestParams::Param>] :params ([]) A list of
7
+ # request params to apply to the request when called.
8
+ def initialize(options = {})
9
+ @method_name = options[:method_name]
10
+ @params = options[:params] || []
11
+ end
12
+
13
+ # @return [String] Name of the method called on the client when this
14
+ # operation is called.
15
+ attr_reader :method_name
16
+
17
+ # @return [Array<RequestParams::Param>]
18
+ attr_reader :params
19
+
20
+ # @option options [required,Resource] :resource
21
+ # @option options [Array<Mixed>] :args
22
+ # @return [Seahorse::Client::Response]
23
+ def call(options)
24
+ client(options).send(@method_name, req_params(options), &options[:block])
25
+ end
26
+
27
+ private
28
+
29
+ def client(options)
30
+ Array(options[:resource]).first.client
31
+ end
32
+
33
+ def req_params(options)
34
+ RequestParams::ParamsHash.new(@params).build(options)
35
+ end
36
+
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,225 @@
1
+ module Aws
2
+ module Resources
3
+ module RequestParams
4
+
5
+ # @api private
6
+ class ParamsHash
7
+
8
+ # @param [Array<RequestParams::Base>] params
9
+ def initialize(params)
10
+ @params = params
11
+ end
12
+
13
+ # @option options [required,Resource] :resource
14
+ # @option options [required,Array<Mixed>] :args
15
+ # @return [Hash]
16
+ def build(options = {})
17
+ deep_merge(user_params(options), computed_params(options))
18
+ end
19
+
20
+ private
21
+
22
+ def user_params(options)
23
+ args = options[:args] || []
24
+ args.last.is_a?(Hash) ? args.last : {}
25
+ end
26
+
27
+ def computed_params(options)
28
+ params_hash = {}
29
+ Array(options[:resource]).each do |resource|
30
+ @params.each do |param|
31
+ param.apply(params_hash, options.merge(resource: resource))
32
+ end
33
+ end
34
+ params_hash
35
+ end
36
+
37
+ def deep_merge(obj1, obj2)
38
+ case obj1
39
+ when Hash then obj1.merge(obj2) { |key, v1, v2| deep_merge(v1, v2) }
40
+ when Array then obj2 + obj1
41
+ else obj2
42
+ end
43
+ end
44
+
45
+ end
46
+
47
+ # Base class for all request parameter types.
48
+ # @see {RequestParams::Identifier}
49
+ # @see {RequestParams::DataMember}
50
+ # @see {RequestParams::String}
51
+ # @see {RequestParams::Integer}
52
+ class Base
53
+
54
+ # @param [String] target
55
+ def initialize(target)
56
+ @target = target.to_s
57
+ @steps = []
58
+ @target.scan(/\w+|\[\]/) do |step|
59
+ case step
60
+ when /\d+/ then @steps += [:array, step.to_i]
61
+ when '[]' then @steps += [:array, -1]
62
+ else @steps += [:hash, step.to_sym]
63
+ end
64
+ end
65
+ @steps.shift
66
+ @final = @steps.pop
67
+ end
68
+
69
+ # @return [String] target
70
+ attr_reader :target
71
+
72
+ # @param [Hash] params
73
+ # @param [Object] value
74
+ # @return [Hash] Returns the modified params hash.
75
+ def apply(params, value)
76
+ if @final == -1
77
+ build_context(params) << value
78
+ else
79
+ build_context(params)[@final] = value
80
+ end
81
+ params
82
+ end
83
+
84
+ private
85
+
86
+ def build_context(params)
87
+ @steps.each_slice(2).inject(params) do |context, (key, type)|
88
+ entry = type == :array ? [] : {}
89
+ if key == -1
90
+ context << entry
91
+ entry
92
+ else
93
+ context[key] ||= entry
94
+ end
95
+ end
96
+ end
97
+
98
+ end
99
+
100
+ class Identifier < Base
101
+
102
+ # @param [String] identifier_name
103
+ # @param (see Base#initialize)
104
+ def initialize(identifier_name, target)
105
+ @identifier_name = identifier_name.to_sym
106
+ super(target)
107
+ end
108
+
109
+ # @param [Symbol] identifier_name
110
+ attr_reader :identifier_name
111
+
112
+ # @param [Hash] params_hash
113
+ # @option [requried, Resource] :resource
114
+ def apply(params_hash, options)
115
+ value = options[:resource].identifiers[identifier_name]
116
+ super(params_hash, value)
117
+ end
118
+
119
+ # @api private
120
+ def self.literal?
121
+ false
122
+ end
123
+
124
+ end
125
+
126
+ class DataMember < Base
127
+
128
+ # @param [String] member_name
129
+ # @param (see Base#initialize)
130
+ def initialize(member_name, target)
131
+ @member_name = member_name
132
+ super(target)
133
+ end
134
+
135
+ # @return [String]
136
+ attr_reader :member_name
137
+
138
+ # @param [Hash] params_hash
139
+ # @option [requried, Resource] :resource
140
+ def apply(params_hash, options)
141
+ value = options[:resource].data[member_name.to_sym]
142
+ super(params_hash, value)
143
+ end
144
+
145
+ # @api private
146
+ def self.literal?
147
+ false
148
+ end
149
+
150
+ end
151
+
152
+ class String < Base
153
+
154
+ # @param [String] value
155
+ # @param (see Base#initialize)
156
+ def initialize(value, target)
157
+ @value = value
158
+ super(target)
159
+ end
160
+
161
+ # @return [String]
162
+ attr_reader :value
163
+
164
+ # @param [Hash] params_hash
165
+ def apply(params_hash, options = {})
166
+ super(params_hash, value)
167
+ end
168
+
169
+ # @api private
170
+ def self.literal?
171
+ true
172
+ end
173
+
174
+ end
175
+
176
+ class Integer < Base
177
+
178
+ # @param [String] value
179
+ # @param (see Base#initialize)
180
+ def initialize(value, target)
181
+ @value = value.to_i
182
+ super(target)
183
+ end
184
+
185
+ # @return [Integer]
186
+ attr_reader :value
187
+
188
+ # @param [Hash] params_hash
189
+ def apply(params_hash, options = {})
190
+ super(params_hash, value)
191
+ end
192
+
193
+ # @api private
194
+ def self.literal?
195
+ true
196
+ end
197
+
198
+ end
199
+
200
+ class Boolean < Base
201
+
202
+ # @param [String<'true'>,String<'false'>] value
203
+ # @param (see Base#initialize)
204
+ def initialize(value, target)
205
+ @value = (value == 'true')
206
+ super(target)
207
+ end
208
+
209
+ # @return [Integer]
210
+ attr_reader :value
211
+
212
+ # @param [Hash] params_hash
213
+ def apply(params_hash, options = {})
214
+ super(params_hash, value)
215
+ end
216
+
217
+ # @api private
218
+ def self.literal?
219
+ true
220
+ end
221
+
222
+ end
223
+ end
224
+ end
225
+ end