$Id: NEWS,v 1.18 2004/06/25 07:10:55 ianmacd Exp $


0.8.3, 2004-06-25

- Users whose environment dictates the use of an HTTP proxy server may now
  define this server in the $http_proxy environment variable. If set,
  Ruby/Amazon will use the server specified in this variable to channel
  outgoing HTTP requests.


0.8.2, 2004-04-16

- To help cope with the unreliable nature of AWS, the Fixnum class has been
  extended with the #attempts method, which allows AWS operations to be
  retried an arbitrary number of times without having to worry about dealing
  with transient errors.

  For example:

  resp = 3.attempts do |x|
    puts "Attempt #{x}..."
    req.keyword_search('blogs', 'books', LITE, ALL_PAGES)
  end

- The Amazon::Search::SearchError exception class has been moved to
  Amazon::Search::Request::SearchError for consistency with other search
  request exceptions.

- Responses to ShoppingCart transactions are no longer cached, regardless of
  whether the user has requested the use of the cache.

- @locale and @cache are now writable in Request objects, so that the user
  may dynamically change the locale and the use of a cache at any time.

- Error-checking during config file parsing has been improved. If an
  error is found during parsing, an Amazon::Search::Request::ConfigError
  exception is raised.

- If a LocaleError exception is raised, the bad locale is now reported.


0.8.1, 2004-04-02

- Having no config file would cause an exception. This has now been fixed.
  The same bug caused the parsing of the first config file to be ditched if
  there was more than one config file.

- Using a cache directory will now create the directory if it does not exist
  and will also raise an Amazon::Search::Cache::PathError if the path given is
  not a directory, or if the directory is either unreadable or unwritable.
	    
- The constant Amazon::Search::Request::ALL_PAGES has now been renamed
  Amazon::Search::ALL_PAGES.

- If a locale is provided in a config file, it will no longer override a
  locale passed directly to a method.

- A workaround for the fact that MerchantSku no longer seems to be returned by
  remote shopping cart procedures has been implemented.


0.8.0, 2004-03-23

- A simple response caching system is now implemented.
  Amazon::Search::Request#initialize now has 'cache' as its 4th argument,
  which defaults to 'true'. If true, a new @cache attribute is initialised to
  point to a cache directory. By default, this is /tmp/amazon, but this can be
  changed by defining 'cache_dir' in either /etc/amazonrc or ~/.amazonrc.

  When a cache directory is used, Ruby/Amazon will check the cache directory
  for a recent copy of a response to the exact search that you are requesting.
  If found, the cached response will be returned instead of the request being
  forwarded to the AWS servers for processing. If no (recent) copy is found,
  the request will be forwarded to the AWS servers as usual. Recency is
  defined here as less than 24 hours old. 
  
  The new module Amazon::Search::Cache provides this new functionality. It
  also provides a couple of methods for flushing the cache. One of these
  deletes all responses from the cache, whilst the other deletes only those
  responses that have expired. No automatic cache expiry takes place.

  At the moment, there is a known interoperability issue between the use of
  the cache and ALL_PAGES searches. Due to the use of threads in ALL_PAGES
  searches, the response corresponding to a given page number may get cached
  as if it were the response to another page number; or it may not get cached
  at all.

  For example, an ALL_PAGES search that yields 56 results will be spread over
  6 pages. Page 3 may get cached as if it were page 4 and page 2 may not get
  cached at all. I'm working to fix the problem, but for time time being, I
  recommend you do not use the cache if ALL_PAGES searches are important to
  you.

- There is a new module, Amazon::Locale, that can be used to determine which
  AWS locale should be used to serve a given request. For example, if a
  customer in Austria is browsing your site and attempts to use code written
  by you to perform a product search via AWS, you would most likely want that
  search to take place in the DE locale, whereas an Irish customer attempting
  to search for a DVD will most likely want to see products from the UK
  catalogue.

  The Amazon::Locale module contains methods that will return a sensible
  locale to use for a given IP address or DNS hostname.

- Passing a sort type parameter to a search method resulted in an error, as
  the URL-encoded first character would later be confused with a format
  specifer during final URL construction.

