rasin 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. data/.document +3 -0
  2. data/.gitignore +6 -0
  3. data/.travis.yml +13 -0
  4. data/CHANGELOG.rdoc +49 -0
  5. data/Gemfile +4 -0
  6. data/Gemfile.lock +54 -0
  7. data/README.rdoc +166 -0
  8. data/asin.gemspec +36 -0
  9. data/lib/asin.rb +8 -0
  10. data/lib/asin/client.rb +398 -0
  11. data/lib/asin/configuration.rb +105 -0
  12. data/lib/asin/simple_cart.rb +54 -0
  13. data/lib/asin/simple_item.rb +44 -0
  14. data/lib/asin/simple_node.rb +44 -0
  15. data/lib/asin/version.rb +3 -0
  16. data/rakefile.rb +11 -0
  17. data/spec/asin.yml +4 -0
  18. data/spec/browse_node_spec.rb +17 -0
  19. data/spec/cart_spec.rb +150 -0
  20. data/spec/cassettes/asin/asin_cart_with_an_existing_cart_should_add_items_to_a_cart.yml +68 -0
  21. data/spec/cassettes/asin/asin_cart_with_an_existing_cart_should_clear_a_cart.yml +66 -0
  22. data/spec/cassettes/asin/asin_cart_with_an_existing_cart_should_get_a_cart.yml +67 -0
  23. data/spec/cassettes/asin/asin_cart_with_an_existing_cart_should_update_a_cart.yml +70 -0
  24. data/spec/cassettes/asin/browse_node_should_lookup_a_browse_node.yml +38 -0
  25. data/spec/cassettes/asin/cart_should_create_a_cart.yml +36 -0
  26. data/spec/cassettes/asin/lookup_and_search_should_have_metadata.yml +81 -0
  27. data/spec/cassettes/asin/lookup_and_search_should_lookup_a_book.yml +81 -0
  28. data/spec/cassettes/asin/lookup_and_search_should_lookup_multiple_books.yml +131 -0
  29. data/spec/cassettes/asin/lookup_and_search_should_lookup_multiple_response_groups.yml +43 -0
  30. data/spec/cassettes/asin/lookup_and_search_should_return_a_custom_item_class.yml +81 -0
  31. data/spec/cassettes/asin/lookup_and_search_should_return_a_mash_value.yml +81 -0
  32. data/spec/cassettes/asin/lookup_and_search_should_return_a_rash_value.yml +81 -0
  33. data/spec/cassettes/asin/lookup_and_search_should_return_a_raw_value.yml +81 -0
  34. data/spec/cassettes/asin/lookup_and_search_should_search_keywords_a_book_with_fulltext.yml +538 -0
  35. data/spec/cassettes/asin/lookup_and_search_should_search_keywords_and_handle_a_single_result.yml +72 -0
  36. data/spec/cassettes/asin/lookup_and_search_should_search_keywords_never_mind_music.yml +119 -0
  37. data/spec/cassettes/asin/lookup_and_search_should_search_music.yml +37 -0
  38. data/spec/cassettes/asin/lookup_and_search_should_search_never_mind_music.yml +122 -0
  39. data/spec/config_spec.rb +53 -0
  40. data/spec/search_spec.rb +101 -0
  41. data/spec/spec_helper.rb +47 -0
  42. metadata +197 -0
