kosher 0.1.12 → 0.2.0
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/README.md +29 -2
- data/Rakefile +0 -1
- data/kosher.gemspec +3 -8
- data/lib/kosher/condition.rb +5 -15
- data/lib/kosher/config.rb +45 -0
- data/lib/kosher/description.rb +9 -17
- data/lib/kosher/offer.rb +32 -25
- data/lib/kosher/seller.rb +3 -21
- data/lib/kosher/version.rb +1 -1
- data/lib/kosher.rb +1 -12
- data/spec/kosher/condition_spec.rb +7 -19
- data/spec/kosher/config_spec.rb +40 -0
- data/spec/kosher/description_spec.rb +18 -26
- data/spec/kosher/offer_spec.rb +111 -67
- data/spec/kosher/seller_spec.rb +25 -39
- data/spec/spec_helper.rb +0 -1
- metadata +9 -91
- data/lib/kosher/algorithm.rb +0 -25
- data/lib/kosher/errors.rb +0 -3
- data/lib/kosher/item.rb +0 -29
- data/lib/kosher/request.rb +0 -28
- data/lib/kosher/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/fixtures/cassette_library/0143105825.yml +0 -239
- data/spec/fixtures/cassette_library/batch-request.yml +0 -30540
- data/spec/kosher/algorithm_spec.rb +0 -49
- data/spec/kosher/item_spec.rb +0 -50
- data/spec/kosher/request_spec.rb +0 -42
- data/spec/kosher/struct_spec.rb +0 -28
- data/spec/support/credentials.rb +0 -3
- data/spec/support/faker.rb +0 -19
- data/spec/support/vcr.rb +0 -12
- data/walter_benjamin.jpg +0 -0
data/README.md
CHANGED
@@ -1,6 +1,33 @@
|
|
1
1
|
Kosher
|
2
2
|
======
|
3
3
|
|
4
|
-
Kosher
|
4
|
+
Kosher models an offer by a bookseller.
|
5
5
|
|
6
|
-
|
6
|
+
It knows if the offer is good or bad. It also knows if the offer is
|
7
|
+
better than another offer. It is somewhat overengineered.
|
8
|
+
|
9
|
+