- A SearchError exception is now raised if a Marketplace search explicitly
  returns zero open listings.


0.7.6, 2004-03-16

- The names of Amazon::Product and Amazon::Exchange::Product properties have
  been normalised, so that you would now refer to foo.total_customer_reviews,
  not foo.totalcustomerreviews, etc.

  Remember that you can use the Amazon::Product#properties method to give you
  the entire list of readable properties.

- Some new search modes have been added to the DE locale, in line with
  Amazon's recent changes to that locale.

- Certain product properties are now returned as integers or floats, not
  strings, where relevant. @average_customer_rating, for example, is now a
  float, whereas @num_media and @sales_rank are integers.

- Some minor code clean-up has been done.


0.7.5, 2004-03-10

Again, this is mostly a bug fix release. There have been some improvements
made to the documentation and robustness has been improved.

- When instantiating Request objects, Ruby/Amazon will now look for
  /etc/amazonrc and possibly also ~/.amazonrc (if $HOME is set appropriately).
  If found, configuration directives will be read and evaluated. These should
  take the following form:

  dev_token = 'foo'
  associate = 'bar-20'

  Using this mechanism, it's possible to avoid passing any parameters
  whatsoever to Amazon::Search::Request.new. Configuration parameters and
  their values are stored in the new @config attribute.

- Amazon::Search::Request#wishlist_search can now take a page parameter.

- An Amazon::SearchError exception is now raised on an ALL_PAGES search if the
  total number of pages to fetch cannot be determined from the first page
  returned by AWS. This affects wishlist searches, which do not provide this
  information. This is a known issue with AWS and Amazon is aware of it.

- New class method, Amazon::ShoppingCart.one_click_form, allows the return of
  an HTML form for making a purchase using Amazon's 1-Click purchasing.

- Improve robustness of error detection when performing a seller profile
  search.

- Fixed bug whereby developer token was missing from HTML form produced by
  baby registry, wedding registry, wishlist and shopping-cart modules.

- Amazon::DEFAULT_ID is now a Hash and is used to set the Associates ID if
  none is provided by the programmer. In that event, the Ruby/Amazon author's
  Associates ID will be used for the given locale.

- New constant Amazon::USER_AGENT provides the default user-agent passed to
  the AWS servers.

- A new example program is provided: cart. This program is rather like the
  example program, rcart, in that it will accept a list of ASINs and add them
  to a remote shopping-cart. However, cart goes further: instead of displaying
  the purchase URL, it logs into Amazon using HTTPS and merges the remote cart
  with the central one.


0.7.0, 2004-02-29

This is mostly a bug fix and code clean-up release.

The design of the lower levels of Ruby/Amazon had been nagging at me for a
while and I didn't want to implement any new features until I had addressed
this. Specifically, having Request objects return Response objects that
subsequently required the programmer to manually invoke the #parse method on
them seemed unnatural. How many programmers are likely to want to conduct
searches without parsing the results? Not many, I'm willing to wager.

As a result, requesting a search now automatically parses the response and
stores the result in an attribute of the Response object. This makes for much
more natural programming. Furthermore, since it's no longer necessary or
possible to manually invoke #parse, you can now pass an optional block to the
search method, which also feels far more natural.

The upshot of all of this is that obtaining search results is now as simple as
this:

  require 'amazon/search'
  include Amazon::Search
  
  req  = Request.new('XXX')   # your token
  resp = req.keyword_search('ruby') {|p| printf("Product:\n%s---\n", p)}

Here follows the full list of changes in this release:

- Amazon::Blended::ProductLine has been moved to Amazon::ProductLine.

- Amazon::Seller, Amazon::Transaction and Amazon::ShoppingCart::Item are now
  all subclasses of Amazon::Product, so that to_s and other utility methods
  can be inherited.

- Amazon::BabyRegistry.add_item has been moved to .add_item_form to make its
  purpose clearer and its use consistent with the identically named methods in
  the ShoppingCart class. Similarly, Amazon::WeddingRegistry.add_item and
  Amazon::Wishlist.add_item have undergone the same renaming.

