fassbinder 0.0.1 → 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/fassbinder.gemspec +1 -2
- data/lib/fassbinder.rb +2 -2
- data/lib/fassbinder/item.rb +4 -0
- data/lib/fassbinder/request.rb +1 -1
- data/lib/fassbinder/response_wrapper.rb +68 -0
- data/lib/fassbinder/version.rb +1 -1
- data/spec/fassbinder/request_spec.rb +1 -1
- data/spec/fassbinder/response_wrapper_spec.rb +49 -0
- data/spec/spec_helper.rb +0 -1
- metadata +14 -50
- data/lib/fassbinder/algorithm.rb +0 -25
- data/lib/fassbinder/book.rb +0 -29
- data/lib/fassbinder/condition.rb +0 -29
- data/lib/fassbinder/description.rb +0 -59
- data/lib/fassbinder/offer.rb +0 -38
- data/lib/fassbinder/seller.rb +0 -29
- data/lib/fassbinder/struct.rb +0 -15
- data/spec/fabricators/condition_fabricator.rb +0 -7
- data/spec/fabricators/offer_fabricator.rb +0 -8
- data/spec/fabricators/seller_fabricator.rb +0 -15
- data/spec/fassbinder/algorithm_spec.rb +0 -49
- data/spec/fassbinder/book_spec.rb +0 -50
- data/spec/fassbinder/condition_spec.rb +0 -31
- data/spec/fassbinder/description_spec.rb +0 -55
- data/spec/fassbinder/offer_spec.rb +0 -133
- data/spec/fassbinder/seller_spec.rb +0 -71
- data/spec/fassbinder/struct_spec.rb +0 -28
- data/spec/support/faker.rb +0 -19
data/fassbinder.gemspec
CHANGED
@@ -19,9 +19,8 @@ Gem::Specification.new do |s|
|
|
19
19
|
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
20
20
|
s.require_paths = ['lib']
|
21
21
|
|
22
|
-
s.add_dependency('kosher', '~> 0.2.
|
22
|
+
s.add_dependency('kosher', '~> 0.2.7')
|
23
23
|
s.add_dependency('sucker', '~> 1.3.1')
|
24
|
-
s.add_development_dependency('fabrication', '~> 0.9.5')
|
25
24
|
s.add_development_dependency('rspec', '~> 2.5.0')
|
26
25
|
s.add_development_dependency('ruby-debug19', '~> 0.11.6')
|
27
26
|
s.add_development_dependency('vcr', '~> 1.7.0')
|
data/lib/fassbinder.rb
CHANGED
data/lib/fassbinder/request.rb
CHANGED
@@ -0,0 +1,68 @@
|
|
1
|
+
module Fassbinder
|
2
|
+
class ResponseWrapper
|
3
|
+
def initialize(response, locale)
|
4
|
+
raise InvalidResponseError unless response.valid?
|
5
|
+
|
6
|
+
@response = response
|
7
|
+
@locale = locale
|
8
|
+
end
|
9
|
+
|
10
|
+
# And I don't believe that melodramatic feelings are laughable -
|
11
|
+
# they should be taken absolutely seriously.
|
12
|
+
def items
|
13
|
+
@response.map('Item') do |doc|
|
14
|
+
Item.new(
|
15
|
+
doc['ASIN'],
|
16
|
+
doc['Offers']['TotalOffers'].to_i,
|
17
|
+
doc['SalesRank'].to_i,
|
18
|
+
[doc['Offers']['Offer']].flatten.compact.map do |doc|
|
19
|
+
if doc['OfferListing']['Price']['CurrencyCode'] == 'JPY'
|
20
|
+
doc['OfferListing']['Price']['Amount'] = doc['OfferListing']['Price']['Amount'].to_i * 100
|
21
|
+
end
|
22
|
+
|
23
|
+
Kosher::Offer.new(
|
24
|
+
doc['OfferListing']['OfferListingId'],
|
25
|
+
Kosher::Item.new(doc['OfferListing']['Price']['Amount'].to_i,
|
26
|
+
doc['OfferListing']['Price']['CurrencyCode'],
|
27
|
+
doc['OfferListing']['Quantity'].to_i,
|
28
|
+
Kosher::Condition.new(case doc['OfferAttributes']['SubCondition']
|
29
|
+
when 'new' then 1
|
30
|
+
when 'mint' then 2
|
31
|
+
when 'verygood' then 3
|
32
|
+
when 'good' then 4
|
33
|
+
when 'acceptable' then 5
|
34
|
+
else 6
|
35
|
+
end),
|
36
|
+
Kosher::Description.new(doc['OfferAttributes']['ConditionNote'].to_s)),
|
37
|
+
Kosher::Seller.new(doc['Merchant']['MerchantId'],
|
38
|
+
doc['Merchant']['Name'],
|
39
|
+
doc['Merchant']['AverageFeedbackRating'].to_f,
|
40
|
+
Kosher::Location.new((doc['Merchant']['Location']['CountryCode'] rescue nil), (doc['Merchant']['Location']['StateCode'] rescue nil))),
|
41
|
+
Kosher::Shipping.new(doc['OfferListing']['IsEligibleForSuperSaverShipping'] == '1' ?
|
42
|
+
0 : (case @locale
|
43
|
+
when :us then 399
|
44
|
+
when :uk then 280
|
45
|
+
when :de then 299
|
46
|
+
when :ca then 649
|
47
|
+
when :fr then 300
|
48
|
+
when :jp then 25000
|
49
|
+
end),
|
50
|
+
doc['OfferListing']['Price']['CurrencyCode'],
|
51
|
+
Kosher::Availability.new(doc['OfferListing']['AvailabilityAttributes']['MaximumHours'].to_i))
|
52
|
+
)
|
53
|
+
end
|
54
|
+
)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def errors
|
59
|
+
@response.errors.map do |error|
|
60
|
+
error['Message'].scan(/[0-9A-Z]{10}/).first rescue nil
|
61
|
+
end.compact
|
62
|
+
end
|
63
|
+
|
64
|
+
def response
|
65
|
+
@response
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
data/lib/fassbinder/version.rb
CHANGED
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Fassbinder
|
4
|
+
describe ResponseWrapper do
|
5
|
+
describe ".new" do
|
6
|
+
it "raises an error if response is not valid" do
|
7
|
+
response = mock('Response')
|
8
|
+
response.stub!(:valid?).and_return(false)
|
9
|
+
|
10
|
+
expect do
|
11
|
+
ResponseWrapper.new(response, :us)
|
12
|
+
end.to raise_error InvalidResponseError
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
describe "#books" do
|
17
|
+
use_vcr_cassette 'batch-request'
|
18
|
+
|
19
|
+
let(:asins) do
|
20
|
+
# The last ASIN does not exist.
|
21
|
+
%w{
|
22
|
+
0816614024 0143105825 0485113600 0816616779 0942299078
|
23
|
+
0816614008 144006654X 0486400360 0486417670 087220474X
|
24
|
+
0486454398 0268018359 1604246014 184467598X 0312427182
|
25
|
+
1844674282 0745640974 0745646441 0826489540 2081232191 }
|
26
|
+
end
|
27
|
+
|
28
|
+
let(:response_wrapper) do
|
29
|
+
request = Request.new(credentials)
|
30
|
+
request.locale = :us
|
31
|
+
request.batchify(asins)
|
32
|
+
request.get
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should return found books" do
|
36
|
+
debugger
|
37
|
+
response_wrapper.items.count.should eql 19
|
38
|
+
response_wrapper.items.first.should be_a Book
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
describe "#errors" do
|
43
|
+
it "should return ASINs that are not found" do
|
44
|
+
algorithm.errors.count.should eql 1
|
45
|
+
algorithm.errors.first.should eql '2081232191'
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
name: fassbinder
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease:
|
5
|
-
version: 0.0.
|
5
|
+
version: 0.0.2
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Paper Cavalier
|
@@ -21,7 +21,7 @@ dependencies:
|
|
21
21
|
requirements:
|
22
22
|
- - ~>
|
23
23
|
- !ruby/object:Gem::Version
|
24
|
-
version: 0.2.
|
24
|
+
version: 0.2.7
|
25
25
|
type: :runtime
|
26
26
|
version_requirements: *id001
|
27
27
|
- !ruby/object:Gem::Dependency
|
@@ -35,61 +35,50 @@ dependencies:
|
|
35
35
|
version: 1.3.1
|
36
36
|
type: :runtime
|
37
37
|
version_requirements: *id002
|
38
|
-
- !ruby/object:Gem::Dependency
|
39
|
-
name: fabrication
|
40
|
-
prerelease: false
|
41
|
-
requirement: &id003 !ruby/object:Gem::Requirement
|
42
|
-
none: false
|
43
|
-
requirements:
|
44
|
-
- - ~>
|
45
|
-
- !ruby/object:Gem::Version
|
46
|
-
version: 0.9.5
|
47
|
-
type: :development
|
48
|
-
version_requirements: *id003
|
49
38
|
- !ruby/object:Gem::Dependency
|
50
39
|
name: rspec
|
51
40
|
prerelease: false
|
52
|
-
requirement: &
|
41
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
53
42
|
none: false
|
54
43
|
requirements:
|
55
44
|
- - ~>
|
56
45
|
- !ruby/object:Gem::Version
|
57
46
|
version: 2.5.0
|
58
47
|
type: :development
|
59
|
-
version_requirements: *
|
48
|
+
version_requirements: *id003
|
60
49
|
- !ruby/object:Gem::Dependency
|
61
50
|
name: ruby-debug19
|
62
51
|
prerelease: false
|
63
|
-
requirement: &
|
52
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
64
53
|
none: false
|
65
54
|
requirements:
|
66
55
|
- - ~>
|
67
56
|
- !ruby/object:Gem::Version
|
68
57
|
version: 0.11.6
|
69
58
|
type: :development
|
70
|
-
version_requirements: *
|
59
|
+
version_requirements: *id004
|
71
60
|
- !ruby/object:Gem::Dependency
|
72
61
|
name: vcr
|
73
62
|
prerelease: false
|
74
|
-
requirement: &
|
63
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
75
64
|
none: false
|
76
65
|
requirements:
|
77
66
|
- - ~>
|
78
67
|
- !ruby/object:Gem::Version
|
79
68
|
version: 1.7.0
|
80
69
|
type: :development
|
81
|
-
version_requirements: *
|
70
|
+
version_requirements: *id005
|
82
71
|
- !ruby/object:Gem::Dependency
|
83
72
|
name: webmock
|
84
73
|
prerelease: false
|
85
|
-
requirement: &
|
74
|
+
requirement: &id006 !ruby/object:Gem::Requirement
|
86
75
|
none: false
|
87
76
|
requirements:
|
88
77
|
- - ~>
|
89
78
|
- !ruby/object:Gem::Version
|
90
79
|
version: 1.6.2
|
91
80
|
type: :development
|
92
|
-
version_requirements: *
|
81
|
+
version_requirements: *id006
|
93
82
|
description: Fassbinder wraps Amazon in a loving embrace.
|
94
83
|
email: code@papercavalier.com
|
95
84
|
executables: []
|
@@ -106,30 +95,15 @@ files:
|
|
106
95
|
- Rakefile
|
107
96
|
- fassbinder.gemspec
|
108
97
|
- lib/fassbinder.rb
|
109
|
-
- lib/fassbinder/algorithm.rb
|
110
|
-
- lib/fassbinder/book.rb
|
111
|
-
- lib/fassbinder/condition.rb
|
112
|
-
- lib/fassbinder/description.rb
|
113
98
|
- lib/fassbinder/errors.rb
|
114
|
-
- lib/fassbinder/
|
99
|
+
- lib/fassbinder/item.rb
|
115
100
|
- lib/fassbinder/request.rb
|
116
|
-
- lib/fassbinder/
|
117
|
-
- lib/fassbinder/struct.rb
|
101
|
+
- lib/fassbinder/response_wrapper.rb
|
118
102
|
- lib/fassbinder/version.rb
|
119
|
-
- spec/fabricators/condition_fabricator.rb
|
120
|
-
- spec/fabricators/offer_fabricator.rb
|
121
|
-
- spec/fabricators/seller_fabricator.rb
|
122
|
-
- spec/fassbinder/algorithm_spec.rb
|
123
|
-
- spec/fassbinder/book_spec.rb
|
124
|
-
- spec/fassbinder/condition_spec.rb
|
125
|
-
- spec/fassbinder/description_spec.rb
|
126
|
-
- spec/fassbinder/offer_spec.rb
|
127
103
|
- spec/fassbinder/request_spec.rb
|
128
|
-
- spec/fassbinder/
|
129
|
-
- spec/fassbinder/struct_spec.rb
|
104
|
+
- spec/fassbinder/response_wrapper_spec.rb
|
130
105
|
- spec/spec_helper.rb
|
131
106
|
- spec/support/credentials.rb
|
132
|
-
- spec/support/faker.rb
|
133
107
|
- spec/support/vcr.rb
|
134
108
|
has_rdoc: true
|
135
109
|
homepage: https://rubygems.org/gems/fassbinder
|
@@ -160,18 +134,8 @@ signing_key:
|
|
160
134
|
specification_version: 3
|
161
135
|
summary: Wraps Amazon in a loving embrace.
|
162
136
|
test_files:
|
163
|
-
- spec/fabricators/condition_fabricator.rb
|
164
|
-
- spec/fabricators/offer_fabricator.rb
|
165
|
-
- spec/fabricators/seller_fabricator.rb
|
166
|
-
- spec/fassbinder/algorithm_spec.rb
|
167
|
-
- spec/fassbinder/book_spec.rb
|
168
|
-
- spec/fassbinder/condition_spec.rb
|
169
|
-
- spec/fassbinder/description_spec.rb
|
170
|
-
- spec/fassbinder/offer_spec.rb
|
171
137
|
- spec/fassbinder/request_spec.rb
|
172
|
-
- spec/fassbinder/
|
173
|
-
- spec/fassbinder/struct_spec.rb
|
138
|
+
- spec/fassbinder/response_wrapper_spec.rb
|
174
139
|
- spec/spec_helper.rb
|
175
140
|
- spec/support/credentials.rb
|
176
|
-
- spec/support/faker.rb
|
177
141
|
- spec/support/vcr.rb
|
data/lib/fassbinder/algorithm.rb
DELETED
@@ -1,25 +0,0 @@
|
|
1
|
-
module Fassbinder
|
2
|
-
class Algorithm
|
3
|
-
def initialize(response)
|
4
|
-
raise InvalidResponseError unless response.valid?
|
5
|
-
|
6
|
-
@response = response
|
7
|
-
end
|
8
|
-
|
9
|
-
def books
|
10
|
-
@response.map('Item') do |item|
|
11
|
-
Book.build(item)
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
|
-
def errors
|
16
|
-
@response.errors.map do |error|
|
17
|
-
error['Message'].scan(/[0-9A-Z]{10}/).first rescue nil
|
18
|
-
end.compact
|
19
|
-
end
|
20
|
-
|
21
|
-
def response
|
22
|
-
@response
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
data/lib/fassbinder/book.rb
DELETED
@@ -1,29 +0,0 @@
|
|
1
|
-
module Kosher
|
2
|
-
class Book < Struct.new(:asin, :offers, :offers_count, :sales_rank)
|
3
|
-
|
4
|
-
class << self
|
5
|
-
def build(doc)
|
6
|
-
asin = doc['ASIN']
|
7
|
-
sales_rank = doc['SalesRank'].to_i
|
8
|
-
offers_count = doc['Offers']['TotalOffers'].to_i
|
9
|
-
offers = build_offers(doc['Offers']['Offer'])
|
10
|
-
|
11
|
-
new(asin, offers, offers_count, sales_rank)
|
12
|
-
end
|
13
|
-
|
14
|
-
private
|
15
|
-
|
16
|
-
def build_offers(offers)
|
17
|
-
[offers].flatten.compact.map do |offer|
|
18
|
-
|
19
|
-
# Senify Yen because Ruby Money says so
|
20
|
-
if offer['OfferListing']['Price']['CurrencyCode'] == 'JPY'
|
21
|
-
offer['OfferListing']['Price']['Amount'] = offer['OfferListing']['Price']['Amount'].to_i * 100
|
22
|
-
end
|
23
|
-
|
24
|
-
Offer.build(offer)
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|
data/lib/fassbinder/condition.rb
DELETED
@@ -1,29 +0,0 @@
|
|
1
|
-
module Kosher
|
2
|
-
class Condition < Struct.new(:grade)
|
3
|
-
|
4
|
-
alias_method :to_i, :grade
|
5
|
-
|
6
|
-
CONDITIONS = {
|
7
|
-
'new' => 1,
|
8
|
-
'mint' => 2,
|
9
|
-
'verygood' => 3,
|
10
|
-
'good' => 4,
|
11
|
-
'acceptable' => 5 }
|
12
|
-
|
13
|
-
def initialize(string = '')
|
14
|
-
self.grade = CONDITIONS[string] || 6
|
15
|
-
end
|
16
|
-
|
17
|
-
def kosher?
|
18
|
-
grade <= 4
|
19
|
-
end
|
20
|
-
|
21
|
-
def new?
|
22
|
-
grade == 1
|
23
|
-
end
|
24
|
-
|
25
|
-
def used?
|
26
|
-
!new?
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|
@@ -1,59 +0,0 @@
|
|
1
|
-
module Kosher
|
2
|
-
class Description < String
|
3
|
-
DAMAGED = "\\b(?:missing|torn|broken|split|discard|withdrawn|rent|stain|school|damaged|water)"
|
4
|
-
EXLIB = "(?:e?x|discarded|retired|former|has|have)[\\s._-]*lib"
|
5
|
-
MARKED = "(highlight|hilit|underlin)"
|
6
|
-
MISSING_VOL = "(vols?|volume) only"
|
7
|
-
REVIEW_COPY = "\\b(?:uncorrected|advanced?\\sreview|arc)\\b"
|
8
|
-
|
9
|
-
def kosher?
|
10
|
-
!(present? && bad?)
|
11
|
-
end
|
12
|
-
|
13
|
-
private
|
14
|
-
|
15
|
-
def bad?
|
16
|
-
damaged? ||
|
17
|
-
ex_library? ||
|
18
|
-
marked? ||
|
19
|
-
missing_volume? ||
|
20
|
-
review_copy?
|
21
|
-
end
|
22
|
-
|
23
|
-
def damaged?
|
24
|
-
matches(DAMAGED)
|
25
|
-
end
|
26
|
-
|
27
|
-
def does_not_match(value)
|
28
|
-
!match(Regexp.new(value, true))
|
29
|
-
end
|
30
|
-
|
31
|
-
def ex_library?
|
32
|
-
matches(EXLIB) && does_not_match(negation_of(EXLIB))
|
33
|
-
end
|
34
|
-
|
35
|
-
def marked?
|
36
|
-
matches(MARKED) && does_not_match(negation_of(MARKED))
|
37
|
-
end
|
38
|
-
|
39
|
-
def matches(value)
|
40
|
-
!does_not_match(value)
|
41
|
-
end
|
42
|
-
|
43
|
-
def missing_volume?
|
44
|
-
matches(MISSING_VOL)
|
45
|
-
end
|
46
|
-
|
47
|
-
def negation_of(value)
|
48
|
-
"(?:no|not an?)\\s+#{value}"
|
49
|
-
end
|
50
|
-
|
51
|
-
def present?
|
52
|
-
self != ''
|
53
|
-
end
|
54
|
-
|
55
|
-
def review_copy?
|
56
|
-
matches(REVIEW_COPY)
|
57
|
-
end
|
58
|
-
end
|
59
|
-
end
|
data/lib/fassbinder/offer.rb
DELETED
@@ -1,38 +0,0 @@
|
|
1
|
-
module Kosher
|
2
|
-
class Offer < Struct.new(
|
3
|
-
:seller,
|
4
|
-
:condition,
|
5
|
-
:description,
|
6
|
-
:ships_in,
|
7
|
-
:ships_free,
|
8
|
-
:cents,
|
9
|
-
:exchange_id,
|
10
|
-
:listing_id)
|
11
|
-
|
12
|
-
def self.build(doc)
|
13
|
-
offer = new
|
14
|
-
offer.seller = Seller.build(doc['Merchant'])
|
15
|
-
|
16
|
-
attributes = doc['OfferAttributes']
|
17
|
-
offer.condition = Condition.new(attributes['SubCondition'])
|
18
|
-
offer.description = Description.new(attributes['ConditionNote'].to_s)
|
19
|
-
|
20
|
-
listing = doc['OfferListing']
|
21
|
-
offer.ships_in = listing['AvailabilityAttributes']['MaximumHours'].to_i
|
22
|
-
offer.ships_free = listing['IsEligibleForSuperSaverShipping'] == '1'
|
23
|
-
offer.cents = listing['Price']['Amount'].to_i
|
24
|
-
offer.exchange_id = listing['ExchangeId']
|
25
|
-
offer.listing_id = listing['OfferListingId']
|
26
|
-
|
27
|
-
offer
|
28
|
-
end
|
29
|
-
|
30
|
-
def kosher?
|
31
|
-
condition.kosher? && seller.kosher? && description.kosher? && ships_now?
|
32
|
-
end
|
33
|
-
|
34
|
-
def ships_now?
|
35
|
-
ships_in.to_i <= 48
|
36
|
-
end
|
37
|
-
end
|
38
|
-
end
|
data/lib/fassbinder/seller.rb
DELETED
@@ -1,29 +0,0 @@
|
|
1
|
-
module Kosher
|
2
|
-
class Seller < Struct.new(:merchant_id, :name, :average_rating)
|
3
|
-
class << self
|
4
|
-
attr_accessor :blacklist
|
5
|
-
|
6
|
-
def build(doc)
|
7
|
-
merchant_id = doc['MerchantId']
|
8
|
-
name = doc['Name']
|
9
|
-
average_rating = doc['AverageFeedbackRating'].to_f
|
10
|
-
|
11
|
-
new(merchant_id, name, average_rating)
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
|
-
def blacklist
|
16
|
-
self.class.blacklist
|
17
|
-
end
|
18
|
-
|
19
|
-
def blacklisted?
|
20
|
-
blacklist.include?(merchant_id) rescue false
|
21
|
-
end
|
22
|
-
|
23
|
-
def kosher?
|
24
|
-
return false if blacklisted?
|
25
|
-
|
26
|
-
average_rating == 0.0 || average_rating > 4.7
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|
data/lib/fassbinder/struct.rb
DELETED
@@ -1,15 +0,0 @@
|
|
1
|
-
Fabricator(:seller, :class_name => 'kosher/seller') do
|
2
|
-
merchant_id Faker::Amazon.merchant_id
|
3
|
-
end
|
4
|
-
|
5
|
-
Fabricator(:new_seller, :from => :seller) do
|
6
|
-
average_rating 0.0
|
7
|
-
end
|
8
|
-
|
9
|
-
Fabricator(:good_seller, :from => :seller) do
|
10
|
-
average_rating 5.0
|
11
|
-
end
|
12
|
-
|
13
|
-
Fabricator(:bad_seller, :from => :seller) do
|
14
|
-
average_rating 4.5
|
15
|
-
end
|
@@ -1,49 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
module Kosher
|
4
|
-
describe Algorithm do
|
5
|
-
use_vcr_cassette 'batch-request'
|
6
|
-
|
7
|
-
let(:asins) do
|
8
|
-
|
9
|
-
# The last ASIN does not exist.
|
10
|
-
%w{
|
11
|
-
0816614024 0143105825 0485113600 0816616779 0942299078
|
12
|
-
0816614008 144006654X 0486400360 0486417670 087220474X
|
13
|
-
0486454398 0268018359 1604246014 184467598X 0312427182
|
14
|
-
1844674282 0745640974 0745646441 0826489540 2081232191 }
|
15
|
-
end
|
16
|
-
|
17
|
-
let(:algorithm) do
|
18
|
-
request = Request.new(credentials)
|
19
|
-
request.locale = :us
|
20
|
-
request.batchify(asins)
|
21
|
-
request.get
|
22
|
-
end
|
23
|
-
|
24
|
-
describe ".new" do
|
25
|
-
it "raises an error if response is not valid" do
|
26
|
-
response = mock('Response')
|
27
|
-
response.stub!(:valid?).and_return(false)
|
28
|
-
|
29
|
-
expect do
|
30
|
-
Algorithm.new(response)
|
31
|
-
end.to raise_error InvalidResponseError
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
describe "#books" do
|
36
|
-
it "should return found books" do
|
37
|
-
algorithm.items.count.should eql 19
|
38
|
-
algorithm.items.first.should be_a Book
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
describe "#errors" do
|
43
|
-
it "should return ASINs that are not found" do
|
44
|
-
algorithm.errors.count.should eql 1
|
45
|
-
algorithm.errors.first.should eql '2081232191'
|
46
|
-
end
|
47
|
-
end
|
48
|
-
end
|
49
|
-
end
|
@@ -1,50 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
module Kosher
|
4
|
-
describe Item do
|
5
|
-
it "should descend from Kosher::Struct" do
|
6
|
-
Item.ancestors.should include Kosher::Struct
|
7
|
-
end
|
8
|
-
|
9
|
-
describe ".build" do
|
10
|
-
use_vcr_cassette '0143105825'
|
11
|
-
|
12
|
-
let(:asin) { '0143105825' }
|
13
|
-
|
14
|
-
it "should build an item" do
|
15
|
-
request = Request.new(credentials)
|
16
|
-
request.locale = :us
|
17
|
-
request.batchify([asin])
|
18
|
-
algorithm = request.get
|
19
|
-
response = algorithm.instance_variable_get(:@response)
|
20
|
-
doc = response.find('Item').first
|
21
|
-
item = Item.build(doc)
|
22
|
-
|
23
|
-
item.should be_a Item
|
24
|
-
item.asin.should eql asin
|
25
|
-
item.offers_count.should be > 0
|
26
|
-
item.sales_rank.should be > 0
|
27
|
-
item.offers.count.should > 0
|
28
|
-
item.offers.first.should be_a Offer
|
29
|
-
end
|
30
|
-
|
31
|
-
it "should senify Yen in Japanese requests" do
|
32
|
-
request = Request.new(credentials)
|
33
|
-
request.locale = :jp
|
34
|
-
request.batchify([asin])
|
35
|
-
algorithm = request.get
|
36
|
-
response = algorithm.instance_variable_get(:@response)
|
37
|
-
doc = response.find('Item').first
|
38
|
-
|
39
|
-
doc['Offers']['Offer'].each do |offer|
|
40
|
-
offer['OfferListing']['Price']['Amount'] = 1
|
41
|
-
end
|
42
|
-
item = Item.build(doc)
|
43
|
-
|
44
|
-
item.offers.each do |offer|
|
45
|
-
offer.cents.should eql 100
|
46
|
-
end
|
47
|
-
end
|
48
|
-
end
|
49
|
-
end
|
50
|
-
end
|
@@ -1,31 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
module Kosher
|
4
|
-
describe Condition do
|
5
|
-
describe "#to_i" do
|
6
|
-
def this(str)
|
7
|
-
Condition.new(str).to_i
|
8
|
-
end
|
9
|
-
|
10
|
-
it "casts as integer" do
|
11
|
-
this('new').should eql 1
|
12
|
-
this('mint').should eql 2
|
13
|
-
this('verygood').should eql 3
|
14
|
-
this('good').should eql 4
|
15
|
-
this('acceptable').should eql 5
|
16
|
-
end
|
17
|
-
|
18
|
-
it "casts unrecognized conditions as 6" do
|
19
|
-
this('refurbished').should eql 6
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
describe "#kosher?" do
|
24
|
-
it "returns true if condition is good or better" do
|
25
|
-
Condition.new('verygood').should be_kosher
|
26
|
-
Condition.new('good').should be_kosher
|
27
|
-
Condition.new('acceptable').should_not be_kosher
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|
@@ -1,55 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
module Kosher
|
4
|
-
describe Description do
|
5
|
-
def this(value)
|
6
|
-
Description.new(value)
|
7
|
-
end
|
8
|
-
|
9
|
-
it "inherits from String" do
|
10
|
-
Description.ancestors.should include String
|
11
|
-
end
|
12
|
-
|
13
|
-
it "validates a blank description" do
|
14
|
-
this('').should be_kosher
|
15
|
-
end
|
16
|
-
|
17
|
-
it "validates a non-blank description" do
|
18
|
-
this('foo').should be_kosher
|
19
|
-
end
|
20
|
-
|
21
|
-
it "does not validate advance review copies" do
|
22
|
-
this('Uncorrected review copy').should_not be_kosher
|
23
|
-
this('arc').should_not be_kosher
|
24
|
-
this('arc.').should_not be_kosher
|
25
|
-
|
26
|
-
this('marc').should be_kosher
|
27
|
-
end
|
28
|
-
|
29
|
-
it "does not validate marked books" do
|
30
|
-
this('Some highlighting').should_not be_kosher
|
31
|
-
this('Underlining.').should_not be_kosher
|
32
|
-
this('Good. Hiliting.').should_not be_kosher
|
33
|
-
|
34
|
-
this('No highlighting.').should be_kosher
|
35
|
-
end
|
36
|
-
|
37
|
-
it "does not validate books with missing volumes" do
|
38
|
-
this('First vol only.').should_not be_kosher
|
39
|
-
end
|
40
|
-
|
41
|
-
it "does not validate damaged or worn books" do
|
42
|
-
this('Different').should be_kosher
|
43
|
-
this('Rental').should_not be_kosher
|
44
|
-
this('Torn pages').should_not be_kosher
|
45
|
-
end
|
46
|
-
|
47
|
-
it "does not validate withdrawn library copies" do
|
48
|
-
this('xlib').should_not be_kosher
|
49
|
-
this('ex-library').should_not be_kosher
|
50
|
-
this('retired library copy').should_not be_kosher
|
51
|
-
|
52
|
-
this('Not an ex-library').should be_kosher
|
53
|
-
end
|
54
|
-
end
|
55
|
-
end
|
@@ -1,133 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
module Kosher
|
4
|
-
describe Offer do
|
5
|
-
let(:offer) { Fabricate(:offer) }
|
6
|
-
|
7
|
-
describe ".build" do
|
8
|
-
use_vcr_cassette '0143105825'
|
9
|
-
|
10
|
-
let(:asin) { '0143105825' }
|
11
|
-
|
12
|
-
let(:doc) do
|
13
|
-
request = Request.new(credentials)
|
14
|
-
request.locale = :us
|
15
|
-
request.batchify([asin])
|
16
|
-
algorithm = request.get
|
17
|
-
|
18
|
-
response = algorithm.instance_variable_get(:@response)
|
19
|
-
response.find('Offer').first
|
20
|
-
end
|
21
|
-
|
22
|
-
it "should build an offer" do
|
23
|
-
offer = Offer.build(doc)
|
24
|
-
|
25
|
-
offer.should be_a Offer
|
26
|
-
expect do
|
27
|
-
offer.kosher?
|
28
|
-
end.should_not raise_error
|
29
|
-
end
|
30
|
-
|
31
|
-
it "populates the offer listing ID" do
|
32
|
-
offer = Offer.build(doc)
|
33
|
-
offer.listing_id.should_not be_nil
|
34
|
-
end
|
35
|
-
|
36
|
-
it "populates the exchange ID" do
|
37
|
-
offer = Offer.build(doc)
|
38
|
-
offer.exchange_id.should_not be_nil
|
39
|
-
end
|
40
|
-
|
41
|
-
it "should handle blank descriptions" do
|
42
|
-
doc['OfferAttributes']['ConditionNote'] = ''
|
43
|
-
offer = Offer.build(doc)
|
44
|
-
|
45
|
-
offer.description.should eql ''
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
describe "#kosher?" do
|
50
|
-
context "when condition is kosher" do
|
51
|
-
before do
|
52
|
-
offer.condition = Fabricate(:kosher_condition, :grade => 1)
|
53
|
-
end
|
54
|
-
|
55
|
-
context "when seller is kosher" do
|
56
|
-
before do
|
57
|
-
offer.seller = Fabricate(:good_seller)
|
58
|
-
end
|
59
|
-
|
60
|
-
context "when description is kosher" do
|
61
|
-
context "when offer ships now" do
|
62
|
-
it "returns true" do
|
63
|
-
offer.should be_kosher
|
64
|
-
end
|
65
|
-
end
|
66
|
-
|
67
|
-
context "when offer does not ship now" do
|
68
|
-
before do
|
69
|
-
offer.ships_in = 96
|
70
|
-
end
|
71
|
-
|
72
|
-
it "returns false" do
|
73
|
-
offer.should_not be_kosher
|
74
|
-
end
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
78
|
-
context "when description is not kosher" do
|
79
|
-
before do
|
80
|
-
offer.description = Kosher::Description.new("Withdrawn library book")
|
81
|
-
end
|
82
|
-
|
83
|
-
it "returns false" do
|
84
|
-
offer.should_not be_kosher
|
85
|
-
end
|
86
|
-
end
|
87
|
-
end
|
88
|
-
|
89
|
-
context "when seller is not kosher" do
|
90
|
-
before do
|
91
|
-
offer.seller = Fabricate(:bad_seller)
|
92
|
-
end
|
93
|
-
|
94
|
-
it "returns false" do
|
95
|
-
offer.should_not be_kosher
|
96
|
-
end
|
97
|
-
end
|
98
|
-
end
|
99
|
-
|
100
|
-
context "when condition is not kosher" do
|
101
|
-
before do
|
102
|
-
offer.condition = Fabricate(:kosher_condition, :grade => 5)
|
103
|
-
end
|
104
|
-
|
105
|
-
it "returns false" do
|
106
|
-
offer.should_not be_kosher
|
107
|
-
end
|
108
|
-
end
|
109
|
-
end
|
110
|
-
|
111
|
-
describe "#ships_now?" do
|
112
|
-
context "when offer ships within 48 hours" do
|
113
|
-
before do
|
114
|
-
offer.ships_in = 48
|
115
|
-
end
|
116
|
-
|
117
|
-
it "returns true" do
|
118
|
-
offer.send(:ships_now?).should be_true
|
119
|
-
end
|
120
|
-
end
|
121
|
-
|
122
|
-
context "when offer ships in over 48 hours" do
|
123
|
-
before do
|
124
|
-
offer.ships_in = 96
|
125
|
-
end
|
126
|
-
|
127
|
-
it "returns false" do
|
128
|
-
offer.send(:ships_now?).should be_false
|
129
|
-
end
|
130
|
-
end
|
131
|
-
end
|
132
|
-
end
|
133
|
-
end
|
@@ -1,71 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
module Kosher
|
4
|
-
describe Seller do
|
5
|
-
describe ".build" do
|
6
|
-
use_vcr_cassette '0143105825'
|
7
|
-
|
8
|
-
let(:asin) { '0143105825' }
|
9
|
-
|
10
|
-
let(:response) do
|
11
|
-
request = Request.new(credentials)
|
12
|
-
request.locale = :us
|
13
|
-
request.batchify([asin])
|
14
|
-
algorithm = request.get
|
15
|
-
|
16
|
-
algorithm.instance_variable_get(:@response)
|
17
|
-
end
|
18
|
-
|
19
|
-
let(:seller) do
|
20
|
-
docs = response.find('Merchant')
|
21
|
-
Seller.build(docs.first)
|
22
|
-
end
|
23
|
-
|
24
|
-
it "populates the merchant ID of a seller" do
|
25
|
-
seller.merchant_id.should match /^[0-9A-Z]{13,14}$/
|
26
|
-
end
|
27
|
-
|
28
|
-
it "populates the name of a seller" do
|
29
|
-
seller.name.should_not be_nil
|
30
|
-
end
|
31
|
-
|
32
|
-
it "populates the average rating of a seller" do
|
33
|
-
seller.average_rating.should be_an_instance_of Float
|
34
|
-
end
|
35
|
-
|
36
|
-
it "builds a newly-launched seller" do
|
37
|
-
doc = response.find('Merchant').detect { |doc| doc["AverageFeedbackRating"] == "0.0" }
|
38
|
-
new_seller = Seller.build(doc)
|
39
|
-
|
40
|
-
new_seller.average_rating.should eql 0.0
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
describe "#kosher?" do
|
45
|
-
it "returns true if seller's average rating is 0.0" do
|
46
|
-
seller = Fabricate(:new_seller)
|
47
|
-
seller.should be_kosher
|
48
|
-
end
|
49
|
-
|
50
|
-
it "returns true if seller's average rating is above 4.7" do
|
51
|
-
seller = Fabricate(:good_seller)
|
52
|
-
seller.should be_kosher
|
53
|
-
end
|
54
|
-
|
55
|
-
it "returns false if sellers' average rating is 4.7 or below" do
|
56
|
-
seller = Fabricate(:bad_seller)
|
57
|
-
seller.should_not be_kosher
|
58
|
-
end
|
59
|
-
|
60
|
-
it "returns false if seller is blacklisted" do
|
61
|
-
seller = Fabricate(:good_seller)
|
62
|
-
seller.should be_kosher
|
63
|
-
|
64
|
-
seller.merchant_id = Faker::Amazon.merchant_id
|
65
|
-
Seller.blacklist = [seller.merchant_id]
|
66
|
-
|
67
|
-
seller.should_not be_kosher
|
68
|
-
end
|
69
|
-
end
|
70
|
-
end
|
71
|
-
end
|
@@ -1,28 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
module Kosher
|
4
|
-
describe Struct do
|
5
|
-
before(:all) do
|
6
|
-
class Foo < Struct.new(:bar); end
|
7
|
-
end
|
8
|
-
|
9
|
-
describe "to_json" do
|
10
|
-
it "converts to JSON" do
|
11
|
-
foo = Foo.new
|
12
|
-
foo.bar = 1
|
13
|
-
|
14
|
-
foo.to_json.should eql "{\"bar\":1}"
|
15
|
-
end
|
16
|
-
|
17
|
-
it "handles nested structs" do
|
18
|
-
foo_1 = Foo.new
|
19
|
-
foo_2 = Foo.new
|
20
|
-
|
21
|
-
foo_2.bar = 1
|
22
|
-
foo_1.bar = foo_2
|
23
|
-
|
24
|
-
foo_1.to_json.should eql "{\"bar\":{\"bar\":1}}"
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|
data/spec/support/faker.rb
DELETED
@@ -1,19 +0,0 @@
|
|
1
|
-
module Faker
|
2
|
-
module Amazon
|
3
|
-
class << self
|
4
|
-
def asin
|
5
|
-
raw = 9.times.map { rand(10).to_s }
|
6
|
-
(raw << Bookland::ISBN.new.send(:check_digit_10, raw)).join
|
7
|
-
end
|
8
|
-
|
9
|
-
def ean
|
10
|
-
Bookland::ISBN.to_13(asin)
|
11
|
-
end
|
12
|
-
|
13
|
-
def merchant_id
|
14
|
-
seed = ('A'..'Z').to_a + (0..9).to_a
|
15
|
-
14.times.map { seed[rand(seed.size)] }.join
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|