@@ -0,0 +1,105 @@
1
+ require "yaml"
2
+ require 'logger'
3
+
4
+ module ASIN
5
+ class Configuration
6
+ class << self
7
+
8
+ attr_accessor :secret, :key, :host, :logger
9
+ attr_accessor :item_type, :cart_type, :node_type
10
+ attr_accessor :version, :associate_tag
11
+
12
+ # Rails initializer configuration.
13
+ #
14
+ # Expects at least +secret+ and +key+ for the API call:
15
+ #
16
+ # ASIN::Configuration.configure do |config|
17
+ # config.secret = 'your-secret'
18
+ # config.key = 'your-key'
19
+ # end
20
+ #
21
+ # With the latest version of the Product Advertising API you need to include your associate_tag[https://affiliate-program.amazon.com/gp/advertising/api/detail/api-changes.html].
22
+ #
23
+ # You may pass options as a hash as well:
24
+ #
25
+ # ASIN::Configuration.configure :secret => 'your-secret', :key => 'your-key'
26
+ #
27
+ # Or configure everything using YAML:
28
+ #
29
+ # ASIN::Configuration.configure :yaml => 'config/asin.yml'
30
+ #
31
+ # ASIN::Configuration.configure :yaml => 'config/asin.yml' do |config, yml|
32
+ # config.key = yml[Rails.env]['aws_access_key']
33
+ # end
34
+ #
35
+ # ==== Options:
36
+ #
37
+ # [secret] the API secret key (required)
38
+ # [key] the API access key (required)
39
+ # [associate_tag] your Amazon associate tag. Default is blank (required in latest API version)
40
+ # [host] the host, which defaults to 'webservices.amazon.com'
41
+ # [logger] a different logger than logging to STDERR (nil for no logging)
42
+ # [version] a custom version of the API calls. Default is 2010-11-01
43
+ # [item_type] a different class for SimpleItem, use :mash / :rash for Hashie::Mash / Hashie::Rash or :raw for a plain hash
44
+ # [cart_type] a different class for SimpleCart, use :mash / :rash for Hashie::Mash / Hashie::Rash or :raw for a plain hash
45
+ # [node_type] a different class for SimpleNode, use :mash / :rash for Hashie::Mash / Hashie::Rash or :raw for a plain hash
46
+ #
47
+ def configure(options={})
48
+ init_config
49
+ if yml_path = options[:yaml] || options[:yml]
50
+ yml = File.open(yml_path) { |file| YAML.load(file) }
51
+ if block_given?
52
+ yield self, yml
53
+ else
54
+ yml.each do |key, value|
55
+ send(:"#{key}=", value)
56
+ end
57
+ end
58
+ elsif block_given?
59
+ yield self
60
+ else
61
+ options.each do |key, value|
62
+ send(:"#{key}=", value)
63
+ end
64
+ end
65
+ self
66
+ end
67
+
68
+ # Checks if given credentials are valid and raises an error if not.
69
+ #
70
+ def validate_credentials!
71
+ raise "you have to configure ASIN: 'configure :secret => 'your-secret', :key => 'your-key'" if blank?(:secret) || blank?(:key)
72
+ [:host, :item_type, :cart_type, :node_type, :version, :associate_tag].each { |item| raise "nil is not a valid value for #{item}" unless self.send item }
73
+ end
74
+
75
+ # Resets configuration to defaults
76
+ #
77
+ def reset
78
+ init_config(true)
79
+ end
80
+
81
+ # Check if a key is set
82
+ #
83
+ def blank?(key)
84
+ val = self.send :key
85
+ val.nil? || val.empty?
86
+ end
87
+
88
+ private()
89
+
90
+ def init_config(force=false)
91
+ return if @init && !force
92
+ @init = true
93
+ @secret = ''
94
+ @key = ''
95
+ @host = 'webservices.amazon.com'
96
+ @logger = Logger.new(STDERR)
97
+ @item_type = SimpleItem
98
+ @cart_type = SimpleCart
99
+ @node_type = SimpleNode
100
+ @version = '2010-11-01'
101
+ @associate_tag = ''
102
+ end
103
+ end
104
+ end
105
+ end
@@ -0,0 +1,54 @@
1
+ require 'hashie'
2
+
3
+ module ASIN
4
+
5
+ # = SimpleCart
6
+ #
7
+ # The +SimpleCart+ class is a wrapper for the Amazon XML-REST-Response.
8
+ #
9
+ # A Hashie::Mash is used for the internal data representation and can be accessed over the +raw+ attribute.
10
+ #
11
+ class SimpleCart
12
+
13
+ attr_reader :raw
14
+
15
+ def initialize(hash)
16
+ @raw = Hashie::Mash.new(hash)
17
+ end
18
+
19
+ def cart_id
20
+ @raw.CartId
21
+ end
22
+
23
+ def hmac
24
+ @raw.HMAC
25
+ end
26
+
27
+ def url
28
+ @raw.PurchaseURL
29
+ end
30
+
31
+ def price
32
+ @raw.SubTotal.FormattedPrice
33
+ end
34
+
35
+ def items
36
+ return [] unless @raw.CartItems
37
+ @raw.CartItems.CartItem.is_a?(Array) ? @raw.CartItems.CartItem : [@raw.CartItems.CartItem]
38
+ end
39
+
40
+ def saved_items
41
+ return [] unless @raw.SavedForLaterItems
42
+ @raw.SavedForLaterItems.SavedForLaterItem.is_a?(Array) ? @raw.SavedForLaterItems.SavedForLaterItem : [@raw.SavedForLaterItems.SavedForLaterItem]
43
+ end
44
+
45
+ def valid?
46
+ @raw.Request.IsValid == 'True'
47
+ end
48
+
49
+ def empty?
50
+ @raw.CartItems.nil?
51
+ end
52
+
53
+ end
54
+ end
@@ -0,0 +1,44 @@
1
+ require 'hashie'
2
+
3
+ module ASIN
4
+
5
+ # =SimpleItem
6
+ #
7
+ # The +SimpleItem+ class is a wrapper for the Amazon XML-REST-Response.
8
+ #
9
+ # A Hashie::Mash is used for the internal data representation and can be accessed over the +raw+ attribute.
10
+ #
11
+ class SimpleItem
12
+
13
+ attr_reader :raw
14
+
15
+ def initialize(hash)
16
+ @raw = Hashie::Mash.new(hash)
17
+ end
18
+
19
+ def asin
20
+ @raw.ASIN
21
+ end
22
+
23
+ def title
24
+ @raw.ItemAttributes!.Title
25
+ end
26
+
27
+ def amount
28
+ @raw.ItemAttributes!.ListPrice!.Amount.to_i
29
+ end
30
+
31
+ def details_url
32
+ @raw.DetailPageURL
33
+ end
34
+
35
+ def review
36
+ @raw.EditorialReviews!.EditorialReview!.Content
37
+ end
38
+
39
+ def image_url
40
+ @raw.LargeImage!.URL
41
+ end
42
+ end
43
+
44
+ end
@@ -0,0 +1,44 @@
1
+ require 'hashie'
2
+
3
+ module ASIN
4
+
5
+ # =SimpleNode
6
+ #
7
+ # The +SimpleNode+ class is a wrapper for the Amazon XML-REST-Response.
8
+ #
9
+ # A Hashie::Mash is used for the internal data representation and can be accessed over the +raw+ attribute.
10
+ #
11
+ class SimpleNode
12
+
13
+ attr_reader :raw
14
+
15
+ def initialize(hash)
16
+ @raw = Hashie::Mash.new(hash)
17
+ end
18
+
19
+ def name
20
+ @raw.Name
21
+ end
22
+
23
+ def node_id
24
+ @raw.BrowseNodeId
25
+ end
26
+
27
+ def children
28
+ return [] unless @raw.Children
29
+ @raw.Children.BrowseNode.is_a?(Array) ? @raw.Children.BrowseNode : [@raw.Children.BrowseNode]
30
+ end
31
+
32
+ def ancestors
33
+ return [] unless @raw.Ancestors
34
+ @raw.Ancestors.BrowseNode.is_a?(Array) ? @raw.Ancestors.BrowseNode : [@raw.Ancestors.BrowseNode]
35
+ end
36
+
37
+ def top_item_set
38
+ return [] unless @raw.TopItemSet
39
+ @raw.TopItemSet.TopItem.is_a?(Array) ? @raw.TopItemSet.TopItem : [@raw.TopItemSet.TopItem]
40
+ end
41
+
42
+ end
43
+
44
+ end
@@ -0,0 +1,3 @@
1
+ module ASIN
2
+ VERSION = "0.7.0"
3
+ end
@@ -0,0 +1,11 @@
1
+ require "bundler"
2
+ require "rspec/core/rake_task"
3
+
4
+ Bundler::GemHelper.install_tasks
5
+
6
+ RSpec::Core::RakeTask.new do |t|
7
+ t.rspec_opts = ["--format Fuubar", "--color"]
8
+ t.pattern = 'spec/**/*_spec.rb'
9
+ end
10
+
11
+ task :default=>:spec
@@ -0,0 +1,4 @@
1
+ secret: 'secret_yml'
2
+ key: 'key_yml'
3
+ host: 'host_yml'
4
+ logger: 'logger_yml'
@@ -0,0 +1,17 @@
1
+ require 'spec_helper'
2
+
3
+ module ASIN
4
+ describe ASIN do
5
+ context "browse_node" do
6
+ before do
7
+ @helper.configure :secret => @secret, :key => @key
8
+ end
9
+
10
+ it "should lookup a browse_node", :vcr do
11
+ item = @helper.browse_node(ANY_BROWSE_NODE_ID)
12
+ item.node_id.should eql(ANY_BROWSE_NODE_ID)
13
+ item.name.should eql('Comedy')
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,150 @@
1
+ require 'spec_helper'
2
+
3
+ module ASIN
4
+ describe ASIN do
5
+ before do
6
+ @helper.configure :secret => @secret, :key => @key
7
+ end
8
+
9
+ context "cart" do
10
+
11
+ it "should create a cart", :vcr do
12
+ cart = @helper.create_cart({:asin => ANY_ASIN, :quantity => 1}, {:asin => ANY_OTHER_ASIN, :quantity => 2})
13
+ cart.valid?.should be(true)
14
+ cart.empty?.should be(false)
15
+ end
16
+
17
+ it "should handle item paramters" do
18
+ params = @helper.send(:create_item_params, [{:asin => 'any_asin', :quantity => 1}, {:cart_item_id => 'any_cart_item_id', :quantity => 2}, {:offer_listing_id => 'any_offer_listing_id', :quantity => 3},{:cart_item_id => 'any_cart_item_id', :action => :SaveForLater}])
19
+ params.should eql({"Item.0.ASIN"=>"any_asin", "Item.0.Quantity"=>"1", "Item.1.CartItemId"=>"any_cart_item_id", "Item.1.Quantity"=>"2", "Item.2.OfferListingId"=>"any_offer_listing_id", "Item.2.Quantity"=>"3", "Item.3.CartItemId"=>"any_cart_item_id", "Item.3.Action"=>"SaveForLater"})
20
+ end
21
+
22
+ context "with an existing cart" do
23
+
24
+ it "should clear a cart", :vcr do
25
+ @cart = @helper.create_cart({:asin => ANY_ASIN, :quantity => 1})
26
+ cart = @helper.clear_cart(@cart)
27
+ cart.valid?.should be(true)
28
+ cart.empty?.should be(true)
29
+ end
30
+
31
+ it "should get a cart", :vcr do
32
+ @cart = @helper.create_cart({:asin => ANY_ASIN, :quantity => 1})
33
+ cart = @helper.get_cart(@cart.cart_id, @cart.hmac)
34
+ cart.valid?.should be(true)
35
+ cart.empty?.should be(false)
36
+ end
37
+
38
+ it "should add items to a cart", :vcr do
39
+ @cart = @helper.create_cart({:asin => ANY_ASIN, :quantity => 1})
40
+ cart = @helper.add_items(@cart, {:asin => ANY_OTHER_ASIN, :quantity => 2})
41
+ cart.valid?.should be(true)
42
+ cart.empty?.should be(false)
43
+ cart.items.should have(2).things
44
+ end
45
+
46
+ it "should update a cart", :vcr do
47
+ @cart = @helper.create_cart({:asin => ANY_ASIN, :quantity => 1})
48
+ item_id = @cart.items.first.CartItemId
49
+ cart = @helper.update_items(@cart, {:cart_item_id => item_id, :action => 'SaveForLater'}, {:cart_item_id => item_id, :quantity => 7})
50
+ cart.saved_items.should have(1).things
51
+ cart.valid?.should be(true)
52
+ end
53
+
54
+ end
55
+
56
+ context SimpleCart do
57
+
58
+ before do
59
+ @helper.configure :secret => @secret, :key => @key
60
+ @two_items = {"Request"=>
61
+ {"IsValid"=>"True",
62
+ "CartAddRequest"=>
63
+ {"CartId"=>"186-8702292-9782208",
64
+ "HMAC"=>"Ck5MXUE+OQiC/Jh8u6NhBf5FbV8=",
65
+ "Items"=>{"Item"=>{"ASIN"=>"1430216263", "Quantity"=>"2"}}}},
66
+ "CartId"=>"186-8702292-9782208",
67
+ "HMAC"=>"Ck5MXUE+OQiC/Jh8u6NhBf5FbV8=",
68
+ "URLEncodedHMAC"=>"Ck5MXUE%2BOQiC%2FJh8u6NhBf5FbV8%3D",
69
+ "PurchaseURL"=>
70
+ "https://www.amazon.com/gp/cart/aws-merge.html?cart-id=186-8702292-9782208%26associate-id=ws%26hmac=Ck5MXUE%2BOQiC/Jh8u6NhBf5FbV8=%26SubscriptionId=AKIAJFA5X7RTOKFNPVZQ%26MergeCart=False",
71
+ "SubTotal"=>
72
+ {"Amount"=>"6595", "CurrencyCode"=>"USD", "FormattedPrice"=>"$65.95"},
73
+ "CartItems"=>
74
+ {"SubTotal"=>
75
+ {"Amount"=>"6595", "CurrencyCode"=>"USD", "FormattedPrice"=>"$65.95"},
76
+ "CartItem"=>
77
+ [{"CartItemId"=>"U3CFEHHIPJNW3L",
78
+ "ASIN"=>"1430216263",
79
+ "MerchantId"=>"ATVPDKIKX0DER",
80
+ "SellerId"=>"A2R2RITDJNW1Q6",
81
+ "SellerNickname"=>"Amazon.com",
82
+ "Quantity"=>"2",
83
+ "Title"=>"Beginning iPhone Development: Exploring the iPhone SDK",
84
+ "ProductGroup"=>"Book",
85
+ "Price"=>
86
+ {"Amount"=>"1978", "CurrencyCode"=>"USD", "FormattedPrice"=>"$19.78"},
87
+ "ItemTotal"=>
88
+ {"Amount"=>"3956", "CurrencyCode"=>"USD", "FormattedPrice"=>"$39.56"}},
89
+ {"CartItemId"=>"U3G241HVLLB8N6",
90
+ "ASIN"=>"1430218150",
91
+ "MerchantId"=>"ATVPDKIKX0DER",
92
+ "SellerId"=>"A2R2RITDJNW1Q6",
93
+ "SellerNickname"=>"Amazon.com",
94
+ "Quantity"=>"1",
95
+ "Title"=>"Learn Objective-C on the Mac (Learn Series)",
96
+ "ProductGroup"=>"Book",
97
+ "Price"=>
98
+ {"Amount"=>"2639", "CurrencyCode"=>"USD", "FormattedPrice"=>"$26.39"},
99
+ "ItemTotal"=>
100
+ {"Amount"=>"2639",
101
+ "CurrencyCode"=>"USD",
102
+ "FormattedPrice"=>"$26.39"}}]}}
103
+ @one_item = {"Request"=>
104
+ {"IsValid"=>"True",
105
+ "CartCreateRequest"=>
106
+ {"Items"=>{"Item"=>{"ASIN"=>"1430218150", "Quantity"=>"1"}}}},
107
+ "CartId"=>"176-9182855-2326919",
108
+ "HMAC"=>"KgeVCA0YJTbuN/7Ibakrk/KnHWA=",
109
+ "URLEncodedHMAC"=>"KgeVCA0YJTbuN%2F7Ibakrk%2FKnHWA%3D",
110
+ "PurchaseURL"=>
111
+ "https://www.amazon.com/gp/cart/aws-merge.html?cart-id=176-9182855-2326919%26associate-id=ws%26hmac=KgeVCA0YJTbuN/7Ibakrk/KnHWA=%26SubscriptionId=AKIAJFA5X7RTOKFNPVZQ%26MergeCart=False",
112
+ "SubTotal"=>
113
+ {"Amount"=>"2639", "CurrencyCode"=>"USD", "FormattedPrice"=>"$26.39"},
114
+ "CartItems"=>
115
+ {"SubTotal"=>
116
+ {"Amount"=>"2639", "CurrencyCode"=>"USD", "FormattedPrice"=>"$26.39"},
117
+ "CartItem"=>
118
+ {"CartItemId"=>"U3G241HVLLB8N6",
119
+ "ASIN"=>"1430218150",
120
+ "MerchantId"=>"ATVPDKIKX0DER",
121
+ "SellerId"=>"A2R2RITDJNW1Q6",
122
+ "SellerNickname"=>"Amazon.com",
123
+ "Quantity"=>"1",
124
+ "Title"=>"Learn Objective-C on the Mac (Learn Series)",
125
+ "ProductGroup"=>"Book",
126
+ "Price"=>
127
+ {"Amount"=>"2639", "CurrencyCode"=>"USD", "FormattedPrice"=>"$26.39"},
128
+ "ItemTotal"=>
129
+ {"Amount"=>"2639", "CurrencyCode"=>"USD", "FormattedPrice"=>"$26.39"}}}}
130
+ end
131
+
132
+ it "should handle response data" do
133
+ cart = SimpleCart.new(@two_items)
134
+ cart.valid?.should be(true)
135
+ cart.cart_id.should eql('186-8702292-9782208')
136
+ cart.hmac.should eql('Ck5MXUE+OQiC/Jh8u6NhBf5FbV8=')
137
+ cart.url.should eql('https://www.amazon.com/gp/cart/aws-merge.html?cart-id=186-8702292-9782208%26associate-id=ws%26hmac=Ck5MXUE%2BOQiC/Jh8u6NhBf5FbV8=%26SubscriptionId=AKIAJFA5X7RTOKFNPVZQ%26MergeCart=False')
138
+ cart.price.should eql('$65.95')
139
+ cart.items.first.CartItemId eql('U3G241HVLLB8N6')
140
+ end
141
+
142
+ it "should handle one item" do
143
+ cart = SimpleCart.new(@two_items)
144
+ cart.items.first.CartItemId eql('U3G241HVLLB8N6')
145
+ end
146
+
147
+ end
148
+ end
149
+ end
150
+ end
@@ -0,0 +1,68 @@
1
+ ---
2
+ - !ruby/struct:VCR::HTTPInteraction
3
+ request: !ruby/struct:VCR::Request
4
+ method: :get
5
+ uri: http://webservices.amazon.com:80/onca/xml?AWSAccessKeyId=AKIAJFA5X7RTOKFNPVZQ&AssociateTag=&Item.0.ASIN=1430218150&Item.0.Quantity=1&Operation=CartCreate&Service=AWSECommerceService&Signature=5sWyeKMk9jtVYoITVfJMjolGlzvDJ0fIk7rP4il81Lo=&Timestamp=2011-11-17T12:26:34Z&Version=2010-11-01
6
+ body:
7
+ headers:
8
+ response: !ruby/struct:VCR::Response
9
+ status: !ruby/struct:VCR::ResponseStatus
10
+ code: 200
11
+ message: OK
12
+ headers:
13
+ date:
14
+ - Thu, 17 Nov 2011 12:26:34 GMT
15
+ server:
16
+ - Server
17
+ content-type:
18
+ - text/xml;charset=UTF-8
19
+ vary:
20
+ - Accept-Encoding,User-Agent
21
+ nncoection:
22
+ - close
23
+ transfer-encoding:
24
+ - chunked
25
+ body: <?xml version="1.0" encoding="UTF-8"?><CartCreateResponse xmlns="http://webservices.amazon.com/AWSECommerceService/2010-11-01"><OperationRequest><HTTPHeaders><Header
26
+ Name="UserAgent" Value="Jakarta Commons-HttpClient/3.0.1"></Header></HTTPHeaders><RequestId>014QB123K7ASW4SE6QEM</RequestId><Arguments><Argument
27
+ Name="AssociateTag"></Argument><Argument Name="Service" Value="AWSECommerceService"></Argument><Argument
28
+ Name="Item.0.Quantity" Value="1"></Argument><Argument Name="Signature" Value="5sWyeKMk9jtVYoITVfJMjolGlzvDJ0fIk7rP4il81Lo="></Argument><Argument
29
+ Name="Item.0.ASIN" Value="1430218150"></Argument><Argument Name="Operation"
30
+ Value="CartCreate"></Argument><Argument Name="AWSAccessKeyId" Value="AKIAJFA5X7RTOKFNPVZQ"></Argument><Argument
31
+ Name="Timestamp" Value="2011-11-17T12:26:34Z"></Argument><Argument Name="Version"
32
+ Value="2010-11-01"></Argument></Arguments><RequestProcessingTime>0.162961006164551</RequestProcessingTime></OperationRequest><Cart><Request><IsValid>True</IsValid><CartCreateRequest><Items><Item><ASIN>1430218150</ASIN><Quantity>1</Quantity></Item></Items></CartCreateRequest></Request><CartId>183-2540013-3419242</CartId><HMAC>QqoPIkmIkhVQ4/giDmvD0ouD1vo=</HMAC><URLEncodedHMAC>QqoPIkmIkhVQ4%2FgiDmvD0ouD1vo%3D</URLEncodedHMAC><PurchaseURL>https://www.amazon.com/gp/cart/aws-merge.html?cart-id=183-2540013-3419242%26associate-id=ws%26hmac=QqoPIkmIkhVQ4/giDmvD0ouD1vo=%26SubscriptionId=AKIAJFA5X7RTOKFNPVZQ%26MergeCart=False</PurchaseURL><SubTotal><Amount>2171</Amount><CurrencyCode>USD</CurrencyCode><FormattedPrice>$21.71</FormattedPrice></SubTotal><CartItems><SubTotal><Amount>2171</Amount><CurrencyCode>USD</CurrencyCode><FormattedPrice>$21.71</FormattedPrice></SubTotal><CartItem><CartItemId>U3G241HVLLB8N6</CartItemId><ASIN>1430218150</ASIN><MerchantId>ATVPDKIKX0DER</MerchantId><SellerId>A2R2RITDJNW1Q6</SellerId><SellerNickname>Amazon.com</SellerNickname><Quantity>1</Quantity><Title>Learn
33
+ Objective-C on the Mac (Learn Series)</Title><ProductGroup>Book</ProductGroup><Price><Amount>2171</Amount><CurrencyCode>USD</CurrencyCode><FormattedPrice>$21.71</FormattedPrice></Price><ItemTotal><Amount>2171</Amount><CurrencyCode>USD</CurrencyCode><FormattedPrice>$21.71</FormattedPrice></ItemTotal></CartItem></CartItems></Cart></CartCreateResponse>
34
+ http_version: '1.1'
35
+ - !ruby/struct:VCR::HTTPInteraction
36
+ request: !ruby/struct:VCR::Request
37
+ method: :get
38
+ uri: http://webservices.amazon.com:80/onca/xml?AWSAccessKeyId=AKIAJFA5X7RTOKFNPVZQ&AssociateTag=&CartId=183-2540013-3419242&HMAC=QqoPIkmIkhVQ4/giDmvD0ouD1vo=&Item.0.ASIN=1430216263&Item.0.Quantity=2&Operation=CartAdd&Service=AWSECommerceService&Signature=FR0UOB+2MqOE9YuJ/CVBCTw9ONTLDa5Q78ISyT0TATw=&Timestamp=2011-11-17T12:26:34Z&Version=2010-11-01
39
+ body:
40
+ headers:
41
+ response: !ruby/struct:VCR::Response
42
+ status: !ruby/struct:VCR::ResponseStatus
43
+ code: 200
44
+ message: OK
45
+ headers:
46
+ date:
47
+ - Thu, 17 Nov 2011 12:26:34 GMT
48
+ server:
49
+ - Server
50
+ content-type:
51
+ - text/xml;charset=UTF-8
52
+ vary:
53
+ - Accept-Encoding,User-Agent
54
+ nncoection:
55
+ - close
56
+ transfer-encoding:
57
+ - chunked
58
+ body: ! '<?xml version="1.0" encoding="UTF-8"?><CartAddResponse xmlns="http://webservices.amazon.com/AWSECommerceService/2010-11-01"><OperationRequest><HTTPHeaders><Header
59
+ Name="UserAgent" Value="Jakarta Commons-HttpClient/3.0.1"></Header></HTTPHeaders><RequestId>0JBNK5NQF7NJE0TSNSM1</RequestId><Arguments><Argument
60
+ Name="AssociateTag"></Argument><Argument Name="Service" Value="AWSECommerceService"></Argument><Argument
61
+ Name="Item.0.Quantity" Value="2"></Argument><Argument Name="Signature" Value="FR0UOB+2MqOE9YuJ/CVBCTw9ONTLDa5Q78ISyT0TATw="></Argument><Argument
62
+ Name="Item.0.ASIN" Value="1430216263"></Argument><Argument Name="HMAC" Value="QqoPIkmIkhVQ4/giDmvD0ouD1vo="></Argument><Argument
63
+ Name="Operation" Value="CartAdd"></Argument><Argument Name="CartId" Value="183-2540013-3419242"></Argument><Argument
64
+ Name="AWSAccessKeyId" Value="AKIAJFA5X7RTOKFNPVZQ"></Argument><Argument Name="Timestamp"
65
+ Value="2011-11-17T12:26:34Z"></Argument><Argument Name="Version" Value="2010-11-01"></Argument></Arguments><RequestProcessingTime>0.119147062301636</RequestProcessingTime></OperationRequest><Cart><Request><IsValid>True</IsValid><CartAddRequest><CartId>183-2540013-3419242</CartId><HMAC>QqoPIkmIkhVQ4/giDmvD0ouD1vo=</HMAC><Items><Item><ASIN>1430216263</ASIN><Quantity>2</Quantity></Item></Items></CartAddRequest></Request><CartId>183-2540013-3419242</CartId><HMAC>QqoPIkmIkhVQ4/giDmvD0ouD1vo=</HMAC><URLEncodedHMAC>QqoPIkmIkhVQ4%2FgiDmvD0ouD1vo%3D</URLEncodedHMAC><PurchaseURL>https://www.amazon.com/gp/cart/aws-merge.html?cart-id=183-2540013-3419242%26associate-id=ws%26hmac=QqoPIkmIkhVQ4/giDmvD0ouD1vo=%26SubscriptionId=AKIAJFA5X7RTOKFNPVZQ%26MergeCart=False</PurchaseURL><SubTotal><Amount>7449</Amount><CurrencyCode>USD</CurrencyCode><FormattedPrice>$74.49</FormattedPrice></SubTotal><CartItems><SubTotal><Amount>7449</Amount><CurrencyCode>USD</CurrencyCode><FormattedPrice>$74.49</FormattedPrice></SubTotal><CartItem><CartItemId>U3CFEHHIPJNW3L</CartItemId><ASIN>1430216263</ASIN><MerchantId>ATVPDKIKX0DER</MerchantId><SellerId>A2R2RITDJNW1Q6</SellerId><SellerNickname>Amazon.com</SellerNickname><Quantity>2</Quantity><Title>Beginning
66
+ iPhone Development: Exploring the iPhone SDK</Title><ProductGroup>Book</ProductGroup><Price><Amount>2639</Amount><CurrencyCode>USD</CurrencyCode><FormattedPrice>$26.39</FormattedPrice></Price><ItemTotal><Amount>5278</Amount><CurrencyCode>USD</CurrencyCode><FormattedPrice>$52.78</FormattedPrice></ItemTotal></CartItem><CartItem><CartItemId>U3G241HVLLB8N6</CartItemId><ASIN>1430218150</ASIN><MerchantId>ATVPDKIKX0DER</MerchantId><SellerId>A2R2RITDJNW1Q6</SellerId><SellerNickname>Amazon.com</SellerNickname><Quantity>1</Quantity><Title>Learn
67
+ Objective-C on the Mac (Learn Series)</Title><ProductGroup>Book</ProductGroup><Price><Amount>2171</Amount><CurrencyCode>USD</CurrencyCode><FormattedPrice>$21.71</FormattedPrice></Price><ItemTotal><Amount>2171</Amount><CurrencyCode>USD</CurrencyCode><FormattedPrice>$21.71</FormattedPrice></ItemTotal></CartItem></CartItems></Cart></CartAddResponse>'
68
+ http_version: '1.1'