barnie 0.1.3 → 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/barnie.gemspec CHANGED
@@ -1,33 +1,30 @@
1
1
  # -*- encoding: utf-8 -*-
2
- $:.push File.expand_path("../lib", __FILE__)
3
- require "barnie/version"
2
+ $:.push File.expand_path('../lib', __FILE__)
3
+ require 'barnie/version'
4
4
 
5
5
  Gem::Specification.new do |s|
6
- s.name = "barnie"
6
+ s.name = 'barnie'
7
7
  s.version = Barnie::VERSION
8
8
  s.platform = Gem::Platform::RUBY
9
- s.email = ["code@papercavalier.com"]
10
- s.homepage = "http://gloss.papercavalier.com/barnie"
11
- s.authors = ["Paper Cavalier"]
9
+ s.email = 'code@papercavalier.com'
10
+ s.homepage = 'http://gloss.papercavalier.com/barnie'
11
+ s.authors = ['Paper Cavalier']
12
12
  s.description = %q{A fake API to a well-known bookstore}
13
13
  s.summary = %q{A fake API to a well-known bookstore}
14
14
 
15
- s.rubyforge_project = "barnie"
15
+ s.rubyforge_project = 'barnie'
16
16
 
17
- s.add_dependency("mechanize", "~> 1.0.0")
17
+ s.add_dependency('kosher', '~> 0.2.10')
18
+ s.add_dependency('mechanize', '~> 1.0.0')
19
+ s.add_development_dependency('launchy', '~> 0.3.7')
20
+ s.add_development_dependency('rspec', '~> 2.5.0')
21
+ s.add_development_dependency('ruby-debug19', '~> 0.11.0')
22
+ s.add_development_dependency('vcr', '~> 1.7.0')
23
+ s.add_development_dependency('webmock', '~> 1.6.2')
18
24
 
19
- s.add_development_dependency("bookland", "0.3.1")
20
- s.add_development_dependency("launchy", "~> 0.3.7")
21
- s.add_development_dependency("rspec", "~> 2.1.0")
22
- s.add_development_dependency("throttler", "~> 0.2.1")
23
- s.add_development_dependency("vcr", "~> 1.3.1")
24
- s.add_development_dependency("webmock", "~> 1.6.1")
25
- if RUBY_VERSION.include?("1.9")
26
- s.add_development_dependency("ruby-debug19", "~> 0.11.0")
27
- end
28
25
 
29
26
  s.files = `git ls-files`.split("\n")
30
27
  s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
31
28
  s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
32
- s.require_paths = ["lib"]
29
+ s.require_paths = ['lib']
33
30
  end
@@ -1,8 +1,8 @@
1
1
  module Barnie
2
2
  module Helpers
3
3
  def sanitize_string(string)
4
- string.gsub!(/^"|"$/, "")
5
- string.gsub!(/\\r|\\n/, "")
4
+ string.gsub!(/^"|"$/, '')
5
+ string.gsub!(/\\r|\\n/, '')
6
6
  string.strip
7
7
  end
8
8
 
@@ -10,13 +10,14 @@ module Barnie
10
10
  if string !~ /\S/
11
11
  0
12
12
  else
13
- string.gsub!(/\D/, "").to_i
13
+ string.gsub!(/\D/, '').to_i
14
14
  end
15
15
  end
16
16
 
17
17
  def title(html)
18
- title = html.search(".title a")
19
- title = html.search(".ebooktitle a") unless title.any?
18
+ title = html.search('.title a')
19
+ title = html.search('.ebooktitle a') unless title.any?
20
+
20
21
  title
21
22
  end
22
23
 
@@ -25,27 +26,27 @@ module Barnie
25
26
  end
26
27
 
27
28
  def extract_isbn(string)
