forforf-aws-sdb 0.5.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/LICENSE ADDED
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2007, 2008 Tim Dysinger
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ THE SOFTWARE.
data/README ADDED
@@ -0,0 +1,8 @@
1
+ Fork of Tim Dysinger's aws-sdb
2
+
3
+ Features added in this fork
4
+
5
+ * Support for AWS Signature Version 2 (SHA256)
6
+ * Updated to support queries using Select Expressions (Query was deprecated)
7
+ * Automatically retries on 503 errors
8
+ * Fixed specs to run and passing all specs
data/Rakefile ADDED
@@ -0,0 +1,20 @@
1
+ require 'rubygems'
2
+ require 'spec/rake/spectask'
3
+ require 'rake/gempackagetask'
4
+
5
+ Spec::Rake::SpecTask.new
6
+
7
+ gem_spec = eval(IO.read(File.join(File.dirname(__FILE__), "aws-sdb.gemspec")))
8
+
9
+ desc "Open an irb session preloaded with this library"
10
+ task :console do
11
+ sh "irb -rubygems -I lib -r aws_sdb.rb"
12
+ end
13
+
14
+ Rake::GemPackageTask.new(gem_spec) do |pkg|
15
+ pkg.gem_spec = gem_spec
16
+ end
17
+
18
+ task :install => [:package] do
19
+ sh %{sudo gem install pkg/#{gem_spec.name}-#{gem_spec.version}}
20
+ end
data/lib/aws_sdb.rb ADDED
@@ -0,0 +1,3 @@
1
+ require 'aws_sdb/error'
2
+ require 'aws_sdb/service'
3
+
@@ -0,0 +1,52 @@
1
+ module AwsSdb
2
+
3
+ class Error < RuntimeError ; end
4
+
5
+ class RequestError < Error
6
+ attr_reader :request_id
7
+
8
+ def initialize(message, request_id=nil)
9
+ super(message)
10
+ @request_id = request_id
11
+ end
12
+ end
13
+
14
+ class ServiceUnavailableError < Error
15
+ attr_reader :request_id
16
+
17
+ def initialize(message, request_id=nil)
18
+ puts "SUESUE"
19
+ super(message)
20
+ @request_id = request_id
21
+ end
22
+ end
23
+
24
+ class InvalidDomainNameError < RequestError ; end
25
+ class InvalidParameterValueError < RequestError ; end
26
+ class InvalidNextTokenError < RequestError ; end
27
+ class InvalidNumberPredicatesError < RequestError ; end
28
+ class InvalidNumberValueTestsError < RequestError ; end
29
+ class InvalidQueryExpressionError < RequestError ; end
30
+ class MissingParameterError < RequestError ; end
31
+ class NoSuchDomainError < RequestError ; end
32
+ class NumberDomainsExceededError < RequestError ; end
33
+ class NumberDomainAttributesExceededError < RequestError ; end
34
+ class NumberDomainBytesExceededError < RequestError ; end
35
+ class NumberItemAttributesExceededError < RequestError ; end
36
+ class RequestTimeoutError < RequestError ; end
37
+
38
+ class FeatureDeprecatedError < RequestError ; end
39
+
40
+ class ConnectionError < Error
41
+ attr_reader :response
42
+
43
+ def initialize(response)
44
+ super(
45
+ "#{response.code} \
46
+ #{response.message if response.respond_to?(:message)}"
47
+ )
48
+ @response = response
49
+ end
50
+ end
51
+
52
+ end
@@ -0,0 +1,270 @@
1
+ require 'logger'
2
+ require 'time'
3
+ require 'cgi'
4
+ require 'uri'
5
+ require 'base64'
6
+ require 'openssl'
7
+ require 'rexml/document'
8
+ require 'rexml/xpath'
9
+ require 'curb-fu'
10
+
11
+ #duck punch so that space converts to %20
12
+ class CGI
13
+ @@accept_charset="UTF-8" unless defined?(@@accept_charset)
14
+
15
+ def CGI::escape(string)
16
+ string.gsub(/([^a-zA-Z0-9_.-]+)/n) do
17
+ '%' + $1.unpack('H2' * $1.size).join('%').upcase
18
+ end
19
+ end
20
+
21
+ end
22
+
23
+ module AwsSdb
24
+
25
+ class Service
26
+ def initialize(options={})
27
+ @access_key_id = options[:access_key_id] || ENV['AMAZON_ACCESS_KEY_ID']
28
+ @secret_access_key = options[:secret_access_key] || ENV['AMAZON_SECRET_ACCESS_KEY']
29
+ @base_url = options[:url] || 'http://sdb.amazonaws.com'
30
+ @logger = options[:logger] || Logger.new("aws_sdb.log")
31
+ end
32
+
33
+ def list_domains(max = nil, token = nil)
34
+ params = { 'Action' => 'ListDomains' }
35
+ params['NextToken'] =
36
+ token unless token.nil? || token.empty?
37
+ params['MaxNumberOfDomains'] =
38
+ max.to_s unless max.nil? || max.to_i == 0
39
+ doc = call(:get, params)
40
+ results = []
41
+ REXML::XPath.each(doc, '//DomainName/text()') do |domain|
42
+ results << domain.to_s
43
+ end
44
+ return results, REXML::XPath.first(doc, '//NextToken/text()').to_s
45
+ end
46
+
47
+ def create_domain(domain)
48
+ domain.strip! if domain
49
+ call(:post, { 'Action' => 'CreateDomain', 'DomainName'=> domain.to_s })
50
+ nil
51
+ end
52
+
53
+ def delete_domain(domain)
54
+ call(
55
+ :delete,
56
+ { 'Action' => 'DeleteDomain', 'DomainName' => domain.to_s }
57
+ )
58
+ nil
59
+ end
60
+
61
+ def select(query, max = nil, token = nil, consistent_read = 'true')
62
+ query
63
+ params = {
64
+ 'Action' => 'Select',
65
+ 'SelectExpression' => query,
66
+ 'ConsistentRead' => consistent_read
67
+ }
68
+ params['NextToken'] =
69
+ token unless token.nil? || token.empty?
70
+ params['MaxNumberOfItems'] =
71
+ max.to_s unless max.nil? || max.to_i == 0
72
+
73
+ @logger.debug { "SELECT EXPRESSION BEFORE CALL: #{query.inspect}" } if @logger.debug?
74
+ doc = call(:get, params)
75
+ item_doc = REXML::XPath.match(doc, '//Item')
76
+ items = {}
77
+ attributes = {}
78
+
79
+ #build the result hash
80
+ REXML::XPath.each(item_doc, '//Item/Name') do |item_name_doc|
81
+ item_name = item_name_doc.text
82
+ REXML::XPath.each(item_doc, '//Attribute') do |attrib_doc|
83
+ attrib_name = nil
84
+ attrib_value = nil
85
+ attrib_doc.elements.each('Name') do |name|
86
+ attrib_name = CGI.unescape(name.text)
87
+ end
88
+ attrib_doc.elements.each('Value') do |value|
89
+ attrib_value = CGI.unescape(value.text)
90
+ end
91
+ add_value(attributes, attrib_name, attrib_value)
92
+ end
93
+ items[item_name] = attributes
94
+ end
95
+ attr_names = REXML::XPath.match(item_doc, '//Attribute/Name/text()')
96
+ results = items
97
+
98
+ return results, REXML::XPath.first(doc, '//NextToken/text()').to_s
99
+ end
100
+
101
+ def put_attributes(domain, item, attributes, replace = true)
102
+ params = {
103
+ 'Action' => 'PutAttributes',
104
+ 'DomainName' => domain.to_s,
105
+ 'ItemName' => item.to_s
106
+ }
107
+ count = 0
108
+ #escaping key and value so signature computes correctly
109
+ attributes.each do | key, values |
110
+ ([]<<values).flatten.each do |value|
111
+ params["Attribute.#{count}.Name"] = CGI.escape(key.to_s)
112
+ params["Attribute.#{count}.Value"] = CGI.escape(value.to_s)
113
+ params["Attribute.#{count}.Replace"] = replace
114
+ count += 1
115
+ end
116
+ end
117
+ call(:put, params)
118
+ nil
119
+ end
120
+
121
+ #updated to support consitent read
122
+ def get_attributes(domain, item, consistent_read = 'true')
123
+ doc = call(
124
+ :get,
125
+ {
126
+ 'Action' => 'GetAttributes',
127
+ 'DomainName' => domain.to_s,
128
+ 'ItemName' => item.to_s,
129
+ 'ConsistentRead' => consistent_read
130
+ }
131
+ )
132
+ attributes = {}
133
+ REXML::XPath.each(doc, "//Attribute") do |attr|
134
+ unesc_key = REXML::XPath.first(attr, './Name/text()').to_s
135
+ unesc_value = REXML::XPath.first(attr, './Value/text()').to_s
136
+ #unescape key and value to return to normal
137
+ key = CGI.unescape(unesc_key)
138
+ value = CGI.unescape(unesc_value)
139
+ ( attributes[key] ||= [] ) << value
140
+ end
141
+ attributes
142
+ end
143
+
144
+ def delete_attributes(domain, item)
145
+ call(
146
+ :delete,
147
+ {
148
+ 'Action' => 'DeleteAttributes',
149
+ 'DomainName' => domain.to_s,
150
+ 'ItemName' => item.to_s
151
+ }
152
+ )
153
+ nil
154
+ end
155
+
156
+ protected
157
+
158
+ def build_canonical_query_string(q_params)
159
+ q_params.sort.collect { |k,v| [CGI.escape(k.to_s), CGI.escape(v.to_s)].join('=')}.join('&')
160
+ end
161
+
162
+ def build_actual_query_string(q_params)
163
+ q_params.sort.collect { |k,v| [CGI.escape(k.to_s), CGI.escape(v.to_s)].join('=')}.join('&')
164
+ end
165
+
166
+ def call(method, params)
167
+ #updated to support signtature version 2
168
+ params.merge!( {
169
+ 'Version' => '2009-04-15',
170
+ 'SignatureMethod' => 'HmacSHA256',
171
+ #'SignatureMethod' => 'HmacSHA1',
172
+ 'SignatureVersion' => '2',
173
+ 'AWSAccessKeyId' => @access_key_id,
174
+ 'Timestamp' => Time.now.gmtime.iso8601
175
+ }
176
+ )
177
+
178
+ @logger.debug { "CALL: #{method} with #{params.inspect}" } if @logger.debug?
179
+
180
+
181
+ canonical_querystring = build_canonical_query_string(params)
182
+
183
+ @logger.debug { "CANONICAL: #{canonical_querystring.inspect}" } if @logger.debug?
184
+
185
+ string_to_sign= "GET\n#{URI.parse(@base_url).host}\n/\n#{canonical_querystring}"
186
+
187
+ #sha256
188
+ digest = OpenSSL::Digest::Digest.new('sha256')
189
+ signature = Base64.encode64(OpenSSL::HMAC.digest(digest, @secret_access_key, string_to_sign)).chomp
190
+
191
+ #sha1
192
+ #digest = OpenSSL::Digest::Digest.new('sha256')
193
+ #signature = Base64.encode64(OpenSSL::HMAC.digest(digest, @secret_access_key, string_to_sign)).chomp
194
+
195
+ params['Signature'] = signature
196
+ querystring = build_actual_query_string(params)
197
+
198
+ @logger.debug { "ACTUALQUERY: #{querystring.inspect}" } if @logger.debug?
199
+
200
+ url = "#{@base_url}?#{querystring}"
201
+ uri = URI.parse(url)
202
+
203
+ resp = request(url)
204
+ resp_body = resp.body
205
+
206
+ @logger.debug { "RESP: #{resp_body.inspect}" } if @logger.debug?
207
+
208
+ doc = REXML::Document.new(resp_body)
209
+
210
+ @logger.debug { "DECODED DOC:" } if @logger.debug?
211
+
212
+ error = doc.get_elements('*/Errors/Error')[0]
213
+
214
+ raise(
215
+ Module.class_eval(
216
+ "AwsSdb::#{error.get_elements('Code')[0].text}Error"
217
+ ).new(
218
+ error.get_elements('Message')[0].text,
219
+ doc.get_elements('*/RequestID')[0].text
220
+ )
221
+ ) unless error.nil?
222
+ doc
223
+ end
224
+
225
+ #request with retries
226
+ def request(url, retry_data={})
227
+ resp = CurbFu.get(url)
228
+ if resp.nil? || resp.status == 503
229
+ resp = retry_req(url, retry_data)
230
+ end
231
+ raise "No response!!" unless resp
232
+ raise "No Body in Response" unless resp.body
233
+ resp
234
+ end
235
+
236
+ private
237
+
238
+ def retry_req(url, retry_data)
239
+ resp = :retry
240
+ #retry parameters
241
+ max_retries = 10||retry_data[:max_retries]
242
+ init_wait = 0.2||retry_data[:init_wait]
243
+ wait_increase = 0.3||retry_data[:wait_increase]
244
+ retry_data[:wait] = init_wait||retry_data[:wait]
245
+
246
+ #wait a tiny bit before the first retry and reset retry data
247
+ #then retry
248
+ 1.upto(max_retries) do |retry_att|
249
+ sleep retry_data[:wait]
250
+ #puts "RETRY: #{retry_att}, WAIT: #{retry_data[:wait]}"
251
+ resp = request(url, retry_data)
252
+ break if resp && resp.status && resp.status != 503 && resp.body
253
+ retry_data[:wait] += wait_increase
254
+ retry_data[:wait_increase] = wait_increase * retry_att #request back off
255
+ end
256
+ resp
257
+ end
258
+
259
+ def add_value(attributes, attrib_name, attrib_value)
260
+ if attributes[attrib_name]
261
+ attributes[attrib_name] << attrib_value
262
+ else
263
+ attributes[attrib_name] = [attrib_value]
264
+ end
265
+ attributes
266
+ end
267
+
268
+ end#class
269
+
270
+ end#module
@@ -0,0 +1,13 @@
1
+ # Logfile created on 2010-12-23 20:04:18 +0000 by logger.rb/25413
2
+ D, [2010-12-23T20:04:18.454524 #25893] DEBUG -- : http://sdb.amazonaws.com?Action=DeleteDomain&AWSAccessKeyId=AKIAJZT2KIZFM36DNBVQ&DomainName=&SignatureVersion=1&Timestamp=2010-12-23T20%3A04%3A18Z&Version=2007-11-07&Signature=xCfsCVEy3dpskdJjmkwYfVIQudY%3D
3
+ D, [2010-12-23T20:04:18.476771 #25893] DEBUG -- : 400
4
+ <?xml version="1.0"?>
5
+ <Response><Errors><Error><Code>InvalidParameterValue</Code><Message>Value () for parameter DomainName is invalid. </Message><BoxUsage>0.0055590278</BoxUsage></Error></Errors><RequestID>5ec30ba5-4b3c-f1f7-c1b2-0c65d16c57b9</RequestID></Response>
6
+ D, [2010-12-23T20:04:18.479966 #25893] DEBUG -- : http://sdb.amazonaws.com?Action=DeleteDomain&AWSAccessKeyId=AKIAJZT2KIZFM36DNBVQ&DomainName=&SignatureVersion=1&Timestamp=2010-12-23T20%3A04%3A18Z&Version=2007-11-07&Signature=xCfsCVEy3dpskdJjmkwYfVIQudY%3D
7
+ D, [2010-12-23T20:04:18.490482 #25893] DEBUG -- : 400
8
+ <?xml version="1.0"?>
9
+ <Response><Errors><Error><Code>InvalidParameterValue</Code><Message>Value () for parameter DomainName is invalid. </Message><BoxUsage>0.0055590278</BoxUsage></Error></Errors><RequestID>1ec92b8e-0053-2452-0140-015fdefa7f8c</RequestID></Response>
10
+ D, [2010-12-23T20:04:18.493872 #25893] DEBUG -- : http://sdb.amazonaws.com?Action=DeleteDomain&AWSAccessKeyId=AKIAJZT2KIZFM36DNBVQ&DomainName=&SignatureVersion=1&Timestamp=2010-12-23T20%3A04%3A18Z&Version=2007-11-07&Signature=xCfsCVEy3dpskdJjmkwYfVIQudY%3D
11
+ D, [2010-12-23T20:04:18.507715 #25893] DEBUG -- : 400
12
+ <?xml version="1.0"?>
13
+ <Response><Errors><Error><Code>InvalidParameterValue</Code><Message>Value () for parameter DomainName is invalid. </Message><BoxUsage>0.0055590278</BoxUsage></Error></Errors><RequestID>756ba7ca-e9f7-e73a-83ed-7d8396498550</RequestID></Response>
@@ -0,0 +1,208 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper.rb'
2
+
3
+ require 'digest/sha1'
4
+ require 'net/http'
5
+ require 'rexml/document'
6
+
7
+ require 'rubygems'
8
+ require 'uuidtools'
9
+
10
+ include AwsSdb
11
+
12
+ describe Service, "when creating a new domain" do
13
+ include UUIDTools
14
+
15
+ before(:all) do
16
+ @service = AwsSdb::Service.new
17
+ @domain = "test-#{UUID.random_create.to_s}"
18
+ domains = @service.list_domains[0]
19
+ domains.each do |d|
20
+ @service.delete_domain(d) if d =~ /^test/
21
+ end
22
+ end
23
+
24
+ after(:all) do
25
+ @service.delete_domain(@domain)
26
+ end
27
+
28
+ it "should not raise an error if a valid new domain name is given" do
29
+ lambda {
30
+ @service.create_domain("test-#{UUID.random_create.to_s}")
31
+ }.should_not raise_error
32
+ end
33
+
34
+ it "should not raise an error if the domain name already exists" do
35
+ domain = "test-#{UUID.random_create.to_s}"
36
+ lambda {
37
+ @service.create_domain(domain)
38
+ @service.create_domain(domain)
39
+ }.should_not raise_error
40
+ end
41
+
42
+ it "should raise an error if an a nil or '' domain name is given" do
43
+ lambda {
44
+ @service.create_domain('')
45
+ }.should raise_error(InvalidParameterValueError)
46
+ lambda {
47
+ @service.create_domain(nil)
48
+ }.should raise_error(InvalidParameterValueError)
49
+ lambda {
50
+ @service.create_domain(' ')
51
+ }.should raise_error(InvalidParameterValueError)
52
+ end
53
+
54
+ it "should raise an error if the domain name length is < 3 or > 255" do
55
+ lambda {
56
+ @service.create_domain('xx')
57
+ }.should raise_error(InvalidParameterValueError)
58
+ lambda {
59
+ @service.create_domain('x'*256)
60
+ }.should raise_error(InvalidParameterValueError)
61
+ end
62
+
63
+ it "should only accept domain names with a-z, A-Z, 0-9, '_', '-', and '.' " do
64
+ lambda {
65
+ @service.create_domain('@$^*()')
66
+ }.should raise_error(InvalidParameterValueError)
67
+ end
68
+
69
+ #it "should only accept a maximum of 100 domain names"
70
+
71
+ #it "should not have to call amazon to determine domain name correctness"
72
+
73
+ end
74
+
75
+ describe Service, "when listing domains" do
76
+ include UUIDTools
77
+
78
+ before(:all) do
79
+ @service = AwsSdb::Service.new
80
+ @domain = "test-#{UUID.random_create.to_s}"
81
+ @service.list_domains[0].each do |d|
82
+ @service.delete_domain(d) if d =~ /^test/
83
+ end
84
+ @service.create_domain(@domain)
85
+ end
86
+
87
+ after(:all) do
88
+ @service.delete_domain(@domain)
89
+ end
90
+
91
+ it "should return a complete list" do
92
+ result = nil
93
+ lambda { result = @service.list_domains[0] }.should_not raise_error
94
+ result.should_not be_nil
95
+ result.should_not be_empty
96
+ result.include?(@domain).should == true
97
+ end
98
+ end
99
+
100
+ describe Service, "when deleting domains" do
101
+ include UUIDTools
102
+ before(:all) do
103
+ @service = AwsSdb::Service.new
104
+ @domain = "test-#{UUID.random_create.to_s}"
105
+ @service.list_domains[0].each do |d|
106
+ @service.delete_domain(d) if d =~ /^test/
107
+ end
108
+ @service.create_domain(@domain)
109
+ end
110
+
111
+ before(:each) do
112
+ #sleep 0.2
113
+ end
114
+
115
+ after do
116
+ @service.delete_domain(@domain)
117
+ end
118
+
119
+ it "should be able to delete an existing domain" do
120
+ lambda { @service.delete_domain(@domain) }.should_not raise_error
121
+ end
122
+
123
+ it "should not raise an error trying to delete a non-existing domain" do
124
+ lambda {
125
+ @service.delete_domain(UUID.random_create.to_s)
126
+ }.should_not raise_error
127
+ end
128
+ end
129
+
130
+ describe Service, "when managing items" do
131
+ include UUIDTools
132
+
133
+ before(:all) do
134
+ @service = AwsSdb::Service.new
135
+ @domain = "test-#{UUID.random_create.to_s}"
136
+ @service.list_domains[0].each do |d|
137
+ @service.delete_domain(d) if d =~ /^test/
138
+ end
139
+ @service.create_domain(@domain)
140
+ @item = "test-#{UUID.random_create.to_s}"
141
+ @attributes = {
142
+ :question => 'What is the answer?',
143
+ :answer => [ true, 'testing123', 4.2, 42, 420 ]
144
+ }
145
+ end
146
+
147
+ before(:each) do
148
+ #sleep 0.2
149
+ end
150
+
151
+ after(:all) do
152
+ @service.delete_domain(@domain)
153
+ end
154
+
155
+ it "should be able to put attributes" do
156
+ lambda {
157
+ @service.put_attributes(@domain, @item, @attributes)
158
+ }.should_not raise_error
159
+ end
160
+
161
+ it "should be able to get attributes" do
162
+ result = nil
163
+ lambda {
164
+ result = @service.get_attributes(@domain, @item)
165
+ }.should_not raise_error
166
+ result.should_not be_nil
167
+ result.should_not be_empty
168
+ result.has_key?('answer').should == true
169
+ @attributes[:answer].each do |v|
170
+ result['answer'].include?(v.to_s).should == true
171
+ end
172
+ end
173
+
174
+ it "should be able to select all from domain" do
175
+ query_str = "select * from `#{@domain}`"
176
+ result = nil
177
+ lambda {
178
+ result = @service.select(query_str)
179
+ }.should_not raise_error
180
+ result.should_not be_nil
181
+ result.should_not be_empty
182
+ result.should_not be_nil
183
+ result[0].keys.include?(@item).should == true
184
+ result[0].values.size.should == 1
185
+ #attribute names
186
+ result[0].values[0].keys.sort.should == ['answer', 'question']
187
+ #questions
188
+ result[0].values[0]['question'].should == ['What is the answer?']
189
+ #answers
190
+ result[0].values[0]['answer'].size == 5
191
+ result[0].values[0]['answer'].include?("42").should == true
192
+ result[0].values[0]['answer'].include?("testing123").should == true
193
+ end
194
+
195
+
196
+ it "should be able to delete attributes" do
197
+ lambda {
198
+ @service.delete_attributes(@domain, @item)
199
+ }.should_not raise_error
200
+ end
201
+ end
202
+
203
+ # TODO Pull the specs from the amazon docs and write more rspec
204
+ # 100 attributes per each call
205
+ # 256 total attribute name-value pairs per item
206
+ # 250 million attributes per domain
207
+ # 10 GB of total user data storage per domain
208
+ # ...etc...
@@ -0,0 +1,4 @@
1
+ $TESTING=true
2
+ $:.push File.join(File.dirname(__FILE__), '..', 'lib')
3
+
4
+ require 'aws_sdb'
metadata ADDED
@@ -0,0 +1,86 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: forforf-aws-sdb
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 5
8
+ - 0
9
+ version: 0.5.0
10
+ platform: ruby
11
+ authors:
12
+ - Tim Dysinger
13
+ - Dave M
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2010-12-26 00:00:00 +00:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: uuidtools
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ segments:
30
+ - 0
31
+ version: "0"
32
+ type: :runtime
33
+ version_requirements: *id001
34
+ description: Amazon SDB API
35
+ email: dmarti21@gmail.com
36
+ executables: []
37
+
38
+ extensions: []
39
+
40
+ extra_rdoc_files:
41
+ - README
42
+ - LICENSE
43
+ files:
44
+ - LICENSE
45
+ - README
46
+ - Rakefile
47
+ - lib/aws_sdb.rb
48
+ - lib/aws_sdb/error.rb
49
+ - lib/aws_sdb/service.rb
50
+ - spec/spec_helper.rb
51
+ - spec/aws_sdb/aws_sdb.log
52
+ - spec/aws_sdb/service_spec.rb
53
+ has_rdoc: true
54
+ homepage: http://github.com/forforf/aws-sdb
55
+ licenses: []
56
+
57
+ post_install_message:
58
+ rdoc_options: []
59
+
60
+ require_paths:
61
+ - lib
62
+ required_ruby_version: !ruby/object:Gem::Requirement
63
+ none: false
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ segments:
68
+ - 0
69
+ version: "0"
70
+ required_rubygems_version: !ruby/object:Gem::Requirement
71
+ none: false
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ segments:
76
+ - 0
77
+ version: "0"
78
+ requirements: []
79
+
80
+ rubyforge_project: forforf-aws-sdb
81
+ rubygems_version: 1.3.7
82
+ signing_key:
83
+ specification_version: 3
84
+ summary: Amazon SDB API
85
+ test_files: []
86
+