- AWS now returns wishlists in ascending order, so we reverse the order of the
  results to present them in descending order, which makes more sense.

- All search methods can now take an optional block. If supplied, the
  products, seller or whichever details are returned by the method are yielded
  to the block.

- It's no longer possible or necessary to manually call #parse on a Response
  object. Instead, this is now automatically done when one of the search
  methods is called by a Request object. Consequently, the now private
  Response#parse no longer returns the object it once did (usually an Array),
  but self. The object it once returned is now stored in an attribute of the
  Response object. See below for more details.

- ShoppingCart transactions now return an object of a new class,
  Amazon::ShoppingCart::Response. This is pretty much transparent to the
  programmer.

- Amazon::Transaction::Response objects now have a @transactions attribute,
  which substitutes for the now private #parse method returning an Array of
  Amazon::Transaction objects.

- Amazon::Search::Blended::Response objects now have a @product_lines
  attribute, which substitutes for the now private #parse method returning an
  Array of Amazon::ProductLine objects.

- Amazon::Search::Exchange::Response objects now have a @products attribute,
  which substitutes for the now private #parse method returning an Array of
  Amazon::Exchange::Product objects.

- Amazon::Search::Seller::Response objects now have a @seller attribute,
  which substitutes for the now private #parse method returning an
  Amazon::Seller object.

- Amazon::Search::Exchange::Marketplace::Response objects now have a @products
  attribute, which substitutes for the now private #parse method returning an
  Array of Amazon::Exchange::Product objects. They also have @open_listings,
  which contains the number of open listings returned by AWS.

- Amazon::Search::Exchange::ThirdParty::Response objects now have a @products
  attribute, which substitutes for the now private #parse method returning an
  Array of Amazon::Exchange::Product objects. It also has @seller_nickname,
  @store_id, @store_name and @open_listings.

- Wishlist IDs can be 12 characters long, not just 13 as stated in the AWS
  documentation. 12 character IDs are now supported.

- Certain types of search on AWS are less reliable than others. Such searches,
  which seem to be seller, marketplace and third-party searches, now detect
  an empty search result set and raise SearchError accordingly. If, however,
  the nature of the error cannot be determined, self (which is the XML page
  returned by Amazon) is passed as the message when raising the SearchError
  exception. Error detection in general has been improved in this release.

- In accordance with AWS Newsletter #7, searches in the JP locale now go to
  xml.amazon.co.jp. This change is transparent to the programmer.


0.6.0, 2004-02-23

- New instance method Amazon::Product#[] allows a product to be referenced by
  any of its instance variables, as if it were a Hash. For example,
  foo['asin'] would give you the ASIN of the Amazon::Product called foo.

- New instance method Amazon::Product#to_h really does convert an
  Amazon::Product to a Hash, so that all of the instance methods of that
  class can be used.

- It's no longer necessary to "require 'amazon'" when using the baby registry,
  wedding registry, wishlist and shopping cart libraries.

- The baby registry, wedding registry, wishlist and shopping cart libraries
  were all producing non-functional forms for adding items to them. This bug
  has been fixed.

- Search errors were not causing exceptions to be properly raised. This has
  now been corrected. Additionally, some types of search nest the error
  message deeper in the XML node tree. This type of error is now also
  detected.

- There are new reader methods for Amazon::Search::Request instance variables
  @id and @token.

- Amazon AWS documentation does not mention that the sort order of search
  results can be influenced when using REST (as opposed to SOAP), but this
  can, in fact, be done. Relevant search methods (those that return multiple
  results) now accept a sort type parameter. These methods are
  #keyword_search, #node_search, #author_search, #power_search,
  #artist_search, #director_search, #manufacturer_search and
  #text_stream_search.

- The valid sort types referred to in the last point can be obtained with the
  Amazon::Search.sort_types method.

- A new exception class, Amazon::Search::Request::SortError, exists for the
  purpose of indicating the passing of an incorrect sort type to a search
  method.

