zanoxrb 0.4 → 0.5

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 619cbe2a3526db513228244f180a67a3b3f493dd
4
- data.tar.gz: 4e5bace7088bf59b45e64d39836466ed82f44c6f
3
+ metadata.gz: b2972b4fe3fec25d73833848f7585a732de4e7c5
4
+ data.tar.gz: ec85cc77504d167494692ba309c9bf1d1769e0a3
5
5
  SHA512:
6
- metadata.gz: 79558047d1956ffa69b617a23b1a120b3b52a7b6b94800bb63f16509a35400c1ad31a7ab21b15a29d38a7334aa92369b88f86fb70102ec3579f25e148cdc0468
7
- data.tar.gz: 8d4f1f09239abe591fc568f981101cb6c3c053cf10ab563cc915a4ec723f185a8f3198f73793b1e6410bc3336111293ce456dc7014ce80d75d13004acf8db656
6
+ metadata.gz: b94269bfb5f10350e230fba309c2c9bc41bd4a87598ba7a0226ba339a958f05ba3af36ab2c74049bec552826dc2da3c4beb0ad2644ae51794e76ac133b51df23
7
+ data.tar.gz: 89a2f98563bc8b42579a66edda97297554fe9eb81584727f586638c5db8e88b3f7144904e70c740364e041e80da5aea4cdcec58ac35720ab2da4b562646a1882
data/Gemfile.lock CHANGED
@@ -1,8 +1,9 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- zanoxrb (0.4)
4
+ zanoxrb (0.5)
5
5
  httparty (~> 0.13)
6
+ ruby-try (~> 1.1)
6
7
 
7
8
  GEM
8
9
  remote: https://rubygems.org/
@@ -29,6 +30,7 @@ GEM
29
30
  diff-lcs (>= 1.2.0, < 2.0)
30
31
  rspec-support (~> 3.3.0)
31
32
  rspec-support (3.3.0)
33
+ ruby-try (1.1.1)
32
34
 
33
35
  PLATFORMS
34
36
  ruby
@@ -38,3 +40,6 @@ DEPENDENCIES
38
40
  rspec (~> 3.3)
39
41
  rspec-collection_matchers (~> 1.1)
40
42
  zanoxrb!
