<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array">
    <added>
      <filename>lib/amazon_sdb/usage.rb</filename>
    </added>
    <added>
      <filename>test/test_item.rb</filename>
    </added>
    <added>
      <filename>test/test_usage.rb</filename>
    </added>
  </added>
  <modified type="array">
    <modified>
      <diff>@@ -1,3 +1,9 @@
+== 0.6.5 / 2008-01-15
+* 3 major enhancements
+  * New usage tracking via the box_usage method
+  * Better docs
+  * Boolean coercion
+
 == 0.6.0 / 2007-12-28
 * 2 major enhancements
   * Correct error handling for API's HTTP responses (with tests)</diff>
      <filename>History.txt</filename>
    </modified>
    <modified>
      <diff>@@ -9,11 +9,11 @@ http://code.nytimes.com/svn/ruby/gems/amazon_sdb
 
 == DESCRIPTION:
   
-Amazon sdb is a Ruby wrapper to Amazon's new Simple Database Service. Amazon sdb is a different type of database:
+Amazon SDB is a Ruby wrapper to Amazon's new Simple Database Service. Amazon sdb is a different type of database:
 
 * Accessed over the network via RESTful calls
 * No schemas or types
-* Each sdb account can have up to 100 domains for data.
+* Each SimpleDB account can have up to 100 domains for data.
 * Domains can hold objects referenced by unique keys
 * Each object can hold up to 256 name/value attributes.
 * 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
 
 == FEATURES:
   