- 'video' is now returned as a valid search mode by Amazon::Search.modes. This
  mode is apparently the union of the 'dvd' and 'vhs' modes, but is not
  documented as such in the AWS documentation. 'video' is now allowed as a
  valid mode by #upc_search, #actor_search and #director_search.

- #parse can now be called on the result of an Amazon::Search::Request,
  regardless of whether an Amazon::Search::Response or an Array of such
  responses is returned. This is achieved by creating a singleton #parse
  method for the Array in the event of multiple page responses.

- Amazon::ShoppingCart is now a class, not a module, and has been greatly
  expanded with a full implementation of the functionality available via the
  Remote Cart section of the AWS API.  After instantiating a member of this
  class, the following instance methods can be used:

  - #add_items adds one or more items to a shopping cart. The first item to be
    added physically creates the cart on Amazon's servers. There is no need
    for the user to track shopping cart ID or HMAC (see the AWS
    documentation), as the objects themselves track these details from one
    operation to the next.

  - #modify_items changes the quantity of one or more items in a shopping
    cart. The number may be zero, which results in an internal call to
    #remove_items.

  - #remove_items directly removes one or more items from a shopping cart.

  - #retrieve_items returns the state of a shopping cart.

  - #clear (or its synonym, #empty) clears a shopping cart of all products,
    but does not destroy the cart. New items may still be added.

  - #[] allows you to refer to an item in a shopping cart by its ASIN. This
    will return an Array of Amazon::ShoppingCart::Item objects, one per entry
    in the shopping cart. Note that adding the same product multiple times to
    a cart will result in an Array of more than one Item for that ASIN. In
    other words, Amazon does not aggregate items.

- The ShoppingCart class has a couple of new supporting Exception classes,
  CartError and QuantityError. These are raised when shopping cart
  transactions fail or an illegal quantity is passed to a method.

- ShoppingCart.add_items module method is now a class method and has been
  renamed ShoppingCart.add_items_form.

- ShoppingCart.add_items method was using the Associates ID in the POST
  action. This should have been the ASIN.

- ShoppingCart.add_marketplace_item module method is now a class method and
  has been renamed ShoppingCart.add_items_form.

- ShoppingCart.add_marketplace_item module was using the Associates ID in the
  POST action. This should have been the ASIN.

- New class Amazon::Transaction allows the use of Amazon's Transaction Details
  API to verify up to five transactions.
  
  After instantiating an Amazon::Transaction::Request object, #get_details may
  be used to request information on transactions. This returns an
  Amazon::Transaction::Response, whose #parse method may be called to return
  an Array of Amazon::Transaction items. Amazon::Transaction::Error objects
  store the details of failed requests for transaction details. An Array of
  these is stored in the @error instance variable of Amazon::Transaction
  items.

- New exception class Amazon::Transaction::Request::OrderIDError is raised
  when an incorrect order ID is passed to #get_details.

- @total_pages and @total_results were not being set in Array objects
  returned by ALL_PAGES searches.

- Classes that have a #parse method now always return the same result, whether
  or not a block was given.


0.5.0, 2004-02-15

- New method Amazon::Search::Request#text_stream supports text stream
  searches.

- It's now no longer necessary to "require 'amazon'" before requiring
  'amazon/search', 'amazon/babyregistry', 'amazon/shoppingcart',
  'amazon/weddingregistry' and 'amazon/wishlist'.

- The Amazon::Search::Offerings module has been removed, as offerings are
  now completely integrated into Amazon::Search.

- Failed searches will now populate the @error attribute of Response objects
  when their #parse method is called.

- New module method Amazon::Search.offer_types replaces method of same name
  in Amazon::Search::Offerings.

- It's now possible to return offering (third-party item) data when using
  #asin_search, #keyword_search, #actor_search, #node_search,
  #director_search, #artist_search, #author_search, #power_search and
  #manufacturer_search. A new parameter must be passed to these methods to
  indicate what type of offering data is desired. This parameter must be
  equal to one of the offer types returned by Amazon::Search.offer_types.
  If it is nil, no offering data is returned with the search results.

