ruby-mws 0.0.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.
data/.gitignore ADDED
@@ -0,0 +1,7 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
5
+ .DS_Store
6
+ spec/credentials.yml
7
+ spec/fixtures/ephemeral_response/*
data/.rvmrc ADDED
@@ -0,0 +1 @@
1
+ rvm use ruby-1.9.3-p0@ruby-mws
data/Gemfile ADDED
@@ -0,0 +1,14 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in ruby-mws.gemspec
4
+ gemspec
5
+
6
+ gem 'httparty'
7
+ gem 'nokogiri'
8
+ gem 'ruby-hmac'
9
+ gem 'hashie'
10
+ gem 'rash'
11
+
12
+ gem 'rspec'
13
+ gem 'ephemeral_response'
14
+ gem 'awesome_print'
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2012 Erik Lyngved
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.markdown ADDED
@@ -0,0 +1,98 @@
1
+ ruby-mws
2
+ ========
3
+
4
+ Under development
5
+ -----------------
6
+
7
+ This is a Ruby gem that wraps the Amazon Marketplace Web Service (MWS) API. It is still missing many features, but some basic requests are available.
8
+
9
+ Please use at your own risk. This has not been tested thoroughly and is not guaranteed to work in any capacity. See the LICENSE file for more details.
10
+
11
+ Quick Start
12
+ -----------
13
+
14
+ ### Initialize the connection object
15
+
16
+ Pass in your developer account credentials. All four params below are required.
17
+
18
+ mws = MWS.new {:aws_access_key_id => "AKIAIFKEXAMPLE4WZHHA",
19
+ :secret_access_key => "abc123def456/SECRET/+ghi789jkl",
20
+ :seller_id => "A27WEXAMPLEBXY",
21
+ :marketplace_id => "ATVPDKIKX0DER"}
22
+
23
+ ### Make a request
24
+
25
+ Let's use the Orders API to retrieve recently updated orders.
26
+
27
+ # Retrieve all orders updated within the last 4 hours
28
+ response = mws.orders.list_orders :last_updated_after => Time.now-4.hours # Rails helper used
29
+
30
+ (All datetime fields accept Time or DateTime objects, as well as strings in iso8601 format.)
31
+
32
+ ### Parse the response
33
+
34
+ We can parse our response to view the orders and any other data returned.
35
+
36
+ response.orders.first # => { "amazon_order_id" => "002-EXAMPLE-0031387",
37
+ "purchase_date" => "2012-01-13T19:11:46.000Z",
38
+ ... }
39
+
40
+ Response objects are accessible in Hash or method notation.
41
+
42
+ response.orders == response[:orders] # => true
43
+
44
+ Use `keys` and `has_key?` to discover what's in the response.
45
+
46
+ response.keys # => ["last_updated_before", "orders"]
47
+ response.has_key? :last_updated_before # => true
48
+
49
+ ### NextToken requests
50
+
51
+ For responses with long lists of data, results are returned from the service in pages (usually 100 per page). Example:
52
+
53
+ response = mws.orders.list_orders :last_updated_after => Time.now-1.week # returns 100 orders
54
+
55
+ Here, there are more orders to be returned. You can call `has_next?` on the same API instance to see if the last response returned has a next page. If so, calling `next` will make the request for the next page.
56
+
57
+ mws.orders.has_next? # => true
58
+ next_response = mws.orders.next # returns next page of orders
59
+
60
+ You can keep calling `next` on the API instance as long as `has_next?` returns true.
61
+
62
+ You can always go about the manual way as per Amazon's docs:
63
+
64
+ next_response = mws.orders.list_orders_by_next_response :next_token => response.next_token
65
+
66
+ ### Underscore notation
67
+
68
+ ruby-mws wraps Amazon's CamelCase convention with Ruby-friendly underscore notation. This goes for request names and params, as well as response field names.
69
+
70
+ Available Requests
71
+ ------------------
72
+
73
+ @mws = MWS.new(authentication_hash) # initialize the connection object
74
+
75
+ This object can be used to access all API services. Below are examples on how to make the different requests that are available so far. Refer to the [Amazon MWS Reference Docs](https://developer.amazonservices.com/) for available fields for each request.
76
+
77
+ ### Orders API
78
+
79
+ * ListOrders - gets orders by time frame and other parameters
80
+
81
+ `@mws.orders.list_orders :last_updated_after => Time.now-4.hours`
82
+
83
+ * GetOrder - gets orders by Amazon order ID
84
+
85
+ `@mws.orders.get_order :amazon_order_id => "002-EXAMPLE-0031387"`
86
+
87
+ `:amazon_order_id` can be an array to retrieve multiple orders.
88
+
89
+ * ListOrderItems - gets order items for one order ID
90
+
91
+ `@mws.orders.list_order_items :amazon_order_id => "002-EXAMPLE-0031387"`
92
+
93
+ ### Fulfillment Inventory API
94
+
95
+ * ListInventorySupply - returns availability of inventory, only returns items based on list of SKUs or last change date
96
+
97
+ `@mws.inventory.list_inventory_supply :seller_skus => %w[PF-5VZN-04XR V4-03EY-LAL1 OC-TUKC-031P`
98
+ `@mws.inventory.list_inventory_supply :query_start_date_time => Time.now-1.day`
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
data/lib/ruby-mws.rb ADDED
@@ -0,0 +1,58 @@
1
+ require 'rubygems'
2
+ require 'httparty'
3
+ require 'base64'
4
+ require 'cgi'
5
+ require 'openssl'
6
+ # require 'hashie/mash'
7
+ require 'hashie'
8
+ require 'rash'
9
+
10
+ module MWS
11
+ def self.new(options={})
12
+ MWS::Base.new(options.symbolize_keys!)
13
+ end
14
+ end
15
+
16
+ # Some convenience methods randomly put here. Thanks, Rails
17
+
18
+ class Hash
19
+ def stringify_keys!
20
+ keys.each do |key|
21
+ self[key.to_s] = delete(key)
22
+ end
23
+ self
24
+ end
25
+
26
+ def symbolize_keys!
27
+ self.replace(self.symbolize_keys)
28
+ end
29
+
30
+ def symbolize_keys
31
+ inject({}) do |options, (key, value)|
32
+ options[(key.to_sym rescue key) || key] = value
33
+ options
34
+ end
35
+ end
36
+ end
37
+
38
+ class String
39
+
40
+ def camelize(first_letter_in_uppercase = true)
41
+ if first_letter_in_uppercase
42
+ self.to_s.gsub(/\/(.?)/) { "::#{$1.upcase}" }.gsub(/(?:^|_)(.)/) { $1.upcase }
43
+ else
44
+ self.to_s[0].chr.downcase + camelize(lower_case_and_underscored_word)[1..-1]
45
+ end
46
+ end
47
+ end
48
+
49
+ require 'ruby-mws/base'
50
+ require 'ruby-mws/connection'
51
+ require 'ruby-mws/exceptions'
52
+ require 'ruby-mws/version'
53
+
54
+ require 'ruby-mws/api/base'
55
+ require 'ruby-mws/api/inventory'
56
+ require 'ruby-mws/api/order'
57
+ require 'ruby-mws/api/query'
58
+ require 'ruby-mws/api/response'
@@ -0,0 +1,80 @@
1
+ # This class serves as a parent class to the API classes.
2
+ # It shares connection handling, query string building, ?? among the models.
3
+
4
+ module MWS
5
+ module API
6
+
7
+ class Base
8
+ include HTTParty
9
+ # debug_output $stderr # only in development
10
+ format :xml
11
+ headers "User-Agent" => "ruby-mws/#{MWS::VERSION} (Language=Ruby/1.9.3-p0)"
12
+ headers "Content-Type" => "text/xml"
13
+
14
+ attr_accessor :response
15
+
16
+ def initialize(connection)
17
+ @connection = connection
18
+ @saved_options = {}
19
+ @next = {}
20
+ self.class.base_uri "https://#{connection.host}"
21
+ end
22
+
23
+ def self.def_request(requests, *options)
24
+ [requests].flatten.each do |name|
25
+ # class variable = a way to store options splat to pass into pseudomethod
26
+ self.class_variable_set("@@#{name}_options", options.first)
27
+ self.class_eval %Q{
28
+ def #{name}(params={})
29
+ send_request(:#{name}, params, @@#{name}_options)
30
+ end
31
+ }
32
+ end
33
+ end
34
+
35
+ def send_request(name, params, options)
36
+ # prepare all required params...
37
+ params = [params, options, @connection.to_hash].inject :merge
38
+
39
+ # default/common params
40
+ params[:action] ||= name.to_s.camelize
41
+ params[:signature_method] ||= 'HmacSHA256'
42
+ params[:signature_version] ||= '2'
43
+ params[:timestamp] ||= Time.now.iso8601
44
+ params[:version] ||= '2009-01-01'
45
+
46
+ params[:lists] ||= {}
47
+ params[:lists][:marketplace_id] = "MarketplaceId.Id"
48
+
49
+ query = Query.new params
50
+ @response = Response.new self.class.send(params[:verb], query.request_uri)
51
+
52
+ begin
53
+ res = @response.send("#{name}_response").send("#{name}_result")
54
+ if @next[:token] = res.next_token # modifying, not comparing
55
+ @next[:action] = params[:next_action] || (name.match(/_by_next_token/) ? name : "#{name}_by_next_token")
56
+ end
57
+ params[:mods].each {|mod| mod.call(res) } if params[:mods]
58
+ res
59
+ rescue NoMethodError
60
+ @response
61
+ end
62
+ end
63
+
64
+ def has_next?
65
+ not @next[:token].nil?
66
+ end
67
+ alias :has_next :has_next?
68
+
69
+ def next
70
+ self.send(@next[:action], :next_token => @next[:token]) unless @next[:token].nil?
71
+ end
72
+
73
+ def inspect
74
+ "#<#{self.class.to_s}:#{object_id}>"
75
+ end
76
+
77
+ end
78
+
79
+ end
80
+ end
@@ -0,0 +1,20 @@
1
+ module MWS
2
+ module API
3
+
4
+ class Inventory < Base
5
+
6
+ def_request [:list_inventory_supply, :list_inventory_supply_by_next_token],
7
+ :verb => :get,
8
+ :uri => '/FulfillmentInventory/2010-10-01',
9
+ :version => '2010-10-01',
10
+ :lists => {
11
+ :seller_skus => "SellerSkus.member"
12
+ },
13
+ :mods => [
14
+ lambda {|r| r.inventory_supply_list = [r.inventory_supply_list.member].flatten}
15
+ ]
16
+
17
+ end
18
+
19
+ end
20
+ end
@@ -0,0 +1,36 @@
1
+ module MWS
2
+ module API
3
+
4
+ class Order < Base
5
+
6
+
7
+ def_request [:list_orders, :list_orders_by_next_token],
8
+ :verb => :get,
9
+ :uri => '/Orders/2011-01-01',
10
+ :version => '2011-01-01',
11
+ :mods => [
12
+ lambda {|r| r.orders = r.orders.order}
13
+ ]
14
+
15
+ def_request [:list_order_items, :list_order_items_by_next_token],
16
+ :verb => :get,
17
+ :uri => '/Orders/2011-01-01',
18
+ :version => '2011-01-01',
19
+ :mods => [
20
+ lambda {|r| r.order_items = [r.order_items.order_item].flatten}
21
+ ]
22
+
23
+ def_request :get_order,
24
+ :verb => :get,
25
+ :uri => '/Orders/2011-01-01',
26
+ :version => '2011-01-01',
27
+ :lists => {
28
+ :amazon_order_id => "AmazonOrderId.Id"
29
+ },
30
+ :mods => [
31
+ lambda {|r| r.orders = [r.orders.order].flatten}
32
+ ]
33
+ end
34
+
35
+ end
36
+ end
@@ -0,0 +1,73 @@
1
+ module MWS
2
+ module API
3
+
4
+ class Query
5
+
6
+ def initialize(params)
7
+ @params = params
8
+ params[:lists].each do |field,label|
9
+ [params.delete(field)].compact.flatten.each_with_index do |item,i|
10
+ params["#{label}.#{i+1}"] = item
11
+ end
12
+ end unless params[:lists].nil?
13
+ end
14
+
15
+ def canonical
16
+ [@params[:verb].to_s.upcase, @params[:host], @params[:uri], build_sorted_query].join("\n")
17
+ end
18
+
19
+ def signature
20
+ digest = OpenSSL::Digest::Digest.new('sha256')
21
+ key = @params[:secret_access_key]
22
+ Base64.encode64(OpenSSL::HMAC.digest(digest, key, canonical)).chomp
23
+ end
24
+
25
+ def request_uri
26
+ "https://" << @params[:host] << @params[:uri] << '?' << build_sorted_query(signature)
27
+ end
28
+
29
+ private
30
+ def build_sorted_query(signature=nil)
31
+ params = @params.dup.delete_if {|k,v| exclude_from_query.include? k}
32
+ params[:signature] = signature if signature
33
+ params.stringify_keys!
34
+
35
+ # hack to capitalize AWS in param names
36
+ # TODO: Allow for multiple marketplace ids
37
+ params = Hash[params.map{|k,v| [k.camelize.sub(/Aws/,'AWS'), v]}]
38
+
39
+ params = params.sort.map! { |p| "#{p[0]}=#{process_param(p[1])}" }
40
+ params.join('&')
41
+ end
42
+
43
+ def process_param(param)
44
+ case param
45
+ when Time, DateTime
46
+ escape(param.iso8601)
47
+ else
48
+ escape(param.to_s)
49
+ end
50
+ end
51
+
52
+ def escape(value)
53
+ value.gsub(/([^a-zA-Z0-9_.~-]+)/) do
54
+ '%' + $1.unpack('H2' * $1.bytesize).join('%').upcase
55
+ end
56
+ end
57
+
58
+ def exclude_from_query
59
+ [
60
+ :verb,
61
+ :host,
62
+ :uri,
63
+ :secret_access_key,
64
+ :return,
65
+ :lists,
66
+ :mods
67
+ ]
68
+ end
69
+
70
+ end
71
+
72
+ end
73
+ end
@@ -0,0 +1,9 @@
1
+ module MWS
2
+ module API
3
+
4
+ class Response < Hashie::Rash
5
+ # Just a wrapper for the Hashie class
6
+ end
7
+
8
+ end
9
+ end
@@ -0,0 +1,26 @@
1
+ module MWS
2
+
3
+ class Base
4
+
5
+ attr_accessor :connection
6
+
7
+ def initialize(options={})
8
+ @connection = MWS::Connection.new(options)
9
+ end
10
+
11
+ def orders
12
+ @orders ||= MWS::API::Order.new(@connection)
13
+ end
14
+
15
+ def inventory
16
+ @inventory ||= MWS::API::Inventory.new(@connection)
17
+ end
18
+
19
+
20
+ # serves as a server ping
21
+ def self.server_time
22
+ MWS::Connection.server_time
23
+ end
24
+
25
+ end
26
+ end
@@ -0,0 +1,52 @@
1
+ module MWS
2
+
3
+ class Connection
4
+
5
+ DEFAULT_HOST = "mws.amazonservices.com"
6
+
7
+ def initialize(options={})
8
+ attrs.each do |a|
9
+ self.class.send(:attr_reader, a)
10
+ instance_variable_set("@#{a}", options[a])
11
+ end
12
+
13
+ @host ||= DEFAULT_HOST
14
+
15
+ attrs.each { |a| raise MissingConnectionOptions, ":#{a} is required" if instance_variable_get("@#{a}").nil?}
16
+ end
17
+
18
+ def public_attrs
19
+ [:aws_access_key_id, :seller_id, :marketplace_id, :host]
20
+ end
21
+
22
+ def private_attrs
23
+ [:secret_access_key]
24
+ end
25
+
26
+ def attrs
27
+ public_attrs + private_attrs
28
+ end
29
+
30
+ # an attempt to hide sensitive login credentials in logs, just being paranoid
31
+ def inspect
32
+ "#<MWS::Connection:#{object_id}>"
33
+ end
34
+
35
+ def server_time
36
+ self.class.server_time @host
37
+ end
38
+
39
+ def to_hash
40
+ hsh = {}
41
+ attrs.each { |a| hsh[a] = instance_variable_get("@#{a}")}
42
+ hsh
43
+ end
44
+
45
+ # No connection needs to be initialized for this call
46
+ def self.server_time(host=DEFAULT_HOST)
47
+ response = HTTParty.get("https://#{host}")
48
+ Time.parse(response['PingResponse']['Timestamp']['timestamp'])
49
+ end
50
+ end
51
+
52
+ end
@@ -0,0 +1,12 @@
1
+ module MWS
2
+
3
+ class MWSException < StandardError
4
+ end
5
+
6
+ class MissingConnectionOptions < MWSException
7
+ end
8
+
9
+ class NoNextToken < MWSException
10
+ end
11
+
12
+ end
@@ -0,0 +1,3 @@
1
+ module MWS
2
+ VERSION = "0.0.2"
3
+ end
data/ruby-mws.gemspec ADDED
@@ -0,0 +1,30 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "ruby-mws/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "ruby-mws"
7
+ s.version = MWS::VERSION
8
+ s.authors = ["Erik Lyngved"]
9
+ s.email = ["elyngved@gmail.com"]
10
+ s.homepage = ""
11
+ s.summary = %q{RubyMWS Gem}
12
+ s.description = %q{Under development!! This gem will serve as a wrapper for Amazon.com's Marketplace Web Service (MWS) API.}
13
+
14
+ s.rubyforge_project = "ruby-mws"
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
+ s.require_paths = ["lib"]
20
+
21
+ # specify any dependencies here; for example:
22
+ s.add_development_dependency "rspec"
23
+ s.add_development_dependency "ephemeral_response"
24
+
25
+ s.add_runtime_dependency "httparty"
26
+ s.add_runtime_dependency "nokogiri"
27
+ s.add_runtime_dependency "ruby-hmac"
28
+ s.add_runtime_dependency "hashie"
29
+ s.add_runtime_dependency "rash"
30
+ end
@@ -0,0 +1,4 @@
1
+ GET
2
+ mws.amazonservices.com
3
+ /Orders/2011-01-01
4
+ AWSAccessKeyId=access&Action=ListOrders&LastUpdatedAfter=2012-01-13T15%3A48%3A55-05%3A00&MarketplaceId.Id.1=ATVPDKIKX0DER&SellerId=A27WNMSA8OPBXY&SignatureMethod=HmacSHA256&SignatureVersion=2&Timestamp=2012-01-14T15%3A48%3A55-05%3A00&Version=2011-01-01
data/spec/mws_spec.rb ADDED
@@ -0,0 +1,11 @@
1
+ require 'spec_helper'
2
+
3
+ describe MWS do
4
+
5
+ context 'connect' do
6
+ it 'should create a MWS::Base object' do
7
+ MWS.new(auth_params).class.should == MWS::Base
8
+ end
9
+ end
10
+
11
+ end
@@ -0,0 +1,42 @@
1
+ require 'spec_helper'
2
+
3
+ describe MWS::API::Base do
4
+ class FakeApi < MWS::API::Base
5
+ def self.test_params
6
+ {
7
+ :verb => :get,
8
+ :uri => '/FakeApi/2011-01-01',
9
+ :version => '2011-01-01'
10
+ }
11
+ end
12
+
13
+ def_request [:list_fake_objects, :list_fake_objects_by_next_token], self.test_params
14
+ end
15
+
16
+ before :all do
17
+ @api = FakeApi.new(mws_object.connection)
18
+ end
19
+
20
+ context "def_request" do
21
+ it "should generate methods for each request defined" do
22
+ @api.respond_to?(:list_fake_objects).should be_true
23
+ @api.respond_to?(:list_fake_objects_by_next_token).should be_true
24
+ end
25
+
26
+ it "should store request options as a class variable" do
27
+ FakeApi.class_variable_get('@@list_fake_objects_options').should be
28
+ FakeApi.class_variable_get('@@list_fake_objects_by_next_token_options').should be
29
+ FakeApi.class_variable_get('@@list_fake_objects_options').should == FakeApi.test_params
30
+ end
31
+ end
32
+
33
+ context "methods generated by def_request" do
34
+ it "should call send_request with the right params" do
35
+ @api.should_receive(:send_request).
36
+ with(:list_fake_objects, {}, FakeApi.test_params).
37
+ and_raise(TestWorksError)
38
+ lambda{ @api.list_fake_objects }.should raise_error TestWorksError
39
+ end
40
+ end
41
+
42
+ end
@@ -0,0 +1,30 @@
1
+ require 'spec_helper'
2
+
3
+ describe MWS::API::Inventory do
4
+
5
+ before :all do
6
+ EphemeralResponse.activate
7
+ @mws = MWS.new(auth_params)
8
+ @timestamp = "2012-01-15T18:07:48-05:00"
9
+ end
10
+
11
+ context "requests" do
12
+
13
+ describe "list_inventory_supply" do
14
+ it "should return items based on seller SKUs" do
15
+ items = @mws.inventory.list_inventory_supply :timestamp => @timestamp,
16
+ :seller_skus => %w[PF-5VZN-04XR V4-03EY-LAL1 OC-TUKC-031P]
17
+ items.should have_key :inventory_supply_list
18
+ items.inventory_supply_list.should be_an_instance_of Array
19
+ end
20
+
21
+ it "should return items with inventory changes since a certain time" do
22
+ items = @mws.inventory.list_inventory_supply :timestamp => @timestamp,
23
+ :query_start_date_time => "2012-01-15T10:04:01-05:00"
24
+ items.should have_key :inventory_supply_list
25
+ items.inventory_supply_list.should be_an_instance_of Array
26
+ end
27
+ end
28
+ end
29
+
30
+ end
@@ -0,0 +1,61 @@
1
+ require 'spec_helper'
2
+
3
+ describe MWS::API::Order do
4
+
5
+ before :all do
6
+ EphemeralResponse.activate
7
+ @mws = MWS.new(auth_params)
8
+ @timestamp = "2012-01-15T17:28:17-05:00"
9
+ end
10
+
11
+ context "requests" do
12
+ describe "list_orders" do
13
+ it "should receive a list_orders_result" do
14
+ orders = @mws.orders.list_orders :last_updated_after => "2012-01-15T13:07:26-05:00" ,
15
+ :timestamp => @timestamp
16
+ orders.orders.should be_an_instance_of Array
17
+ orders.should == @mws.orders.response.list_orders_response.list_orders_result
18
+ end
19
+ end
20
+
21
+ describe "list_orders_by_next_token" do
22
+ it "should receive a list_orders_by_next_token_result" do
23
+ orders = @mws.orders.list_orders_by_next_token :timestamp => @timestamp,
24
+ :next_token => "zwR7fTkqiKp/YYuZQbKv1QafEPREmauvizt1MIhPYZZl3LSdPSOgN1byEfyVqilNBpcRD1uxgRxTg2dsYWmzKd8ytOVgN7d/KyNtf5fepe2OEd7gVZif6X81/KsTyqd1e64rGQd1TyCS68vI7Bqws+weLxD7b1CVZciW6QBe7o2FizcdzSXGSiKsUkM4/6QGllhc4XvGqg5e0zIeaOVNezxWEXvdeDL7eReo//Hc3LMRF18hF5ZYNntoCB8irbDGcVkxA+q0fZYwE7+t4NjazyEZY027dXAVTSGshRBy6ZTthhfBGj6Dwur8WCwcU8Vc25news0zC1w6gK1h3EdXw7a3u+Q12Uw9ZROnI57RGr4CrtRODNGKSRdGvNrxcHpI2aLZKrJa2MgKRa+KsojCckrDiHqb8mBEJ88g6izJN42dQcLTGQRwBej+BBOOHYP4"
25
+ orders.orders.should be_an_instance_of Array
26
+ end
27
+ end
28
+
29
+ describe "get_order" do
30
+ it "should return one order for one order id" do
31
+ order = @mws.orders.get_order :amazon_order_id => "102-4850183-7065809",
32
+ :timestamp => @timestamp
33
+ order.should have_key :orders
34
+ order.orders.should be_an_instance_of Array
35
+ order.orders.first.should have_key :amazon_order_id
36
+ end
37
+
38
+ it "should return multiple orders for multiple order ids" do
39
+ orders = @mws.orders.get_order :amazon_order_id => ["102-4850183-7065809", "002-3400187-5292203"],
40
+ :timestamp => @timestamp
41
+ orders.orders.should be_an_instance_of Array
42
+ orders.orders.size.should == 2
43
+ end
44
+ end
45
+
46
+ describe "list_order_items" do
47
+ it "should return a list of items for an order" do
48
+ order = @mws.orders.list_order_items :amazon_order_id => "102-4850183-7065809",
49
+ :timestamp => @timestamp
50
+ order.should have_key :amazon_order_id
51
+ order.should have_key :order_items
52
+ order.order_items.should be_an_instance_of Array
53
+ end
54
+ end
55
+
56
+ describe "list_order_items_by_next_token" do
57
+
58
+ end
59
+ end
60
+
61
+ end
@@ -0,0 +1,43 @@
1
+ require 'spec_helper'
2
+
3
+ describe MWS::API::Query do
4
+ before do
5
+ @query = MWS::API::Query.new(default_params)
6
+ @query.stub!(:signature).and_return("SIGNATURE")
7
+ end
8
+
9
+ context ".query" do
10
+ it "should assemble the canonical query" do
11
+ @query.canonical.should == %Q{GET
12
+ mws.amazonservices.com
13
+ /Orders/2011-01-01
14
+ AWSAccessKeyId=#{default_params[:aws_access_key_id]}&Action=ListOrders&LastUpdatedAfter=2012-01-13T15%3A48%3A55-05%3A00&MarketplaceId.Id.1=#{default_params[:marketplace_id]}&SellerId=#{default_params[:seller_id]}&SignatureMethod=HmacSHA256&SignatureVersion=2&Timestamp=2012-01-14T15%3A48%3A55-05%3A00&Version=2011-01-01}
15
+ end
16
+ end
17
+
18
+ context ".request_uri" do
19
+ it "should assemble the request uri" do
20
+ @query.request_uri.should == "https://mws.amazonservices.com/Orders/2011-01-01?AWSAccessKeyId=#{default_params[:aws_access_key_id]}&Action=ListOrders&LastUpdatedAfter=2012-01-13T15%3A48%3A55-05%3A00&MarketplaceId.Id.1=#{default_params[:marketplace_id]}&SellerId=#{default_params[:seller_id]}&Signature=SIGNATURE&SignatureMethod=HmacSHA256&SignatureVersion=2&Timestamp=2012-01-14T15%3A48%3A55-05%3A00&Version=2011-01-01"
21
+ end
22
+ end
23
+
24
+ def default_params
25
+ # some random keys
26
+ params = {
27
+ :last_updated_after => "2012-01-13T15:48:55-05:00",
28
+ :verb => :get,
29
+ :uri => "/Orders/2011-01-01",
30
+ :version => "2011-01-01",
31
+ :host => "mws.amazonservices.com",
32
+ :action => "ListOrders",
33
+ :signature_method => "HmacSHA256",
34
+ :signature_version => "2",
35
+ :timestamp => "2012-01-14T15:48:55-05:00",
36
+ :lists => {
37
+ :marketplace_id => "MarketplaceId.Id"
38
+ }
39
+ }.merge(auth_params)
40
+ end
41
+
42
+ end
43
+
@@ -0,0 +1,18 @@
1
+ require 'spec_helper'
2
+
3
+ describe MWS::Base do
4
+
5
+ it "should connect and get a timestamp" do
6
+ MWS::Base.server_time.class.should == Time
7
+ end
8
+
9
+ context 'initialize' do
10
+ it "should create a connection object" do
11
+ mws = MWS::Base.new(auth_params)
12
+ mws.should be
13
+ mws.connection.should be
14
+ mws.connection.class.should == MWS::Connection
15
+ end
16
+ end
17
+
18
+ end
@@ -0,0 +1,26 @@
1
+ require 'spec_helper'
2
+
3
+ describe MWS::Connection do
4
+
5
+ context "initialize" do
6
+ it "should intialize with all requires params" do
7
+ conn = MWS::Connection.new auth_params
8
+ conn.class.should == MWS::Connection
9
+ auth_params.each do |k,v|
10
+ conn.send(k).should == v
11
+ end
12
+ conn.host.should == "mws.amazonservices.com"
13
+ end
14
+
15
+ it "should raise an exception when a required param is missing" do
16
+ auth_params.each do |k,v|
17
+ lambda { MWS::Connection.new auth_params.delete(k) }.should raise_error
18
+ end
19
+ end
20
+
21
+ it "should override host when sent a host param" do
22
+ conn = MWS::Connection.new auth_params.merge({host: 'newhost.com'})
23
+ conn.host.should == 'newhost.com'
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,34 @@
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+ require 'awesome_print'
4
+ require 'ephemeral_response'
5
+
6
+ require 'ruby-mws'
7
+
8
+ RSpec.configure do |config|
9
+ def fixture(path)
10
+ File.open(File.join(File.expand_path(File.dirname(__FILE__)), 'fixtures', path)).read
11
+ end
12
+
13
+ def mws_object
14
+ @mws_object ||= MWS.new(auth_params)
15
+ end
16
+
17
+ def auth_params
18
+ @auth_params ||=
19
+ begin
20
+ hsh = YAML.load(File.open(File.join(File.expand_path(File.dirname(__FILE__)), 'credentials.yml'))).symbolize_keys!
21
+ rescue
22
+ # some fake auth values
23
+ {
24
+ :aws_access_key_id => 'access',
25
+ :secret_access_key => 'super_secret',
26
+ :seller_id => 'doma',
27
+ :marketplace_id => '123'
28
+ }
29
+ end
30
+ end
31
+ end
32
+
33
+ class TestWorksError < StandardError
34
+ end
metadata ADDED
@@ -0,0 +1,158 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ruby-mws
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Erik Lyngved
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-01-16 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rspec
16
+ requirement: &70093283680840 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: *70093283680840
25
+ - !ruby/object:Gem::Dependency
26
+ name: ephemeral_response
27
+ requirement: &70093283680380 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: *70093283680380
36
+ - !ruby/object:Gem::Dependency
37
+ name: httparty
38
+ requirement: &70093283679760 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ! '>='
42
+ - !ruby/object:Gem::Version
43
+ version: '0'
44
+ type: :runtime
45
+ prerelease: false
46
+ version_requirements: *70093283679760
47
+ - !ruby/object:Gem::Dependency
48
+ name: nokogiri
49
+ requirement: &70093283679200 !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ type: :runtime
56
+ prerelease: false
57
+ version_requirements: *70093283679200
58
+ - !ruby/object:Gem::Dependency
59
+ name: ruby-hmac
60
+ requirement: &70093283678440 !ruby/object:Gem::Requirement
61
+ none: false
62
+ requirements:
63
+ - - ! '>='
64
+ - !ruby/object:Gem::Version
65
+ version: '0'
66
+ type: :runtime
67
+ prerelease: false
68
+ version_requirements: *70093283678440
69
+ - !ruby/object:Gem::Dependency
70
+ name: hashie
71
+ requirement: &70093283678000 !ruby/object:Gem::Requirement
72
+ none: false
73
+ requirements:
74
+ - - ! '>='
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
77
+ type: :runtime
78
+ prerelease: false
79
+ version_requirements: *70093283678000
80
+ - !ruby/object:Gem::Dependency
81
+ name: rash
82
+ requirement: &70093283677580 !ruby/object:Gem::Requirement
83
+ none: false
84
+ requirements:
85
+ - - ! '>='
86
+ - !ruby/object:Gem::Version
87
+ version: '0'
88
+ type: :runtime
89
+ prerelease: false
90
+ version_requirements: *70093283677580
91
+ description: Under development!! This gem will serve as a wrapper for Amazon.com's
92
+ Marketplace Web Service (MWS) API.
93
+ email:
94
+ - elyngved@gmail.com
95
+ executables: []
96
+ extensions: []
97
+ extra_rdoc_files: []
98
+ files:
99
+ - .gitignore
100
+ - .rvmrc
101
+ - Gemfile
102
+ - LICENSE
103
+ - README.markdown
104
+ - Rakefile
105
+ - lib/ruby-mws.rb
106
+ - lib/ruby-mws/api/base.rb
107
+ - lib/ruby-mws/api/inventory.rb
108
+ - lib/ruby-mws/api/order.rb
109
+ - lib/ruby-mws/api/query.rb
110
+ - lib/ruby-mws/api/response.rb
111
+ - lib/ruby-mws/base.rb
112
+ - lib/ruby-mws/connection.rb
113
+ - lib/ruby-mws/exceptions.rb
114
+ - lib/ruby-mws/version.rb
115
+ - ruby-mws.gemspec
116
+ - spec/fixtures/list_orders_canonical.txt
117
+ - spec/mws_spec.rb
118
+ - spec/ruby-mws/api/base_spec.rb
119
+ - spec/ruby-mws/api/inventory_spec.rb
120
+ - spec/ruby-mws/api/order_spec.rb
121
+ - spec/ruby-mws/api/query_spec.rb
122
+ - spec/ruby-mws/base_spec.rb
123
+ - spec/ruby-mws/connection_spec.rb
124
+ - spec/spec_helper.rb
125
+ homepage: ''
126
+ licenses: []
127
+ post_install_message:
128
+ rdoc_options: []
129
+ require_paths:
130
+ - lib
131
+ required_ruby_version: !ruby/object:Gem::Requirement
132
+ none: false
133
+ requirements:
134
+ - - ! '>='
135
+ - !ruby/object:Gem::Version
136
+ version: '0'
137
+ required_rubygems_version: !ruby/object:Gem::Requirement
138
+ none: false
139
+ requirements:
140
+ - - ! '>='
141
+ - !ruby/object:Gem::Version
142
+ version: '0'
143
+ requirements: []
144
+ rubyforge_project: ruby-mws
145
+ rubygems_version: 1.8.15
146
+ signing_key:
147
+ specification_version: 3
148
+ summary: RubyMWS Gem
149
+ test_files:
150
+ - spec/fixtures/list_orders_canonical.txt
151
+ - spec/mws_spec.rb
152
+ - spec/ruby-mws/api/base_spec.rb
153
+ - spec/ruby-mws/api/inventory_spec.rb
154
+ - spec/ruby-mws/api/order_spec.rb
155
+ - spec/ruby-mws/api/query_spec.rb
156
+ - spec/ruby-mws/base_spec.rb
157
+ - spec/ruby-mws/connection_spec.rb
158
+ - spec/spec_helper.rb