fassbinder 0.0.8 → 0.0.9
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +5 -0
- data/Rakefile +1 -0
- data/bin/rainer +3 -0
- data/fassbinder.gemspec +4 -7
- data/lib/fassbinder/book_builder.rb +35 -0
- data/lib/fassbinder/cli.rb +52 -0
- data/lib/fassbinder/errors.rb +4 -0
- data/lib/fassbinder/item_builder.rb +46 -0
- data/lib/fassbinder/offer_builder.rb +47 -0
- data/lib/fassbinder/request.rb +10 -1
- data/lib/fassbinder/response.rb +26 -51
- data/lib/fassbinder/seller_builder.rb +28 -0
- data/lib/fassbinder/shipping_builder.rb +27 -0
- data/lib/fassbinder/version.rb +1 -1
- data/lib/fassbinder.rb +0 -8
- data/spec/fassbinder/request_spec.rb +38 -8
- data/spec/fassbinder/response_spec.rb +14 -7
- metadata +19 -44
data/Gemfile
CHANGED
data/Rakefile
CHANGED
data/bin/rainer
ADDED
data/fassbinder.gemspec
CHANGED
@@ -9,8 +9,8 @@ Gem::Specification.new do |s|
|
|
9
9
|
s.authors = ['Paper Cavalier']
|
10
10
|
s.email = 'code@papercavalier.com'
|
11
11
|
s.homepage = 'https://rubygems.org/gems/fassbinder'
|
12
|
-
s.summary = %q{
|
13
|
-
s.description = %q{Fassbinder
|
12
|
+
s.summary = %q{Crawls book offers on Amazon}
|
13
|
+
s.description = %q{Fassbinder crawls book offers on Amazon.}
|
14
14
|
|
15
15
|
s.rubyforge_project = 'fassbinder'
|
16
16
|
|
@@ -19,10 +19,7 @@ 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.23')
|
23
23
|
s.add_dependency('sucker', '~> 1.4.0')
|
24
|
-
s.
|
25
|
-
s.add_development_dependency('ruby-debug19', '~> 0.11.6')
|
26
|
-
s.add_development_dependency('vcr', '~> 1.7.0')
|
27
|
-
s.add_development_dependency('webmock', '~> 1.6.2')
|
24
|
+
s.add_dependency('thor', '~> 0.14.6')
|
28
25
|
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'kosher'
|
2
|
+
require 'fassbinder/offer_builder'
|
3
|
+
|
4
|
+
module Fassbinder
|
5
|
+
class BookBuilder
|
6
|
+
attr_reader :book
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
@book = Kosher::Book.new
|
10
|
+
@book.offers = []
|
11
|
+
end
|
12
|
+
|
13
|
+
def add_offer(hash)
|
14
|
+
builder = OfferBuilder.new
|
15
|
+
builder.id = hash['OfferListing']['OfferListingId']
|
16
|
+
builder.venue = @book.venue
|
17
|
+
builder.add_item(hash)
|
18
|
+
builder.add_seller(hash['Merchant'])
|
19
|
+
builder.add_shipping(hash)
|
20
|
+
@book.offers << builder.offer
|
21
|
+
end
|
22
|
+
|
23
|
+
def asin=(asin)
|
24
|
+
@book.asin = asin
|
25
|
+
end
|
26
|
+
|
27
|
+
def venue=(venue)
|
28
|
+
@book.venue = venue
|
29
|
+
end
|
30
|
+
|
31
|
+
def offers_total=(count)
|
32
|
+
@book.offers_total = count.to_i
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'pp'
|
2
|
+
require 'thor'
|
3
|
+
require 'fassbinder'
|
4
|
+
|
5
|
+
module Fassbinder
|
6
|
+
class CLI < Thor
|
7
|
+
desc 'all', 'Looks up all offers for an ASIN'
|
8
|
+
method_option :locale, :required => true, :aliases => '-l'
|
9
|
+
def all(asin)
|
10
|
+
locale = options[:locale] || :us
|
11
|
+
lookup(asin, locale)
|
12
|
+
end
|
13
|
+
map 'a' => 'all'
|
14
|
+
|
15
|
+
desc 'kosher', 'Looks up kosher offers for an ASIN'
|
16
|
+
method_option :locale, :required => true, :aliases => '-l'
|
17
|
+
def kosher(asin)
|
18
|
+
locale = options[:locale] || :us
|
19
|
+
lookup(asin, locale, true)
|
20
|
+
end
|
21
|
+
map 'k' => 'kosher'
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def lookup(asin, locale, kosher_only=false)
|
26
|
+
request = Request.new(credentials)
|
27
|
+
request.locale = locale
|
28
|
+
request.batchify(asin)
|
29
|
+
offers = request.get.to_a.first.offers
|
30
|
+
|
31
|
+
offers.select!(&:kosher?) if kosher_only
|
32
|
+
|
33
|
+
offers.each do |offer|
|
34
|
+
puts offer.kosher? ? 'kosher' : 'unkosher'
|
35
|
+
|
36
|
+
offer.id = offer.id[0, 24] + '...'
|
37
|
+
|
38
|
+
description = offer.item.description.text
|
39
|
+
if description.size > 77
|
40
|
+
offer.item.description.text = description[0, 77] + '...'
|
41
|
+
end
|
42
|
+
|
43
|
+
pp offer
|
44
|
+
puts
|
45
|
+
end
|
46
|
+
end
|
47
|
+
def credentials
|
48
|
+
{ 'key' => ENV['AMAZON_KEY'],
|
49
|
+
'secret' => ENV['AMAZON_SECRET'] }
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module Fassbinder
|
2
|
+
class ItemBuilder
|
3
|
+
attr_reader :item
|
4
|
+
|
5
|
+
def initialize
|
6
|
+
@item = Kosher::Item.new
|
7
|
+
end
|
8
|
+
|
9
|
+
def price=(price)
|
10
|
+
cents = price['Amount'].to_i
|
11
|
+
currency = price['CurrencyCode']
|
12
|
+
|
13
|
+
cents *= 100 if currency == 'JPY'
|
14
|
+
|
15
|
+
@item.cents = cents
|
16
|
+
@item.currency = currency
|
17
|
+
end
|
18
|
+
|
19
|
+
def quantity=(quantity)
|
20
|
+
@item.quantity = quantity.to_i
|
21
|
+
end
|
22
|
+
|
23
|
+
def add_condition(grade)
|
24
|
+
condition = Kosher::Condition.new
|
25
|
+
condition.grade =
|
26
|
+
case grade
|
27
|
+
when 'new' then 1
|
28
|
+
when 'mint' then 2
|
29
|
+
when 'verygood' then 3
|
30
|
+
when 'good' then 4
|
31
|
+
when 'acceptable' then 5
|
32
|
+
else 6
|
33
|
+
end
|
34
|
+
|
35
|
+
@item.condition = condition
|
36
|
+
end
|
37
|
+
|
38
|
+
def add_description(text)
|
39
|
+
text ||= ''
|
40
|
+
description = Kosher::Description.new
|
41
|
+
description.text = text
|
42
|
+
|
43
|
+
@item.description = description
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'fassbinder/item_builder'
|
2
|
+
require 'fassbinder/seller_builder'
|
3
|
+
require 'fassbinder/shipping_builder'
|
4
|
+
|
5
|
+
module Fassbinder
|
6
|
+
class OfferBuilder
|
7
|
+
attr_reader :offer
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
@offer = Kosher::Offer.new
|
11
|
+
end
|
12
|
+
|
13
|
+
def add_item(hash)
|
14
|
+
builder = ItemBuilder.new
|
15
|
+
builder.price = hash['OfferListing']['Price']
|
16
|
+
builder.quantity = hash['OfferListing']['Quantity']
|
17
|
+
builder.add_condition(hash['OfferAttributes']['SubCondition'])
|
18
|
+
builder.add_description(hash['OfferAttributes']['ConditionNote'])
|
19
|
+
@offer.item = builder.item
|
20
|
+
end
|
21
|
+
|
22
|
+
def add_seller(hash)
|
23
|
+
builder = SellerBuilder.new
|
24
|
+
builder.id = hash['MerchantId']
|
25
|
+
builder.name = hash['Name']
|
26
|
+
builder.rating = hash['AverageFeedbackRating']
|
27
|
+
builder.add_location(hash['Location']) if hash['Location']
|
28
|
+
@offer.seller = builder.seller
|
29
|
+
end
|
30
|
+
|
31
|
+
def add_shipping(hash)
|
32
|
+
builder = ShippingBuilder.new
|
33
|
+
builder.add_availability(hash['OfferListing']['AvailabilityAttributes']['MaximumHours'])
|
34
|
+
is_free = (hash['OfferListing']['IsEligibleForSuperSaverShipping'] == '1')
|
35
|
+
builder.calculate_price(is_free, @offer.venue, hash['OfferListing']['Price']['CurrencyCode'])
|
36
|
+
@offer.shipping = builder.shipping
|
37
|
+
end
|
38
|
+
|
39
|
+
def id=(id)
|
40
|
+
@offer.id = id
|
41
|
+
end
|
42
|
+
|
43
|
+
def venue=(venue)
|
44
|
+
@offer.venue = venue
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
data/lib/fassbinder/request.rb
CHANGED
@@ -1,3 +1,6 @@
|
|
1
|
+
require 'sucker'
|
2
|
+
require 'fassbinder/response'
|
3
|
+
|
1
4
|
module Fassbinder
|
2
5
|
class Request < Sucker::Request
|
3
6
|
def initialize(args = {})
|
@@ -7,10 +10,16 @@ module Fassbinder
|
|
7
10
|
'ItemLookup.Shared.IdType' => 'ASIN',
|
8
11
|
'ItemLookup.Shared.Condition' => 'All',
|
9
12
|
'ItemLookup.Shared.MerchantId' => 'All',
|
10
|
-
'ItemLookup.Shared.ResponseGroup' => ['OfferFull'
|
13
|
+
'ItemLookup.Shared.ResponseGroup' => ['OfferFull'] })
|
11
14
|
end
|
12
15
|
|
13
16
|
def batchify(asins)
|
17
|
+
asins = [asins].flatten
|
18
|
+
|
19
|
+
if asins.size > 20
|
20
|
+
raise ArgumentError, 'You cannot add more than 20 ASINs to a batch'
|
21
|
+
end
|
22
|
+
|
14
23
|
self.<<({ 'ItemLookup.1.ItemId' => asins[0, 10] })
|
15
24
|
self.<<({ 'ItemLookup.2.ItemId' => asins[10, 10] }) if asins.size > 10
|
16
25
|
end
|
data/lib/fassbinder/response.rb
CHANGED
@@ -1,29 +1,30 @@
|
|
1
|
-
|
1
|
+
require 'fassbinder/book_builder'
|
2
|
+
require 'fassbinder/errors'
|
2
3
|
|
3
|
-
|
4
|
-
# be taken absolutely seriously.
|
5
|
-
#
|
4
|
+
module Fassbinder
|
6
5
|
class Response
|
7
6
|
include Enumerable
|
8
7
|
|
9
|
-
DEFAULT_SHIPPING_CENTS = { :us => 399,
|
10
|
-
:uk => 280,
|
11
|
-
:de => 299,
|
12
|
-
:ca => 649,
|
13
|
-
:fr => 300,
|
14
|
-
:jp => 25000 }
|
15
|
-
|
16
8
|
def initialize(response, locale)
|
17
|
-
|
9
|
+
unless response.valid?
|
10
|
+
message =
|
11
|
+
if response.has_errors?
|
12
|
+
response.errors.first['Message']
|
13
|
+
else
|
14
|
+
response.code
|
15
|
+
end
|
16
|
+
|
17
|
+
raise InvalidResponse, message
|
18
|
+
end
|
18
19
|
|
19
20
|
@response = response
|
20
|
-
@locale = locale
|
21
|
+
@locale = locale.to_sym
|
21
22
|
end
|
22
23
|
|
23
24
|
# Yields each snapshot to given block.
|
24
25
|
#
|
25
26
|
def each(&block)
|
26
|
-
@response.each('Item') { |doc| block.call(
|
27
|
+
@response.each('Item') { |doc| block.call(build_book(doc)) }
|
27
28
|
end
|
28
29
|
|
29
30
|
def errors
|
@@ -34,44 +35,18 @@ module Fassbinder
|
|
34
35
|
|
35
36
|
private
|
36
37
|
|
37
|
-
def
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
end
|
38
|
+
def build_book(doc)
|
39
|
+
builder = BookBuilder.new
|
40
|
+
|
41
|
+
builder.asin = doc['ASIN']
|
42
|
+
builder.offers_total = doc['Offers']['TotalOffers']
|
43
|
+
host = Sucker::Request::HOSTS[@locale]
|
44
|
+
builder.venue = "amazon.#{host.match(/[^.]+$/)}"
|
45
|
+
|
46
|
+
offers = doc['Offers']['Offer']
|
47
|
+
offers.each { |offer| builder.add_offer(offer) }
|
48
48
|
|
49
|
-
|
50
|
-
doc['OfferListing']['OfferListingId'],
|
51
|
-
Kosher::Item.new(doc['OfferListing']['Price']['Amount'].to_i,
|
52
|
-
doc['OfferListing']['Price']['CurrencyCode'],
|
53
|
-
doc['OfferListing']['Quantity'].to_i,
|
54
|
-
Kosher::Condition.new(case doc['OfferAttributes']['SubCondition']
|
55
|
-
when 'new' then 1
|
56
|
-
when 'mint' then 2
|
57
|
-
when 'verygood' then 3
|
58
|
-
when 'good' then 4
|
59
|
-
when 'acceptable' then 5
|
60
|
-
else 6
|
61
|
-
end),
|
62
|
-
Kosher::Description.new(doc['OfferAttributes']['ConditionNote'].to_s)),
|
63
|
-
Kosher::Seller.new(doc['Merchant']['MerchantId'],
|
64
|
-
doc['Merchant']['Name'],
|
65
|
-
doc['Merchant']['AverageFeedbackRating'].to_f,
|
66
|
-
Kosher::Location.new((doc['Merchant']['Location']['CountryCode'] rescue nil),
|
67
|
-
(doc['Merchant']['Location']['StateCode'] rescue nil))),
|
68
|
-
Kosher::Shipping.new(doc['OfferListing']['IsEligibleForSuperSaverShipping'] == '1' ?
|
69
|
-
0 : DEFAULT_SHIPPING_CENTS[@locale],
|
70
|
-
doc['OfferListing']['Price']['CurrencyCode'],
|
71
|
-
Kosher::Availability.new(doc['OfferListing']['AvailabilityAttributes']['MaximumHours'].to_i))
|
72
|
-
)
|
73
|
-
end
|
74
|
-
)
|
49
|
+
builder.book
|
75
50
|
end
|
76
51
|
end
|
77
52
|
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Fassbinder
|
2
|
+
class SellerBuilder
|
3
|
+
attr_reader :seller
|
4
|
+
|
5
|
+
def initialize
|
6
|
+
@seller = Kosher::Seller.new
|
7
|
+
end
|
8
|
+
|
9
|
+
def id=(id)
|
10
|
+
@seller.id = id
|
11
|
+
end
|
12
|
+
|
13
|
+
def name=(name)
|
14
|
+
@seller.name = name
|
15
|
+
end
|
16
|
+
|
17
|
+
def rating=(rating)
|
18
|
+
@seller.rating = rating.to_f
|
19
|
+
end
|
20
|
+
|
21
|
+
def add_location(hash)
|
22
|
+
location = Kosher::Location.new
|
23
|
+
location.country = hash['CountryCode']
|
24
|
+
location.state = hash['StateCode']
|
25
|
+
@seller.location = location
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Fassbinder
|
2
|
+
class ShippingBuilder
|
3
|
+
DEFAULT_SHIPPING_CENTS = { 'amazon.com' => 399,
|
4
|
+
'amazon.co.uk' => 280,
|
5
|
+
'amazon.de' => 299,
|
6
|
+
'amazon.ca' => 649,
|
7
|
+
'amazon.fr' => 300,
|
8
|
+
'amazon.co.jp' => 25000 }
|
9
|
+
|
10
|
+
attr_reader :shipping
|
11
|
+
|
12
|
+
def initialize
|
13
|
+
@shipping = Kosher::Shipping.new
|
14
|
+
end
|
15
|
+
|
16
|
+
def add_availability(hours)
|
17
|
+
availability = Kosher::Availability.new
|
18
|
+
availability.hours = hours.to_i
|
19
|
+
@shipping.availability = availability
|
20
|
+
end
|
21
|
+
|
22
|
+
def calculate_price(is_free, venue, currency)
|
23
|
+
@shipping.cents = is_free ? 0 : DEFAULT_SHIPPING_CENTS[venue]
|
24
|
+
@shipping.currency = currency
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
data/lib/fassbinder/version.rb
CHANGED
data/lib/fassbinder.rb
CHANGED
@@ -5,22 +5,52 @@ module Fassbinder
|
|
5
5
|
let(:request) { Request.new(credentials) }
|
6
6
|
|
7
7
|
describe ".new" do
|
8
|
-
it "
|
8
|
+
it "sets up an item request" do
|
9
9
|
request.parameters['Operation'].should eql 'ItemLookup'
|
10
|
+
end
|
11
|
+
|
12
|
+
it "looks up ASINs" do
|
10
13
|
request.parameters['ItemLookup.Shared.IdType'].should eql 'ASIN'
|
14
|
+
end
|
15
|
+
|
16
|
+
it "looks up all conditions" do
|
11
17
|
request.parameters['ItemLookup.Shared.Condition'].should eql 'All'
|
18
|
+
end
|
19
|
+
|
20
|
+
it "looks up all merchants" do
|
12
21
|
request.parameters['ItemLookup.Shared.MerchantId'].should eql 'All'
|
13
|
-
|
22
|
+
end
|
23
|
+
|
24
|
+
it "looks up full offers" do
|
25
|
+
request.parameters['ItemLookup.Shared.ResponseGroup'].should eql ['OfferFull']
|
14
26
|
end
|
15
27
|
end
|
16
28
|
|
17
29
|
describe "#batchify" do
|
18
|
-
|
19
|
-
|
20
|
-
|
30
|
+
context "when passed one ASIN" do
|
31
|
+
it "adds the ASIN to the batch" do\
|
32
|
+
request.batchify('foo')
|
33
|
+
request.parameters['ItemLookup.1.ItemId'].should eql ['foo']
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
context "when passed up to 20 ASINs" do
|
38
|
+
it "adds the ASINs to the batch" do
|
39
|
+
asins = (0..19).to_a
|
40
|
+
request.batchify(asins)
|
41
|
+
|
42
|
+
request.parameters['ItemLookup.1.ItemId'].should eql (0..9).to_a
|
43
|
+
request.parameters['ItemLookup.2.ItemId'].should eql (10..19).to_a
|
44
|
+
end
|
45
|
+
end
|
21
46
|
|
22
|
-
|
23
|
-
|
47
|
+
context "when passed over 20 ASINs" do
|
48
|
+
it "raises an error" do
|
49
|
+
expect do
|
50
|
+
asins = (0..20).to_a
|
51
|
+
request.batchify(asins)
|
52
|
+
end.to raise_error ArgumentError
|
53
|
+
end
|
24
54
|
end
|
25
55
|
end
|
26
56
|
|
@@ -29,7 +59,7 @@ module Fassbinder
|
|
29
59
|
VCR.http_stubbing_adapter.http_connections_allowed = true
|
30
60
|
end
|
31
61
|
|
32
|
-
it "returns
|
62
|
+
it "returns a response" do
|
33
63
|
Request.stub!(:get)
|
34
64
|
|
35
65
|
request.locale = :us
|
@@ -21,13 +21,20 @@ module Fassbinder
|
|
21
21
|
end
|
22
22
|
|
23
23
|
describe ".new" do
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
24
|
+
context "when response is not valid" do
|
25
|
+
it "raises an error" do
|
26
|
+
response = mock('Response')
|
27
|
+
response.stub!(:valid?).and_return(false)
|
28
|
+
response.stub!(:has_errors?).and_return(true)
|
29
|
+
response.stub!(:errors).and_return([{
|
30
|
+
'Code' => 'AccountLimitExceeded',
|
31
|
+
'Message' => 'YOU FAIL'
|
32
|
+
}])
|
33
|
+
|
34
|
+
expect do
|
35
|
+
Response.new(response, :us)
|
36
|
+
end.to raise_error InvalidResponse, 'YOU FAIL'
|
37
|
+
end
|
31
38
|
end
|
32
39
|
end
|
33
40
|
|
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.9
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Paper Cavalier
|
@@ -10,7 +10,7 @@ autorequire:
|
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
12
|
|
13
|
-
date: 2011-
|
13
|
+
date: 2011-04-15 00:00:00 +01:00
|
14
14
|
default_executable:
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
@@ -21,7 +21,7 @@ dependencies:
|
|
21
21
|
requirements:
|
22
22
|
- - ~>
|
23
23
|
- !ruby/object:Gem::Version
|
24
|
-
version: 0.2.
|
24
|
+
version: 0.2.23
|
25
25
|
type: :runtime
|
26
26
|
version_requirements: *id001
|
27
27
|
- !ruby/object:Gem::Dependency
|
@@ -36,53 +36,20 @@ dependencies:
|
|
36
36
|
type: :runtime
|
37
37
|
version_requirements: *id002
|
38
38
|
- !ruby/object:Gem::Dependency
|
39
|
-
name:
|
39
|
+
name: thor
|
40
40
|
prerelease: false
|
41
41
|
requirement: &id003 !ruby/object:Gem::Requirement
|
42
42
|
none: false
|
43
43
|
requirements:
|
44
44
|
- - ~>
|
45
45
|
- !ruby/object:Gem::Version
|
46
|
-
version:
|
47
|
-
type: :
|
46
|
+
version: 0.14.6
|
47
|
+
type: :runtime
|
48
48
|
version_requirements: *id003
|
49
|
-
|
50
|
-
name: ruby-debug19
|
51
|
-
prerelease: false
|
52
|
-
requirement: &id004 !ruby/object:Gem::Requirement
|
53
|
-
none: false
|
54
|
-
requirements:
|
55
|
-
- - ~>
|
56
|
-
- !ruby/object:Gem::Version
|
57
|
-
version: 0.11.6
|
58
|
-
type: :development
|
59
|
-
version_requirements: *id004
|
60
|
-
- !ruby/object:Gem::Dependency
|
61
|
-
name: vcr
|
62
|
-
prerelease: false
|
63
|
-
requirement: &id005 !ruby/object:Gem::Requirement
|
64
|
-
none: false
|
65
|
-
requirements:
|
66
|
-
- - ~>
|
67
|
-
- !ruby/object:Gem::Version
|
68
|
-
version: 1.7.0
|
69
|
-
type: :development
|
70
|
-
version_requirements: *id005
|
71
|
-
- !ruby/object:Gem::Dependency
|
72
|
-
name: webmock
|
73
|
-
prerelease: false
|
74
|
-
requirement: &id006 !ruby/object:Gem::Requirement
|
75
|
-
none: false
|
76
|
-
requirements:
|
77
|
-
- - ~>
|
78
|
-
- !ruby/object:Gem::Version
|
79
|
-
version: 1.6.2
|
80
|
-
type: :development
|
81
|
-
version_requirements: *id006
|
82
|
-
description: Fassbinder wraps Amazon in a loving embrace.
|
49
|
+
description: Fassbinder crawls book offers on Amazon.
|
83
50
|
email: code@papercavalier.com
|
84
|
-
executables:
|
85
|
-
|
51
|
+
executables:
|
52
|
+
- rainer
|
86
53
|
extensions: []
|
87
54
|
|
88
55
|
extra_rdoc_files: []
|
@@ -93,11 +60,19 @@ files:
|
|
93
60
|
- LICENSE
|
94
61
|
- README.md
|
95
62
|
- Rakefile
|
63
|
+
- bin/rainer
|
96
64
|
- fassbinder.gemspec
|
97
65
|
- fassbinder.jpg
|
98
66
|
- lib/fassbinder.rb
|
67
|
+
- lib/fassbinder/book_builder.rb
|
68
|
+
- lib/fassbinder/cli.rb
|
69
|
+
- lib/fassbinder/errors.rb
|
70
|
+
- lib/fassbinder/item_builder.rb
|
71
|
+
- lib/fassbinder/offer_builder.rb
|
99
72
|
- lib/fassbinder/request.rb
|
100
73
|
- lib/fassbinder/response.rb
|
74
|
+
- lib/fassbinder/seller_builder.rb
|
75
|
+
- lib/fassbinder/shipping_builder.rb
|
101
76
|
- lib/fassbinder/version.rb
|
102
77
|
- spec/fassbinder/request_spec.rb
|
103
78
|
- spec/fassbinder/response_spec.rb
|
@@ -128,10 +103,10 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
128
103
|
requirements: []
|
129
104
|
|
130
105
|
rubyforge_project: fassbinder
|
131
|
-
rubygems_version: 1.
|
106
|
+
rubygems_version: 1.6.2
|
132
107
|
signing_key:
|
133
108
|
specification_version: 3
|
134
|
-
summary:
|
109
|
+
summary: Crawls book offers on Amazon
|
135
110
|
test_files:
|
136
111
|
- spec/fassbinder/request_spec.rb
|
137
112
|
- spec/fassbinder/response_spec.rb
|