- #asin_search now accepts an offer_page parameter, which is ignored if
  the offerings parameter is nil. Otherwise, it determines which page of
  offering results to return.

- Search heaviness is now stored in the @type attribute of Request objects.

- ALL_PAGES searches are now threaded, but this makes little difference if
  Amazon::Search::RATE_LIMIT_REQUESTS is set, which, by default, it is.

- Amazon::Search::Request#parse and similarly named methods in the subclasses
  now return @args if a block was passed to them.

- Amazon::Search::Response objects now populate a hash attribute, @args, when
  their #parse method is called. This corresponds to the args nodes returned
  by Amazon's servers.

- The HTTP response code will now be printed whenever an HTTPError exception
  is generated.

- A minor bug was fixed, whereby the user-agent was not set when searching
  for the second and subsequent pages of ALL_PAGES requests.

- 'apparel' and 'wireless-phones' are now a valid search mode, although their
  status with AWS is unofficial.


0.4.0, 2004-02-07

- New instance method Amazon::Search::Request#blended_search supports
  blended searches, which return products from up to 15 Amazon categories.

- New instance method Amazon::Search::Request#wishlist_search supports
  wishlist searches, although these are currently broken on Amazon's AWS
  servers.

- New Amazon::Search::Exchange module supports exchange searches. Exchange
  items are those offered for sale by third-parties. This module allows you
  to search for them by their unique ID.

- New Amazon::Search::Offerings module supports searching for offerings.
  Offerings are products sold by third-party sellers. This module allows you
  to search for them by their ASIN.

- New Amazon::Search::Seller module supports seller profile searches.

- New Amazon::Search::Exchange::ThirdParty module supports third party
  product searches. This allows you to find all products for sale by a
  given seller.

- New Amazon::BabyRegistry module generates HTML form for adding an item to a
  baby registry.

- New Amazon::ShoppingCart module generates HTML form for adding items to a
  shopping cart.

- New Amazon::WeddingRegistry module generates HTML form for adding an item to
  a wedding registry.

- New Amazon::Wishlist module generates HTML form for adding an item to a
  wishlist.

- New Amazon::Product#to_s method allows for easy human-friendly printing
  of products.

- Amazon::Search::Response#parse and other such #parse methods in subclasses
  can now act as iterators to an optional block, e.g.

  products.parse {|p| puts p}

- Amazon::Search::Request#similarity_search now allows up to 5 ASINs to be
  searched for. These may be passed as a comma- or space-separaterd string,
  or as an array of strings.

- Amazon::Search::Request methods #author_search, #keyword_search and
  #power_search now support an extra parameter at the end of the parameter
  list. Set this to Amazon::Search::ALL_EDITIONS to retrieve multiple editions
  of the same book or Amazon::Search::SINGLE_EDITION to retrieve just the
  latest. The default is SINGLE_EDITION.

- Amazon::Search::Response objects now contain new instance variables
  @total_results and @total_pages for tracking the total number of results and
  pages for each search.

- New exception class Amazon::Search::HTTPError.

- The URL of the page to be fetched is now printed if Ruby is run with -d.

- Amazon::Marketplace::Product has been renamed Amazon::Exchange::Product.

- Exception Amazon::Search::Request::SearchError has moved to
  Amazon::Search::SearchError, as it's useful to the Response class, too.

- Amazon::Search::Exchange::Marketplace#parse returns nil if no listings
  were found.

- Amazon::Search::Exchange::Marketplace#parse no longer returns a two-
  element array, consisting of an array of products and the number of open
  listings. Instead, a singleton array of products is returned, with the
  number of open listings available as @openlistings.

- Amazon::Search::Exchange::Marketplace class methods renamed:

  Marketplace.keyword_searches	->  Marketplace.keyword_search_types
  Marketplace.geos		->  Marketplace.geo_types
  Marketplace.sorts		->  Marketplace.sort_types
  Marketplace.indices		->  Marketplace.index_types

- New classes Amazon::Offerings::Product, Amazon::Blended::ProductLine,
  Amazon::Feedback, Amazon::ThirdPartyInfo and Amazon::Seller. These classes
  are needed by the new types of search that have been added in this version.

