ruby-mws 0.0.2

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