aws_sdb_bare 1.2.0

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.
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ README.rdoc
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ LICENSE
data/.gitignore ADDED
@@ -0,0 +1,5 @@
1
+ *.sw?
2
+ .DS_Store
3
+ coverage
4
+ rdoc
5
+ pkg
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Paolo Negri
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.rdoc ADDED
@@ -0,0 +1,88 @@
1
+ = aws_sdb_bare
2
+
3
+ AwsSdb Bare is a ruby gem intended to provide a basic modular interface to use
4
+ the SimpleDB service provided by Amazon.
5
+
6
+ == Concept
7
+
8
+ The aim of the project is to not commit to any http handling strategy and to
9
+ not enforce any response parsing solution by default.
10
+
11
+ The idea behind this project is to provide a basic layer on top of which
12
+ more high level libraries can be built.
13
+
14
+ The library provides XML response parsing through Hpricot or Nokogiri to
15
+ run the test against a specific parser
16
+
17
+ rake nokogiri test
18
+
19
+ Or
20
+
21
+ rake hpricot test
22
+
23
+
24
+ == Project sources
25
+
26
+ the project is hosted on github http://github.com/hungryblank/aws_sdb_bare
27
+
28
+ blog posts explaining the usage can be found on http://assertbuggy.blogspot.com
29
+
30
+ == Support and bug tracking
31
+
32
+ issues can be posted on github http://github.com/hungryblank/aws_sdb_bare
33
+ forking and patch proposal throguh github are encouraged
34
+
35
+ == Installation
36
+
37
+ sudo gem install hungryblank-aws_sdb_bare -s http://gems.github.com
38
+
39
+ == Usage - Requests
40
+
41
+ The most basic primitive is the request, as a sample here's how a ListDomains
42
+ request is generated
43
+
44
+ require 'rubygems'
45
+ require 'aws_sdb_bare'
46
+
47
+ ENV['AMAZON_ACCESS_KEY_ID'] = 'your_amazon_access_key'
48
+ ENV['AMAZON_SECRET_ACCESS_KEY'] = 'your_amazon_secret'
49
+
50
+ #create the request object
51
+ request = AwsSdb::Request::Base.new('GET', 'Action' => 'ListDomains')
52
+
53
+ #using curl we can send the request as http get and print out the xml
54
+ #response with the domains under your account
55
+ puts `curl #{request.uri}`
56
+
57
+ The gem provides classes to create directly all the requests listed in
58
+ Amazon's 2007 11 07 specs so you can do
59
+
60
+ request = AwsSdb::Request::ListDomains.new
61
+
62
+ Instead of using the Base class like the previous example.
63
+
64
+ Please refer to the gem rdocs and to the amazon documentation to see
65
+ a list of all the available requests and their parameters
66
+
67
+ == Usage - Responses
68
+
69
+ To parse a response you simply call AwsSdb::Response.parse(xml_doc) example:
70
+
71
+ require 'open-uri'
72
+ require 'aws_sdb_bare'
73
+ #the following line could require nokogiri instead
74
+ require 'hpricot'
75
+
76
+ request = AwsSdb::Request::ListDomains.new
77
+ xml_response = open request.uri
78
+ response = AwsSdb::Response.parse(xml_response)
79
+ puts response.domains
80
+ puts response.metadata.box_usage
81
+
82
+ == Documentation
83
+
84
+ Rdoc are available at http://rdoc.elastastic.com/aws_sdb_bare
85
+
86
+ == Copyright
87
+
88
+ Copyright (c) 2009 Paolo Negri. See LICENSE for details.
data/Rakefile ADDED
@@ -0,0 +1,64 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "aws_sdb_bare"
8
+ gem.summary = %Q{Amazon AWS SDB SimpleDB client library, low level and http lib agnostic}
9
+ gem.email = "hungryblank@gmail.com"
10
+ gem.homepage = "http://github.com/hungryblank/aws_sdb_bare"
11
+ gem.authors = ["Paolo Negri"]
12
+
13
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
14
+ end
15
+ rescue LoadError
16
+ puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
17
+ end
18
+
19
+ require 'rake/testtask'
20
+ Rake::TestTask.new(:test) do |test|
21
+ test.libs << 'lib' << 'test'
22
+ test.pattern = 'test/**/*_test.rb'
23
+ test.verbose = true
24
+ end
25
+
26
+ begin
27
+ require 'rcov/rcovtask'
28
+ Rcov::RcovTask.new do |test|
29
+ test.libs << 'test'
30
+ test.pattern = 'test/**/*_test.rb'
31
+ test.verbose = true
32
+ end
33
+ rescue LoadError
34
+ task :rcov do
35
+ abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
36
+ end
37
+ end
38
+
39
+
40
+ task :default => :test
41
+
42
+ task :hpricot do
43
+ ENV['PARSER'] = 'hpricot'
44
+ end
45
+
46
+ task :nokogiri do
47
+ ENV['PARSER'] = 'nokogiri'
48
+ end
49
+
50
+ require 'rake/rdoctask'
51
+ Rake::RDocTask.new do |rdoc|
52
+ if File.exist?('VERSION.yml')
53
+ config = YAML.load(File.read('VERSION.yml'))
54
+ version = "#{config[:major]}.#{config[:minor]}.#{config[:patch]}"
55
+ else
56
+ version = ""
57
+ end
58
+
59
+ rdoc.rdoc_dir = 'rdoc'
60
+ rdoc.title = "aws_sdb_bare #{version}"
61
+ rdoc.rdoc_files.include('README*')
62
+ rdoc.rdoc_files.include('lib/**/*.rb')
63
+ end
64
+
data/VERSION.yml ADDED
@@ -0,0 +1,4 @@
1
+ ---
2
+ :patch: 0
3
+ :major: 1
4
+ :minor: 2
@@ -0,0 +1,58 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{aws_sdb_bare}
8
+ s.version = "1.2.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Paolo Negri"]
12
+ s.date = %q{2010-02-20}
13
+ s.email = %q{hungryblank@gmail.com}
14
+ s.extra_rdoc_files = [
15
+ "LICENSE",
16
+ "README.rdoc"
17
+ ]
18
+ s.files = [
19
+ ".document",
20
+ ".gitignore",
21
+ "LICENSE",
22
+ "README.rdoc",
23
+ "Rakefile",
24
+ "VERSION.yml",
25
+ "aws_sdb_bare.gemspec",
26
+ "lib/aws_sdb_bare.rb",
27
+ "lib/aws_sdb_bare/request.rb",
28
+ "lib/aws_sdb_bare/response.rb",
29
+ "test/aws_sdb_request_template_test.rb",
30
+ "test/aws_sdb_request_test.rb",
31
+ "test/aws_sdb_response_test.rb",
32
+ "test/samples/responses.rb",
33
+ "test/test_helper.rb"
34
+ ]
35
+ s.homepage = %q{http://github.com/hungryblank/aws_sdb_bare}
36
+ s.rdoc_options = ["--charset=UTF-8"]
37
+ s.require_paths = ["lib"]
38
+ s.rubygems_version = %q{1.3.5}
39
+ s.summary = %q{Amazon AWS SDB SimpleDB client library, low level and http lib agnostic}
40
+ s.test_files = [
41
+ "test/test_helper.rb",
42
+ "test/aws_sdb_request_test.rb",
43
+ "test/samples/responses.rb",
44
+ "test/aws_sdb_response_test.rb",
45
+ "test/aws_sdb_request_template_test.rb"
46
+ ]
47
+
48
+ if s.respond_to? :specification_version then
49
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
50
+ s.specification_version = 3
51
+
52
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
53
+ else
54
+ end
55
+ else
56
+ end
57
+ end
58
+
@@ -0,0 +1,318 @@
1
+ module AwsSdb
2
+
3
+ module Request
4
+
5
+ class Base
6
+
7
+ HOST = 'sdb.amazonaws.com'
8
+
9
+ attr_accessor :account, :secret, :params
10
+
11
+ def initialize(method, params, opts={})
12
+ @account = opts[:account] || ENV['AMAZON_ACCESS_KEY_ID']
13
+ @secret = opts[:secret] || ENV['AMAZON_SECRET_ACCESS_KEY']
14
+ raise <<-end_msg unless @account && @secret
15
+ Amazon AWS account or access key not defined
16
+ Please pass {:account => 'your account', :secret => 'your secret'}
17
+ as a last argument or define the following environment variables
18
+ ENV['AMAZON_ACCESS_KEY_ID']
19
+ ENV['AMAZON_SECRET_ACCESS_KEY']
20
+ end_msg
21
+ @method = method
22
+ @params = params
23
+ add_req_data_to_params
24
+ end
25
+
26
+ #Hostname for the request
27
+ def host
28
+ HOST
29
+ end
30
+
31
+ #Uri path
32
+ def path
33
+ '/'
34
+ end
35
+
36
+ #The full uri for the request, it takes the protocol as argument
37
+ def uri(protocol = 'http')
38
+ "#{protocol}://" + host + path + '?' + uri_query
39
+ end
40
+
41
+ #Only the query part of the uri
42
+ def uri_query
43
+ params_query + '&Signature=' + signature
44
+ end
45
+
46
+ alias :to_s :uri
47
+
48
+ private
49
+
50
+ def add_req_data_to_params
51
+ @params.update({'Version' => '2007-11-07',
52
+ 'SignatureVersion' => '2',
53
+ 'SignatureMethod' => 'HmacSHA256',
54
+ 'AWSAccessKeyId' => @account,
55
+ 'Timestamp' => Time.now.gmtime.iso8601})
56
+ end
57
+
58
+ def params_query
59
+ @params_query ||= @params.keys.sort.map do |key|
60
+ key + '=' + escape(@params[key].to_s)
61
+ end.join('&')
62
+ end
63
+
64
+ def data_to_sign
65
+ [@method, host, path, params_query].join("\n")
66
+ end
67
+
68
+ def signature
69
+ @signature ||= begin
70
+ digest = OpenSSL::Digest::Digest.new('sha256')
71
+ hmac = OpenSSL::HMAC.digest(digest, @secret, data_to_sign)
72
+ escape(Base64.encode64(hmac).strip)
73
+ end
74
+ end
75
+
76
+ def escape(string)
77
+ URI.escape(string, /[^-_.~a-zA-Z\d]/)
78
+ end
79
+
80
+ end
81
+
82
+ #Is the parent of all the request templates, defines some methods
83
+ class Template
84
+
85
+ class << self
86
+
87
+ #Generates method to allow shorter expressions in parameter
88
+ #definition takes an hash
89
+ #
90
+ # shortcuts({'LongUrlQueryParams' => :abbr})
91
+ #
92
+ #will cause :abbr params to be expanded in LongUrlQueryParams
93
+ def shortcuts(shortcuts_hash)
94
+ shortcuts_hash.each do |full_key, shortcut|
95
+ define_method("#{shortcut}=") do |value|
96
+ @params[full_key] = value
97
+ end
98
+ end
99
+ end
100
+
101
+ end
102
+
103
+ #takes the params for the request and an optional options hash
104
+ #params for the request are request specific, options accepted are only
105
+ #AWS credentials in form of
106
+ #
107
+ # {:account => 'your account', :secret => 'your secret'}
108
+ def initialize(params={}, opts={})
109
+ @params, @opts = params, opts
110
+ end
111
+
112
+ def token=(value)
113
+ @params['NextToken'] = value
114
+ end
115
+
116
+ def attributes=(attributes)
117
+ attributes.each_with_index do |attribute, index|
118
+ @params["AttributeName.#{index}"] = attribute.to_s
119
+ end
120
+ end
121
+
122
+ def request
123
+ expand!
124
+ @request ||= begin
125
+ Base.new('GET', @params.merge('Action' => self.class.to_s.split(':')[-1]), @opts)
126
+ end
127
+ end
128
+
129
+ [:to_s, :uri, :uri_query].each do |method|
130
+ define_method(method) do
131
+ request.send(method)
132
+ end
133
+ end
134
+
135
+ private
136
+
137
+ def expand!
138
+ @params.keys.each do |key|
139
+ send("#{key}=", @params.delete(key)) if respond_to?("#{key}=")
140
+ end
141
+ @params
142
+ end
143
+
144
+ end
145
+
146
+ #List the domains
147
+ #
148
+ # ListDomains.new({:max => 4}, {:account => 'account', :secret => 'secret'})
149
+ #
150
+ #Shortcut in params:
151
+ #
152
+ # :max - the maximum number of domain that can be returned
153
+ # :token - the token for follow up requests
154
+ class ListDomains < Template
155
+ shortcuts({'MaxNumberOfDomains' => :max})
156
+ end
157
+
158
+ #Creates a new domain
159
+ #
160
+ # CreateDomain.new({:name => 'my_domain'})
161
+ #
162
+ #Shortcut in params:
163
+ #
164
+ # :name - the name for the new domain
165
+ class CreateDomain < Template
166
+ shortcuts({'DomainName' => :name})
167
+ end
168
+
169
+ #Deletes a domain
170
+ #
171
+ # DeleteDomain.new({:name => 'my_domain'})
172
+ #
173
+ #Shortcut in params:
174
+ #
175
+ # :name - the name for domain
176
+ class DeleteDomain < Template
177
+ shortcuts({'DomainName' => :name})
178
+ end
179
+
180
+ #Provides informations for a domain
181
+ #
182
+ # DomainMetadata.new({:name => 'my_domain'})
183
+ #
184
+ #Shortcut in params:
185
+ #
186
+ # :name - the name for domain
187
+ class DomainMetadata < Template
188
+ shortcuts({'DomainName' => :name})
189
+ end
190
+
191
+ #Get the attributes for an item
192
+ #
193
+ # GetAttributes.new({:name => 'my_item', :attributes => [:first, :second]})
194
+ #
195
+ #Shortcut in params:
196
+ #
197
+ # :name - the item name
198
+ # :attributes - the list of the attributes to fetch, if not specified
199
+ # fetches all the attributes
200
+ class GetAttributes < Template
201
+ shortcuts({'ItemName' => :name, 'DomainName' => :domain})
202
+ end
203
+
204
+ #Add attributes to an item or create a new item whith the given attributes
205
+ #
206
+ # req = PutAttributes.new({:name => 'my_item'})
207
+ # req.attributes = {:color => :black, :shape => {:value => :square, :replace => true}}
208
+ #
209
+ #Note: in this request the value 'black' will be added to other color
210
+ #values if they already exist, while the shape value 'square' will replace
211
+ #pre existing values of shape
212
+ #the request, adding the :attributes to the params hash in the new method
213
+ #would have the same effect
214
+ #
215
+ #Note: in the sample above attributes are defined after initializing
216
+ #the request, adding the :attributes to the params hash in the new method
217
+ #would have the same effect
218
+ class PutAttributes < Template
219
+
220
+ attr_accessor :attributes
221
+
222
+ class << self
223
+
224
+ #multiple PutAttributes requests can be batched in one BatchPutAttributes
225
+ #just define the single PutAttributes and then pass them as args to
226
+ #the PutAttributes::batch method and you'll be returned the batched
227
+ #request.
228
+ #At the moment of writing the maximum number of requests you can batch
229
+ #are 25
230
+ def batch(*requests)
231
+ items_params = requests.map { |r| r.send(:expand!) }
232
+ first_request = requests.first.request
233
+ account = first_request.account
234
+ secret = first_request.secret
235
+ batch_params = {}
236
+ batch_params['DomainName'] ||= first_request.params['DomainName']
237
+ items_params.each_with_index do |params, index|
238
+ params.keys.each do |key|
239
+ batch_params["Item.#{index.to_s + '.' + key}"] = params[key] if key =~ /^ItemName|Attribute/
240
+ end
241
+ end
242
+ BatchPutAttributes.new(batch_params, {:account => account, :secret => secret})
243
+ end
244
+ end
245
+
246
+ shortcuts({'ItemName' => :name, 'DomainName' => :domain})
247
+
248
+ def expand_attributes!
249
+ index = 0
250
+ @attributes.keys.each do |attr_name|
251
+ replace = nil
252
+ values = case @attributes[attr_name]
253
+ when Hash
254
+ replace = @attributes[attr_name][:replace].to_s
255
+ @attributes[attr_name][:value].to_s
256
+ else
257
+ @attributes[attr_name].to_s
258
+ end
259
+ values = [values] unless values.is_a?(Array)
260
+ values.each do |value|
261
+ @params["Attribute.#{index}.Replace"] = replace if replace
262
+ @params["Attribute.#{index}.Name"] = attr_name.to_s
263
+ @params["Attribute.#{index}.Value"] = value
264
+ index += 1
265
+ end
266
+ end
267
+ end
268
+
269
+ private
270
+
271
+ def expand!
272
+ super
273
+ expand_attributes!
274
+ end
275
+
276
+ end
277
+
278
+ class BatchPutAttributes < Template
279
+ shortcuts({'DomainName' => :domain})
280
+ end
281
+
282
+ #delete some attributes from the given item, if no attributes
283
+ #are provided the whole item is deleted
284
+ #
285
+ # DeleteAttributes.new(:domain => 'test_domain', :name => 'item_1'
286
+ # :attributes => [:color, :shape])
287
+ class DeleteAttributes < Template
288
+ shortcuts({'ItemName' => :name, 'DomainName' => :domain})
289
+ end
290
+
291
+ #execute a select statement
292
+ # Select.new(:query => "SELECT * FROM test_domain")
293
+ class Select < Template
294
+ shortcuts({'SelectExpression' => :query})
295
+ end
296
+
297
+ #execute a query statement returns the array of the item names
298
+ #satisfying the statment
299
+ #
300
+ # Query.new(:domain => 'test_domain', :query => "['shape' = 'square']")
301
+ class Query < Template
302
+ shortcuts({'DomainName' => :domain,
303
+ 'QueryExpression' => :query,
304
+ 'MaxNumberOfItems' => :max})
305
+ end
306
+
307
+ #execute a query with attributes statement returns the items
308
+ #satisfying statement
309
+ #
310
+ # QueryWithAttributes.new(:domain => 'test_domain', :query => "['shape' = 'square']")
311
+ class QueryWithAttributes < Template
312
+ shortcuts({'DomainName' => :domain,
313
+ 'QueryExpression' => :query,
314
+ 'MaxNumberOfItems' => :max})
315
+ end
316
+ end
317
+
318
+ end
@@ -0,0 +1,163 @@
1
+ module AwsSdb
2
+
3
+ module Response
4
+
5
+ MEMBERS = {}
6
+
7
+ class UnknownResponse < ArgumentError
8
+ end
9
+
10
+ #returns an instance of the response, the class of the response is determined
11
+ #by the response content
12
+ def self.parse(doc)
13
+ @@parser ||= Hpricot if defined?(Hpricot)
14
+ @@parser ||= Nokogiri if defined?(Nokogiri)
15
+ parsed_doc = @@parser.XML(doc)
16
+ begin
17
+ MEMBERS[parsed_doc.root.name].new(parsed_doc)
18
+ rescue
19
+ raise UnknownResponse, "unkwonw response #{doc.inspect}"
20
+ end
21
+ end
22
+
23
+ module XmlUtils
24
+
25
+ private
26
+
27
+ def xml_attr_reader(*attributes)
28
+ attributes.each do |attr|
29
+ define_method(attr.gsub(/[A-Z]+/,'\1_\0').downcase[1..-1]) do
30
+ value = @doc.at(attr).inner_html
31
+ value = yield(value) if block_given?
32
+ value
33
+ end
34
+ end
35
+ end
36
+
37
+ end
38
+
39
+ class Base
40
+
41
+ class << self
42
+
43
+ def register
44
+ Response::MEMBERS[to_s.split(':').pop + 'Response'] = self
45
+ end
46
+
47
+ def has_items
48
+ define_method :items do
49
+ @items ||= begin
50
+ (@doc / 'Item').inject({}) do |items_hash, item|
51
+ items_hash[item.at('Name').inner_html] = attributes_hash(item)
52
+ items_hash
53
+ end
54
+ end
55
+ end
56
+ end
57
+
58
+ end
59
+
60
+ def initialize(doc)
61
+ @doc = doc
62
+ end
63
+
64
+ def metadata
65
+ @metadata ||= Metadata.new(@doc.at('ResponseMetadata'))
66
+ end
67
+
68
+ #the token to get the following chunk of response in case the response
69
+ #is broken in parts due to the size limit being exceeded
70
+ def token
71
+ if token_element = @doc.at('NextToken')
72
+ token_element.inner_html
73
+ end
74
+ end
75
+
76
+ private
77
+
78
+ def attributes_hash(element)
79
+ attr_hash = Hash.new() { |h, k| h[k] = [] }
80
+ (element / 'Attribute').each do |attribute|
81
+ attr_hash[attribute.at('Name').inner_html] << attribute.at('Value').inner_html
82
+ end
83
+ attr_hash
84
+ end
85
+
86
+ end
87
+
88
+ %w(BatchPutAttributesResponse)
89
+
90
+ class GetAttributes < Base
91
+
92
+ register
93
+
94
+ #hash of item attributes
95
+ def attributes
96
+ @attributes ||= attributes_hash(@doc)
97
+ end
98
+
99
+ end
100
+
101
+ class Select < Base
102
+ register
103
+ has_items
104
+ end
105
+
106
+ class QueryWithAttributes < Base
107
+ register
108
+ has_items
109
+ end
110
+
111
+ class Query < Base
112
+
113
+ register
114
+
115
+ def item_names
116
+ @items ||= (@doc / 'ItemName').map { |i| i.inner_html }
117
+ end
118
+
119
+ end
120
+
121
+ class ListDomains < Base
122
+
123
+ register
124
+
125
+ def domains
126
+ @domains ||= (@doc / 'DomainName').map { |d| d.inner_html }
127
+ end
128
+
129
+ end
130
+
131
+ class DomainMetadata < Base
132
+
133
+ extend XmlUtils
134
+ register
135
+ xml_attr_reader('ItemCount', 'ItemNamesSizeBytes', 'AttributeNameCount',
136
+ 'AttributeNamesSizeBytes', 'AttributeValueCount',
137
+ 'AttributeValuesSizeBytes', 'Timestamp') { |value| value.to_i }
138
+
139
+ end
140
+
141
+ %w(CreateDomain DeleteDomain PutAttributes BatchPutAttributes DeleteAttributes).each do |klass|
142
+ module_eval <<-eval_end
143
+ class #{klass} < Base
144
+ register
145
+ end
146
+ eval_end
147
+ end
148
+
149
+ class Metadata
150
+
151
+ extend XmlUtils
152
+
153
+ xml_attr_reader 'RequestId', 'BoxUsage'
154
+
155
+ def initialize(doc)
156
+ @doc = doc
157
+ end
158
+
159
+ end
160
+
161
+ end
162
+
163
+ end
@@ -0,0 +1,7 @@
1
+ require 'base64'
2
+ require 'time'
3
+ require 'uri'
4
+ require 'openssl'
5
+ Dir.glob(File.dirname(__FILE__) + '/aws_sdb_bare/**/*.rb').each do |lib|
6
+ require lib
7
+ end
@@ -0,0 +1,75 @@
1
+ require File.join(File.dirname(__FILE__), 'test_helper')
2
+
3
+ class AwsSdbRequestTemplateTest < Test::Unit::TestCase
4
+
5
+ include AwsSdb::Request
6
+
7
+ def setup
8
+ ENV['AMAZON_ACCESS_KEY_ID'] = 'a'
9
+ ENV['AMAZON_SECRET_ACCESS_KEY'] = 'a'
10
+ end
11
+
12
+ should "add the token using shortcut" do
13
+ req = Template.new({'a' => '1', :token => 'this_is_the_token'})
14
+ assert_attribute({'NextToken' => 'this_is_the_token'}, req.uri_query)
15
+ end
16
+
17
+ should "add attributes and number them" do
18
+ req = Template.new({'a' => 1, :attributes => [:attr_1, :attr_2]}, {:account => 'account', :secret => 'secret'})
19
+ assert_attribute({'AttributeName.0' => 'attr_1'}, req.uri_query)
20
+ assert_attribute({'AttributeName.1' => 'attr_2'}, req.uri_query)
21
+ end
22
+
23
+ should "generate all the parameters for a ListDomains" do
24
+ req = ListDomains.new({:max => 4}, {:account => 'account', :secret => 'secret'})
25
+ assert_attribute({'Action' => 'ListDomains'}, req.uri_query)
26
+ assert_attribute({'MaxNumberOfDomains' => '4'}, req.uri_query)
27
+ end
28
+
29
+ should "generate all the parameters for an CreateDomain" do
30
+ req = CreateDomain.new({:name => 'my_domain'}, {:account => 'account', :secret => 'secret'})
31
+ assert_attribute({'Action' => 'CreateDomain'}, req.uri_query)
32
+ assert_attribute({'DomainName' => 'my_domain'}, req.uri_query)
33
+ end
34
+
35
+ should "generate all the parameters for a DeleteDomain" do
36
+ req = DeleteDomain.new({:name => 'my_domain'}, {:account => 'account', :secret => 'secret'})
37
+ assert_attribute({'Action' => 'DeleteDomain'}, req.uri_query)
38
+ assert_attribute({'DomainName' => 'my_domain'}, req.uri_query)
39
+ end
40
+
41
+ should "generate all the parameters for a GetAttributes" do
42
+ req = GetAttributes.new({:name => 'my_item', :attributes => [:first, :second]}, {:account => 'account', :secret => 'secret'})
43
+ assert_attribute({'Action' => 'GetAttributes'}, req.uri_query)
44
+ assert_attribute({'ItemName' => 'my_item'}, req.uri_query)
45
+ end
46
+
47
+ should "generate all the parameters for a PutAttributes" do
48
+ req = PutAttributes.new({:name => 'my_domain', :name => 'my_item'},
49
+ {:account => 'account', :secret => 'secret'})
50
+ req.attributes = {:color => :black, :shape => {:value => :square, :replace => true}}
51
+ assert_attribute({'Action' => 'PutAttributes'}, req.uri_query)
52
+ assert_attribute({'ItemName' => 'my_item'}, req.uri_query)
53
+ shape_index = query_hash(req.uri_query)['Attribute.0.Name'] == 'shape' ? 0 : 1
54
+ assert_attribute({"Attribute.#{shape_index}.Name" => 'shape'}, req.uri_query)
55
+ assert_attribute({"Attribute.#{shape_index}.Value" => 'square'}, req.uri_query)
56
+ assert_attribute({"Attribute.#{shape_index}.Replace" => 'true'}, req.uri_query)
57
+ color_index = (shape_index - 1).abs
58
+ assert_attribute({"Attribute.#{color_index}.Name" => 'color'}, req.uri_query)
59
+ assert_attribute({"Attribute.#{color_index}.Value" => 'black'}, req.uri_query)
60
+ assert_attribute({"Attribute.#{color_index}.Replace" => nil}, req.uri_query)
61
+ end
62
+
63
+ should "generate all the parameters for a Select" do
64
+ req = Select.new({:query => 'Select * from my_domain'}, {:account => 'account', :secret => 'secret'})
65
+ assert_attribute({'Action' => 'Select'}, req.uri_query)
66
+ assert_attribute({'SelectExpression' => /^Select/}, req.uri_query)
67
+ end
68
+
69
+ should "generate all the parameters for a Query" do
70
+ req = Query.new({:query => "['Color' = 'blue']", :domain => 'my_domain', :max => 10 }, {:account => 'account', :secret => 'secret'})
71
+ assert_attribute({'Action' => 'Query'}, req.uri_query)
72
+ assert_attribute({'QueryExpression' => /Color.*blue/}, req.uri_query)
73
+ end
74
+
75
+ end
@@ -0,0 +1,45 @@
1
+ require File.join(File.dirname(__FILE__), 'test_helper')
2
+
3
+ class AwsSdbRequestTest < Test::Unit::TestCase
4
+
5
+ include AwsSdb::Request
6
+
7
+ def setup
8
+ ENV['AMAZON_ACCESS_KEY_ID'] = 'a'
9
+ ENV['AMAZON_SECRET_ACCESS_KEY'] = 'a'
10
+ end
11
+
12
+ should "prepend the verb and host to the params for signing" do
13
+ req = Base.new('GET', 'Action' => 'ListDomains')
14
+ assert_match /^GET\n#{AwsSdb::Request::Base::HOST}/, req.send(:data_to_sign)
15
+ end
16
+
17
+ should "build the query and sort alphabetically the parameters" do
18
+ req = Base.new('GET', 'b' => '2', 'x' => '1', 'a' => '1')
19
+ assert_match /a=1&b=2&x=1/, req.send(:params_query)
20
+ end
21
+
22
+ should "url encode the param values" do
23
+ safe_chars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_.~"
24
+ some_unsafe_chars = "+*!@£$%^&*()"
25
+ req = Base.new('GET', 'SafeChars' => safe_chars, 'UnsafeChars' => some_unsafe_chars)
26
+ assert_attribute({'SafeChars' => safe_chars}, req.send(:params_query))
27
+ assert_attribute({'UnsafeChars' => '%2B%2A%21%40%C2%A3%24%25%5E%26%2A%28%29'}, req.send(:params_query))
28
+ end
29
+
30
+ should "append the signature method to the request" do
31
+ req = Base.new('GET', {'a' => '1'}, {:account => 'account', :secret => 'secret'})
32
+ assert_match /&SignatureMethod=HmacSHA256&SignatureVersion=2/, req.uri_query
33
+ end
34
+
35
+ should "add the actual signature" do
36
+ req = Base.new('GET', {'a' => '1'}, {:account => 'account', :secret => 'secret'})
37
+ assert_attribute({'Signature' => /^[0-9a-zA-Z%]+$/}, req.uri_query)
38
+ end
39
+
40
+ should "build a correct uri" do
41
+ req = Base.new('GET', {'a' => '1'}, {:account => 'account', :secret => 'secret'})
42
+ assert URI.parse(req.uri)
43
+ end
44
+
45
+ end
@@ -0,0 +1,111 @@
1
+ require File.join(File.dirname(__FILE__), 'test_helper')
2
+ require File.join(File.dirname(__FILE__), 'samples/responses')
3
+
4
+ ENV['PARSER'] ||= 'hpricot'
5
+
6
+ require ENV['PARSER']
7
+
8
+ class AwsSdbRequestTest < Test::Unit::TestCase
9
+
10
+ include AwsSdb
11
+
12
+ context "parsing a GetAttributes" do
13
+
14
+ should "generate the attributes hash" do
15
+ response = Response.parse(SAMPLE_RESPONSES['GetAttributes'])
16
+ assert_same_elements ["20:45:22", "22:50:25", "22:51:06", "20:44:30", "20:44:19",
17
+ "22:50:55", "22:49:55", "20:30:08", "22:51:02"], response.attributes['last_visit']
18
+ assert_equal ['62'], response.attributes['code']
19
+ end
20
+
21
+ end
22
+
23
+ context "parsing a Select" do
24
+
25
+ should "generate the items hash" do
26
+ response = Response.parse(SAMPLE_RESPONSES['Select'])
27
+ assert_same_elements ["bar81", "bar83", "bar98", "my_entity5"], response.items.keys
28
+ end
29
+
30
+ should "generate the attributes for each item" do
31
+ response = Response.parse(SAMPLE_RESPONSES['Select'])
32
+ assert_equal({"code" => ["48"], "foo" => ["value"]}, response.items['bar98'])
33
+ end
34
+
35
+ end
36
+
37
+ context "parsing a Query" do
38
+
39
+ should "generate the item names array" do
40
+ response = Response.parse(SAMPLE_RESPONSES['Query'])
41
+ assert_same_elements ["bar81", "bar83", "bar98", "my_entity5"], response.item_names
42
+ end
43
+
44
+ end
45
+
46
+ context "parsing a QueryWithAttributes" do
47
+
48
+ should "generate the items hash" do
49
+ response = Response.parse(SAMPLE_RESPONSES['QueryWithAttributes'])
50
+ assert_equal({"code" => ["48"], "foo" => ["value"]}, response.items['bar98'])
51
+ end
52
+
53
+ end
54
+
55
+ context "parsing a response with token" do
56
+
57
+ should "find and return the token" do
58
+ response = Response.parse(SAMPLE_RESPONSES['ResWithToken'])
59
+ assert_equal "rO0ABXNyACdjb20uYW1hem9uLnNkcy5RdWVyeVByb2Nlc3Nvci5Nb3JlVG9rZW7racXLnINNqwMA\nCkkAFGluaXRpYWxDb25qdW5jdEluZGV4WgAOaXNQYWdlQm91bmRhcnlKAAxsYXN0RW50aXR5SURa\nAApscnFFbmFibGVkSQAPcXVlcnlDb21wbGV4aXR5SgATcXVlcnlTdHJpbmdDaGVja3N1bUkACnVu\naW9uSW5kZXhaAA11c2VRdWVyeUluZGV4TAASbGFzdEF0dHJpYnV0ZVZhbHVldAASTGphdmEvbGFu\nZy9TdHJpbmc7TAAJc29ydE9yZGVydAAvTGNvbS9hbWF6b24vc2RzL1F1ZXJ5UHJvY2Vzc29yL1F1\nZXJ5JFNvcnRPcmRlcjt4cAAAAAAATZbLYbTOwAAAAAAAAAAAAAArd5WtAAAAAAF0AAI0M35yAC1j\nb20uYW1hem9uLnNkcy5RdWVyeVByb2Nlc3Nvci5RdWVyeSRTb3J0T3JkZXIAAAAAAAAAABIAAHhy\nAA5qYXZhLmxhbmcuRW51bQAAAAAAAAAAEgAAeHB0AAlBU0NFTkRJTkd4", response.token
60
+ end
61
+
62
+ end
63
+
64
+ context "parsing ListDomains" do
65
+
66
+ should "return the list of domains" do
67
+ response = Response.parse(SAMPLE_RESPONSES['ListDomains'])
68
+ assert_same_elements ['myapp_development', 'myapp_production', 'myapp_test', 'test_domain'], response.domains
69
+ end
70
+ %w(ListDomains DomainMetadata)
71
+
72
+ end
73
+
74
+ context "parsing a request" do
75
+
76
+ should "return the metadata" do
77
+ response = Response.parse(SAMPLE_RESPONSES['ListDomains'])
78
+ assert_equal '0.0000071759', response.metadata.box_usage
79
+ end
80
+ %w(ListDomains DomainMetadata)
81
+
82
+ end
83
+
84
+ context "parsing DomainMetadata" do
85
+
86
+ should "provide direct acceess to attributes" do
87
+ response = Response.parse(SAMPLE_RESPONSES['DomainMetadata'])
88
+ assert_equal 282, response.item_count
89
+ assert_equal 7237, response.item_names_size_bytes
90
+ assert_equal 13, response.attribute_name_count
91
+ assert_equal 92, response.attribute_names_size_bytes
92
+ assert_equal 1095, response.attribute_value_count
93
+ assert_equal 5689, response.attribute_values_size_bytes
94
+ assert_equal 1241131496, response.timestamp
95
+ end
96
+
97
+ end
98
+
99
+ context "parsing simple responses" do
100
+
101
+ %w(CreateDomain DeleteDomain PutAttributes BatchPutAttributes DeleteAttributes).each do |simple_request|
102
+
103
+ should "recognize #{simple_request}" do
104
+ assert_nothing_raised { Response.parse(SAMPLE_RESPONSES[simple_request]) }
105
+ end
106
+
107
+ end
108
+
109
+ end
110
+
111
+ end
@@ -0,0 +1,27 @@
1
+ SAMPLE_RESPONSES = {
2
+ 'GetAttributes' =>
3
+ "<?xml version=\"1.0\"?>\n<GetAttributesResponse xmlns=\"http://sdb.amazonaws.com/doc/2007-11-07/\"><GetAttributesResult><Attribute><Name>code</Name><Value>62</Value></Attribute><Attribute><Name>last_visit</Name><Value>20:30:08</Value></Attribute><Attribute><Name>last_visit</Name><Value>20:44:19</Value></Attribute><Attribute><Name>last_visit</Name><Value>20:44:30</Value></Attribute><Attribute><Name>last_visit</Name><Value>20:45:22</Value></Attribute><Attribute><Name>last_visit</Name><Value>22:49:55</Value></Attribute><Attribute><Name>last_visit</Name><Value>22:50:25</Value></Attribute><Attribute><Name>last_visit</Name><Value>22:50:55</Value></Attribute><Attribute><Name>last_visit</Name><Value>22:51:02</Value></Attribute><Attribute><Name>last_visit</Name><Value>22:51:06</Value></Attribute></GetAttributesResult><ResponseMetadata><RequestId>0d5da91d-e2c4-1de0-7106-cc1d08bf0e8f</RequestId><BoxUsage>0.0000093282</BoxUsage></ResponseMetadata></GetAttributesResponse>",
4
+ 'Select' =>
5
+ "<?xml version=\"1.0\"?>\n<SelectResponse xmlns=\"http://sdb.amazonaws.com/doc/2007-11-07/\"><SelectResult><Item><Name>my_entity5</Name><Attribute><Name>last_visit</Name><Value>12:58:53</Value></Attribute><Attribute><Name>last_visit</Name><Value>13:13:05</Value></Attribute><Attribute><Name>last_visit</Name><Value>13:13:22</Value></Attribute><Attribute><Name>last_visit</Name><Value>21:45:29</Value></Attribute><Attribute><Name>last_visit</Name><Value>22:11:18</Value></Attribute><Attribute><Name>code</Name><Value>16</Value></Attribute></Item><Item><Name>bar83</Name><Attribute><Name>code</Name><Value>43</Value></Attribute></Item><Item><Name>bar81</Name><Attribute><Name>foo</Name><Value>value</Value></Attribute><Attribute><Name>code</Name><Value>44</Value></Attribute></Item><Item><Name>bar98</Name><Attribute><Name>foo</Name><Value>value</Value></Attribute><Attribute><Name>code</Name><Value>48</Value></Attribute></Item></SelectResult><ResponseMetadata><RequestId>0201e630-dea7-8c4e-88ad-d76cc297388c</RequestId><BoxUsage>0.0000503747</BoxUsage></ResponseMetadata></SelectResponse>",
6
+ 'Query' =>
7
+ "<?xml version=\"1.0\"?>\n<QueryResponse xmlns=\"http://sdb.amazonaws.com/doc/2007-11-07/\"><QueryResult><ItemName>my_entity5</ItemName><ItemName>bar83</ItemName><ItemName>bar81</ItemName><ItemName>bar98</ItemName></QueryResult><ResponseMetadata><RequestId>48de733e-b08d-7aeb-b855-e08e376da538</RequestId><BoxUsage>0.0000140320</BoxUsage></ResponseMetadata></QueryResponse>",
8
+ 'QueryWithAttributes' =>
9
+ "<?xml version=\"1.0\"?>\n<QueryWithAttributesResponse xmlns=\"http://sdb.amazonaws.com/doc/2007-11-07/\"><QueryWithAttributesResult><Item><Name>my_entity5</Name><Attribute><Name>last_visit</Name><Value>12:58:53</Value></Attribute><Attribute><Name>last_visit</Name><Value>13:13:05</Value></Attribute><Attribute><Name>last_visit</Name><Value>13:13:22</Value></Attribute><Attribute><Name>last_visit</Name><Value>21:45:29</Value></Attribute><Attribute><Name>last_visit</Name><Value>22:11:18</Value></Attribute><Attribute><Name>code</Name><Value>16</Value></Attribute></Item><Item><Name>bar83</Name><Attribute><Name>code</Name><Value>43</Value></Attribute></Item><Item><Name>bar81</Name><Attribute><Name>foo</Name><Value>value</Value></Attribute><Attribute><Name>code</Name><Value>44</Value></Attribute></Item><Item><Name>bar98</Name><Attribute><Name>foo</Name><Value>value</Value></Attribute><Attribute><Name>code</Name><Value>48</Value></Attribute></Item></QueryWithAttributesResult><ResponseMetadata><RequestId>d849662b-b02b-f0b8-45d2-e13685d10026</RequestId><BoxUsage>0.0000503747</BoxUsage></ResponseMetadata></QueryWithAttributesResponse>",
10
+ 'CreateDomain' =>
11
+ "<?xml version=\"1.0\"?>\n<CreateDomainResponse xmlns=\"http://sdb.amazonaws.com/doc/2007-11-07/\"><ResponseMetadata><RequestId>606100ad-9b94-9e55-09f5-21de864591f2</RequestId><BoxUsage>0.0055590278</BoxUsage></ResponseMetadata></CreateDomainResponse>",
12
+ 'DeleteDomain' =>
13
+ "<?xml version=\"1.0\"?>\n<DeleteDomainResponse xmlns=\"http://sdb.amazonaws.com/doc/2007-11-07/\"><ResponseMetadata><RequestId>ba116912-8684-41fd-b60f-87dda3a6d301</RequestId><BoxUsage>0.0055590278</BoxUsage></ResponseMetadata></DeleteDomainResponse>",
14
+ 'PutAttributes' =>
15
+ "<?xml version=\"1.0\"?>\n<PutAttributesResponse xmlns=\"http://sdb.amazonaws.com/doc/2007-11-07/\"><ResponseMetadata><RequestId>9583937f-4127-20c8-d34c-bd44a676afad</RequestId><BoxUsage>0.0000219923</BoxUsage></ResponseMetadata></PutAttributesResponse>",
16
+ 'BatchPutAttributes' =>
17
+ "<?xml version=\"1.0\"?>\n<BatchPutAttributesResponse xmlns=\"http://sdb.amazonaws.com/doc/2007-11-07/\"><ResponseMetadata><RequestId>ab252f42-e5f5-dca5-9aa9-f695cc1fb113</RequestId><BoxUsage>0.0000307892</BoxUsage></ResponseMetadata></BatchPutAttributesResponse>",
18
+ 'DeleteAttributes' =>
19
+ "<?xml version=\"1.0\"?>\n<DeleteAttributesResponse xmlns=\"http://sdb.amazonaws.com/doc/2007-11-07/\"><ResponseMetadata><RequestId>cafe7877-cc29-8c41-fa68-f14101665b3a</RequestId><BoxUsage>0.0000219907</BoxUsage></ResponseMetadata></DeleteAttributesResponse>",
20
+ 'ResWithToken' =>
21
+ "<?xml version=\"1.0\"?>\n<QueryWithAttributesResponse xmlns=\"http://sdb.amazonaws.com/doc/2007-11-07/\"><QueryWithAttributesResult><Item><Name>bar83</Name><Attribute><Name>code</Name><Value>43</Value></Attribute></Item><NextToken>rO0ABXNyACdjb20uYW1hem9uLnNkcy5RdWVyeVByb2Nlc3Nvci5Nb3JlVG9rZW7racXLnINNqwMA\nCkkAFGluaXRpYWxDb25qdW5jdEluZGV4WgAOaXNQYWdlQm91bmRhcnlKAAxsYXN0RW50aXR5SURa\nAApscnFFbmFibGVkSQAPcXVlcnlDb21wbGV4aXR5SgATcXVlcnlTdHJpbmdDaGVja3N1bUkACnVu\naW9uSW5kZXhaAA11c2VRdWVyeUluZGV4TAASbGFzdEF0dHJpYnV0ZVZhbHVldAASTGphdmEvbGFu\nZy9TdHJpbmc7TAAJc29ydE9yZGVydAAvTGNvbS9hbWF6b24vc2RzL1F1ZXJ5UHJvY2Vzc29yL1F1\nZXJ5JFNvcnRPcmRlcjt4cAAAAAAATZbLYbTOwAAAAAAAAAAAAAArd5WtAAAAAAF0AAI0M35yAC1j\nb20uYW1hem9uLnNkcy5RdWVyeVByb2Nlc3Nvci5RdWVyeSRTb3J0T3JkZXIAAAAAAAAAABIAAHhy\nAA5qYXZhLmxhbmcuRW51bQAAAAAAAAAAEgAAeHB0AAlBU0NFTkRJTkd4</NextToken></QueryWithAttributesResult><ResponseMetadata><RequestId>5f1cd665-843a-17df-bb07-8c3a3bbbcbdd</RequestId><BoxUsage>0.0000228636</BoxUsage></ResponseMetadata></QueryWithAttributesResponse>",
22
+ 'DomainMetadata' =>
23
+ "<?xml version=\"1.0\"?>\n<DomainMetadataResponse xmlns=\"http://sdb.amazonaws.com/doc/2007-11-07/\"><DomainMetadataResult><ItemCount>282</ItemCount><ItemNamesSizeBytes>7237</ItemNamesSizeBytes><AttributeNameCount>13</AttributeNameCount><AttributeNamesSizeBytes>92</AttributeNamesSizeBytes><AttributeValueCount>1095</AttributeValueCount><AttributeValuesSizeBytes>5689</AttributeValuesSizeBytes><Timestamp>1241131496</Timestamp></DomainMetadataResult><ResponseMetadata><RequestId>fdca49d6-5d0c-1006-5571-648d29e7f183</RequestId><BoxUsage>0.0000071759</BoxUsage></ResponseMetadata></DomainMetadataResponse>",
24
+ 'ListDomains' =>
25
+ "<?xml version=\"1.0\"?>\n<ListDomainsResponse xmlns=\"http://sdb.amazonaws.com/doc/2007-11-07/\"><ListDomainsResult><DomainName>myapp_development</DomainName><DomainName>myapp_production</DomainName><DomainName>myapp_test</DomainName><DomainName>test_domain</DomainName></ListDomainsResult><ResponseMetadata><RequestId>f79cd7ab-5f1e-4a32-5a90-de630ed679b8</RequestId><BoxUsage>0.0000071759</BoxUsage></ResponseMetadata></ListDomainsResponse>"
26
+
27
+ }
@@ -0,0 +1,27 @@
1
+ require 'rubygems'
2
+ require 'test/unit'
3
+ require 'shoulda'
4
+
5
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
6
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
7
+ require 'aws_sdb_bare'
8
+
9
+ class Test::Unit::TestCase
10
+
11
+ def assert_attribute(attribute_hash, query_string)
12
+ query_hash = query_hash(query_string)
13
+ attribute_hash.keys.each do |key|
14
+ method = attribute_hash[key].is_a?(Regexp) ? :assert_match : :assert_equal
15
+ send(method, attribute_hash[key], query_hash[key])
16
+ end
17
+ end
18
+
19
+ def query_hash(query_string)
20
+ query_hash = query_string.split('&').inject({}) do |hash, token|
21
+ key, value = *token.split('=')
22
+ hash[key] = value
23
+ hash
24
+ end
25
+ end
26
+
27
+ end
metadata ADDED
@@ -0,0 +1,74 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: aws_sdb_bare
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.2.0
5
+ platform: ruby
6
+ authors:
7
+ - Paolo Negri
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2010-02-20 00:00:00 -08:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description:
17
+ email: hungryblank@gmail.com
18
+ executables: []
19
+
20
+ extensions: []
21
+
22
+ extra_rdoc_files:
23
+ - LICENSE
24
+ - README.rdoc
25
+ files:
26
+ - .document
27
+ - .gitignore
28
+ - LICENSE
29
+ - README.rdoc
30
+ - Rakefile
31
+ - VERSION.yml
32
+ - aws_sdb_bare.gemspec
33
+ - lib/aws_sdb_bare.rb
34
+ - lib/aws_sdb_bare/request.rb
35
+ - lib/aws_sdb_bare/response.rb
36
+ - test/aws_sdb_request_template_test.rb
37
+ - test/aws_sdb_request_test.rb
38
+ - test/aws_sdb_response_test.rb
39
+ - test/samples/responses.rb
40
+ - test/test_helper.rb
41
+ has_rdoc: true
42
+ homepage: http://github.com/hungryblank/aws_sdb_bare
43
+ licenses: []
44
+
45
+ post_install_message:
46
+ rdoc_options:
47
+ - --charset=UTF-8
48
+ require_paths:
49
+ - lib
50
+ required_ruby_version: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: "0"
55
+ version:
56
+ required_rubygems_version: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: "0"
61
+ version:
62
+ requirements: []
63
+
64
+ rubyforge_project:
65
+ rubygems_version: 1.3.5
66
+ signing_key:
67
+ specification_version: 3
68
+ summary: Amazon AWS SDB SimpleDB client library, low level and http lib agnostic
69
+ test_files:
70
+ - test/test_helper.rb
71
+ - test/aws_sdb_request_test.rb
72
+ - test/samples/responses.rb
73
+ - test/aws_sdb_response_test.rb
74
+ - test/aws_sdb_request_template_test.rb