ramazon_advertising 0.3.2

Sign up to get free protection for your applications and to get access to all the features.
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
+