ECS 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +7 -0
- data/MIT-LICENSE +20 -0
- data/README +3 -0
- data/lib/ecs.rb +268 -0
- data/lib/ecs/help.rb +282 -0
- data/lib/ecs/help_response_group.rb +67 -0
- data/lib/ecs/operations.rb +39 -0
- data/lib/ecs/response_groups.rb +7 -0
- data/lib/ecs/time_management.rb +58 -0
- data/lib/libxml_additions.rb +51 -0
- data/lib/string_additions.rb +15 -0
- data/test/all_tests.rb +16 -0
- data/test/unit/ecs_test.rb +379 -0
- data/test/unit/libxml_additions_test.rb +121 -0
- data/test/unit/string_additions_test.rb +27 -0
- data/test/unit/unit_test_setup.rb +40 -0
- metadata +67 -0
data/CHANGELOG
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
0.1.0
|
2
|
+
* Initial release
|
3
|
+
* Forces ECS API version 2007-01-17
|
4
|
+
* Requires libxml-ruby (tested with libxml-ruby-0.3.8.4)
|
5
|
+
* The XML returned from ECS, when parsed into an XML::Document or XML::Node object (libxml-ruby-0.3.8.4)
|
6
|
+
breaks the find() method on both classes. If I strip the namespace, it works.
|
7
|
+
ECS.strip_namespace? governs this behavior.
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2007 Zachary Holt
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README
ADDED
data/lib/ecs.rb
ADDED
@@ -0,0 +1,268 @@
|
|
1
|
+
#!/usr/local/bin/ruby
|
2
|
+
|
3
|
+
dir = File::dirname( __FILE__ )
|
4
|
+
|
5
|
+
require 'rubygems'
|
6
|
+
require 'xml/libxml'
|
7
|
+
require 'digest/md5'
|
8
|
+
require 'net/http'
|
9
|
+
require 'erb'
|
10
|
+
|
11
|
+
module ECS
|
12
|
+
Dir[File.join( File.dirname( __FILE__ ), "*.rb" )].each { |f| require f }
|
13
|
+
|
14
|
+
require File.join( File.dirname( __FILE__ ), 'ecs', 'operations' )
|
15
|
+
require File.join( File.dirname( __FILE__ ), 'ecs', 'response_groups' )
|
16
|
+
require File.join( File.dirname( __FILE__ ), 'ecs', 'help' )
|
17
|
+
require File.join( File.dirname( __FILE__ ), 'ecs', 'help_response_group' )
|
18
|
+
require File.join( File.dirname( __FILE__ ), 'ecs', 'time_management' )
|
19
|
+
|
20
|
+
# [ 'help', 'help_response_group', 'operations', 'response_groups', 'time_management' ].each { |f| require( File.join( File.dirname( __FILE__ ), 'ecs', f ) ) }
|
21
|
+
# Dir[File.join( File.join( File.dirname( __FILE__ ), 'ecs' ), "*.rb" )].each { |f| require f }
|
22
|
+
# Dir[File.join( File.join( File.dirname( __FILE__ ), 'ecs', 'operation' ), "*.rb" )].each { |f| require f }
|
23
|
+
# Dir[File.join( File.join( File.dirname( __FILE__ ), 'ecs', 'response_group' ), "*.rb" )].each { |f| require f }
|
24
|
+
|
25
|
+
@@associate_id = 'limn-20'
|
26
|
+
@@access_key_id = ''
|
27
|
+
@@default_default_locale = :us
|
28
|
+
@@default_locale = @@default_default_locale
|
29
|
+
@@cache_directory = ''
|
30
|
+
@@cache = true
|
31
|
+
@@cache_suffix = 'ecs_cache'
|
32
|
+
|
33
|
+
# libxml-ruby is not able to do XML::Document#find or XML::Node#find with xml returned from Amazon.
|
34
|
+
# If you remove the namespace from the xml, it works perfectly
|
35
|
+
@@strip_namespace = true
|
36
|
+
|
37
|
+
def self.method_missing( meth, *args )
|
38
|
+
meth_s = meth.to_s
|
39
|
+
begin
|
40
|
+
klass_name = meth_s.camel_case
|
41
|
+
instance = nil
|
42
|
+
if meth_s =~ /^(.*)_response_group$/
|
43
|
+
instance = self.resolve_response_group_klass( klass_name )
|
44
|
+
else
|
45
|
+
klass = self.resolve_operation_klass( klass_name )
|
46
|
+
|
47
|
+
# string_to_eval = "#{klass_name}.new"
|
48
|
+
# puts "Now going to #{string_to_eval}"
|
49
|
+
instance = klass.new
|
50
|
+
# instance = instance_eval( string_to_eval, __FILE__, __LINE__ )
|
51
|
+
instance.parameters = *args
|
52
|
+
instance.parameters = {} unless instance.parameters.is_a?( Hash )
|
53
|
+
|
54
|
+
# If no ResponsGroup is set, then allow the defaults
|
55
|
+
unless instance.parameters[:ResponseGroup].nil?
|
56
|
+
# Otherwise, be sure :Request is included
|
57
|
+
instance.parameters[:ResponseGroup] = [instance.parameters[:ResponseGroup]] unless instance.parameters[:ResponseGroup].is_a?( Array )
|
58
|
+
instance.parameters[:ResponseGroup] << :Request unless instance.parameters[:ResponseGroup].include?( :Request ) || instance.parameters[:ResponseGroup].include?( 'Request' )
|
59
|
+
end
|
60
|
+
end
|
61
|
+
instance
|
62
|
+
rescue NameError => e
|
63
|
+
raise NameError, "#{e.message}"#Are you sure that ECS::#{klass_name} is defined?"
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
|
68
|
+
def self.associate_id
|
69
|
+
@@associate_id
|
70
|
+
end
|
71
|
+
def self.associate_id=( k )
|
72
|
+
@@associate_id = k.to_s
|
73
|
+
end
|
74
|
+
def self.access_key_id
|
75
|
+
@@access_key_id
|
76
|
+
end
|
77
|
+
def self.access_key_id=( i )
|
78
|
+
@@access_key_id = i.to_s
|
79
|
+
end
|
80
|
+
|
81
|
+
def self.default_locale
|
82
|
+
@@default_locale
|
83
|
+
end
|
84
|
+
def self.default_locale=( loc )
|
85
|
+
@@default_locale = self.resolve_locale( loc )
|
86
|
+
end
|
87
|
+
def self.reset_default_locale
|
88
|
+
@@default_locale = @@default_default_locale
|
89
|
+
end
|
90
|
+
|
91
|
+
def self.cache_directory
|
92
|
+
@@cache_directory
|
93
|
+
end
|
94
|
+
def self.cache_directory=( d='' )
|
95
|
+
directory = File.expand_path( d )
|
96
|
+
Dir.mkdir( directory ) unless File.exist?( directory )
|
97
|
+
raise( EACCESS, "#{directory} is not a suitable cache directory" ) unless File.writable?( directory ) && File.directory?( directory )
|
98
|
+
@@cache_directory = directory
|
99
|
+
end
|
100
|
+
|
101
|
+
|
102
|
+
def self.available_locales
|
103
|
+
[ :ca, :de, :fr, :jp, :uk, :us ]
|
104
|
+
end
|
105
|
+
|
106
|
+
def self.base_urls
|
107
|
+
{
|
108
|
+
:ca => 'http://webservices.amazon.ca/onca/xml?Service=AWSECommerceService',
|
109
|
+
:de => 'http://webservices.amazon.de/onca/xml?Service=AWSECommerceService',
|
110
|
+
:fr => 'http://webservices.amazon.fr/onca/xml?Service=AWSECommerceService',
|
111
|
+
:jp => 'http://webservices.amazon.co.jp/onca/xml?Service=AWSECommerceService',
|
112
|
+
:uk => 'http://webservices.amazon.co.uk/onca/xml?Service=AWSECommerceService',
|
113
|
+
:us => 'http://webservices.amazon.com/onca/xml?Service=AWSECommerceService'
|
114
|
+
}
|
115
|
+
end
|
116
|
+
|
117
|
+
|
118
|
+
def self.api_version
|
119
|
+
'2007-02-22'
|
120
|
+
end
|
121
|
+
|
122
|
+
def self.strip_namespace?
|
123
|
+
@@strip_namespace != false
|
124
|
+
end
|
125
|
+
def self.strip_namespace=( s )
|
126
|
+
@@strip_namespace = s != false
|
127
|
+
end
|
128
|
+
|
129
|
+
def self.call_web_service( p={} )
|
130
|
+
parameters = p.is_a?( Hash ) ? p : {}
|
131
|
+
|
132
|
+
locale = self.resolve_locale( parameters[:locale] )
|
133
|
+
parameters.delete( :locale )
|
134
|
+
|
135
|
+
sleep( ECS::TimeManagement.sleep_duration )
|
136
|
+
url = "#{ self.base_urls[locale] }&AWSAccessKeyId=#{self.access_key_id}&Version=#{self.api_version}&AssociateTag=#{self.associate_id}&#{ parameters.keys.map{ |k| "#{ERB::Util.url_encode( k.to_s ) }=#{ERB::Util.url_encode( parameters[k].is_a?( Array ) ? parameters[k].join( ',' ) : parameters[k].to_s )}" }.join( '&' ) }"
|
137
|
+
#puts url
|
138
|
+
r = Net::HTTP.get_response( URI.parse( url ) )
|
139
|
+
r.value # this will raise an error if there was one.
|
140
|
+
@@strip_namespace && r.body =~ /(.*)xmlns\s*=\s*".*?"(.*)/m ? "#{$1}#{$2}" : r.body
|
141
|
+
end
|
142
|
+
|
143
|
+
def self.resolve_locale( l=nil )
|
144
|
+
!l.nil? && self.available_locales.include?( l.to_s.downcase.to_sym ) ? l.to_s.downcase.to_sym : self.default_locale
|
145
|
+
end
|
146
|
+
|
147
|
+
def self.resolve_response_group_klass( name='' )
|
148
|
+
klass_name = ECS::HelpResponseGroup.resolve_response_group_name( name )
|
149
|
+
klass = ECS::ResponseGroups[klass_name]
|
150
|
+
if klass.nil?
|
151
|
+
string_to_eval = "class #{klass_name} < HelpResponseGroup
|
152
|
+
@@response_group_name=nil
|
153
|
+
@@valid_operations=nil
|
154
|
+
@@elements=nil
|
155
|
+
@@help_xml=nil
|
156
|
+
ECS::ResponseGroups['#{klass_name}'] = self
|
157
|
+
end
|
158
|
+
#{klass_name}"
|
159
|
+
#puts string_to_eval
|
160
|
+
klass = instance_eval( string_to_eval, __FILE__, __LINE__ )
|
161
|
+
end
|
162
|
+
klass
|
163
|
+
end
|
164
|
+
def self.resolve_operation_klass( name='' )
|
165
|
+
klass_name = ECS::Help.resolve_operation_name( name )
|
166
|
+
klass = ECS::Operations[klass_name]
|
167
|
+
if klass.nil?
|
168
|
+
string_to_eval = "class #{klass_name} < Help
|
169
|
+
@@operation_name=nil
|
170
|
+
@@help_xml=nil
|
171
|
+
@@required_parameters=nil
|
172
|
+
@@available_parameters=nil
|
173
|
+
@@default_response_groups=nil
|
174
|
+
@@available_response_groups=nil
|
175
|
+
ECS::Operations['#{klass_name}'] = self
|
176
|
+
end
|
177
|
+
#{klass_name}"
|
178
|
+
# puts string_to_eval
|
179
|
+
klass = instance_eval( string_to_eval, __FILE__, __LINE__ )
|
180
|
+
end
|
181
|
+
klass
|
182
|
+
end
|
183
|
+
|
184
|
+
def self.xml_for_parameters( parameters={}, force=false )
|
185
|
+
# if you pass a block to this method, the XML::Document object
|
186
|
+
# will be yielded (if it's not cached) and you will be able to return
|
187
|
+
# true to cache it or false to not cache it. The object is yielded
|
188
|
+
# regardless of the value of ECS.cache?
|
189
|
+
# In other words, ECS.cache? is respected only when there is no block
|
190
|
+
tag = self.resolve_cache_tag( parameters )
|
191
|
+
xml = nil
|
192
|
+
|
193
|
+
xml = self.read_cache( tag ) unless force
|
194
|
+
|
195
|
+
if xml.nil?
|
196
|
+
xml = self.call_web_service( parameters )
|
197
|
+
parser = XML::Parser.new
|
198
|
+
parser.string = xml
|
199
|
+
xml = parser.parse
|
200
|
+
we_should_cache = block_given? ? yield( xml ) : self.cache?
|
201
|
+
self.write_cache( tag, xml.to_s ) if we_should_cache
|
202
|
+
end
|
203
|
+
|
204
|
+
xml
|
205
|
+
end
|
206
|
+
|
207
|
+
def self.read_cache( tag_or_parameters )
|
208
|
+
tag = tag_or_parameters.is_a?( String ) ? tag_or_parameters : self.resolve_cache_tag( tag_or_parameters )
|
209
|
+
XML::Document.file( tag ) if File.exist?( tag )
|
210
|
+
end
|
211
|
+
def self.write_cache( tag_or_parameters, content )
|
212
|
+
tag = tag_or_parameters.is_a?( String ) ? tag_or_parameters : self.resolve_cache_tag( tag_or_parameters )
|
213
|
+
File.open( tag, 'w' ) { |f| f << content }
|
214
|
+
end
|
215
|
+
|
216
|
+
def self.clear_cache( tag=nil )
|
217
|
+
if tag.nil?
|
218
|
+
Dir[File.join( self.cache_directory, "*.#{@@cache_suffix}" )].each { |f| File.unlink( f ) }
|
219
|
+
else
|
220
|
+
File.unlink( tag )
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
def self.cache?
|
225
|
+
@@cache != false
|
226
|
+
end
|
227
|
+
def self.cache=( true_or_false=true )
|
228
|
+
@@cache = true_or_false != false
|
229
|
+
end
|
230
|
+
|
231
|
+
def self.cached?( p={} )
|
232
|
+
File.exist?( p.is_a?( String ) ? p : self.resolve_cache_tag( p ) )
|
233
|
+
end
|
234
|
+
|
235
|
+
|
236
|
+
def self.query_string( p={} )
|
237
|
+
( p.is_a?( Hash ) ? p : {} ).keys.map{ |k| k.to_s }.sort.map{ |k| "#{k}=#{p[k.to_sym]}" }.join( '&' )
|
238
|
+
end
|
239
|
+
|
240
|
+
def self.resolve_cache_tag( p={} )
|
241
|
+
"#{cache_directory}/#{Digest::MD5.hexdigest( p.is_a?( String ) ? p : query_string( p ) )}.#{@@cache_suffix}"
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
245
|
+
##At this point I can do
|
246
|
+
##
|
247
|
+
##b = ECS.browse_node_lookup( :BrowseNodeId => 43242 )
|
248
|
+
##
|
249
|
+
##and b is an object of class ECS::BrowseNodeLookup
|
250
|
+
##
|
251
|
+
##
|
252
|
+
##What I would like to be able to do is say
|
253
|
+
##
|
254
|
+
##1) b.results (or some such)
|
255
|
+
##
|
256
|
+
##and get either one ECS::BroseNodeInfo (which include ECS::ResponseGroup) object
|
257
|
+
##or an array of ECS::BrowseNodeInfo objects
|
258
|
+
##
|
259
|
+
##
|
260
|
+
##This should happen by
|
261
|
+
##
|
262
|
+
##2) Checking a @results instance variable
|
263
|
+
##
|
264
|
+
##3) If @results is null, parse and iterate over the xml, creating a ECS::BrowseNodeInfo object for each <BrowseNodeInfo> element
|
265
|
+
##
|
266
|
+
##4) If the xml is null, check the disk to see whether there is a cached version
|
267
|
+
##
|
268
|
+
##5) If there is no cached version, call the web service and get the xml, caching it when you are done with it
|
data/lib/ecs/help.rb
ADDED
@@ -0,0 +1,282 @@
|
|
1
|
+
#!/usr/local/bin/ruby
|
2
|
+
|
3
|
+
module ECS
|
4
|
+
class Help
|
5
|
+
instance_variable_set( '@operation_name', nil )
|
6
|
+
instance_variable_set( '@help_xml', nil )
|
7
|
+
instance_variable_set( '@required_parameters', nil )
|
8
|
+
instance_variable_set( '@available_parameters', nil )
|
9
|
+
instance_variable_set( '@default_response_groups', nil )
|
10
|
+
instance_variable_set( '@available_response_groups', nil )
|
11
|
+
|
12
|
+
|
13
|
+
@@help_map = {
|
14
|
+
:required_parameters => { :call_path => 'HelpResponse.Information.OperationInformation.RequiredParameters.Parameter' },
|
15
|
+
:available_parameters => { :call_path => 'HelpResponse.Information.OperationInformation.AvailableParameters.Parameter' },
|
16
|
+
:default_response_groups => { :call_path => 'HelpResponse.Information.OperationInformation.DefaultResponseGroups.ResponseGroup' },
|
17
|
+
:available_response_groups => { :call_path => 'HelpResponse.Information.OperationInformation.AvailableResponseGroups.ResponseGroup' }
|
18
|
+
}
|
19
|
+
|
20
|
+
attr_accessor :parameters, :xml
|
21
|
+
ECS::Operations['Help'] = self
|
22
|
+
|
23
|
+
def self.operation_name
|
24
|
+
@operation_name ||= self.resolve_operation_name( self.name )
|
25
|
+
end
|
26
|
+
def self.help_xml( force=false )
|
27
|
+
if force || @help_xml.nil?
|
28
|
+
@help_xml = ECS.help( :HelpType => 'Operation', :About => self.operation_name ) { |x| ECS::Help.valid_aws_response( x ) }.xml
|
29
|
+
end
|
30
|
+
@help_xml
|
31
|
+
end
|
32
|
+
|
33
|
+
|
34
|
+
def self.valid_aws_response?( x )
|
35
|
+
xml = x
|
36
|
+
unless x.is_a?( XML::Document )
|
37
|
+
p = XML::Parser.new
|
38
|
+
p.string = x
|
39
|
+
xml = p.parse
|
40
|
+
end
|
41
|
+
|
42
|
+
if self.errors_from_aws( xml ).empty?
|
43
|
+
n = xml.find( '//Request/IsValid' ).first
|
44
|
+
n.nil? || n.content.downcase != 'false'
|
45
|
+
else
|
46
|
+
false
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def self.errors_from_aws( x )
|
51
|
+
xml = x
|
52
|
+
unless x.is_a?( XML::Document )
|
53
|
+
p = XML::Parser.new
|
54
|
+
p.string = x
|
55
|
+
xml = p.parse
|
56
|
+
end
|
57
|
+
|
58
|
+
errors = []
|
59
|
+
xml.find( '//Errors/Error' ).each do |error_node|
|
60
|
+
begin
|
61
|
+
m = error_node.Message.content
|
62
|
+
c = error_node.Code.content.gsub( /[\.:\s,\-_]/, '' )
|
63
|
+
errors << RuntimeError.new( m )
|
64
|
+
rescue Exception => e
|
65
|
+
end
|
66
|
+
end
|
67
|
+
errors
|
68
|
+
end
|
69
|
+
|
70
|
+
|
71
|
+
def self.required_parameters( force=false )
|
72
|
+
if force || @required_parameters.nil?
|
73
|
+
@required_parameters = []
|
74
|
+
self.help_xml.HelpResponse.Information.OperationInformation.RequiredParameters.Parameter.each do |p|
|
75
|
+
@required_parameters << p.content.to_s.to_sym
|
76
|
+
end
|
77
|
+
end
|
78
|
+
@required_parameters
|
79
|
+
rescue
|
80
|
+
[]
|
81
|
+
end
|
82
|
+
def self.available_parameters( force=false )
|
83
|
+
if force || @available_parameters.nil?
|
84
|
+
@available_parameters = []
|
85
|
+
self.help_xml.HelpResponse.Information.OperationInformation.AvailableParameters.Parameter.each do |p|
|
86
|
+
@available_parameters << p.content.to_s.to_sym
|
87
|
+
end
|
88
|
+
end
|
89
|
+
@available_parameters
|
90
|
+
end
|
91
|
+
def self.optional_parameters( force=false )
|
92
|
+
self.available_parameters( force )
|
93
|
+
end
|
94
|
+
|
95
|
+
def self.default_response_groups( force=false )
|
96
|
+
if force || @default_response_groups.nil?
|
97
|
+
@default_response_groups = []
|
98
|
+
self.help_xml.HelpResponse.Information.OperationInformation.DefaultResponseGroups.ResponseGroup.each do |p|
|
99
|
+
@default_response_groups << ECS.resolve_response_group_klass( "#{p.content.to_s}ResponseGroup" )
|
100
|
+
end
|
101
|
+
end
|
102
|
+
@default_response_groups
|
103
|
+
end
|
104
|
+
def self.available_response_groups( force=false )
|
105
|
+
if force || @available_response_groups.nil?
|
106
|
+
@available_response_groups = []
|
107
|
+
self.help_xml.HelpResponse.Information.OperationInformation.AvailableResponseGroups.ResponseGroup.each do |p|
|
108
|
+
@available_response_groups << ECS.resolve_response_group_klass( "#{p.content.to_s}ResponseGroup" )
|
109
|
+
end
|
110
|
+
end
|
111
|
+
@available_response_groups
|
112
|
+
end
|
113
|
+
|
114
|
+
|
115
|
+
def self.resolve_operation_name( t )
|
116
|
+
t =~ /::([^:]*)$/ ? $1 : t
|
117
|
+
end
|
118
|
+
|
119
|
+
def operation_name
|
120
|
+
self.class.operation_name
|
121
|
+
end
|
122
|
+
|
123
|
+
def help_xml( force=false )
|
124
|
+
self.class.help_xml( force )
|
125
|
+
end
|
126
|
+
|
127
|
+
def xml( force=false )
|
128
|
+
if force || @xml.nil?
|
129
|
+
self.class.required_parameters.each do |p|
|
130
|
+
raise(
|
131
|
+
ArgumentError,
|
132
|
+
"#{p} is a required parameter for the #{ self.operation_name } operation"
|
133
|
+
) if !self.parameters.keys.include?( p.to_sym ) || self.parameters[p.to_sym].to_s.empty?
|
134
|
+
end
|
135
|
+
|
136
|
+
# Cache the xml only if it's a valid AWS Response
|
137
|
+
@xml = ECS.xml_for_parameters( self.parameters_for_xml ) { |x| ECS::Help.valid_aws_response?( x ) }
|
138
|
+
end
|
139
|
+
@xml
|
140
|
+
end
|
141
|
+
|
142
|
+
def parameters_for_xml
|
143
|
+
self.parameters.merge( :Operation => self.operation_name )
|
144
|
+
end
|
145
|
+
|
146
|
+
def cached?
|
147
|
+
ECS.cached?( self.parameters_for_xml )
|
148
|
+
end
|
149
|
+
|
150
|
+
def cached_content
|
151
|
+
ECS.read_cache( self.parameters_for_xml )
|
152
|
+
end
|
153
|
+
|
154
|
+
def headers( force=false )
|
155
|
+
if force || @headers.nil?
|
156
|
+
@headers = {}
|
157
|
+
self.xml.find( '//OperationRequest/HTTPHeaders/Header' ).each do |header|
|
158
|
+
name = ''
|
159
|
+
value = ''
|
160
|
+
header.each_attr do |attribute|
|
161
|
+
name = attribute.value.to_sym if attribute.name == 'Name'
|
162
|
+
value = attribute.value if attribute.name == 'Value'
|
163
|
+
end
|
164
|
+
@headers[name] = value
|
165
|
+
end
|
166
|
+
end
|
167
|
+
@headers
|
168
|
+
rescue
|
169
|
+
@headers = []
|
170
|
+
end
|
171
|
+
|
172
|
+
def request_id( force=false )
|
173
|
+
if force || @request_id.nil?
|
174
|
+
@request_id = self.xml.find( '//OperationRequest/RequestId' ).first.content
|
175
|
+
end
|
176
|
+
@request_id
|
177
|
+
rescue
|
178
|
+
@request_id = 'Could not determine request_id'
|
179
|
+
end
|
180
|
+
|
181
|
+
def arguments( force=false )
|
182
|
+
if force || @arguments.nil?
|
183
|
+
@arguments = {}
|
184
|
+
self.xml.find( '//OperationRequest/Arguments/Argument' ).each do |argument|
|
185
|
+
name = ''
|
186
|
+
value = ''
|
187
|
+
argument.each_attr do |attribute|
|
188
|
+
name = attribute.value.to_sym if attribute.name == 'Name'
|
189
|
+
value = attribute.value if attribute.name == 'Value'
|
190
|
+
end
|
191
|
+
@arguments[name] = value
|
192
|
+
end
|
193
|
+
end
|
194
|
+
@arguments
|
195
|
+
rescue
|
196
|
+
@arguments = {}
|
197
|
+
end
|
198
|
+
|
199
|
+
def request_processing_time( force=false )
|
200
|
+
if force || @request_processing_time.nil?
|
201
|
+
@request_processing_time = self.xml.find( '//OperationRequest/RequestProcessingTime' ).first.content.to_f
|
202
|
+
end
|
203
|
+
@request_processing_time
|
204
|
+
rescue
|
205
|
+
@request_processing_time = -1.0
|
206
|
+
end
|
207
|
+
|
208
|
+
def response_groups( force=false )
|
209
|
+
#these are the response groups that are included in this instance,
|
210
|
+
#not all those available to the class
|
211
|
+
if force || @response_groups.nil?
|
212
|
+
@response_groups = []
|
213
|
+
|
214
|
+
response_group_names = self.arguments[:ResponseGroup]
|
215
|
+
|
216
|
+
if response_group_names.nil?
|
217
|
+
@response_groups = self.class.default_response_groups
|
218
|
+
else
|
219
|
+
response_group_names.split( ',' ).each do |response_group_name|
|
220
|
+
@response_groups << ECS.resolve_response_group_klass( "#{response_group_name}ResponseGroup" )
|
221
|
+
end
|
222
|
+
end
|
223
|
+
end
|
224
|
+
@response_groups
|
225
|
+
end
|
226
|
+
|
227
|
+
def potential_elements( force=false )
|
228
|
+
if force || @potential_elements.nil?
|
229
|
+
@potential_elements = []
|
230
|
+
self.response_groups.each do |response_group|
|
231
|
+
@potential_elements << response_group.elements
|
232
|
+
end
|
233
|
+
@potential_elements.flatten!.uniq!
|
234
|
+
end
|
235
|
+
@potential_elements
|
236
|
+
end
|
237
|
+
|
238
|
+
def errors( force=false )
|
239
|
+
@errors = self.class.errors_from_aws( self.xml ) if force || @errors.nil?
|
240
|
+
@errors
|
241
|
+
end
|
242
|
+
|
243
|
+
def valid?( force=false )
|
244
|
+
@valid = self.class.valid_aws_response?( self.xml ) if force || @valid.nil?
|
245
|
+
@valid
|
246
|
+
end
|
247
|
+
|
248
|
+
|
249
|
+
def method_missing( meth, *args )
|
250
|
+
method_name = meth.to_s
|
251
|
+
|
252
|
+
# Note that if there is an element in the xml called each_*,
|
253
|
+
# in order to get to it, you can't pass a block
|
254
|
+
if method_name =~ /^each_(.*)$/ && block_given?
|
255
|
+
x = self.send( $1.to_sym, *args )
|
256
|
+
if [ Array, XML::Node::Set].include?( x.class )
|
257
|
+
x.each { |y| yield( y ) }
|
258
|
+
else
|
259
|
+
yield( x )
|
260
|
+
end
|
261
|
+
elsif method_name =~ /^(.*)_count$/
|
262
|
+
# Note that this will return the count for all descendants
|
263
|
+
# Not just children
|
264
|
+
x = self.send( $1.to_sym, *args )
|
265
|
+
x.respond_to?( :size ) ? x.size : 1
|
266
|
+
else
|
267
|
+
instance_variable_name = "@#{method_name}_var"
|
268
|
+
self.instance_eval( "
|
269
|
+
def #{method_name}( force=false )
|
270
|
+
if force || #{instance_variable_name}.nil?
|
271
|
+
#{instance_variable_name} = self.xml.find( '//#{method_name}' )
|
272
|
+
#{instance_variable_name} = #{instance_variable_name}.first if #{instance_variable_name}.size == 1
|
273
|
+
end
|
274
|
+
#{instance_variable_name}
|
275
|
+
end
|
276
|
+
" )
|
277
|
+
|
278
|
+
self.send( meth, *args )
|
279
|
+
end
|
280
|
+
end
|
281
|
+
end
|
282
|
+
end
|