28
- string.scan(/e\/\d{11,13}\//).first.gsub(/\D/, "").rjust(13,"0") unless string !~ /\S/
29
+ string.scan(/e\/\d{11,13}\//).first.gsub(/\D/, '').rjust(13, '0') unless string !~ /\S/
29
30
  end
30
31
 
31
32
  def extract_ships_in(string)
32
33
  return nil if string !~ /\S/
33
34
  string = sanitize_string(string)
34
35
 
35
- if string.include?("hours")
36
+ if string.include?('hours')
36
37
  string.scan(/\d{2}/).last.to_i
37
- elsif string.include?("days")
38
+ elsif string.include?('days')
38
39
  string.scan(/\d{1}/).last.to_i * 24
39
40
  end
40
41
  end
41
42
 
42
43
  def extract_link(title)
43
- title.first.attributes["href"].value
44
+ title.first.attributes['href'].value
44
45
  end
45
46
 
46
47
  def extract_authors(html)
47
- authors = html.search(".contrib a")
48
- authors = html.search(".ebookcontrib a") unless authors.any?
48
+ authors = html.search('.contrib a')
49
+ authors = html.search('.ebookcontrib a') unless authors.any?
49
50
  authors.map { |author| sanitize_string(author.text) }
50
51
  end
51
52
 
@@ -0,0 +1,34 @@
1
+ require 'mechanize'
2
+ require 'uri'
3
+
4
+ module Barnie
5
+ class Request
6
+ attr_reader :agent
7
+
8
+ def initialize(user_agent)
9
+ @agent = Mechanize.new { |a| a.user_agent = "iPhone #{user_agent}" }
10
+ end
11
+
12
+ def <<(isbns)
13
+ @isbns = isbns
14
+ end
15
+
16
+ def get
17
+ page = @agent.get(uri)
18
+ Response.new(page)
19
+ end
20
+
21
+ private
22
+
23
+ def query
24
+ "ISBNLIST=#{@isbns[0, 50].join(',')}"
25
+ end
26
+
27
+ def uri
28
+ URI::HTTP.build(
29
+ :host => 'productsearch.barnesandnoble.com',
30
+ :path => '/search/results.aspx',
31
+ :query => query)
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,43 @@
1
+ require 'kosher'
2
+ require 'barnie/helpers'
3
+
4
+ module Barnie
5
+ class Response
6
+ include Helpers
7
+
8
+ attr_accessor :page
9
+
10
+ def initialize(page)
11
+ self.page = page
12
+ end
13
+
14
+ def snapshots
15
+ raise Error.new('Blank page') if page.body == '' && page.code == 200
16
+
17
+ container = page.search('#prod-container')
18
+ container.map do |html|
19
+
20
+ price = extract_price(html.search('.price strong').text)
21
+ hours = extract_ships_in(html.search('.availability').text) || 999
22
+ title = title(html)
23
+ link = extract_link(title)
24
+ isbn = extract_isbn(link)
25
+
26
+ Kosher::Snapshot.new(
27
+ 'bn.com',
28
+ isbn,
29
+ nil,
30
+ nil,
31
+ price > 0 ? 1 : 0,
32
+ price > 0 ?
33
+ [Kosher::Offer.new(
34
+ nil,
35
+ Kosher::Item.new(price, 'USD', 1, Kosher::Condition.new(1), Kosher::Description.new('')),
36
+ Kosher::Seller.new(nil, 'Barnes & Noble.com', nil, Kosher::Location.new('US')),
37
+ Kosher::Shipping.new(0, 'USD', Kosher::Availability.new(hours))
38
+ )] :
39
+ [])
40
+ end
41
+ end
42
+ end
43
+ end
@@ -1,3 +1,3 @@
1
1
  module Barnie #:nodoc:
2
- VERSION = "0.1.3"
2
+ VERSION = '0.2.0'
3
3
  end
data/lib/barnie.rb CHANGED
@@ -1,16 +1,6 @@
1
- require "mechanize"
2
- require "uri"
3
- require "barnie/error"
4
- require "barnie/helpers"
5
- require "barnie/client"
1
+ require 'barnie/request'
2
+ require 'barnie/response'
6
3
 
7
- # = Barnie
8
- # Barnie is a fake Barnes & Noble API
9
4
  module Barnie
10
-
11
- # Instantiates a new Barnie::Request
12
- def self.new(args={})
13
- Barnie::Client.new(args)
14
- end
15
-
5
+ class Error < StandardError; end
16
6
  end
@@ -4,7 +4,7 @@ require "spec_helper"
4
4
  module Barnie
5
5
  describe Helpers do
6
6
  before do
7
- @client = Barnie.new("company details")
7
+ @client = Response.new(nil)
8
8
  end
9
9
 
10
10
  it "sanitizes string" do
@@ -42,8 +42,12 @@ module Barnie
42
42
  end
43
43
 
44
44
  context "requiring real HTML objects" do
45
+ let(:request) do
46
+ Request.new('Company Info')
47
+ end
48
+
45
49
  before do
46
- VCR.insert_cassette('barnie_helpers')
50
+ VCR.insert_cassette('barnie')
47
51
  end
48
52
 
49
53
  after do
@@ -52,8 +56,9 @@ module Barnie
52
56
 
53
57
  context "ebook" do
54
58
  before do
55
- @client.isbns = ["9781400826094"]
56
- @html = @client.request.search("#prod-container").first
59
+ request << ["9781400826094"]
60
+ @client = request.get
61
+ @html = @client.page.search("#prod-container").first
57
62
  end
58
63
 
59
64
  it "returns title as XML NodeSet" do
@@ -75,8 +80,9 @@ module Barnie
75
80
 
76
81
  context "paperback" do
77
82
  before do
78
- @client.isbns = ["9780816614028"]
79
- @html = @client.request.search("#prod-container").first
83
+ request << ["9780816614028"]
84
+ @client = request.get
85
+ @html = @client.page.search("#prod-container").first
80
86
  end
81
87
 
82
88
  it "returns title as XML NodeSet" do
@@ -92,7 +98,7 @@ module Barnie
92
98
  end
93
99
 
94
100
  it "extracts authors" do
95
- @client.extract_authors(@html).should =~ ["Felix Guattari", "Gilles Deleuze"]
101
+ @client.extract_authors(@html).should =~ ["Brian Massumi", "Gilles Deleuze"]
96
102
  end
97
103
  end
98
104
  end
@@ -0,0 +1,48 @@
1
+ require 'spec_helper'
2
+
3
+ module Barnie
4
+ describe Request do
5
+ let (:request) { Request.new('Company Info') }
6
+
7
+ before do
8
+ VCR.insert_cassette('barnie')
9
+ end
10
+
11
+ after do
12
+ VCR.eject_cassette
13
+ end
14
+
15
+ describe ".new" do
16
+ it "requires user agent" do
17
+ expect do
18
+ Request.new
19
+ end.to raise_error /wrong number of arguments/
20
+ end
21
+
22
+ it "sets up a Mechanize agent" do
23
+ request.instance_variable_get(:@agent).should be_an_instance_of Mechanize
24
+ end
25
+ end
26
+
27
+ describe "#<<" do
28
+ it "sets the ISBNs to query" do
29
+ request << isbns
30
+ request.instance_variable_get(:@isbns).should == isbns
31
+ end
32
+ end
33
+
34
+ describe "#get" do
35
+ it "gets a response" do
36
+ request << isbns[0, 50]
37
+ response = request.get
38
+ response.should be_an_instance_of Response
39
+ end
40
+
41
+ it "raises an exception if no ISBNs are specified" do
42
+ expect do
43
+ request.get
44
+ end.to raise_error
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,91 @@
1
+ require 'spec_helper'
2
+
3
+ module Barnie
4
+ describe Response do
5
+ let(:request) do
6
+ Request.new('Company Info')
7
+ end
8
+
9
+ let(:response) do
10
+ request << isbns[0, 50]
11
+ request.get
12
+ end
13
+
14
+ before do
15
+ VCR.insert_cassette('barnie')
16
+ end
17
+
18
+ after do
19
+ VCR.eject_cassette
20
+ end
21
+
22
+ it "includes Helpers" do
23
+ Response.ancestors.should include Helpers
24
+ end
25
+
26
+ describe "#snapshots" do
27
+ it "returns snapshots" do
28
+ snapshots = response.snapshots
29
+
30
+ snapshots.should be_an_instance_of Array
31
+ snapshots.first.should be_a Kosher::Snapshot
32
+ end
33
+
34
+ it "returns a result for a single ISBN" do
35
+ request << [isbns.first]
36
+ response = request.get
37
+
38
+ response.snapshots.size.should eql 1
39
+ end
40
+
41
+ context "when page does not include #prod-container element" do
42
+
43
+ let(:mock_page) do
44
+ page = mock("response")
45
+ page.stub!(:search).and_return(nil)
46
+ page
47
+ end
48
+
49
+ context "when page body is empty and HTTP is OK" do
50
+ before do
51
+ mock_page.stub!(:body).and_return("")
52
+ mock_page.stub!(:code).and_return(200)
53
+ end
54
+
55
+ it "throws a Barnie error" do
56
+ expect do
57
+ Response.new(mock_page).snapshots
58
+ end.to raise_error Barnie::Error, 'Blank page'
59
+ end
60
+ end
61
+ end
62
+
63
+ it "returns a book that is available for sale" do
64
+ request << ['9780816614028']
65
+ response = request.get
66
+ snapshot = response.snapshots.first
67
+ snapshot.offers_count.should eql 1
68
+ end
69
+
70
+ it "returns an ebook" do
71
+ request << ["9781400826094", "9780203029923"]
72
+ request.get.snapshots.each do |snapshot|
73
+ snapshot.isbn.should be_an_instance_of String
74
+ snapshot.offers.first.price.cents.should > 0
75
+ snapshot.offers.first.shipping.should_not be_kosher
76
+ end
77
+ end
78
+
79
+ it "returns a book that is not available for sale" do
80
+ request << ["9780002189347"]
81
+ snapshot = request.get.snapshots.first
82
+ snapshot.offers_count.should eql 0
83
+ end
84
+
85
+ it "does not return a book that is not in the Barnes & Noble catalogue" do
86
+ request << ["9780002196642"]
87
+ request.get.snapshots.should be_empty
88
+ end
89
+ end
90
+ end
91
+ end