amazon_sdb 0.6.0 → 0.6.5

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.
@@ -1,3 +1,9 @@
1
+ == 0.6.5 / 2008-01-15
2
+ * 3 major enhancements
3
+ * New usage tracking via the box_usage method
4
+ * Better docs
5
+ * Boolean coercion
6
+
1
7
  == 0.6.0 / 2007-12-28
2
8
  * 2 major enhancements
3
9
  * Correct error handling for API's HTTP responses (with tests)
data/README.txt CHANGED
@@ -9,11 +9,11 @@ http://code.nytimes.com/svn/ruby/gems/amazon_sdb
9
9
 
10
10
  == DESCRIPTION:
11
11
 
12
- Amazon sdb is a Ruby wrapper to Amazon's new Simple Database Service. Amazon sdb is a different type of database:
12
+ Amazon SDB is a Ruby wrapper to Amazon's new Simple Database Service. Amazon sdb is a different type of database:
13
13
 
14
14
  * Accessed over the network via RESTful calls
15
15
  * No schemas or types
16
- * Each sdb account can have up to 100 domains for data.
16
+ * Each SimpleDB account can have up to 100 domains for data.
17
17
  * Domains can hold objects referenced by unique keys
18
18
  * Each object can hold up to 256 name/value attributes.
19
19
  * Only name/value pairs must be unique in an objects attributes, there can be multiple name/value attributes with the same name.
@@ -22,9 +22,9 @@ Amazon sdb is a Ruby wrapper to Amazon's new Simple Database Service. Amazon sdb
22
22
 
23
23
  == FEATURES:
24
24
 