|
10
|
+
|
11
|
+
Usage
|
12
|
+
-----
|
13
|
+
|
14
|
+
include Kosher
|
15
|
+
|
16
|
+
offer = Offer.new(1234,
|
17
|
+
Seller.new('ABCDEF',
|
18
|
+
'John Doe Books',
|
19
|
+
4.8),
|
20
|
+
Condition.new(1),
|
21
|
+
Description.new('A fine copy'),
|
22
|
+
48,
|
23
|
+
1000,
|
24
|
+
399,
|
25
|
+
'USD',
|
26
|
+
'http://bookseller.com/listings/1234'
|
27
|
+
|
28
|
+
offer.kosher?
|
29
|
+
=> true
|
30
|
+
|
31
|
+
offer.description = "Withdrawn library book"
|
32
|
+
offer.kosher?
|
33
|
+
=> false
|
data/Rakefile
CHANGED
data/kosher.gemspec
CHANGED
@@ -14,16 +14,11 @@ Gem::Specification.new do |s|
|
|
14
14
|
|
15
15
|
s.rubyforge_project = 'kosher'
|
16
16
|
|
17
|
+
s.add_dependency('money', '~> 3.6.1')
|
18
|
+
s.add_development_dependency('rspec', '~> 2.5.0')
|
19
|
+
|
17
20
|
s.files = `git ls-files`.split("\n")
|
18
21
|
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
19
22
|
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
20
23
|
s.require_paths = ['lib']
|
21
|
-
|
22
|
-
s.add_dependency('json', '~> 1.5.1')
|
23
|
-
s.add_dependency('sucker', '~> 1.3.1')
|
24
|
-
s.add_development_dependency('fabrication', '~> 0.9.5')
|
25
|
-
s.add_development_dependency('rspec', '~> 2.5.0')
|
26
|
-
s.add_development_dependency('ruby-debug19', '~> 0.11.6')
|
27
|
-
s.add_development_dependency('vcr', '~> 1.7.0')
|
28
|
-
s.add_development_dependency('webmock', '~> 1.6.2')
|
29
24
|
end
|
data/lib/kosher/condition.rb
CHANGED
@@ -1,25 +1,15 @@
|
|
1
1
|
module Kosher
|
2
|
-
class Condition
|
3
|
-
|
4
|
-
|
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
|
2
|
+
class Condition
|
3
|
+
def initialize(grade)
|
4
|
+
@grade = grade
|
15
5
|
end
|
16
6
|
|
17
7
|
def kosher?
|
18
|
-
grade <=
|
8
|
+
@grade <= Config.min_condition
|
19
9
|
end
|
20
10
|
|
21
11
|
def new?
|
22
|
-
grade == 1
|
12
|
+
@grade == 1
|
23
13
|
end
|
24
14
|
|
25
15
|
def used?
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module Kosher
|
2
|
+
module Config
|
3
|
+
extend self
|
4
|
+
|
5
|
+
def base_currency
|
6
|
+
@base_currency ||= 'EUR'
|
7
|
+
end
|
8
|
+
|
9
|
+
def base_currency=(code)
|
10
|
+
@base_currency = code
|
11
|
+
end
|
12
|
+
|
13
|
+
def blacklist
|
14
|
+
@blacklist ||= []
|
15
|
+
end
|
16
|
+
|
17
|
+
def blacklist=(seller_ids)
|
18
|
+
@blacklist = seller_ids
|
19
|
+
end
|
20
|
+
|
21
|
+
def max_hours_shipped
|
22
|
+
@max_hours_shipped ||= 48
|
23
|
+
end
|
24
|
+
|
25
|
+
def max_hours_shipped=(hours)
|
26
|
+
@max_hours_shipped = hours
|
27
|
+
end
|
28
|
+
|
29
|
+
def min_rating
|
30
|
+
@min_rating ||= 4.8
|
31
|
+
end
|
32
|
+
|
33
|
+
def min_rating=(rating)
|
34
|
+
@min_rating = rating
|
35
|
+
end
|
36
|
+
|
37
|
+
def min_condition
|
38
|
+
@min_condition ||= 4
|
39
|
+
end
|
40
|
+
|
41
|
+
def min_condition=(grade)
|
42
|
+
@min_condition = grade
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
data/lib/kosher/description.rb
CHANGED
@@ -1,31 +1,27 @@
|
|
1
1
|
module Kosher
|
2
|
-
class Description
|
2
|
+
class Description
|
3
3
|
DAMAGED = "\\b(?:missing|torn|broken|split|discard|withdrawn|rent|stain|school|damaged|water)"
|
4
4
|
EXLIB = "(?:e?x|discarded|retired|former|has|have)[\\s._-]*lib"
|
5
5
|
MARKED = "(highlight|hilit|underlin)"
|
6
6
|
MISSING_VOL = "(vols?|volume) only"
|
7
7
|
REVIEW_COPY = "\\b(?:uncorrected|advanced?\\sreview|arc)\\b"
|
8
8
|
|
9
|
+
def initialize(string = '')
|
10
|
+
@description = string
|
11
|
+
end
|
12
|
+
|
9
13
|
def kosher?
|
10
|
-
!(
|
11
|
-
|
14
|
+
!(damaged? || ex_library? || marked? || missing_volume? || review_copy?)
|
15
|
+
end
|
12
16
|
|
13
17
|
private
|
14
18
|
|
15
|
-
def bad?
|
16
|
-
damaged? ||
|
17
|
-
ex_library? ||
|
18
|
-
marked? ||
|
19
|
-
missing_volume? ||
|
20
|
-
review_copy?
|
21
|
-
end
|
22
|
-
|
23
19
|
def damaged?
|
24
20
|
matches(DAMAGED)
|
25
21
|
end
|
26
22
|
|
27
23
|
def does_not_match(value)
|
28
|
-
!
|
24
|
+
!matches(value)
|
29
25
|
end
|
30
26
|
|
31
27
|
def ex_library?
|
@@ -37,7 +33,7 @@ module Kosher
|
|
37
33
|
end
|
38
34
|
|
39
35
|
def matches(value)
|
40
|
-
|
36
|
+
@description.match(Regexp.new(value, true))
|
41
37
|
end
|
42
38
|
|
43
39
|
def missing_volume?
|
@@ -48,10 +44,6 @@ module Kosher
|
|
48
44
|
"(?:no|not an?)\\s+#{value}"
|
49
45
|
end
|
50
46
|
|
51
|
-
def present?
|
52
|
-
self != ''
|
53
|
-
end
|
54
|
-
|
55
47
|
def review_copy?
|
56
48
|
matches(REVIEW_COPY)
|
57
49
|
end
|
data/lib/kosher/offer.rb
CHANGED
@@ -1,38 +1,45 @@
|
|
1
|
+
require 'money'
|
2
|
+
|
1
3
|
module Kosher
|
2
4
|
class Offer < Struct.new(
|
5
|
+
:id,
|
3
6
|
:seller,
|
4
7
|
:condition,
|
5
8
|
:description,
|
6
|
-
:
|
7
|
-
:
|
8
|
-
:
|
9
|
-
:
|
10
|
-
:
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
9
|
+
:hours_shipped,
|
10
|
+
:price_in_cents,
|
11
|
+
:shipping_in_cents,
|
12
|
+
:currency,
|
13
|
+
:url)
|
14
|
+
|
15
|
+
include Comparable
|
16
|
+
|
17
|
+
def <=>(another)
|
18
|
+
if self.kosher? != another.kosher?
|
19
|
+
self.kosher? ? 1 : -1
|
20
|
+
else
|
21
|
+
-(self.final_price.exchange_to(Config.base_currency) <=> another.final_price.exchange_to(Config.base_currency))
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def available?
|
26
|
+
hours_shipped.to_i <= Config.max_hours_shipped
|
27
|
+
end
|
28
|
+
|
29
|
+
def final_price
|
30
|
+
price + shipping
|
28
31
|
end
|
29
32
|
|
30
33
|
def kosher?
|
31
|
-
condition.kosher? && seller.kosher? && description.kosher? &&
|
34
|
+
condition.kosher? && seller.kosher? && description.kosher? && available?
|
35
|
+
end
|
36
|
+
|
37
|
+
def price
|
38
|
+
Money.new(price_in_cents, currency)
|
32
39
|
end
|
33
40
|
|
34
|
-
def
|
35
|
-
|
41
|
+
def shipping
|
42
|
+
Money.new(shipping_in_cents.to_i, currency)
|
36
43
|
end
|
37
44
|
end
|
38
45
|
end
|
data/lib/kosher/seller.rb
CHANGED
@@ -1,29 +1,11 @@
|
|
1
1
|
module Kosher
|
2
|
-
class Seller < Struct.new(:
|
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
|
-
|
2
|
+
class Seller < Struct.new(:id, :name, :rating)
|
19
3
|
def blacklisted?
|
20
|
-
blacklist.include?(
|
4
|
+
Config.blacklist.include?(id)
|
21
5
|
end
|
22
6
|
|
23
7
|
def kosher?
|
24
|
-
|
25
|
-
|
26
|
-
average_rating == 0.0 || average_rating > 4.7
|
8
|
+
!blacklisted? && (rating.to_f == 0.0 || rating >= Config.min_rating)
|
27
9
|
end
|
28
10
|
end
|
29
11
|
end
|
data/lib/kosher/version.rb
CHANGED
data/lib/kosher.rb
CHANGED
@@ -1,16 +1,5 @@
|
|
1
|
-
require 'sucker'
|
2
|
-
require 'kosher/struct'
|
3
|
-
require 'kosher/algorithm'
|
4
1
|
require 'kosher/condition'
|
2
|
+
require 'kosher/config'
|
5
3
|
require 'kosher/description'
|
6
|
-
require 'kosher/errors'
|
7
|
-
require 'kosher/item'
|
8
4
|
require 'kosher/offer'
|
9
|
-
require 'kosher/request'
|
10
5
|
require 'kosher/seller'
|
11
|
-
|
12
|
-
module Kosher
|
13
|
-
def self.new(args={})
|
14
|
-
Request.new(args)
|
15
|
-
end
|
16
|
-
end
|
@@ -2,29 +2,17 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
module Kosher
|
4
4
|
describe Condition do
|
5
|
-
describe "#
|
6
|
-
|
7
|
-
|
5
|
+
describe "#kosher?" do
|
6
|
+
before do
|
7
|
+
Config.min_condition = 1
|
8
8
|
end
|
9
9
|
|
10
|
-
it "
|
11
|
-
|
12
|
-
this('mint').should eql 2
|
13
|
-
this('verygood').should eql 3
|
14
|
-
this('good').should eql 4
|
15
|
-
this('acceptable').should eql 5
|
10
|
+
it "returns true if condition is equal to or better than minimum condition" do
|
11
|
+
Condition.new(1).should be_kosher
|
16
12
|
end
|
17
13
|
|
18
|
-
it "
|
19
|
-
|
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
|
14
|
+
it "returns false if condition is less than minimum condition" do
|
15
|
+
Condition.new(2).should_not be_kosher
|
28
16
|
end
|
29
17
|
end
|
30
18
|
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Kosher
|
4
|
+
describe Config do
|
5
|
+
describe ".base_currency" do
|
6
|
+
it "defaults to EUR" do
|
7
|
+
Config.base_currency = nil
|
8
|
+
Config.base_currency.should eql 'EUR'
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
describe ".blacklist" do
|
13
|
+
it "defaults to an empty array" do
|
14
|
+
Config.blacklist = nil
|
15
|
+
Config.blacklist.should eql []
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
describe ".max_hours_shipped" do
|
20
|
+
it "defaults to 48" do
|
21
|
+
Config.max_hours_shipped = nil
|
22
|
+
Config.max_hours_shipped.should eql 48
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe ".min_rating" do
|
27
|
+
it "defaults to 4.8" do
|
28
|
+
Config.min_rating = nil
|
29
|
+
Config.min_rating.should eql 4.8
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
describe ".min_condition" do
|
34
|
+
it "defaults to 4" do
|
35
|
+
Config.min_condition = nil
|
36
|
+
Config.min_condition.should eql 4
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -2,54 +2,46 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
module Kosher
|
4
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
5
|
it "validates a blank description" do
|
14
|
-
|
6
|
+
Description.new('').should be_kosher
|
15
7
|
end
|
16
8
|
|
17
9
|
it "validates a non-blank description" do
|
18
|
-
|
10
|
+
Description.new('foo').should be_kosher
|
19
11
|
end
|
20
12
|
|
21
13
|
it "does not validate advance review copies" do
|
22
|
-
|
23
|
-
|
24
|
-
|
14
|
+
Description.new('Uncorrected review copy').should_not be_kosher
|
15
|
+
Description.new('arc').should_not be_kosher
|
16
|
+
Description.new('arc.').should_not be_kosher
|
25
17
|
|
26
|
-
|
18
|
+
Description.new('marc').should be_kosher
|
27
19
|
end
|
28
20
|
|
29
21
|
it "does not validate marked books" do
|
30
|
-
|
31
|
-
|
32
|
-
|
22
|
+
Description.new('Some highlighting').should_not be_kosher
|
23
|
+
Description.new('Underlining.').should_not be_kosher
|
24
|
+
Description.new('Good. Hiliting.').should_not be_kosher
|
33
25
|
|
34
|
-
|
26
|
+
Description.new('No highlighting.').should be_kosher
|
35
27
|
end
|
36
28
|
|
37
29
|
it "does not validate books with missing volumes" do
|
38
|
-
|
30
|
+
Description.new('First vol only.').should_not be_kosher
|
39
31
|
end
|
40
32
|
|
41
33
|
it "does not validate damaged or worn books" do
|
42
|
-
|
43
|
-
|
44
|
-
|
34
|
+
Description.new('Different').should be_kosher
|
35
|
+
Description.new('Rental').should_not be_kosher
|
36
|
+
Description.new('Torn pages').should_not be_kosher
|
45
37
|
end
|
46
38
|
|
47
39
|
it "does not validate withdrawn library copies" do
|
48
|
-
|
49
|
-
|
50
|
-
|
40
|
+
Description.new('xlib').should_not be_kosher
|
41
|
+
Description.new('ex-library').should_not be_kosher
|
42
|
+
Description.new('retired library copy').should_not be_kosher
|
51
43
|
|
52
|
-
|
44
|
+
Description.new('Not an ex-library').should be_kosher
|
53
45
|
end
|
54
46
|
end
|
55
47
|
end
|