forforf-aws-sdb 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
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
+