25
- * A basic interface to Amazon sdb
26
- * Includes a class for representing attribute sets in sdb
27
- * Automatic conversion to/from sdb representations for integers and dates (for floats, it's suggested you use the Multimap#numeric function)
25
+ * A basic interface to Amazon SimpleDB
26
+ * Includes a class for representing attribute sets in SimpleDB
27
+ * Automatic conversion to/from SimpleDB representations for integers and dates (for floats, it's suggested you use the Multimap#numeric function)
28
28
  * The beginnings of mock-based tests for methods derived from Amazon's docs
29
29
 
30
30
  == CAVEATS
@@ -41,7 +41,7 @@ Amazon sdb is a Ruby wrapper to Amazon's new Simple Database Service. Amazon sdb
41
41
 
42
42
  == SYNOPSIS:
43
43
 
44
- b = Amazon::sdb::Base.new(aws_public_key, aws_secret_key)
44
+ b = Amazon::SDB::Base.new(aws_public_key, aws_secret_key)
45
45
  b.domains #=> list of domain
46
46
  domain = b.create_domain 'my domain'
47
47
 
@@ -30,10 +30,11 @@ require 'amazon_sdb/domain'
30
30
  require 'amazon_sdb/item'
31
31
  require 'amazon_sdb/resultset'
32
32
  require 'amazon_sdb/exceptions'
33
+ require 'amazon_sdb/usage'
33
34
 
34
35
  module Amazon
35
36
  module SDB
36
- VERSION = '0.6.0'
37
+ VERSION = '0.6.5'
37
38
  end
38
39
  end
39
40
 
@@ -15,6 +15,8 @@ module Amazon
15
15
  def initialize(aws_access_key, aws_secret_key)
16
16
  @access_key = aws_access_key
17
17
  @secret_key = aws_secret_key
18
+ @usage = Usage.new
19
+ raise @usage
18
20
  end
19
21
 
20
22
  ##
@@ -32,16 +34,42 @@ module Amazon
32
34
  @@number_padding = num
33
35
  end
34
36
 
37
+ ##
38
+ # The number of digits after the decimal points to use by default
35
39
  def self.float_precision
36
40
  return @@float_precision
37
41
  end
38
42
 
43
+ ##
44
+ # Set the #float_precision
39
45
  def self.float_precision=(num)
40
46
  return @@float_precision
41
47
  end
42
48
 
43
49
  ##
44
- # Retrieves a list of domains in your SDS database. Each entry is a Domain object.
50
+ # Returns the Box Usage accumulated since the beginning of the session. Box Usage represents computation time and is one of
51
+ # the parameters in your monthly SimpleDB bill. As an alternative, when passed a block (no parameters yielded), it returns
52
+ # the box usage only for the operations within the block.
53
+ def box_usage
54
+ unless block_given?
55
+ @usage.box_usage
56
+ else
57
+ # return the usage of the actions in the block
58
+ usage1 = @usage.box_usage
59
+ yield
60
+ usage2 = @usage.box_usage
61
+ return usage2 - usage1
62
+ end
63
+ end
64
+
65
+ ##
66
+ # Resets the box usage accumulated within the current session. Not sure why you'd need to do this, but it's provided.
67
+ def reset_usage!
68
+ @usage.reset!
69
+ end
70
+
71
+ ##
72
+ # Retrieves a list of domains in your SDS database. Each entry is a Domain object.
45
73
  def domains
46
74
  domains = []
47
75
  nextToken = nil
@@ -67,10 +95,35 @@ module Amazon
67
95
  end
68
96
 
69
97
  ##
70
- # Returns a domain object for SDS. Assumes the domain already exists, so errors might occur if you didn't create it.
98
+ # Returns a domain object for SimpleDB. Assumes the domain already exists, so a ParameterError (NoSuchDomain) might occur if it's not there. This
99
+ # method is useful for getting a domain object without having to incur the operational costs of querying all domains.
71
100
  def domain(name)
72
101
  Domain.new(@access_key, @secret_key, name)
73
102
  end
103
+
104
+ ##
105
+ # Creates a domain. This operation is idempotent, but it is slow and if you are sure the domain already exists, you might
106
+ # want to use the #domain method instead. Each SimpleDB account is allowed up to 100 domains; a LimitError will be raised
107
+ # if you attempt to create more.
108
+ def create_domain(name)
109
+ sdb_query({:Action => 'CreateDomain', 'DomainName' => name}) do |h|
110
+ domain(name)
111
+ end
112
+ end
113
+
114
+ ##
115
+ # Deletes a domain. Running this command multiple times or on a domain that does not exist will NOT return an error.
116
+ def delete_domain!(name)
117
+ sdb_query({:Action => 'DeleteDomain', 'DomainName' => name})
118
+ end
119
+
120
+ private
121
+ def parse_usage(hpricot)
122
+ usagenode = hpricot.at('//BoxUsage')
123
+ return unless usagenode
124
+
125
+ @usage.add_usage usagenode.innerText.to_f
126
+ end
74
127
 
75
128
  def raise_errors(hpricot)
76
129
  errnode = hpricot.at('//Errors/Error')
@@ -102,18 +155,6 @@ module Amazon
102
155
  end
103
156
  end
104
157
 
105
- def create_domain(name)
106
- sdb_query({:Action => 'CreateDomain', 'DomainName' => name}) do |h|
107
- domain(name)
108
- end
109
- end
110
-
111
- ##
112
- # Deletes a domain. This operation is currently not supported by SDS.
113
- def delete_domain!(name)
114
- sdb_query({:Action => 'DeleteDomain', 'DomainName' => name})
115
- end
116
-
117
158
  def timestamp
118
159
  Time.now.iso8601
119
160
  end
@@ -148,11 +189,13 @@ module Amazon
148
189
  open(url) do |f|
149
190
  h = Hpricot.XML(f)
150
191
 
192
+ parse_usage h
151
193
  raise_errors h
152
194
  yield h if block_given?
153
195
  end
154
196
  rescue OpenURI::HTTPError => e
155
197
  h = Hpricot.XML(e.io.read)
198
+ parse_usage h
156
199
  raise_errors h
157
200
  end
158
201
  end
@@ -166,7 +209,6 @@ module Amazon
166
209
  return hmac(key, option_array.map {|pair| pair[0]+pair[1]}.join('')).chop
167
210
  end
168
211
 
169
- private
170
212
  @@number_padding = 32
171
213
  @@float_precision = 8
172
214
 
@@ -22,9 +22,9 @@ module Amazon
22
22
  ##
23
23
  # Sets attributes for a given key in the domain. If there are no attributes supplied, it creates an empty set.
24
24
  # Takes the following arguments:
25
- # - key - a string key for the attribute set
26
- # - multimap - an collection of attributes for the set in a Multimap object. If nothing, creates an empty set.
27
- # - options - for put options
25
+ # - <tt>key</tt> - a string key for the attribute set
26
+ # - <tt>multimap</tt> - an collection of attributes for the set in a Multimap object (can convert a Hash and Array too). If nothing, creates an empty set.
27
+ # - <tt>options</tt> - for put options. Currently the only option is :replace, which either takes an array of attribute names to replace or :all for all of them
28
28
  def put_attributes(key, multimap=nil, options = {})
29
29
  req_options = {'Action' => 'PutAttributes', 'DomainName' => name, 'ItemName' => key}
30
30
 
@@ -52,6 +52,7 @@ module Amazon
52
52
  ##
53
53
  # Gets the attribute list for a key. Arguments:
54
54
  # - <tt>key</tt> - the key for the attribute set
55
+ # - <tt>attr_list</tt> - by default, this function returns all the attributes of an item. If you wanted to limit the response to only a few named attributes, you can pass them here.
55
56
  def get_attributes(key, *attr_list)
56
57
  options = {'Action' => 'GetAttributes', 'DomainName' => name, 'ItemName' => key}
57
58
 
@@ -75,7 +76,9 @@ module Amazon
75
76
  end
76
77
 
77
78
  ##
78
- # Not implemented yet.
79
+ # Deletes the attributes associated with a particular item. If the optional <tt>multimap</tt> argument is nil, deletes the entire
80
+ # object. Otherwise, the optional multimap argument can be used to delete specific key/value pairs in the object (also accepts
81
+ # a String or Symbol for a single name, an Array for multiple keys or a Hash for key/value pairs)
79
82
  def delete_attributes(key, multimap=nil)
80
83
  options = {'Action' => 'DeleteAttributes', 'DomainName' => name, 'ItemName' => key}
81
84
 
@@ -106,9 +109,10 @@ module Amazon
106
109
  ##
107
110
  # Returns a list of matching items that match a filter
108
111
  # Options include:
109
- # - <tt>max_results</tt> = the max items to return for a listing (top/default is 100)
110
- # - <tt>:more_token</tt> = to retrieve a second or more page of results, the more token should be provided
111
- # - <tt>:load_attrs</tt> = this query normally returns just a list of names, the attributes have to be retrieved separately. To load the attributes for matching results automatically, set to true (normally false)
112
+ # - <tt>:expr</tt> - a query expression to evaluate (see the Amazon SimpleDB documentation for details)
113
+ # - <tt>:max_results</tt> - the max items to return for a listing (top/default is 100)
114
+ # - <tt>:next_token</tt> - to retrieve a second or more page of results, the more token should be provided
115
+ # - <tt>:load_attrs</tt> - this query normally returns just a list of names, the attributes have to be retrieved separately. To load the attributes for matching results automatically, set to true (normally false). Be aware this will lead to N additional requests to SimpleDB.
112
116
  def query(query_options = {})
113
117
  req_options = {'Action' => 'Query', 'DomainName' => name}
114
118
 
@@ -4,46 +4,80 @@ module Amazon
4
4
  end
5
5
 
6
6
  ACCESS_ERROR_CODES = %w{AccessFailure}
7
+
8
+ ##
9
+ # The AccessError represents access problems connecting to SimpleDB
7
10
  class AccessError < Error
8
11
  end
9
12
 
10
13
  AUTH_ERROR_CODES = %w{AuthFailure AuthMissingFailure InvalidHTTPAuthHeader OptInRequired}
14
+
15
+ ##
16
+ # AuthError represents several different authentication problems that may occur when connecting to Amazon SimpleDB. See the
17
+ # message for details.
11
18
  class AuthError < Error
12
19
  end
13
20
 
14
21
  PARAMETER_ERROR_CODES = %w(InvalidAction InvalidNextToken InvalidParameterError
15
22
  InvalidParameterCombination InvalidParameterValue MissingAction MissingParameter NoSuchDomain
16
23
  )
24
+
25
+ ##
26
+ # ParameterError is returned when a parameter to SimpleDB is invalid or missing. See the error for details.
17
27
  class ParameterError < Error
18
28
  end
19
29
 
20
30
  QUERY_ERROR_CODES = %w{InvalidNumberPredicates InvalidNumberValueTests InvalidQueryExpression}
31
+
32
+ ##
33
+ # The QuerySyntaxError covers several errors that may result from an invalid <tt>:expr</tt> passed into the Domain#Query method.
21
34
  class QuerySyntaxError < Error
22
35
  end
23
36
 
24
37
  LIMIT_ERROR_CODES = %w{NumberDomainsExceeded NumberDomainAttributesExceeded NumberDomainBytesExceeded NumberDomainBytesExceeeded URITooLong}
38
+
39
+ ##
40
+ # A LimitError is returned when you hit one of the fundamental limits for SimpleDB accounts. See the message content for details.
25
41
  class LimitError < Error
26
42
  end
27
43
 
28
44
  SERVER_ERROR_CODES = %w{InternalError ServiceOverload ServiceUnavailable}
45
+
46
+ ##
47
+ # ServerErrors represent server problems on SimpleDB.
29
48
  class ServerError < Error
30
49
  end
31
50
 
51
+ ##
52
+ # Huh? What? For when SimpleDB sends me an error code I've never seen before (and isn't in the docs)
32
53
  class UnknownError < Error
33
54
  end
34
55
 
35
56
  REQUEST_ERROR_CODES = %w{InvalidHttpRequest InvalidSOAPRequest InvalidURI InvalidService UnsupportedHttpVerb}
57
+
58
+ ##
59
+ # For incorrectly constructed HTTP queries against the SimpleDB server. If you see this error, it's my fault, and let me know
60
+ # the command that caused it.
36
61
  class RequestError < Error
37
62
  end
38
63
 
39
64
  TIMEOUT_ERROR_CODES = %w{RequestExpired RequestTimeout RequestThrottled}
65
+
66
+ ##
67
+ # Amazon SimpleDB times out any operation that lasts more than 5 seconds. This error will be returned.
40
68
  class TimeoutError < Error
41
69
  end
42
70
 
43
71
  VERSION_ERROR_CODES = %w{FeatureDeprecated NoSuchVersion NotYetImplemented}
72
+
73
+ ##
74
+ # For when there is a mismatch between this gem and the API being called.
44
75
  class VersionError < Error
45
76
  end
46
77
 
78
+ ##
79
+ # When GetAttributes doesn't match, Amazon returns an empty record. I prefer to raise an exception instead, so there will be no
80
+ # confusion.
47
81
  class RecordNotFoundError < Error
48
82
  end
49
83
  end
@@ -1,7 +1,7 @@
1
1
  module Amazon
2
2
  module SDB
3
3
  ##
4
- # An item from sdb. This basically is a key for the item in the domain and a Multimap of the attributes. You should never
4
+ # An item from SimpleDB. This basically is a key for the item in the domain and a Multimap of the attributes. You should never
5
5
  # call Item#new, instead it is returned by various methods in Domain and ResultSet
6
6
  class Item
7
7
  include Enumerable
@@ -13,23 +13,34 @@ module Amazon
13
13
  @attributes = multimap
14
14
  end
15
15
 
16
+ ##
17
+ # Reloads from the domain
16
18
  def reload!
17
19
  item = @domain.get_attributes(@key)
18
20
  @attributes = item.attributes
19
21
  end
20
22
 
23
+ ##
24
+ # Returns true if the attributes are empty
21
25
  def empty?
26
+ return true if @attributes.nil?
22
27
  @attributes.size == 0
23
28
  end
24
29
 
30
+ ##
31
+ # Deletes the item in SimpleDB
25
32
  def destroy!
26
33
  @domain.delete_attributes(@key)
27
34
  end
28
35
 
36
+ ##
37
+ # Saves the item back (like a put_attributes with :replace => :all
29
38
  def save
30
- @domain.put_attributes(@key, @attributes)
39
+ @domain.put_attributes(@key, @attributes, :replace => :all)
31
40
  end
32
41
 
42
+ ##
43
+ # Reloads the item if necessary
33
44
  def get(key)
34
45
  reload! if @attributes.nil?
35
46
  @attributes.get(key)
@@ -172,6 +172,10 @@ module Amazon
172
172
 
173
173
  def sdb_value_escape(value)
174
174
  case value
175
+ when TrueClass
176
+ "true"
177
+ when FalseClass
178
+ "false"
175
179
  when Fixnum
176
180
  sprintf("%0#{Base.number_padding}d", value)
177
181
  when Float
@@ -204,6 +208,10 @@ module Amazon
204
208
 
205
209
  def coerce(value)
206
210
  case value
211
+ when 'true'
212
+ true
213
+ when 'false'
214
+ false
207
215
  when /^0+\d+$/
208
216
  value.to_i
209
217
  when /^0+\d*.\d+$/
@@ -0,0 +1,56 @@
1
+ require "test_sdb_harness"
2
+
3
+ class TestItem < Test::Unit::TestCase
4
+ def setup
5
+ @domain = Amazon::SDB::Domain.new 'API_KEY', 'SECRET_KEY', 'testdb'
6
+ @key = 'TEST_ITEM'
7
+ @multimap = Amazon::SDB::Multimap.new({"foo" => "bar", "baz" => "quux"})
8
+
9
+ @empty_item = Amazon::SDB::Item.new(@domain, @key)
10
+ @item = Amazon::SDB::Item.new(@domain, @key, @multimap)
11
+ end
12
+
13
+ def test_save
14
+ @domain.responses << generic_response('PutAttributes')
15
+ @item.save
16
+
17
+ assert_in_url_query({'Action' => 'PutAttributes', 'DomainName' => 'testdb', 'ItemName' => 'TEST_ITEM',
18
+ 'Attribute.0.Replace' => 'true', 'Attribute.1.Replace' => 'true'}, @domain.uris.first)
19
+ end
20
+
21
+ def test_reload!
22
+ # tests sends a get attributes
23
+ @domain.responses << <<-EOF
24
+ <GetAttributesResponse xmlns="http://sdb.amazonaws.com/doc/2007-11-07">
25
+ <GetAttributesResult>
26
+ <Attribute><Name>Color</Name><Value>Blue</Value></Attribute>
27
+ <Attribute><Name>Size</Name><Value>Med</Value></Attribute>
28
+ <Attribute><Name>Price</Name><Value>14</Value></Attribute>
29
+ </GetAttributesResult>
30
+ <ResponseMetadata>
31
+ <RequestId>b1e8f1f7-42e9-494c-ad09-2674e557526d</RequestId>
32
+ <BoxUsage>0.0000219907/<BoxUsage>
33
+ </ResponseMetadata>
34
+ </GetAttributesResponse>
35
+ EOF
36
+
37
+ @item.reload!
38
+
39
+ assert_in_url_query({'Action' => 'GetAttributes', 'DomainName' => 'testdb', 'ItemName' => 'TEST_ITEM'}, @domain.uris.first)
40
+ end
41
+
42
+ def test_empty?
43
+ assert @empty_item.empty?
44
+ assert !@item.empty?
45
+ end
46
+
47
+ def test_destroy!
48
+ # tests sends a delete attributes with 0 attrs
49
+ @domain.responses << generic_response('DeleteAttributes')
50
+
51
+ @item.destroy!
52
+ assert_in_url_query({'Action' => 'DeleteAttributes', 'DomainName' => 'testdb', 'ItemName' => 'TEST_ITEM'}, @domain.uris.first)
53
+ end
54
+ end
55
+
56
+
@@ -105,6 +105,12 @@ class TestMultimap < Test::Unit::TestCase
105
105
  @m['Num'] = Amazon::SDB::Multimap.numeric(12.34, 10, 4)
106
106
  assert_equal '00012.3400', @m['Num']
107
107
  end
108
+
109
+ def test_boolean_to_sdb
110
+ @m['a'] = true
111
+
112
+ assert_equal 'true', @m.to_sdb['Attribute.0.Value']
113
+ end
108
114
 
109
115
  def test_to_sdb_replace_all
110
116
  @m[:a] = "foo"
@@ -166,6 +172,14 @@ class TestMultimap < Test::Unit::TestCase
166
172
  assert_equal "0000000000034.3400000000", m.get("a", :before_cast => true)
167
173
  end
168
174
 
175
+ def test_coerce_boolean
176
+ m = Multimap.new
177
+ m.from_sdb([["a", "true"], ["b", "false"]])
178
+
179
+ assert_equal true, m["a"]
180
+ assert_equal false, m["b"]
181
+ end
182
+
169
183
  def test_coerce_datetime
170
184
  now = Time.now
171
185
 
@@ -9,6 +9,7 @@ class Amazon::SDB::Base
9
9
  def initialize(aws_access_key, aws_secret_key)
10
10
  @access_key = aws_access_key
11
11
  @secret_key = aws_secret_key
12
+ @usage = Amazon::SDB::Usage.new
12
13
  @responses = []
13
14
  @uris = []
14
15
  end
@@ -0,0 +1,113 @@
1
+ require "test_sdb_harness"
2
+
3
+ class TestUsage < Test::Unit::TestCase
4
+ include Amazon::SDB
5
+
6
+ def setup
7
+ @sdb = Amazon::SDB::Base.new 'API_KEY', 'SECRET_KEY'
8
+ end
9
+
10
+ def test_accumulate
11
+ u = Amazon::SDB::Usage.new
12
+
13
+ u << 0.50
14
+ u << 0.25
15
+
16
+ assert_in_delta(0.75, u.box_usage, 2 ** -20)
17
+ end
18
+
19
+ def test_reset
20
+ u = Amazon::SDB::Usage.new
21
+
22
+ u << 0.50
23
+ u << 0.25
24
+
25
+ u.reset!
26
+
27
+ assert_in_delta(0.0, u.box_usage, 2 ** -20)
28
+ end
29
+
30
+ def test_request_usage
31
+ @sdb.responses << <<-EOF
32
+ <?xml version="1.0" encoding="utf-8" ?>
33
+ <ListDomainsResponse xmlns="http://sdb.amazonaws.com/doc/2007-11-07">
34
+ <ListDomainsResult>
35
+ <DomainName>foo</DomainName>
36
+ <DomainName>bar</DomainName>
37
+ <DomainName>baz</DomainName>
38
+ </ListDomainsResult>
39
+ <ResponseMetadata>
40
+ <RequestId>eb13162f-1b95-4511-8b12-489b86acfd28</RequestId>
41
+ <BoxUsage>0.00777</BoxUsage>
42
+ </ResponseMetadata>
43
+ </ListDomainsResponse>
44
+ EOF
45
+
46
+ @sdb.domains
47
+
48
+ assert_in_delta(0.00777, @sdb.box_usage, 2 ** -20)
49
+ end
50
+
51
+ def test_error_usage
52
+ @sdb.responses << error_response('RequestTimeout')
53
+
54
+ assert_raise(Amazon::SDB::TimeoutError) { @sdb.domains }
55
+ assert_in_delta(0.0000219907, @sdb.box_usage, 2 ** -20)
56
+ end
57
+
58
+ def test_block_usage
59
+ @sdb.responses << <<-EOF
60
+ <?xml version="1.0" encoding="utf-8" ?>
61
+ <ListDomainsResponse xmlns="http://sdb.amazonaws.com/doc/2007-11-07">
62
+ <ListDomainsResult>
63
+ <DomainName>foo</DomainName>
64
+ <DomainName>bar</DomainName>
65
+ <DomainName>baz</DomainName>
66
+ </ListDomainsResult>
67
+ <ResponseMetadata>
68
+ <RequestId>eb13162f-1b95-4511-8b12-489b86acfd28</RequestId>
69
+ <BoxUsage>0.50</BoxUsage>
70
+ </ResponseMetadata>
71
+ </ListDomainsResponse>
72
+ EOF
73
+
74
+ @sdb.responses << <<-EOF
75
+ <?xml version="1.0" encoding="utf-8" ?>
76
+ <ListDomainsResponse xmlns="http://sdb.amazonaws.com/doc/2007-11-07">
77
+ <ListDomainsResult>
78
+ <DomainName>foo</DomainName>
79
+ <DomainName>bar</DomainName>
80
+ <DomainName>baz</DomainName>
81
+ </ListDomainsResult>
82
+ <ResponseMetadata>
83
+ <RequestId>eb13162f-1b95-4511-8b12-489b86acfd28</RequestId>
84
+ <BoxUsage>0.25</BoxUsage>
85
+ </ResponseMetadata>
86
+ </ListDomainsResponse>
87
+ EOF
88
+
89
+ @sdb.responses << <<-EOF
90
+ <?xml version="1.0" encoding="utf-8" ?>
91
+ <ListDomainsResponse xmlns="http://sdb.amazonaws.com/doc/2007-11-07">
92
+ <ListDomainsResult>
93
+ <DomainName>foo</DomainName>
94
+ <DomainName>bar</DomainName>
95
+ <DomainName>baz</DomainName>
96
+ </ListDomainsResult>
97
+ <ResponseMetadata>
98
+ <RequestId>eb13162f-1b95-4511-8b12-489b86acfd28</RequestId>
99
+ <BoxUsage>0.01</BoxUsage>
100
+ </ResponseMetadata>
101
+ </ListDomainsResponse>
102
+ EOF
103
+
104
+ @sdb.domains
105
+
106
+ usage = @sdb.box_usage do
107
+ @sdb.domains
108
+ @sdb.domains
109
+ end
110
+
111
+ assert_in_delta(0.26, usage, 2 ** -20)
112
+ end
113
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: amazon_sdb
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.0
4
+ version: 0.6.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jacob Harris
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2007-12-28 00:00:00 -05:00
12
+ date: 2008-01-14 00:00:00 -05:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -79,7 +79,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
79
79
  requirements: []
80
80
 
81
81
  rubyforge_project: nytimes
82
- rubygems_version: 1.0.0
82
+ rubygems_version: 1.0.1
83
83
  signing_key:
84
84
  specification_version: 2
85
85
  summary: A ruby wrapper to Amazon's sdb service
@@ -87,5 +87,7 @@ test_files:
87
87
  - test/test_amazon_base.rb
88
88
  - test/test_amazon_domain.rb
89
89
  - test/test_exceptions.rb
90
+ - test/test_item.rb
90
91
  - test/test_multimap.rb
91
92
  - test/test_sdb_harness.rb
93
+ - test/test_usage.rb