43
+
44
+ BUNDLED WITH
45
+ 1.10.4
data/README.md CHANGED
@@ -1,7 +1,8 @@
1
1
  ZanoxRB [![Build Status](https://travis-ci.org/mozestudio/zanox-rb.svg)](https://travis-ci.org/mozestudio/zanox-rb)
2
2
  =======
3
3
  A Ruby wrapper for Zanox's RESTful APIs because all the current alternatives outta here are shit.
4
- Currently supporting only `GET` requests (aka, read-only).
4
+
5
+ Currently it supports only `GET` requests (aka, read-only).
5
6
 
6
7
  Install
7
8
  =======
@@ -17,7 +18,10 @@ $ export ZANOX_SECRET_KEY=''
17
18
 
18
19
  To make requests to the APIs, call `Zanox::API#request` passing the endpoint of the method you want to call and optionally a hash with one or more params (such as `q`, `date`, `programs`, etc.) based on the official documentation you can find [here](https://developer.zanox.com/web/guest/publisher-api-2011/).
19
20
 
20
- Every call will return a native Ruby hash or an array reflecting the original documentation provided by Zanox (I plan to also wrap every response inside a class that allows to get every value following the Ruby-way, btw).
21
+ Every call will return a native Ruby hash or an array reflecting the original documentation provided by Zanox.
22
+
23
+ Alternatively you can use the native wrappers provided inside `resources/`.
24
+ They are a few and also they're under development, and if you need something complex probably they might be not the best choice, but for just reading and manipulate collections they're useful enough since there is no need to work on raw data.
21
25
 
22
26
  Note also that the pagination in Zanox APIs is 0-indexed. For example, if you want to get the second page of the requested products list you have to pass `page: 1` to the optional params, otherwise you'll get, of course, the first page that actually is referrable as `page: 0`.
23
27
  Consider using `Zanox::Response#next_page` and `Zanox::Response#previous_page` to navigate through the pages.
data/Rakefile CHANGED
@@ -17,4 +17,10 @@ task :test do
17
17
  sh "rspec #{spec} --backtrace --color --format doc"
18
18
  end
19
19
  end
20
+
21
+ FileUtils.cd 'specs/resources' do
22
+ Dir['*_spec.rb'].each do |spec|
23
+ sh "rspec #{spec} --backtrace --color --format doc"
24
+ end
25
+ end
20
26
  end
@@ -0,0 +1,43 @@
1
+ #--
2
+ # Copyright(C) 2015 Giovanni Capuano <webmaster@giovannicapuano.net>
3
+ #
4
+ # Redistribution and use in source and binary forms, with or without modification, are
5
+ # permitted provided that the following conditions are met:
6
+ #
7
+ # 1. Redistributions of source code must retain the above copyright notice, this list of
8
+ # conditions and the following disclaimer.
9
+ #
10
+ # THIS SOFTWARE IS PROVIDED BY Giovanni Capuano ''AS IS'' AND ANY EXPRESS OR IMPLIED
11
+ # WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
12
+ # FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Giovanni Capuano OR
13
+ # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
14
+ # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
15
+ # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
16
+ # ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
17
+ # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
18
+ # ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
19
+ #
20
+ # The views and conclusions contained in the software and documentation are those of the
21
+ # authors and should not be interpreted as representing official policies, either expressed
22
+ # or implied, of Giovanni Capuano.
23
+ #++
24
+
25
+ module Zanox
26
+ module Hashable
27
+ def to_hash
28
+ attributes.each_with_object({}) do |attr, hash|
29
+ key = attr.to_s.delete('@')
30
+ hash[key] = attribute(attr)
31
+ end
32
+ end
33
+
34
+ protected
35
+ def attributes
36
+ instance_variables
37
+ end
38
+
39
+ def attribute(attr)
40
+ instance_variable_get(attr)
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,74 @@
1
+ #--
2
+ # Copyright(C) 2015 Giovanni Capuano <webmaster@giovannicapuano.net>
3
+ #
4
+ # Redistribution and use in source and binary forms, with or without modification, are
5
+ # permitted provided that the following conditions are met:
6
+ #
7
+ # 1. Redistributions of source code must retain the above copyright notice, this list of
8
+ # conditions and the following disclaimer.
9
+ #
10
+ # THIS SOFTWARE IS PROVIDED BY Giovanni Capuano ''AS IS'' AND ANY EXPRESS OR IMPLIED
11
+ # WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
12
+ # FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Giovanni Capuano OR
13
+ # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
14
+ # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
15
+ # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
16
+ # ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
17
+ # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
18
+ # ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
19
+ #
20
+ # The views and conclusions contained in the software and documentation are those of the
21
+ # authors and should not be interpreted as representing official policies, either expressed
22
+ # or implied, of Giovanni Capuano.
23
+ #++
24
+
25
+ module Zanox
26
+ class AdSpace < Item
27
+ attr_reader :pid, :name, :url, :description, :type, :visitors, :impressions,
28
+ :scope, :regions, :categories, :language, :check_number
29
+
30
+ ###################
31
+ # - pid (Integer) AdSpace ID
32
+ # - name (String) The name of the adspace
33
+ # - url (String) The URL to the adspace
34
+ # - description (String) The description of the adspace
35
+ # - type (String) The type of the adspace (website, email, searchengine)
36
+ # - visitors (Integer) How many visitors Zanox tracked for you
37
+ # - impressions (Integer) The number of impressions of the adspace
38
+ # - scope (String) The scope of the adspace (private, bussiness)
39
+ # - regions (String[]) The regions where the adspace works
40
+ # - categories (String[]) The categories of the adspace
41
+ # - language (String) The language used inside the adspace
42
+ # - check_number (Integer)
43
+ ###################
44
+ def initialize(data)
45
+ @pid = data['@id'].to_i
46
+ @name = data['name']
47
+ @url = data['url']
48
+ @description = data['description']
49
+ @type = data['adspaceType']
50
+ @visitors = data['visitors'].to_i
51
+ @impressions = data['impressions'].to_i
52
+ @scope = data['scope']
53
+ @regions = [data['regions'].try { |r| r.map(&:values) }].flatten.compact
54
+ @categories = [].tap do |categories|
55
+ categories_ = data['categories'].try { |p| p[0]['category'] }
56
+ data['categories'].try { |p| p[0]['category'] }.each do |category|
57
+ categories << {
58
+ id: category['@id'],
59
+ name: category['$'],
60
+ }
61
+ end
62
+ end
63
+ @language = data['language']
64
+ @check_number = data['checkNumber']
65
+ end
66
+
67
+ class << self
68
+ def find(args = {})
69
+ response = API.request(:adspaces, args)
70
+ response.adspace_items.map { |adspace| new(adspace) }
71
+ end
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,39 @@
1
+ #--
2
+ # Copyright(C) 2015 Giovanni Capuano <webmaster@giovannicapuano.net>
3
+ #
4
+ # Redistribution and use in source and binary forms, with or without modification, are
5
+ # permitted provided that the following conditions are met:
6
+ #
7
+ # 1. Redistributions of source code must retain the above copyright notice, this list of
8
+ # conditions and the following disclaimer.
9
+ #
10
+ # THIS SOFTWARE IS PROVIDED BY Giovanni Capuano ''AS IS'' AND ANY EXPRESS OR IMPLIED
11
+ # WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
12
+ # FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Giovanni Capuano OR
13
+ # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
14
+ # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
15
+ # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
16
+ # ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
17
+ # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
18
+ # ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
19
+ #
20
+ # The views and conclusions contained in the software and documentation are those of the
21
+ # authors and should not be interpreted as representing official policies, either expressed
22
+ # or implied, of Giovanni Capuano.
23
+ #++
24
+
25
+ module Zanox
26
+ class Item
27
+ include Hashable
28
+
29
+ def initialize
30
+ raise NotImplementedError, '#initialize has not been implemented'
31
+ end
32
+
33
+ class << self
34
+ def find(*args)
35
+ raise NotImplementedError, '#find has not been implemented'
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,89 @@
1
+ #--
2
+ # Copyright(C) 2015 Giovanni Capuano <webmaster@giovannicapuano.net>
3
+ #
4
+ # Redistribution and use in source and binary forms, with or without modification, are
5
+ # permitted provided that the following conditions are met:
6
+ #
7
+ # 1. Redistributions of source code must retain the above copyright notice, this list of
8
+ # conditions and the following disclaimer.
9
+ #
10
+ # THIS SOFTWARE IS PROVIDED BY Giovanni Capuano ''AS IS'' AND ANY EXPRESS OR IMPLIED
11
+ # WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
12
+ # FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Giovanni Capuano OR
13
+ # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
14
+ # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
15
+ # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
16
+ # ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
17
+ # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
18
+ # ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
19
+ #
20
+ # The views and conclusions contained in the software and documentation are those of the
21
+ # authors and should not be interpreted as representing official policies, either expressed
22
+ # or implied, of Giovanni Capuano.
23
+ #++
24
+
25
+ module Zanox
26
+ class Product < Item
27
+ attr_reader :pid, :name, :program, :description, :excerpt, :manufacturer, :category,
28
+ :images, :currency, :price, :shipping_costs, :delivery_time, :tracking_link
29
+
30
+ ###################
31
+ # - pid (String) Product ID
32
+ # - name (String) The name of the product
33
+ # - program (Hash) Hash containing the id and the name of the shop which sells this product (e.g. EuronicsIT)
34
+ # - description (HTML) The description of the product
35
+ # - excerpt (String) A short description of the product
36
+ # - manufacturer (String) The manufacturer of the product (e.g. Apple)
37
+ # - images (String[]) A collection of images representing the product in different sizes
38
+ # - currency (String) The currency used to calculate the price
39
+ # - price (Float) The price of the product calculated with the relative currency
40
+ # - shipping_costs (Float) The price of the shipping
41
+ # - delivery_time (Integer) The number of the days required by the shop to deliver the product
42
+ # - tracking_link (String ) The link that redirects to the advertiser's shop
43
+ ###################
44
+ def initialize(data)
45
+ @pid = data['@id']
46
+ @name = data['name']
47
+ @program = {
48
+ id: data['program']['@id'].to_i,
49
+ name: data['program']['$']
50
+ }
51
+ @description = strip_cdata(data['descriptionLong'])
52
+ @excerpt = data['description']
53
+ @manufacturer = data['manufacturer']
54
+ @category = data['merchantCategory']
55
+ @images = {
56
+ small: data['image'].try { |i| i['small'] },
57
+ medium: data['image'].try { |i| i['medium'] },
58
+ large: data['image'].try { |i| i['large'] },
59
+ }
60
+ @currency = data['currency']
61
+ @price = data['price'].to_f
62
+ @shipping_costs = data['shippingCosts'].try(:to_f)
63
+ @delivery_time = only_numbers(data['deliveryTime'])
64
+ @tracking_link = data['trackingLinks'].try { |d| d['trackingLink'] }.try { |d| d[0] }.try { |d| d['ppc'] }
65
+ end
66
+
67
+ class << self
68
+ def find(keyword, args = {})
69
+ args.merge!({ q: keyword })
70
+ response = API.request(:products, args)
71
+ response.product_items.map { |product| new(product) }
72
+ end
73
+
74
+ def from_shop(shop_id)
75
+ response = API.request(:products, programs: shop_id)
76
+ response.product_items.map { |product| new(product) }
77
+ end
78
+ end
79
+
80
+ private
81
+ def strip_cdata(s)
82
+ s ? s.gsub(/<!\[CDATA\[(.*)\]\]>/, '\1') : s
83
+ end
84
+
85
+ def only_numbers(s)
86
+ s ? s.scan(/\d+/).last.to_i : s
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,58 @@
1
+ #--
2
+ # Copyright(C) 2015 Giovanni Capuano <webmaster@giovannicapuano.net>
3
+ #
4
+ # Redistribution and use in source and binary forms, with or without modification, are
5
+ # permitted provided that the following conditions are met:
6
+ #
7
+ # 1. Redistributions of source code must retain the above copyright notice, this list of
8
+ # conditions and the following disclaimer.
9
+ #
10
+ # THIS SOFTWARE IS PROVIDED BY Giovanni Capuano ''AS IS'' AND ANY EXPRESS OR IMPLIED
11
+ # WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
12
+ # FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Giovanni Capuano OR
13
+ # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
14
+ # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
15
+ # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
16
+ # ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
17
+ # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
18
+ # ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
19
+ #
20
+ # The views and conclusions contained in the software and documentation are those of the
21
+ # authors and should not be interpreted as representing official policies, either expressed
22
+ # or implied, of Giovanni Capuano.
23
+ #++
24
+
25
+ module Zanox
26
+ class ProgramApplication < Item
27
+ attr_reader :pid, :program, :adspace, :status, :allow_tpv
28
+
29
+ ###################
30
+ # - pid (Integer) ProgramApplication ID
31
+ # - program (Hash) Infos about the program (activation status, id and name)
32
+ # - adspace (Hash) Infos about the adspace (id and name)
33
+ # - status (String) The status of the program (open, confirmed, rejected, deferred, waiting, blocked, terminated, canceled, called, declined, deleted)
34
+ # - allow_tpv (Boolean)
35
+ ###################
36
+ def initialize(data)
37
+ @pid = data['@id'].to_i
38
+ @program = {
39
+ active: data['program']['@active'] == 'true',
40
+ id: data['program']['@id'].to_i,
41
+ name: data['program']['$']
42
+ }
43
+ @adspace = {
44
+ id: data['adspace']['@id'],
45
+ name: data['adspace']['$']
46
+ }
47
+ @status = data['status']
48
+ @allow_tpv = data['allowTpv']
49
+ end
50
+
51
+ class << self
52
+ def find(args = {})
53
+ response = API.request(:programapplications, args)
54
+ response.program_application_items.map { |program_application| new(program_application) }
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,113 @@
1
+ #--
2
+ # Copyright(C) 2015 Giovanni Capuano <webmaster@giovannicapuano.net>
3
+ #
4
+ # Redistribution and use in source and binary forms, with or without modification, are
5
+ # permitted provided that the following conditions are met:
6
+ #
7
+ # 1. Redistributions of source code must retain the above copyright notice, this list of
8
+ # conditions and the following disclaimer.
9
+ #
10
+ # THIS SOFTWARE IS PROVIDED BY Giovanni Capuano ''AS IS'' AND ANY EXPRESS OR IMPLIED
11
+ # WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
12
+ # FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Giovanni Capuano OR
13
+ # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
14
+ # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
15
+ # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
16
+ # ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
17
+ # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
18
+ # ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
19
+ #
20
+ # The views and conclusions contained in the software and documentation are those of the
21
+ # authors and should not be interpreted as representing official policies, either expressed
22
+ # or implied, of Giovanni Capuano.
23
+ #++
24
+
25
+ module Zanox
26
+ class Shop < Item
27
+ attr_reader :pid, :name, :rank, :description, :excerpt, :products_count,
28
+ :regions, :categories, :url, :image, :currency, :available, :terms, :policies
29
+
30
+ ###################
31
+ # - pid (Integer) Shop ID
32
+ # - name (String) The name of the product
33
+ # - rank (Float) The rank of the shop
34
+ # - description (HTML) The description of the shop
35
+ # - excerpt (String) A short description of the shop
36
+ # - products_count (Integer) The number of products in stock
37
+ # - regions (String[]) A collection of regions where the shop is located
38
+ # - categories (String[]) A collection of the main categories of products
39
+ # - url (String) The direct link to the shop
40
+ # - image (String) An image representing the shop
41
+ # - currency (String) The currency used inside the shop
42
+ # - terms (HTML) The terms applied by the shop
43
+ # - policies (String[]) A collection of the policies followed by the shop
44
+ ###################
45
+ def initialize(data)
46
+ @pid = data['@id'].to_i
47
+ @name = data['name']
48
+ @rank = data['adrank'].to_f
49
+ @description = strip_cdata(data['descriptionLocal'])
50
+ @excerpt = data['description']
51
+ @products_count = data['products'].to_i
52
+ @regions = [data['regions'].try { |r| r.map(&:values) }].flatten.compact
53
+ @categories = [].tap do |categories|
54
+ [data['categories'].try { |p| p[0]['category'] }].flatten.each do |category|
55
+ categories << {
56
+ id: category['@id'],
57
+ name: category['$'],
58
+ }
59
+ end
60
+ end
61
+ @url = data['url']
62
+ @image = data['image']
63
+ @currency = data['currency']
64
+ @terms = strip_cdata(data['terms'])
65
+ @policies = [].tap do |policies|
66
+ [data['policies'].try { |p| p['policy'] }].flatten.each do |policy|
67
+ policies << {
68
+ id: policy['@id'],
69
+ name: policy['$'],
70
+ } if policy
71
+ end
72
+ end
73
+ end
74
+
75
+ class << self
76
+ def find(param, args = {})
77
+ param.is_a?(Numeric) ? find_by_id(param) : find_by_keyword(param)
78
+ end
79
+
80
+ def find_by_id(id, args = {})
81
+ response = ::Zanox::API.request("programs/program/#{id}", args)
82
+ response.program_item.map { |program| new(program) }
83
+ end
84
+
85
+ def find_by_keyword(keyword, args = {})
86
+ args.merge!({ q: keyword })
87
+ response = API.request(:programs, args)
88
+ response.program_items.map { |program| new(program) }
89
+ end
90
+
91
+ # TODO: we could cache these results
92
+ def confirmed_shops
93
+ confirmed_ids.map { |id| find(id) }.flatten
94
+ end
95
+
96
+ private
97
+ def confirmed
98
+ adspaces = AdSpace.find.first
99
+ applications = ProgramApplication.find(adspace: adspaces.pid)
100
+ applications.select { |application| application.status == 'confirmed' }
101
+ end
102
+
103
+ def confirmed_ids
104
+ confirmed.map { |application| application.program[:id] }
105
+ end
106
+ end
107
+
108
+ private
109
+ def strip_cdata(s)
110
+ s ? s.gsub(/<!\[CDATA\[(.*)\]\]>/, '\1') : s
111
+ end
112
+ end
113
+ end
@@ -68,7 +68,7 @@ module Zanox
68
68
  response
69
69
  end
70
70
 
71
- key.end_with?('_items') && !results ? [] : results
71
+ (key.end_with?('_item') || key.end_with?('_items')) && (!results || !results.kind_of?(Enumerable)) ? [] : results
72
72
  end
73
73
 
74
74
  private
data/lib/zanox/version.rb CHANGED
@@ -23,5 +23,5 @@
23
23
  #++
24
24
 
25
25
  module Zanox
26
- VERSION = '0.4'
26
+ VERSION = '0.5'
27
27
  end
data/lib/zanox.rb CHANGED
@@ -22,6 +22,7 @@
22
22
  # or implied, of Giovanni Capuano.
23
23
  #++
24
24
  require 'httparty'
25
+ require 'ruby-try'
25
26
  require 'openssl'
26
27
 
27
28
  require 'zanox/logger'
@@ -30,4 +31,12 @@ require 'zanox/exceptions/access_denied'
30
31
  require 'zanox/exceptions/invalid_request'
31
32
  require 'zanox/response'
32
33
  require 'zanox/api'
34
+
35
+ require 'zanox/hashable'
36
+ require 'zanox/resources/item'
37
+ require 'zanox/resources/adspace'
38
+ require 'zanox/resources/product'
39
+ require 'zanox/resources/program_application'
40
+ require 'zanox/resources/shop'
41
+
33
42
  require 'zanox/version'
@@ -0,0 +1,100 @@
1
+ require_relative '../spec_helper'
2
+
3
+ describe Zanox::Product do
4
+ before :each do
5
+ Zanox::API::Session.connect_id = '43EEF0445509C7205827'
6
+ end
7
+
8
+ describe '#find' do
9
+ let(:iphone) { Zanox::Product.find('iphone') }
10
+ let(:book) { Zanox::Product.find('book') }
11
+ let(:nike) { Zanox::Product.find('nike') }
12
+
13
+ it 'finds products by keyword' do
14
+ expect(iphone.length).to be >= 8
15
+ expect(book.length).to be >= 8
16
+ expect(nike.length).to be >= 8
17
+ end
18
+
19
+ it 'returns a collection of Products' do
20
+ expect(iphone.last).to be_a(Zanox::Product)
21
+ end
22
+ end
23
+
24
+ describe '#from_shop' do
25
+ let(:products) { Zanox::Product.from_shop(7187) }
26
+
27
+ it 'finds products by keyword' do
28
+ expect(products.length).to be >= 8
29
+ end
30
+
31
+ it 'returns a collection of Products' do
32
+ expect(products.last).to be_a(Zanox::Product)
33
+ end
34
+
35
+ it 'returns only Products that belongs to given shop' do
36
+ expect(products.all? { |product| product.program[:id] == 7187 }).to be_truthy
37
+ end
38
+ end
39
+
40
+ describe '#initialize' do
41
+ let(:data) do
42
+ {
43
+ "@id" => "7f3b1f59484c49b8cbf6b70356b20d6f",
44
+ "name" => "Nike - Jordan - Socken - Weiß",
45
+ "modified" => "2015-04-28T03:06:58+02:00",
46
+ "program" => {"@id" => "7408", "$" => "Asos.com DE"},
47
+ "price" => 17.99,
48
+ "currency" => "EUR",
49
+ "trackingLinks" => { "trackingLink" =>
50
+ [
51
+ {
52
+ "@adspaceId" => "1009338",
53
+ "ppv" => "http://ad.zanox.com/ppv/?22436292C14041752&ULP=[[Nike/Nike-Jordan-Socks/Prod/pgeproduct.aspx?iid=4955490&istCompanyId=030f1ff6-3a15-4425-bccd-ba2bdee3fa38&istItemId=piiiarxql&istBid=t&channelref=affiliate]]&zpar9=[[43EEF0445509C7205827]]",
54
+ "ppc" => "http://ad.zanox.com/ppc/?22436292C14041752&ULP=[[Nike/Nike-Jordan-Socks/Prod/pgeproduct.aspx?iid=4955490&istCompanyId=030f1ff6-3a15-4425-bccd-ba2bdee3fa38&istItemId=piiiarxql&istBid=t&channelref=affiliate]]&zpar9=[[43EEF0445509C7205827]]"
55
+ }
56
+ ]
57
+ },
58
+ "description" => "Nike - Jordan - Socken - Weiß - Farbe:Weiß",
59
+ "descriptionLong" => "ÜBER MICH Hauptmaterial: 58% Baumwolle, 39% Nylon, 3% Elastan SO PFLEGEN SIE MICH Wie auf dem Pflegeetikett angegeben in der Maschine waschen",
60
+ "manufacturer" => "Nike",
61
+ "deliveryTime" => "2 to 4 days",
62
+ "category" => {"@id" => "3230000", "$" => "Bodywear & Lingerie"},
63
+ "image" => {"large" => "http://images.asos-media.com/inv/media/0/9/4/5/4955490/white/image1xxl.jpg"},
64
+ "shippingCosts" => 3,
65
+ "shipping" => 3,
66
+ "merchantCategory" => "Startseite / Herren / Nike / Unterwäsche & Socken",
67
+ "merchantProductId" => 3420722
68
+ }
69
+ end
70
+
71
+ let(:invalid_data) do
72
+ obj = data.dup
73
+ obj['image'] = nil
74
+ obj['price'] = nil
75
+ obj
76
+ end
77
+
78
+ context 'valid input' do
79
+ it 'creates a new instance of Product' do
80
+ product = Zanox::Product.new(data)
81
+ expect(product.price).to be_a(Float)
82
+ expect(product.shipping_costs).to be_a(Float)
83
+ expect(product.delivery_time).to eq 4
84
+ expect(product.description).to eq 'ÜBER MICH Hauptmaterial: 58% Baumwolle, 39% Nylon, 3% Elastan SO PFLEGEN SIE MICH Wie auf dem Pflegeetikett angegeben in der Maschine waschen'
85
+ expect(product.tracking_link).to eq 'http://ad.zanox.com/ppc/?22436292C14041752&ULP=[[Nike/Nike-Jordan-Socks/Prod/pgeproduct.aspx?iid=4955490&istCompanyId=030f1ff6-3a15-4425-bccd-ba2bdee3fa38&istItemId=piiiarxql&istBid=t&channelref=affiliate]]&zpar9=[[43EEF0445509C7205827]]'
86
+ expect(product.images).to be_a(Hash)
87
+ expect(product.images[:small]).to be_nil
88
+ expect(product.images[:large]).to eq 'http://images.asos-media.com/inv/media/0/9/4/5/4955490/white/image1xxl.jpg'
89
+ end
90
+ end
91
+
92
+ context 'invalid input' do
93
+ it 'creates a new instance of Product' do
94
+ product = Zanox::Product.new(invalid_data)
95
+ expect(product.price).to eq 0.0
96
+ expect(product.images.values.compact).to eq []
97
+ end
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,145 @@
1
+ require_relative '../spec_helper'
2
+
3
+ describe Zanox::Shop do
4
+ describe '#find' do
5
+ let(:shops) { Zanox::Shop.find('zalando') }
6
+
7
+ it 'finds shops by keyword' do
8
+ expect(shops.length).to be > 0
9
+ end
10
+
11
+ it 'returns a collection of Shops' do
12
+ expect(shops.last).to be_a(Zanox::Shop)
13
+ end
14
+ end
15
+
16
+ describe '#confirmed' do
17
+ let(:programs) { Zanox::Shop.instance_eval { confirmed } }
18
+
19
+ it 'contains at least one program' do
20
+ expect(programs.length).to be > 0
21
+ end
22
+
23
+ it 'contains only approved program' do
24
+ expect(programs.all? { |program| program.status == 'confirmed' }).to be_truthy
25
+ end
26
+ end
27
+
28
+ ## Well, this test will never work with the default API keys...
29
+ # describe '#confirmed_shops' do
30
+ # let(:shops) { Zanox::Shop.confirmed_shops }
31
+
32
+ # it 'contains at least one shop' do
33
+ # expect(shops.length).to be > 0
34
+ # end
35
+
36
+ # it 'returns a collection of Shops' do
37
+ # expect(shops.last).to be_a(Zanox::Shop)
38
+ # end
39
+
40
+ # it 'returns only confirmed programs' do
41
+ # expect(shops.length).to be > 0
42
+ # end
43
+ # end
44
+
45
+ describe '#initialize' do
46
+ let(:data) do
47
+ {
48
+ "@id" => "2283",
49
+ "name" => "Amazon Buy VIP DE",
50
+ "adrank" => 4.1,
51
+ "applicationRequired" => true,
52
+ "description" => "Amazon BuyVIP – der Shopping Club für Fashion & Lifestyle. Verdienen Sie 6% Provision an unseren exklusiven Verkaufsaktionen mit Preisvorteilen von bis zu 70% auf begehrte Top Marken und Insider Labels sowie 1€ Provision für jedes neue Mitglied!",
53
+ "descriptionLocal" => "<![CDATA[<p> <strong>Sale-Vergütung jetzt auch für Bestandskunden! </strong></p><p> &nbsp;</p><p> <strong>Amazon BuyVIP</strong></p><p> Amazon BuyVIP &ndash; der Shopping Club für Fashion &amp; Lifestyle. Der Zutritt zu Amazon BuyVIP ist limitiert: Nur registrierte Mitglieder erhalten Zugang zu exklusiven und zeitlich begrenzten Verkaufsaktionen mit Preisvorteilen von bis zu 70% gegenüber der UVP des Herstellers. Angeboten werden begehrte Top Marken und Insider Labels&nbsp; aus dem Bereich Fashion und Lifestyle.</p><p> &nbsp;</p><p> <strong>Amazon BuyVIP Produktsortiment</strong></p><p> Das Sortiment umfasst Verkaufsaktionen mit folgenden Produkten:</p><p> &middot;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Damen-, Herren- und Kindermode</p><p> &middot;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Accessories wie Taschen, Schals, Schmuck und Sonnenbrillen</p><p> &middot;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Wellness- &amp; Beauty-Produkte</p><p> &middot;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Edle Wohnaccessoires und Möbel</p><p> &nbsp;</p><p> <strong>Amazon BuyVIP Publisher-Vorteile auf einen Blick</strong></p><p> &middot;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Sale-Vergütung für Neu- &amp; Bestandskunden</p><p> &middot;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Conversionstarke Werbemittel, saisonal gepflegt</p><p> &middot;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Cookie-Laufzeit: 30 Tage</p><p> &middot;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Regelmäßiger Affiliate-Newsletter</p><p> &middot;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Saisonale Pflege aller Werbemittel</p><p> &nbsp;</p><p> <strong>Amazon BuyVIP Kundenvorteile auf einen Blick</strong></p><p> &middot;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Breites Angebot begehrter Top Marken und Insider Labels</p><p> &middot;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Bis zu 70% Preisvorteil gegenüber der UVP des Herstellers</p><p> &middot;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Einfache Anmeldung mit dem Amazon Konto</p><p> &middot;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Kostenlose &amp; unverbindliche Mitgliedschaft</p><p> &middot;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Ein Warenkorb für alle Verkaufsaktionen</p><p> &middot;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Gratisversand ab 100 Euro Bestellwert</p><p> &middot;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Bezahlung erst beim Versand der Bestellung</p><p> &middot;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Versand in 27 Länder</p><p> &middot;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Servicezeiten von 6 bis 24 Uhr</p><p> &middot;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 30 Tage Rückgabegarantie</p><p> &middot;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 10 Euro Gutschein für jeden eingeladenen Freund</p><p> &nbsp;</p><p> <strong>Amazon BuyVIP Provisionsmodell</strong></p><p> &nbsp;</p><p> Sale: 6% auf jeden bestätigten Sale (Neu- &amp; Bestandskunden)</p><p> Lead: 1 EUR &nbsp;für jedes valide neue Mitglied<br /> &nbsp;</p><p> Ab 1.500 Leads pro Monat erhalten Sie 1,50 EUR pro Lead und 6% pro Sale.</p><p> &nbsp;</p><p> <strong>Die Sale-Provisionen gelten auch für Bestandskunden!</strong><br /> <br /> &nbsp;</p><p> &nbsp;</p><p> <strong>Suchmaschinenmarketing</strong></p><p> SEM darf nur nach ausdrücklicher Einwilligung von Amazon BuyVIP angewendet werden.</p><p> &middot;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Die Verwendung der Standard Amazon BuyVIP Display-URL ist ausdrücklich untersagt. Sie benötigen eine eigene Domain.</p><p> &middot;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Wir weisen darauf hin, dass keine geschützten Brand Namen verwendet werden dürfen</p><p> &middot;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Die Buchung von Brand Keywords der direkten Mitbewerber zu Amazon BuyVIP ist ausdrücklich untersagt</p><p> &middot;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Die Buchung von BuyVIP Brand Keywords (auch Falschschreibweisen) ist ausdrücklich untersagt</p><p> Zuwiderhandlungen führen zum Ausschluss aus dem Amazon BuyVIP-Partnerprogramm!</p><p> &nbsp;</p><p> <strong>Was muss ich noch beachten, wenn ich Amazon BuyVIP bewerbe? </strong></p><p> &middot;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Jegliche Veränderungen der Verlinkungen sind nicht gestattet. Dies betrifft vor allem das Anhängen der Zanox-ID, Download und Einfügen von Werbemitteln auf Drittseiten, usw.</p><p> &middot;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Das Kommunizieren von Endpreisen aus dem Amazon BuyVIP Shop ist ausdrücklich untersagt.</p><p> &middot;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Es ist nicht gestattet, die Freundschaftswerbung von Amazon BuyVIP zu bewerben.</p><p> &middot;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; Weiterhin nicht gestattet sind: Paidmails, Keyword Advertising, Forced Clicks, Meta-Netzwerke, Cashback&nbsp;</p><p> &middot;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Es ist nicht gestattet, gleichzeitig dieselbe Platzierung über das Amazon PartnerNet&nbsp; zu verlinken.</p><p> Zuwiderhandlungen führen zum Ausschluss aus dem Amazon BuyVIP-Partnerprogramm!</p><p> &nbsp;</p><p> <strong>Kontakt</strong></p><p> Für Fragen und Wünsche stehen wir Ihnen gerne zur Verfügung. Wenden Sie sich einfach an Ihren persönlichen Ansprechpartner:</p><p> &nbsp;</p><p> <strong>Adreana Starke</strong></p><p> E-Mail: adreana@amazon.com<br /> &nbsp;</p>]]>",
54
+ "products" => 0,
55
+ "vertical" => {
56
+ "@id" => "78",
57
+ "$" => "Retail&Shopping"
58
+ },
59
+ "regions" => [
60
+ {
61
+ "region" => "DE"
62
+ }
63
+ ],
64
+ "categories" => [
65
+ {
66
+ "category" => [
67
+ {
68
+ "@id" => "11",
69
+ "$" => "Internet services"
70
+ },
71
+ {
72
+ "@id" => "33",
73
+ "$" => "Clothing & Accessories"
74
+ },
75
+ {
76
+ "@id" => "34",
77
+ "$" => "Shopping & Mail Order Shops"
78
+ }
79
+ ]
80
+ }
81
+ ],
82
+ "startDate" => "2006-08-01T02:00:00+02:00",
83
+ "url" => "http://de.buyvip.com",
84
+ "image" => "http://ui.zanox.com/images/programs/2283/2283_lgo_buy_vip.jpg",
85
+ "currency" => "EUR",
86
+ "status" => "active",
87
+ "terms" => "<p> <strong>Was muss ich noch beachten, wenn ich Amazon BuyVIP bewerbe? </strong></p><p>  </p><p> · Jegliche Veränderungen der Verlinkungen sind nicht gestattet. Dies betrifft vor allem das Anhängen der Zanox-ID, Download und Einfügen von Werbemitteln auf Drittseiten, usw.</p><p> · Das Kommunizieren von Endpreisen aus dem Amazon BuyVIP Shop ist ausdrücklich untersagt.</p><p> · Weiterhin nicht gestattet sind: Paidmails, Keyword Advertising, Forced Clicks, Meta-Netzwerke, Cashback&nbsp;</p><p> · Es ist nicht gestattet, gleichzeitig dieselbe Platzierung über das Amazon PartnerNet&nbsp; zu verlinken.</p><p> · Es ist nicht gestattet, die Freundschaftswerbung von Amazon BuyVIP zu bewerben.</p><p> . SEM: eingeschränkt, siehe Regelungen in Branding</p><p>  </p><p> Zuwiderhandlungen führen zum Ausschluss aus dem Amazon BuyVIP-Partnerprogramm!</p>",
88
+ "policies" => {
89
+ "policy" => [
90
+ {
91
+ "@id" => "102",
92
+ "$" => "Popups/Popunders allowed"
93
+ },
94
+ {
95
+ "@id" => "106",
96
+ "$" => "Cashback/Loyalty allowed"
97
+ },
98
+ {
99
+ "@id" => "105",
100
+ "$" => "Co-Registration allowed"
101
+ },
102
+ {
103
+ "@id" => "103",
104
+ "$" => "Layers allowed"
105
+ },
106
+ {
107
+ "@id" => "107",
108
+ "$" => "Exclusive zanox advertiser"
109
+ }
110
+ ]
111
+ },
112
+ "returnTimeLeads" => 2592000,
113
+ "returnTimeSales" => 2592000
114
+ }
115
+ end
116
+
117
+ let(:invalid_data) do
118
+ obj = data.dup
119
+ obj['regions'] = nil
120
+ obj['policies'] = nil
121
+ obj
122
+ end
123
+
124
+ context 'valid input' do
125
+ it 'creates a new instance of Shop' do
126
+ shop = Zanox::Shop.new(data)
127
+ expect(shop.rank).to eq 4.1
128
+ expect(shop.products_count).to eq 0
129
+ expect(shop.regions).to eq ['DE']
130
+ expect(shop.description).to eq '<p> <strong>Sale-Vergütung jetzt auch für Bestandskunden! </strong></p><p> &nbsp;</p><p> <strong>Amazon BuyVIP</strong></p><p> Amazon BuyVIP &ndash; der Shopping Club für Fashion &amp; Lifestyle. Der Zutritt zu Amazon BuyVIP ist limitiert: Nur registrierte Mitglieder erhalten Zugang zu exklusiven und zeitlich begrenzten Verkaufsaktionen mit Preisvorteilen von bis zu 70% gegenüber der UVP des Herstellers. Angeboten werden begehrte Top Marken und Insider Labels&nbsp; aus dem Bereich Fashion und Lifestyle.</p><p> &nbsp;</p><p> <strong>Amazon BuyVIP Produktsortiment</strong></p><p> Das Sortiment umfasst Verkaufsaktionen mit folgenden Produkten:</p><p> &middot;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Damen-, Herren- und Kindermode</p><p> &middot;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Accessories wie Taschen, Schals, Schmuck und Sonnenbrillen</p><p> &middot;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Wellness- &amp; Beauty-Produkte</p><p> &middot;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Edle Wohnaccessoires und Möbel</p><p> &nbsp;</p><p> <strong>Amazon BuyVIP Publisher-Vorteile auf einen Blick</strong></p><p> &middot;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Sale-Vergütung für Neu- &amp; Bestandskunden</p><p> &middot;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Conversionstarke Werbemittel, saisonal gepflegt</p><p> &middot;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Cookie-Laufzeit: 30 Tage</p><p> &middot;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Regelmäßiger Affiliate-Newsletter</p><p> &middot;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Saisonale Pflege aller Werbemittel</p><p> &nbsp;</p><p> <strong>Amazon BuyVIP Kundenvorteile auf einen Blick</strong></p><p> &middot;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Breites Angebot begehrter Top Marken und Insider Labels</p><p> &middot;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Bis zu 70% Preisvorteil gegenüber der UVP des Herstellers</p><p> &middot;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Einfache Anmeldung mit dem Amazon Konto</p><p> &middot;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Kostenlose &amp; unverbindliche Mitgliedschaft</p><p> &middot;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Ein Warenkorb für alle Verkaufsaktionen</p><p> &middot;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Gratisversand ab 100 Euro Bestellwert</p><p> &middot;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Bezahlung erst beim Versand der Bestellung</p><p> &middot;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Versand in 27 Länder</p><p> &middot;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Servicezeiten von 6 bis 24 Uhr</p><p> &middot;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 30 Tage Rückgabegarantie</p><p> &middot;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 10 Euro Gutschein für jeden eingeladenen Freund</p><p> &nbsp;</p><p> <strong>Amazon BuyVIP Provisionsmodell</strong></p><p> &nbsp;</p><p> Sale: 6% auf jeden bestätigten Sale (Neu- &amp; Bestandskunden)</p><p> Lead: 1 EUR &nbsp;für jedes valide neue Mitglied<br /> &nbsp;</p><p> Ab 1.500 Leads pro Monat erhalten Sie 1,50 EUR pro Lead und 6% pro Sale.</p><p> &nbsp;</p><p> <strong>Die Sale-Provisionen gelten auch für Bestandskunden!</strong><br /> <br /> &nbsp;</p><p> &nbsp;</p><p> <strong>Suchmaschinenmarketing</strong></p><p> SEM darf nur nach ausdrücklicher Einwilligung von Amazon BuyVIP angewendet werden.</p><p> &middot;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Die Verwendung der Standard Amazon BuyVIP Display-URL ist ausdrücklich untersagt. Sie benötigen eine eigene Domain.</p><p> &middot;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Wir weisen darauf hin, dass keine geschützten Brand Namen verwendet werden dürfen</p><p> &middot;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Die Buchung von Brand Keywords der direkten Mitbewerber zu Amazon BuyVIP ist ausdrücklich untersagt</p><p> &middot;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Die Buchung von BuyVIP Brand Keywords (auch Falschschreibweisen) ist ausdrücklich untersagt</p><p> Zuwiderhandlungen führen zum Ausschluss aus dem Amazon BuyVIP-Partnerprogramm!</p><p> &nbsp;</p><p> <strong>Was muss ich noch beachten, wenn ich Amazon BuyVIP bewerbe? </strong></p><p> &middot;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Jegliche Veränderungen der Verlinkungen sind nicht gestattet. Dies betrifft vor allem das Anhängen der Zanox-ID, Download und Einfügen von Werbemitteln auf Drittseiten, usw.</p><p> &middot;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Das Kommunizieren von Endpreisen aus dem Amazon BuyVIP Shop ist ausdrücklich untersagt.</p><p> &middot;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Es ist nicht gestattet, die Freundschaftswerbung von Amazon BuyVIP zu bewerben.</p><p> &middot;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; Weiterhin nicht gestattet sind: Paidmails, Keyword Advertising, Forced Clicks, Meta-Netzwerke, Cashback&nbsp;</p><p> &middot;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Es ist nicht gestattet, gleichzeitig dieselbe Platzierung über das Amazon PartnerNet&nbsp; zu verlinken.</p><p> Zuwiderhandlungen führen zum Ausschluss aus dem Amazon BuyVIP-Partnerprogramm!</p><p> &nbsp;</p><p> <strong>Kontakt</strong></p><p> Für Fragen und Wünsche stehen wir Ihnen gerne zur Verfügung. Wenden Sie sich einfach an Ihren persönlichen Ansprechpartner:</p><p> &nbsp;</p><p> <strong>Adreana Starke</strong></p><p> E-Mail: adreana@amazon.com<br /> &nbsp;</p>'
131
+ expect(shop.excerpt).to eq 'Amazon BuyVIP – der Shopping Club für Fashion & Lifestyle. Verdienen Sie 6% Provision an unseren exklusiven Verkaufsaktionen mit Preisvorteilen von bis zu 70% auf begehrte Top Marken und Insider Labels sowie 1€ Provision für jedes neue Mitglied!'
132
+ expect(shop.terms).to be_a(String)
133
+ expect(shop.policies).to be_a(Array)
134
+ end
135
+ end
136
+
137
+ context 'invalid input' do
138
+ it 'creates a new instance of Shop' do
139
+ shop = Zanox::Shop.new(invalid_data)
140
+ expect(shop.regions).to eq []
141
+ expect(shop.policies).to eq []
142
+ end
143
+ end
144
+ end
145
+ end
data/zanoxrb.gemspec CHANGED
@@ -15,6 +15,7 @@ Gem::Specification.new { |s|
15
15
  s.require_paths = ['lib']
16
16
 
17
17
  s.add_dependency 'httparty', '~> 0.13'
18
+ s.add_dependency 'ruby-try', '~> 1.1'
18
19
  s.add_development_dependency 'rake', '~> 10.4'
19
20
  s.add_development_dependency 'rspec', '~> 3.3'
20
21
  s.add_development_dependency 'rspec-collection_matchers', '~> 1.1'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: zanoxrb
3
3
  version: !ruby/object:Gem::Version
4
- version: '0.4'
4
+ version: '0.5'
5
5
  platform: ruby
6
6
  authors:
7
7
  - Giovanni Capuano
@@ -24,6 +24,20 @@ dependencies:
24
24
  - !ruby/object:Gem::Version
25
25
  version: '0.13'
26
26
  type: :runtime
27
+ - !ruby/object:Gem::Dependency
28
+ version_requirements: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - "~>"
31
+ - !ruby/object:Gem::Version
32
+ version: '1.1'
33
+ name: ruby-try
34
+ prerelease: false
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '1.1'
40
+ type: :runtime
27
41
  - !ruby/object:Gem::Dependency
28
42
  version_requirements: !ruby/object:Gem::Requirement
29
43
  requirements:
@@ -83,7 +97,13 @@ files:
83
97
  - lib/zanox/api.rb
84
98
  - lib/zanox/exceptions/access_denied.rb
85
99
  - lib/zanox/exceptions/invalid_request.rb
100
+ - lib/zanox/hashable.rb
86
101
  - lib/zanox/logger.rb
102
+ - lib/zanox/resources/adspace.rb
103
+ - lib/zanox/resources/item.rb
104
+ - lib/zanox/resources/product.rb
105
+ - lib/zanox/resources/program_application.rb
106
+ - lib/zanox/resources/shop.rb
87
107
  - lib/zanox/response.rb
88
108
  - lib/zanox/session.rb
89
109
  - lib/zanox/version.rb
@@ -91,6 +111,8 @@ files:
91
111
  - specs/profiles_spec.rb
92
112
  - specs/program_application_spec.rb
93
113
  - specs/programs_spec.rb
114
+ - specs/resources/product_spec.rb
115
+ - specs/resources/shop_spec.rb
94
116
  - specs/response_spec.rb
95
117
  - specs/spec_helper.rb
96
118
  - zanoxrb.gemspec