ramazon_advertising 0.3.2

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.
Files changed (43) hide show
  1. data/.document +5 -0
  2. data/.gitignore +7 -0
  3. data/LICENSE +20 -0
  4. data/README.rdoc +46 -0
  5. data/Rakefile +84 -0
  6. data/VERSION +1 -0
  7. data/features/friendly_errors.feature +15 -0
  8. data/features/generate_root_browse_nodes.feature +13 -0
  9. data/features/getting_offer_details.feature +30 -0
  10. data/features/getting_search_bins.feature +22 -0
  11. data/features/retrieve_browse_node_information.feature +16 -0
  12. data/features/retrieving_a_product.feature +32 -0
  13. data/features/searching_for_products.feature +47 -0
  14. data/features/step_definitions/auth_steps.rb +8 -0
  15. data/features/step_definitions/browse_node_steps.rb +55 -0
  16. data/features/step_definitions/error_steps.rb +14 -0
  17. data/features/step_definitions/product_collection_steps.rb +20 -0
  18. data/features/step_definitions/product_steps.rb +75 -0
  19. data/features/step_definitions/ramazon_advertising_steps.rb +0 -0
  20. data/features/support/env.rb +7 -0
  21. data/features/support/ramazon_advertising.example.yml +2 -0
  22. data/lib/ramazon/abstract_element.rb +18 -0
  23. data/lib/ramazon/browse_node.rb +69 -0
  24. data/lib/ramazon/configuration.rb +66 -0
  25. data/lib/ramazon/error.rb +12 -0
  26. data/lib/ramazon/image.rb +18 -0
  27. data/lib/ramazon/merchant.rb +21 -0
  28. data/lib/ramazon/offer.rb +27 -0
  29. data/lib/ramazon/price.rb +18 -0
  30. data/lib/ramazon/product.rb +303 -0
  31. data/lib/ramazon/product_collection.rb +30 -0
  32. data/lib/ramazon/rails_additions.rb +99 -0
  33. data/lib/ramazon/request.rb +82 -0
  34. data/lib/ramazon/search_bin.rb +11 -0
  35. data/lib/ramazon/search_bin_parameter.rb +9 -0
  36. data/lib/ramazon/search_bin_set.rb +11 -0
  37. data/lib/ramazon/signatory.rb +10 -0
  38. data/lib/ramazon_advertising.rb +41 -0
  39. data/lib/root_nodes.yml +64 -0
  40. data/lib/tasks/ramazon.rake +9 -0
  41. data/spec/ramazon/configuration_spec.rb +21 -0
  42. data/spec/spec_helper.rb +11 -0
  43. metadata +157 -0
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ README.rdoc
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ LICENSE
data/.gitignore ADDED
@@ -0,0 +1,7 @@
1
+ *.sw?
2
+ .DS_Store
3
+ coverage
4
+ rdoc
5
+ pkg
6
+ features/support/ramazon_advertising.yml
7
+ features/support/root_nodes.yml
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Dan Pickett
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,46 @@
1
+ = ramazon_advertising
2
+
3
+ Ruby + Amazon Advertising == Car RAmazon_Advertising - Say Car RAmazon_Advertising!
4
+
5
+ Ruh roh' Rorge it's an object oriented approach to Amazon's overly complicated product api that has a new name every 2 weeks.
6
+
7
+ Complete with the ability to use nokogiri selectors for results
8
+
9
+ Currently only supports product search and retrieval. Requests are signed properly. More soon!
10
+
11
+ Ramazon::Configuration.access_key = "Your Access Key"
12
+ Ramazon::Configuration.secret_key = "Your Secret Key"
13
+
14
+ @products = Ramazon::Product.find(:item_id => "B000NU2CY4", :response_group => "Medium")
15
+ @products[0].title
16
+ @products[0].asin
17
+ @products[0].upc
18
+ @products[0].large_image.url
19
+ @products[0].url
20
+
21
+ #you can also use a nokogiri search string to get elements that don't have built-in accessors
22
+ @products[0].get("ItemAttributes Actor").collect{|a| a.content}
23
+
24
+ More documentation at http://rdoc.info/projects/dpickett/ramazon_advertising
25
+
26
+ == What's under the hood?
27
+
28
+ * HTTParty
29
+ * HappyMapper
30
+ * will_paginate
31
+ * nokogiri
32
+
33
+ == Note on Patches/Pull Requests
34
+
35
+ * Fork the project.
36
+ * Make your feature addition or bug fix.
37
+ * Add tests for it. This is important so I don't break it in a
38
+ future version unintentionally.
39
+ * Commit, do not mess with rakefile, version, or history.
40
+ (if you want to have your own version, that is fine but
41
+ bump version in a commit by itself I can ignore when I pull)
42
+ * Send me a pull request. Bonus points for topic branches.
43
+
44
+ == Copyright
45
+
46
+ Copyright (c) 2009 Dan Pickett. See LICENSE for details.
data/Rakefile ADDED
@@ -0,0 +1,84 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ require 'lib/ramazon_advertising'
5
+ load File.join(File.dirname(__FILE__), 'lib', 'tasks', 'ramazon.rake')
6
+
7
+ begin
8
+ require 'jeweler'
9
+ Jeweler::Tasks.new do |gem|
10
+ gem.name = "ramazon_advertising"
11
+ gem.summary = %Q{Amazon Advertising Wrapper - Use nokogiri to target the elements you want}
12
+ gem.description = %Q{ Amazon Advertising Wrapper - Use nokogiri to target the elements you want. An object oriented approach}
13
+ gem.email = "dpickett@enlightsolutions.com"
14
+ gem.homepage = "http://github.com/dpickett/ramazon_advertising"
15
+ gem.authors = ["Dan Pickett"]
16
+ gem.add_dependency("jnunemaker-httparty", ">= 0.4.3")
17
+ gem.add_dependency("jnunemaker-happymapper", ">= 0.2.5")
18
+ gem.add_dependency("mislav-will_paginate", ">= 2.3.11")
19
+ gem.add_dependency("nokogiri", ">= 1.3.3")
20
+ gem.add_dependency("configatron", ">= 2.4.1")
21
+ gem.add_dependency("ruby-hmac", ">= 0.3.2")
22
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
23
+ end
24
+
25
+ rescue LoadError
26
+ puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
27
+ end
28
+
29
+ require 'spec/rake/spectask'
30
+ Spec::Rake::SpecTask.new(:spec) do |spec|
31
+ spec.libs << 'lib' << 'spec'
32
+ spec.spec_files = FileList['spec/**/*_spec.rb']
33
+ end
34
+
35
+ Spec::Rake::SpecTask.new(:rcov) do |spec|
36
+ spec.libs << 'lib' << 'spec'
37
+ spec.pattern = 'spec/**/*_spec.rb'
38
+ spec.rcov = true
39
+ end
40
+
41
+ task :default => :spec
42
+
43
+ begin
44
+ require 'cucumber/rake/task'
45
+ Cucumber::Rake::Task.new(:cucumber)
46
+ rescue LoadError
47
+ task :cucumber do
48
+ abort "Cucumber is not available. In order to run features, you must: sudo gem install cucumber"
49
+ end
50
+ end
51
+
52
+ task :default => :test
53
+
54
+ require 'rake/rdoctask'
55
+ Rake::RDocTask.new do |rdoc|
56
+ if File.exist?('VERSION.yml')
57
+ config = YAML.load(File.read('VERSION.yml'))
58
+ version = "#{config[:major]}.#{config[:minor]}.#{config[:patch]}"
59
+ else
60
+ version = ""
61
+ end
62
+
63
+ rdoc.rdoc_dir = 'rdoc'
64
+ rdoc.title = "ramazon_advertising #{version}"
65
+ rdoc.rdoc_files.include('README*')
66
+ rdoc.rdoc_files.include('lib/**/*.rb')
67
+ end
68
+
69
+ begin
70
+ require "YARD"
71
+ if File.exist?('VERSION.yml')
72
+ config = YAML.load(File.read('VERSION.yml'))
73
+ version = "#{config[:major]}.#{config[:minor]}.#{config[:patch]}"
74
+ else
75
+ version = ""
76
+ end
77
+
78
+ YARD::Rake::YardocTask.new do |t|
79
+ end
80
+ rescue LoadError
81
+
82
+ end
83
+
84
+
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.3.2
@@ -0,0 +1,15 @@
1
+ @errors
2
+ Feature: Friendly errors
3
+ As a user of ramazon_advertising
4
+ I want to get friendly error messages
5
+ So that I know I did something wrong
6
+
7
+ Background:
8
+ Given I have a valid access key
9
+ And I have a valid secret key
10
+
11
+ Scenario: I don't specify a keyword for search
12
+ When I perform the product search
13
+ Then I should get an error
14
+ And the error should have a "code" of "AWS.MinimumParameterRequirement"
15
+ And the error should have a "message"
@@ -0,0 +1,13 @@
1
+ Feature: As a user of the Ramazon Advertising API
2
+ I want a list of browse nodes
3
+ So that I have starting points for browse node traversal
4
+
5
+ Scenario: Retrieving root browse nodes
6
+ Given I want browse nodes to be stored in a temporary file
7
+ And the browse node temporary file doesn't exist
8
+ When I retrieve root nodes
9
+ Then I should get a temporary file for root nodes
10
+ And I should have a "Books" root node
11
+ And I should have a "Grocery" root node
12
+ And I should have a list of root nodes
13
+
@@ -0,0 +1,30 @@
1
+ Feature: Retrieving offer details
2
+ As a user of the Ramazon_advertising api
3
+ I want to get offer details
4
+ In order to get pricing information about a given product
5
+
6
+ Background:
7
+ Given I have a valid access key
8
+ And I have a valid secret key
9
+
10
+ Scenario: Getting offers on a DVD
11
+ Given I am searching with the "item_id" of "B000NTPDSW"
12
+ And I am searching with the "condition" of "Used"
13
+ And I am searching with the "response_group" of "Medium,OfferListings"
14
+ And I am searching with the "merchant_id" of "All"
15
+ When I perform the product search
16
+ Then I should get a product
17
+ And the product should have "offers"
18
+ And each of the product's "offers" should have a "price"
19
+ And each of the product's "offers" should have a "condition"
20
+ And each of the product's "offers" should have a "sub_condition"
21
+ And the product should have "used_offers"
22
+ And each of the product's "used_offers" should have a "condition" of "Used"
23
+
24
+ Scenario: Getting offers by subcondition hash
25
+ Given I am searching with the "item_id" of "B000NTPDSW"
26
+ And I am searching with the "response_group" of "Medium,OfferListings"
27
+ When I perform the product search
28
+ Then I should get a product
29
+ And the product should have "offers_by_condition"
30
+ And the product should have "lowest_offers"
@@ -0,0 +1,22 @@
1
+ Feature: As a user of the Ramazon Advertising wrapper
2
+ I want to get search bins
3
+ So I can efficiently narrow down results
4
+
5
+ Scenario: Getting DVD search bins
6
+ Given I am searching with the "search_index" of "DVD"
7
+ And I am searching with the "response_group" of "Medium,SearchBins"
8
+ And I am searching with the "browse_node" of "130"
9
+ When I perform the product search
10
+ Then I should get a list of products
11
+ And the list of products should have more than 1 product
12
+ And the list of products should have "search_bin_sets"
13
+ And each "search_bin_set" in the list of products should have "search_bins"
14
+
15
+ Scenario: Getting Genre search bins
16
+ Given I am searching with the "search_index" of "DVD"
17
+ And I am searching with the "response_group" of "Medium,SearchBins"
18
+ And I am searching with the "browse_node" of "405391011"
19
+ When I perform the product search
20
+ Then I should get a list of products
21
+ And the list of products should have "search_bin_sets"
22
+ And each "search_bin_set" in the list of products should have "search_bins"
@@ -0,0 +1,16 @@
1
+ Feature: As a user of the ramazon advertising api
2
+ I want to get browse node information
3
+ So I can retrieve Amazon product data more effectively
4
+
5
+ Scenario: Fetch "Other Video Games" Node
6
+ Given I want browse node information for the node "294940"
7
+ When I retrieve the browse node
8
+ Then the browse node should have a name
9
+ And the browse node should have "children"
10
+ And the browse node should have a "child_hash"
11
+
12
+ Scenario: Fetch "DVD" Node
13
+ Given I want browse node information for the node "130"
14
+ When I retrieve the browse node
15
+ Then the browse node should have a name
16
+ And the browse node should have "children"
@@ -0,0 +1,32 @@
1
+ Feature: Retrieving a product
2
+ As a user of the Ramazon_advertising_api
3
+ I want to get specific information
4
+ In order to leverage the data provided by the api
5
+
6
+ Background:
7
+ Given I have a valid access key
8
+ And I have a valid secret key
9
+
10
+ Scenario: Finding a DVD
11
+ When I try to find the asin "B000NU2CY4"
12
+ Then I should get a product
13
+ And the product should have the "title" "Gladiator [Blu-ray]"
14
+ And the product should have a "manufacturer"
15
+ And the product should have a "product_group"
16
+ And the product should have a "sales_rank"
17
+ And the product should have a "large_image"
18
+ And the product should have a "list_price"
19
+ And the product should have a "upc"
20
+ And the product should have a "lowest_new_price"
21
+ And the product should have a "new_count"
22
+ And the product should have a "used_count"
23
+
24
+ Scenario: Finding a Video Game with a deep category tree
25
+ When I try to find the asin "B001COQW14"
26
+ Then I should get a product
27
+ And the product should have a category tree for "Categories"
28
+
29
+ Scenario: Finding a Movie with a Genre tree
30
+ When I try to find the asin "B002CMLIJ6"
31
+ Then I should get a product
32
+ And the product should have a category tree for "Genres"
@@ -0,0 +1,47 @@
1
+ Feature: Search for products
2
+ As a user of the Ramazon_advertising api
3
+ I want to perform a search
4
+ In order to find products my customers will want to purchase
5
+
6
+ Background:
7
+ Given I have a valid access key
8
+ And I have a valid secret key
9
+
10
+ Scenario: Finding dvds
11
+ Given I am searching with the "search_index" of "DVD"
12
+ And I am searching with the "browse_node" of "130"
13
+ When I perform the product search
14
+ Then I should get a list of products
15
+ And the list of products should have more than 1 product
16
+ And each product should have the "product_group" "DVD"
17
+
18
+ Scenario: Finding video games
19
+ Given I am searching with the "search_index" of "VideoGames"
20
+ And I am searching with the "response_group" of "Medium,BrowseNodes"
21
+ And I am searching with the "browse_node" of "294940"
22
+ When I perform the product search
23
+ Then I should get a list of products
24
+ And the list of products should have more than 1 product
25
+
26
+ Scenario: Finding multiple browse nodes
27
+ Given I am searching with the "search_index" of "VideoGames"
28
+ And I am searching with the "response_group" of "Medium"
29
+ And I am searching with the "browse_node" of "11075221"
30
+ When I perform the product search
31
+ Then I should get a list of products
32
+ And the list of products should have more than 1 product
33
+ And each product should have the "product_group" "Video Games"
34
+
35
+ Scenario: Finding All Offers optimization
36
+ Given I am searching with the "search_index" of "VideoGames"
37
+ And I am searching with the "response_group" of "Medium,OfferListings"
38
+ And I am searching with the "merchant_id" of "All"
39
+ And I am searching with the "condition" of "All"
40
+ And I am searching with the "offer_page" of "1"
41
+ And I am searching with the "browse_node" of "11075221"
42
+ When I perform the product search
43
+ Then I should get a list of products
44
+ And each product should have "offer_pages"
45
+ And each product should have "has_first_page_of_full_offers"
46
+
47
+
@@ -0,0 +1,8 @@
1
+ Given /^I have a valid access key$/ do
2
+ configatron.ramazon.access_key.should_not be_nil
3
+ end
4
+
5
+ Given /^I have a valid secret key$/ do
6
+ configatron.ramazon.secret_key.should_not be_nil
7
+ end
8
+
@@ -0,0 +1,55 @@
1
+ Given /^I want browse nodes to be stored in a temporary file$/ do
2
+ @browse_root_filename = File.join(File.dirname(__FILE__), '..', 'support', 'root_nodes.yml')
3
+ end
4
+
5
+ Given /^the browse node temporary file doesn't exist$/ do
6
+ FileUtils.rm_f @browse_root_filename
7
+ end
8
+
9
+ Given /^I want browse node information for the node "([^\"]*)"$/ do |node_id|
10
+ @node_id = node_id
11
+ end
12
+
13
+ When /^I retrieve root nodes$/ do
14
+ if @browse_root_filename
15
+ Ramazon::BrowseNode.generate_root_nodes @browse_root_filename
16
+ else
17
+ Ramazon::BrowseNode.generate_root_nodes
18
+ end
19
+ end
20
+
21
+ When /^I retrieve the browse node$/ do
22
+ @node = Ramazon::BrowseNode.find(@node_id)
23
+ end
24
+
25
+ Then /^the browse node should have a name$/ do
26
+ @node.name.should_not be_nil
27
+ end
28
+
29
+ Then /^the browse node should have (a\s)?"(.*)"$/ do |a, attr|
30
+ @node.send(attr).should_not be_nil
31
+ if @node.send(attr).respond_to?(:empty?)
32
+ @node.send(attr).should_not be_empty
33
+ end
34
+ end
35
+
36
+ Then /^I should get a temporary file for root nodes$/ do
37
+ FileTest.exists?(@browse_root_filename).should be_true
38
+ end
39
+
40
+ Then /^I should have a "([^\"]*)" root node$/ do |name|
41
+ get_root_nodes[name].should_not be_nil
42
+ end
43
+
44
+ Then /^I should have a list of root nodes$/ do
45
+ get_root_nodes.should_not be_empty
46
+ end
47
+
48
+ def get_root_nodes
49
+ if @browse_root_filename
50
+ nodes = Ramazon::BrowseNode.root_nodes(@browse_root_filename)
51
+ else
52
+ nodes = Ramazon::BrowseNode.root_nodes
53
+ end
54
+
55
+ end
@@ -0,0 +1,14 @@
1
+ Then /^I should get an error$/ do
2
+ @error.should_not be_nil
3
+ end
4
+
5
+ Then /^the error should have a "([^\"]*)" of "([^\"]*)"$/ do |attr, value|
6
+ @error.send(attr).should eql(value)
7
+ end
8
+
9
+ Then /^the error should have a "([^\"]*)"$/ do |attr|
10
+ @error.send(attr).should_not be_nil
11
+ end
12
+
13
+
14
+
@@ -0,0 +1,20 @@
1
+ Then /^the list of products should have "([^\"]*)"$/ do |attr|
2
+ @products.send(attr).should_not be_nil
3
+ if @products.respond_to?(:empty?)
4
+ @products.should_not be_empty
5
+ end
6
+ end
7
+
8
+ Then /^each "([^\"]*)" in the list of products should have "([^\"]*)"$/ do |collection, attr|
9
+ collection = collection.pluralize
10
+ @products.send(collection).should_not be_nil
11
+ @products.send(collection).should_not be_empty
12
+
13
+ @products.send(collection).each do |i|
14
+ i.send(attr).should_not be_nil
15
+ if i.send(attr).respond_to?(:empty?)
16
+ i.send(attr).should_not be_empty
17
+ end
18
+ end
19
+ end
20
+