-* A basic interface to Amazon sdb
-* Includes a class for representing attribute sets in sdb
-* Automatic conversion to/from sdb representations for integers and dates (for floats, it's suggested you use the Multimap#numeric function)
+* A basic interface to Amazon SimpleDB
+* Includes a class for representing attribute sets in SimpleDB
+* Automatic conversion to/from SimpleDB representations for integers and dates (for floats, it's suggested you use the Multimap#numeric function)
 * The beginnings of mock-based tests for methods derived from Amazon's docs
 
 == CAVEATS
@@ -41,7 +41,7 @@ Amazon sdb is a Ruby wrapper to Amazon's new Simple Database Service. Amazon sdb
 
 == SYNOPSIS:
 
-  b = Amazon::sdb::Base.new(aws_public_key, aws_secret_key)
+  b = Amazon::SDB::Base.new(aws_public_key, aws_secret_key)
 	b.domains #=&gt; list of domain
 	domain = b.create_domain 'my domain'
 	</diff>
      <filename>README.txt</filename>
    </modified>
    <modified>
      <diff>@@ -30,6 +30,7 @@ require 'amazon_sdb/domain'
 require 'amazon_sdb/item'
 require 'amazon_sdb/resultset'
 require 'amazon_sdb/exceptions'
+require 'amazon_sdb/usage'
 
 module Amazon
   module SDB</diff>
      <filename>lib/amazon_sdb.rb</filename>
    </modified>
    <modified>
      <diff>@@ -15,6 +15,8 @@ module Amazon
       def initialize(aws_access_key, aws_secret_key)
         @access_key = aws_access_key
         @secret_key = aws_secret_key
+        @usage = Usage.new
+        raise @usage
       end
 
       ##
@@ -32,16 +34,42 @@ module Amazon
         @@number_padding = num
       end
       
+      ##
+      # The number of digits after the decimal points to use by default
       def self.float_precision
         return @@float_precision
       end
       
+      ##
+      # Set the #float_precision
       def self.float_precision=(num)
         return @@float_precision
       end
 
       ##
-      # Retrieves a list of domains in your SDS database. Each entry is a Domain object.
+      # Returns the Box Usage accumulated since the beginning of the session. Box Usage represents computation time and is one of
+      # the parameters in your monthly SimpleDB bill. As an alternative, when passed a block (no parameters yielded), it returns 
+      # the box usage only for the operations within the block.
+      def box_usage
+        unless block_given?
+          @usage.box_usage
+        else
+          # return the usage of the actions in the block
+          usage1 = @usage.box_usage
+          yield
+          usage2 = @usage.box_usage
+          return usage2 - usage1
+        end
+      end
+      
+      ##
+      # Resets the box usage accumulated within the current session. Not sure why you'd need to do this, but it's provided.
+      def reset_usage!
+        @usage.reset!
+      end
+
+      ##
+      # Retrieves a list of domains in your SDS database. Each entry is a Domain object. 
       def domains
         domains = []
         nextToken = nil
@@ -67,10 +95,35 @@ module Amazon
       end
 
       ##
-      # Returns a domain object for SDS. Assumes the domain already exists, so errors might occur if you didn't create it.
+      # Returns a domain object for SimpleDB. Assumes the domain already exists, so a ParameterError (NoSuchDomain) might occur if it's not there. This
+      # method is useful for getting a domain object without having to incur the operational costs of querying all domains.
       def domain(name)
         Domain.new(@access_key, @secret_key, name)
       end
+      
+      ##
+      # Creates a domain. This operation is idempotent, but it is slow and if you are sure the domain already exists, you might
+      # want to use the #domain method instead. Each SimpleDB account is allowed up to 100 domains; a LimitError will be raised
+      # if you attempt to create more.
+      def create_domain(name)
+        sdb_query({:Action =&gt; 'CreateDomain', 'DomainName' =&gt; name}) do |h|
+          domain(name)
+        end
+      end
+
+      ##
+      # Deletes a domain. Running this command multiple times or on a domain that does not exist will NOT return an error.
+      def delete_domain!(name)
+        sdb_query({:Action =&gt; 'DeleteDomain', 'DomainName' =&gt; name})
+      end
+
+    private
+      def parse_usage(hpricot)
+        usagenode = hpricot.at('//BoxUsage')
+        return unless usagenode
+        
+        @usage.add_usage usagenode.innerText.to_f
+      end
 
       def raise_errors(hpricot)
         errnode = hpricot.at('//Errors/Error')
@@ -102,18 +155,6 @@ module Amazon
         end
       end
       
-      def create_domain(name)
-        sdb_query({:Action =&gt; 'CreateDomain', 'DomainName' =&gt; name}) do |h|
-          domain(name)
-        end
-      end
-
-      ##
-      # Deletes a domain. This operation is currently not supported by SDS.
-      def delete_domain!(name)
-        sdb_query({:Action =&gt; 'DeleteDomain', 'DomainName' =&gt; name})
-      end
-
       def timestamp
         Time.now.iso8601
       end
@@ -148,11 +189,13 @@ module Amazon
           open(url) do |f|
             h = Hpricot.XML(f)
 
+            parse_usage h
             raise_errors h
             yield h if block_given?
           end
         rescue OpenURI::HTTPError =&gt; e
           h = Hpricot.XML(e.io.read)
+          parse_usage h
           raise_errors h
         end
       end
@@ -166,7 +209,6 @@ module Amazon
         return hmac(key, option_array.map {|pair| pair[0]+pair[1]}.join('')).chop
       end
 
-    private
       @@number_padding                 = 32
       @@float_precision                = 8
 </diff>
      <filename>lib/amazon_sdb/base.rb</filename>
    </modified>
    <modified>
      <diff>@@ -22,9 +22,9 @@ module Amazon
       ##
       # Sets attributes for a given key in the domain. If there are no attributes supplied, it creates an empty set.
       # Takes the following arguments:
-      # - key - a string key for the attribute set
-      # - multimap - an collection of attributes for the set in a Multimap object. If nothing, creates an empty set.
-      # - options - for put options
+      # - &lt;tt&gt;key&lt;/tt&gt; - a string key for the attribute set
+      # - &lt;tt&gt;multimap&lt;/tt&gt; - an collection of attributes for the set in a Multimap object (can convert a Hash and Array too). If nothing, creates an empty set.
+      # - &lt;tt&gt;options&lt;/tt&gt; - 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
       def put_attributes(key, multimap=nil, options = {})
         req_options = {'Action' =&gt; 'PutAttributes', 'DomainName' =&gt; name, 'ItemName' =&gt; key}
         
@@ -52,6 +52,7 @@ module Amazon
       ##
       # Gets the attribute list for a key. Arguments:
       # - &lt;tt&gt;key&lt;/tt&gt; - the key for the attribute set
+      # - &lt;tt&gt;attr_list&lt;/tt&gt; - 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.
       def get_attributes(key, *attr_list)
         options = {'Action' =&gt; 'GetAttributes', 'DomainName' =&gt; name, 'ItemName' =&gt; key}
         
@@ -75,7 +76,9 @@ module Amazon
       end
 
       ##
-      # Not implemented yet.
+      # Deletes the attributes associated with a particular item. If the optional &lt;tt&gt;multimap&lt;/tt&gt; argument is nil, deletes the entire
+      # object. Otherwise, the optional multimap argument can be used to delete specific key/value pairs in the object (also accepts
+      # a String or Symbol for a single name, an Array for multiple keys or a Hash for key/value pairs)
       def delete_attributes(key, multimap=nil)
         options = {'Action' =&gt; 'DeleteAttributes', 'DomainName' =&gt; name, 'ItemName' =&gt; key}
         
@@ -106,9 +109,10 @@ module Amazon
       ##
       # Returns a list of matching items that match a filter
       # Options include:
-      # - &lt;tt&gt;max_results&lt;/tt&gt; = the max items to return for a listing (top/default is 100)
-      # - &lt;tt&gt;:more_token&lt;/tt&gt; = to retrieve a second or more page of results, the more token should be provided
-      # - &lt;tt&gt;:load_attrs&lt;/tt&gt; = 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)
+      # - &lt;tt&gt;:expr&lt;/tt&gt; - a query expression to evaluate (see the Amazon SimpleDB documentation for details)
+      # - &lt;tt&gt;:max_results&lt;/tt&gt; - the max items to return for a listing (top/default is 100)
+      # - &lt;tt&gt;:next_token&lt;/tt&gt; - to retrieve a second or more page of results, the more token should be provided
+      # - &lt;tt&gt;:load_attrs&lt;/tt&gt; - 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.
       def query(query_options = {})
         req_options = {'Action' =&gt; 'Query', 'DomainName' =&gt; name}
         </diff>
      <filename>lib/amazon_sdb/domain.rb</filename>
    </modified>
    <modified>
      <diff>@@ -4,46 +4,80 @@ module Amazon
     end
     
     ACCESS_ERROR_CODES = %w{AccessFailure}
+
+    ##
+    # The AccessError represents access problems connecting to SimpleDB
     class AccessError &lt; Error
     end
     
     AUTH_ERROR_CODES = %w{AuthFailure AuthMissingFailure InvalidHTTPAuthHeader OptInRequired}
+
+    ##
+    # AuthError represents several different authentication problems that may occur when connecting to Amazon SimpleDB. See the
+    # message for details.
     class AuthError &lt; Error
     end
     
     PARAMETER_ERROR_CODES = %w(InvalidAction InvalidNextToken InvalidParameterError 
     InvalidParameterCombination InvalidParameterValue MissingAction MissingParameter NoSuchDomain
     )
+
+    ## 
+    # ParameterError is returned when a parameter to SimpleDB is invalid or missing. See the error for details.
     class ParameterError &lt; Error
     end
     
     QUERY_ERROR_CODES = %w{InvalidNumberPredicates InvalidNumberValueTests InvalidQueryExpression}
+    
+    ##
+    # The QuerySyntaxError covers several errors that may result from an invalid &lt;tt&gt;:expr&lt;/tt&gt; passed into the Domain#Query method.
     class QuerySyntaxError &lt; Error
     end
     
     LIMIT_ERROR_CODES = %w{NumberDomainsExceeded NumberDomainAttributesExceeded NumberDomainBytesExceeded NumberDomainBytesExceeeded URITooLong}
+  
+    ##
+    # A LimitError is returned when you hit one of the fundamental limits for SimpleDB accounts. See the message content for details.
     class LimitError &lt; Error
     end
     
     SERVER_ERROR_CODES = %w{InternalError ServiceOverload ServiceUnavailable}
+    
+    ##
+    # ServerErrors represent server problems on SimpleDB.
     class ServerError &lt; Error
     end
     
+    ##
+    # Huh? What? For when SimpleDB sends me an error code I've never seen before (and isn't in the docs)
     class UnknownError &lt; Error
     end
     
     REQUEST_ERROR_CODES = %w{InvalidHttpRequest InvalidSOAPRequest InvalidURI InvalidService UnsupportedHttpVerb}
+    
+    ##
+    # For incorrectly constructed HTTP queries against the SimpleDB server. If you see this error, it's my fault, and let me know
+    # the command that caused it.
     class RequestError &lt; Error
     end
     
     TIMEOUT_ERROR_CODES = %w{RequestExpired RequestTimeout RequestThrottled}
+    
+    ##
+    # Amazon SimpleDB times out any operation that lasts more than 5 seconds. This error will be returned.
     class TimeoutError &lt; Error
     end
     
     VERSION_ERROR_CODES = %w{FeatureDeprecated NoSuchVersion NotYetImplemented}
+    
+    ##
+    # For when there is a mismatch between this gem and the API being called.
     class VersionError &lt; Error
     end
     
+    ##
+    # When GetAttributes doesn't match, Amazon returns an empty record. I prefer to raise an exception instead, so there will be no
+    # confusion.
     class RecordNotFoundError &lt; Error
     end
   end</diff>
      <filename>lib/amazon_sdb/exceptions.rb</filename>
    </modified>
    <modified>
      <diff>@@ -1,7 +1,7 @@
 module Amazon
   module SDB
     ##
-    # An item from sdb. This basically is a key for the item in the domain and a Multimap of the attributes. You should never
+    # An item from SimpleDB. This basically is a key for the item in the domain and a Multimap of the attributes. You should never
     # call Item#new, instead it is returned by various methods in Domain and ResultSet
     class Item
       include Enumerable
@@ -13,23 +13,34 @@ module Amazon
         @attributes = multimap
       end
       
+      ##
+      # Reloads from the domain
       def reload!
         item = @domain.get_attributes(@key)
         @attributes = item.attributes
       end
       
+      ##
+      # Returns true if the attributes are empty
       def empty?
+        return true if @attributes.nil?
         @attributes.size == 0
       end
       
+      ##
+      # Deletes the item in SimpleDB
       def destroy!
         @domain.delete_attributes(@key)
       end
       
+      ##
+      # Saves the item back (like a put_attributes with :replace =&gt; :all
       def save
-        @domain.put_attributes(@key, @attributes)
+        @domain.put_attributes(@key, @attributes, :replace =&gt; :all)
       end
       
+      ##
+      # Reloads the item if necessary
       def get(key)
         reload! if @attributes.nil?
         @attributes.get(key)</diff>
      <filename>lib/amazon_sdb/item.rb</filename>
    </modified>
    <modified>
      <diff>@@ -172,6 +172,10 @@ module Amazon
 
       def sdb_value_escape(value)
         case value
+        when TrueClass
+          &quot;true&quot;
+        when FalseClass
+          &quot;false&quot;
         when Fixnum
           sprintf(&quot;%0#{Base.number_padding}d&quot;, value)
         when Float
@@ -204,6 +208,10 @@ module Amazon
 
       def coerce(value)
         case value
+        when 'true'
+          true
+        when 'false'
+          false
         when /^0+\d+$/
           value.to_i
         when /^0+\d*.\d+$/</diff>
      <filename>lib/amazon_sdb/multimap.rb</filename>
    </modified>
    <modified>
      <diff>@@ -105,6 +105,12 @@ class TestMultimap &lt; Test::Unit::TestCase
     @m['Num'] = Amazon::SDB::Multimap.numeric(12.34, 10, 4)
     assert_equal '00012.3400', @m['Num']
   end
+  
+  def test_boolean_to_sdb
+    @m['a'] = true
+   
+    assert_equal 'true', @m.to_sdb['Attribute.0.Value']
+  end
     
   def test_to_sdb_replace_all
     @m[:a] = &quot;foo&quot;
@@ -166,6 +172,14 @@ class TestMultimap &lt; Test::Unit::TestCase
     assert_equal &quot;0000000000034.3400000000&quot;, m.get(&quot;a&quot;, :before_cast =&gt; true)
   end
   
+  def test_coerce_boolean
+    m = Multimap.new
+    m.from_sdb([[&quot;a&quot;, &quot;true&quot;], [&quot;b&quot;, &quot;false&quot;]])
+  
+    assert_equal true, m[&quot;a&quot;]
+    assert_equal false, m[&quot;b&quot;]
+  end
+  
   def test_coerce_datetime
     now = Time.now
     </diff>
      <filename>test/test_multimap.rb</filename>
    </modified>
    <modified>
      <diff>@@ -9,6 +9,7 @@ class Amazon::SDB::Base
   def initialize(aws_access_key, aws_secret_key)
     @access_key = aws_access_key
     @secret_key = aws_secret_key
+    @usage = Amazon::SDB::Usage.new
     @responses = []
     @uris = []  
   end</diff>
      <filename>test/test_sdb_harness.rb</filename>
    </modified>
  </modified>
  <removed type="array"/>
  <parents type="array">
    <parent>
      <id>48f5498f8b23e0b7145f2c07eb4e173edd375dc8</id>
    </parent>
  </parents>
  <author>
    <name>harrisj</name>
    <email>harrisj@f6ba467f-1a71-446b-a959-e5960c5d402f</email>
  </author>
  <url>http://github.com/harrisj/amazon-sdb/commit/ca9957146205f702f610080c521a202879a83203</url>
  <id>ca9957146205f702f610080c521a202879a83203</id>
  <committed-date>2008-01-14T19:56:07-08:00</committed-date>
  <authored-date>2008-01-14T19:56:07-08:00</authored-date>
  <message>amazon_sdb: new usage class, testing for item methods, rdoc improvements

git-svn-id: svn+ssh://code.nytimes.com/var/open/repos/ruby/gems/amazon_sdb@12 f6ba467f-1a71-446b-a959-e5960c5d402f</message>
  <tree>4cebca15b94af91bac6e85578cf5286fbd00f39d</tree>
  <committer>
    <name>harrisj</name>
    <email>harrisj@f6ba467f-1a71-446b-a959-e5960c5d402f</email>
  </committer>
</commit>