- Search facilities must now be specifically called, using:

  require 'amazon'
  require 'amazon/search'

- Fixed bad exception raising on HTTP errors.

- Fixed bug with searches using 'software' mode in 'uk' locale.

- Fixed a bug in ALL_PAGES requests that caused the first page of results
  to be fetched twice, resulting in duplicate products. The same bug caused
  the last page to not be returned at all.

- Improvements to RDoc documentation.

- Lots of new unit tests.


0.3.0, 2004-01-31

- Amazon::Search::Request#search has been subdivided into #keyword_search,
  #node_search, #asin_search, #upc_search, #author_search, #power_search,
  #artist_search, #actor_search, #director_search, #manufacturer_search,
  #listmania_search and #similarity_search.
  
  Rather than passing nil parameters where arguments were irrelevant, each of
  these new methods requires only those arguments that make sense for the
  particular type of search it supports.

- New module Amazon::Search::Marketplace for Amazon Marketplace searches.

- New product class Amazon::Search::Marketplace::Product.

- New instance methods Amazon::Search::Marketplace#keyword_search and
  Amazon::Search::Marketplace#listing_search for marketplace searches.
  These return Amazon::Search::Marketplace::Response objects.

- New class methods Amazon::Search::Marketplace.keyword_searches,
  Amazon::Search::Marketplace.geos, Amazon::Search::Marketplace.sorts and
  Amazon::Search::Marketplace.indices for determining valid keyword search
  types, geos types, sort types and index types when doing a marketplace
  search.

- The international properties amazon.co.uk, amazon.de and amazon.co.jp are
  now also supported via a 3rd parameter to Amazon::Search::Request.new. A two
  letter string, 'us', 'uk', 'de' or 'jp', can be passed. Request objects
  now contain a new instance variable, @locale, to track this when performing
  searches.

- Amazon::Search::Request.new can now take a 4th argument, which is a
  user-agent to pass on to Amazon's Web Services

- New Amazon::NAME constant gives library name.

- ALL_PAGES searches are now returned more efficiently, as XML parsing
  can be deferred until Amazon::Search#parse is used.

- UPC search now accepts extra modes: classical, software, dvd, vhs,
  electronics, pc-hardware.

- Price range restrictions are now supported on relevant searches.

- Single page ALL_PAGES searches now yield a single-element array, rather than
  directly returning an Amazon::Search::Response object.

- Exception classes are now subclasses of StandardError, not RuntimeError.

- Better error-checking and exception raising all around.


0.2.0, 2004-01-22

- The Associates ID is now optional in Amazon::Search::Request.new. As such,
  it has swapped places with the developer token as the second parameter. If
  you don't have an Associates ID, don't pass the second argument to the
  method and a default ('webservices-20') value will be used instead.

- When passing an explicit page number to Amazon::Search::Request#search, you
  can now use the constant Amazon::Search::Request::ALL_PAGES as the page
  number. This will cause all pages pertaining to your search to be returned.
  This can take quite some time for non-specific searches.

- If ALL_PAGES is given, an Array of Amazon::Search::Responses will be
  returned instead of a single Amazon::Search::Response, unless your search
  returns a single page.

- Search types that logically have no use for the 'page' parameter now ignore
  it if it is specified. The searches in question are ASIN, UPC and Listmania
  searches.

- The Amazon::Search::TypeError exception class has been added to catch
  non-existent search types.

- @avgcustomerrating was not being set in Amazon::Search::Review objects.

- There are new constants Amazon::Search::Request::HEAVY,
  Amazon::Search::Request::LITE (and Amazon::Search::Request::LIGHT, just for
  the sake of correct spelling).

- Amazon::Search::Request::POWER_SEARCH is supported as a new search type.

- Ruby/Amazon now makes calls to version 3 of the Amazon Web Services API.

- The Amazon::Search::Review struct is now a real class. This was done in
  order to make its instance variables read-only, which they now are.


0.1.0, 2004-01-17

- first public release
