campusbooks 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Marshall Roch
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,7 @@
1
+ = campusbooks
2
+
3
+ Description goes here.
4
+
5
+ == Copyright
6
+
7
+ Copyright (c) 2009 Marshall Roch. See LICENSE for details.
@@ -0,0 +1,4 @@
1
+ ---
2
+ :patch: 0
3
+ :major: 0
4
+ :minor: 2
@@ -0,0 +1,15 @@
1
+ module CampusBooks
2
+ class Error < StandardError ; end
3
+
4
+ def self.api_key
5
+ @api_key
6
+ end
7
+
8
+ def self.api_key=(key)
9
+ @api_key = key
10
+ end
11
+ end
12
+
13
+ require 'campusbooks/base'
14
+ require 'campusbooks/book'
15
+ require 'campusbooks/offer'
@@ -0,0 +1,25 @@
1
+ require 'httparty'
2
+
3
+ module CampusBooks
4
+ class Base
5
+ include HTTParty
6
+ base_uri 'http://api.campusbooks.com/3/rest'
7
+ format :xml
8
+
9
+ protected
10
+ def self.get_response(path, options={})
11
+ res = self.get(path, options)
12
+ case res['response']['status']
13
+ when 'ok'
14
+ return res['response']
15
+
16
+ when 'error'
17
+ err_count = res['response']['errors']['error'].length
18
+ raise Error, err_count == 1 ? 'An error' : "#{err_count} errors" +
19
+ " occured while getting path '#{path}' with options #{options.inspect}:\n " +
20
+ res['response']['errors']['error'].join("\n ")
21
+ end
22
+ end
23
+
24
+ end
25
+ end
@@ -0,0 +1,83 @@
1
+ require 'isbn/tools'
2
+
3
+ module CampusBooks
4
+ class Book < Base
5
+ SUPPORTED_PARAMS = [
6
+ :isbn10, # Ten-Digit ISBN for this book
7
+ :isbn13, # Thirteen-Digit ISBN for this book
8
+ :title, # Book Title
9
+ :author, # Book Author
10
+ :binding, # Book Binding
11
+ :msrp, # List price for the book
12
+ :pages, # Number of pages in the book
13
+ :publisher, # Book Publisher
14
+ :published_date, # Published Date
15
+ :edition, # Edition
16
+ :description # A text description for the book
17
+ ]
18
+ attr_reader *SUPPORTED_PARAMS
19
+ alias_method :isbn, :isbn13
20
+
21
+ def self.find(isbn, opts = {})
22
+ isbn = isbn.to_s
23
+ canonical_isbn = (ISBN_Tools.is_valid_isbn13?(isbn) ? isbn : ISBN_Tools.isbn10_to_isbn13(isbn)) or raise ArgumentError.new('isbn is invalid')
24
+
25
+ include_prices = opts[:include] && [*opts[:include]].include?(:prices)
26
+
27
+ raw_result = get_response(include_prices ? '/bookprices' : '/bookinfo', :query => {
28
+ :isbn => canonical_isbn, :key => CampusBooks.api_key
29
+ })
30
+
31
+ book_params = include_prices ? raw_result['page']['book'] : raw_result['page']
32
+
33
+ if raw_result['page']['offers']
34
+ book_params['offers'] = flatten_offers(raw_result['page']['offers'])
35
+ end
36
+
37
+ new(book_params)
38
+ end
39
+
40
+ def initialize(params = {})
41
+ create_offers(params.delete('offers')) if params.key?('offers')
42
+
43
+ SUPPORTED_PARAMS.each do |param|
44
+ instance_variable_set("@#{param}", params[param.to_s]) if params.key?(param.to_s)
45
+ end
46
+ end
47
+
48
+ def published_date
49
+ @parsed_published_date ||= Date.parse(@published_date)
50
+ end
51
+
52
+ def offers
53
+ if !@offers_loaded
54
+ raw_offers = get_response('/prices', :query => { :isbn => @isbn, :key => CampusBooks.api_key })['page']
55
+ create_offers(self.class.flatten_offers(raw_offers))
56
+ end
57
+ @offers
58
+ end
59
+
60
+ private
61
+ def self.flatten_offers(data)
62
+ result = []
63
+ data['condition'].each do |condition|
64
+ if condition['offer']
65
+ if condition['offer'].is_a?(Array)
66
+ condition['offer'].each do |offer|
67
+ result.push(offer)
68
+ end
69
+ else
70
+ result.push(condition['offer'])
71
+ end
72
+ end
73
+ end
74
+ result
75
+ end
76
+
77
+ def create_offers(offer_hashes)
78
+ @offers = offer_hashes.inject([]) { |ary, offer_hash| ary.push(Offer.new(offer_hash)) }
79
+ @offers_loaded = true
80
+ return @offers
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,35 @@
1
+ module CampusBooks
2
+ class Offer < Base
3
+ SUPPORTED_PARAMS = [
4
+ :isbn, # The ISBN for this offer
5
+ :isbn13, # The thirteen digit ISBN for this offer
6
+ :isbn10, # The ten digit ISBN for this offer
7
+ :merchant_id, # A numeric merchant ID (Note, this value may be signed)
8
+ :merchant_name, # The Name of the merchant (looked up from the defined constants)
9
+ :price, # The price that this merchant is listing this item for
10
+ :shipping_ground, # The cost to ship to an address in the US via ground services
11
+ :total_price, # Seller price plus the ground shipping price
12
+ :link, # Link to purchase the book
13
+ :condition_id, # Numeric representation of the condition (see constants)
14
+ :condition_text, # Text representation of the condition
15
+ :availability_id, # Numeric representation of the availability (how long it takes for the seller to ship it)
16
+ :availability_text, # Text representation of the availability
17
+ :location, # Geographic location where this item ships from (not always present)
18
+ :their_id, # The merchant's id for this offer (not always present)
19
+ :comments, # Comments about this offering
20
+ :condition_text # Text representation of the condition
21
+ ]
22
+ attr_reader *SUPPORTED_PARAMS
23
+
24
+ def initialize(params = {})
25
+ SUPPORTED_PARAMS.each do |param|
26
+ instance_variable_set("@#{param}", params[param.to_s]) if params.key?(param.to_s)
27
+ end
28
+ end
29
+
30
+ # Fall back on ISBN13 or ISBN10 if @isbn isn't set
31
+ def isbn
32
+ @isbn || @isbn13 || @isbn10
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,67 @@
1
+ require 'test_helper'
2
+
3
+ class BaseTest < Test::Unit::TestCase
4
+
5
+ def setup
6
+ CampusBooks.api_key = 'SmT8KuLkGvy7SexotRTB'
7
+ end
8
+
9
+ should "parse OK response and return just the response" do
10
+ expected_response = {
11
+ "status"=>"ok",
12
+ "version"=>"1",
13
+ "page" => {
14
+ "name"=>"bookinfo",
15
+ "rating"=>"5.0",
16
+ "category"=>nil,
17
+ "title"=>"The Ruby Programming Language",
18
+ "isbn10"=>"0596516177",
19
+ "tried_amazon"=>"1",
20
+ "author"=>"David Flanagan - Yukihiro Matsumoto",
21
+ "msrp"=>"39.99",
22
+ "rank"=>"19257",
23
+ "isbn13"=>"9780596516178",
24
+ "publisher"=>"O'Reilly Media, Inc.",
25
+ "pages"=>"446",
26
+ "edition"=>"Paperback",
27
+ "binding"=>"Paperback",
28
+ "published_date"=>"2008-01-25",
29
+ "image"=>"http://ecx.images-amazon.com/images/I/41n-JSlBHkL._SL75_.jpg"
30
+ },
31
+ "label"=>{
32
+ "name"=>"Scheduleman Tartan",
33
+ "plid"=>"1709"
34
+ }
35
+ }
36
+ CampusBooks::Base.expects(:get).once.returns({
37
+ "response" => expected_response
38
+ })
39
+ actual_response = CampusBooks::Base.get_response('/bookinfo', :query => { :isbn => '9780596516178' })
40
+ assert_equal expected_response, actual_response
41
+ end
42
+
43
+ should "raise an exception when an API error occurs" do
44
+ CampusBooks::Base.expects(:get).once.returns({
45
+ "response" => {
46
+ "status" => "error",
47
+ "errors" => {
48
+ "error" => [
49
+ "Permission Denied - Invalid or missing API Key",
50
+ "'isbn' parameter is required",
51
+ "'' is not a valid ISBN",
52
+ "Unable to create a book with isbn "
53
+ ]
54
+ },
55
+ "version" => "3"
56
+ }
57
+ })
58
+ exception = assert_raise CampusBooks::Error do
59
+ CampusBooks::Base.get_response('/bookinfo', :query => { :isbn => '' })
60
+ end
61
+ assert_equal %Q{4 errors occured while getting path '/bookinfo' with options {:query=>{:isbn=>""}}:
62
+ Permission Denied - Invalid or missing API Key
63
+ 'isbn' parameter is required
64
+ '' is not a valid ISBN
65
+ Unable to create a book with isbn }, exception.message
66
+ end
67
+ end
@@ -0,0 +1,100 @@
1
+ require 'test_helper'
2
+
3
+ class BookTest < Test::Unit::TestCase
4
+ VALID_ISBN13 = '9780596516178'
5
+ VALID_ISBN10 = '0596516177'
6
+
7
+ def setup
8
+ CampusBooks.api_key = 'SmT8KuLkGvy7SexotRTB' # 'AbC123dEFG4H5jkl6MNO'
9
+ end
10
+
11
+ should "store ISBN from constructor" do
12
+ mock_successful_request
13
+ book = CampusBooks::Book.find(VALID_ISBN13)
14
+ assert_equal VALID_ISBN13, book.isbn
15
+ end
16
+
17
+ should "convert ISBN10 to ISBN13" do
18
+ mock_successful_request
19
+ book = CampusBooks::Book.find(VALID_ISBN10)
20
+ assert_equal VALID_ISBN13, book.isbn
21
+ end
22
+
23
+ should "validate ISBN during construction" do
24
+ assert_nothing_raised do
25
+ mock_successful_request
26
+ CampusBooks::Book.find(VALID_ISBN10)
27
+ end
28
+ assert_raise ArgumentError, 'isbn is invalid' do
29
+ CampusBooks::Book.find('0-596-51617-8')
30
+ end
31
+ end
32
+
33
+ should "get valid values" do
34
+ mock_successful_request
35
+ book = CampusBooks::Book.find(VALID_ISBN13)
36
+ assert_equal VALID_ISBN10, book.isbn10
37
+ assert_equal VALID_ISBN13, book.isbn13
38
+ assert_equal VALID_ISBN13, book.isbn
39
+ assert_equal 'The Ruby Programming Language', book.title
40
+ assert_equal 'David Flanagan - Yukihiro Matsumoto', book.author
41
+ assert_equal 'Paperback', book.binding
42
+ assert_equal '39.99', book.msrp
43
+ assert_equal '446', book.pages
44
+ assert_equal "O'Reilly Media, Inc.", book.publisher
45
+ assert_equal Date.parse('2008-01-25'), book.published_date
46
+ assert_equal 'Paperback', book.edition
47
+ assert_equal 'Foo bar', book.description
48
+ end
49
+
50
+ should "include prices" do
51
+ book = CampusBooks::Book.find(VALID_ISBN13, :include => :prices)
52
+ end
53
+
54
+ private
55
+ def mock_successful_request
56
+ CampusBooks::Book.expects(:get).once.returns({
57
+ "response" => {
58
+ "status"=>"ok",
59
+ "version"=>"1",
60
+ "page" => {
61
+ "name"=>"bookinfo",
62
+ "rating"=>"5.0",
63
+ "category"=>nil,
64
+ "title"=>"The Ruby Programming Language",
65
+ "isbn10"=>"0596516177",
66
+ "tried_amazon"=>"1",
67
+ "author"=>"David Flanagan - Yukihiro Matsumoto",
68
+ "msrp"=>"39.99",
69
+ "rank"=>"19257",
70
+ "isbn13"=>"9780596516178",
71
+ "publisher"=>"O'Reilly Media, Inc.",
72
+ "pages"=>"446",
73
+ "edition"=>"Paperback",
74
+ "binding"=>"Paperback",
75
+ "published_date"=>"2008-01-25",
76
+ "image"=>"http://ecx.images-amazon.com/images/I/41n-JSlBHkL._SL75_.jpg",
77
+ "description" => 'Foo bar'
78
+ },
79
+ "label"=>{
80
+ "name"=>"Scheduleman Tartan",
81
+ "plid"=>"1709"
82
+ }
83
+ }
84
+ })
85
+ end
86
+
87
+ def mock_failed_request(isbn = '0-596-51617-8')
88
+ CampusBooks::Book.expects(:get).once.returns({
89
+ "response" => {
90
+ "status" => "error",
91
+ "errors" => {
92
+ "error" => [
93
+ "'#{isbn}' is not a valid ISBN"
94
+ ]
95
+ },
96
+ "version" => "3"
97
+ }
98
+ })
99
+ end
100
+ end
@@ -0,0 +1,41 @@
1
+ require 'test_helper'
2
+
3
+ class OfferTest < Test::Unit::TestCase
4
+
5
+ should "set params in constructor" do
6
+ offer = CampusBooks::Offer.new({
7
+ "merchant_id" => "24",
8
+ "price"=>"11.93",
9
+ "shipping_ground"=>"3.99",
10
+ "condition_id"=>"2",
11
+ "availability_id"=>"2",
12
+ "comments"=>"Good condition. Absolutely no highlighting or markings inside the books. Decent covers subject to prior use.",
13
+ "isbn10"=>"0596516177",
14
+ "total_price"=>"15.92",
15
+ "isbn13"=>"9780596516178",
16
+ "merchant_name"=>"Amazon Marketplace",
17
+ "availability_text"=>"Ready to ship",
18
+ "link"=>"http://partners.campusbooks.com/link.php?params=ABCDEF",
19
+ "condition_text"=>"Used"
20
+ })
21
+ #assert_equal '9780596516178', offer.isbn
22
+ assert_equal '9780596516178', offer.isbn13
23
+ assert_equal '0596516177', offer.isbn10
24
+ assert_equal '24', offer.merchant_id
25
+ assert_equal 'Amazon Marketplace', offer.merchant_name
26
+ assert_equal '11.93', offer.price
27
+ assert_equal '3.99', offer.shipping_ground
28
+ assert_equal '15.92', offer.total_price
29
+ assert_equal 'http://partners.campusbooks.com/link.php?params=ABCDEF', offer.link
30
+ assert_equal '2', offer.condition_id
31
+ assert_equal 'Used', offer.condition_text
32
+ assert_equal '2', offer.availability_id
33
+ assert_equal 'Ready to ship', offer.availability_text
34
+
35
+ # FIXME: Need an example of these
36
+ # assert_equal 'foo', offer.location
37
+ # assert_equal 'foo', offer.their_id
38
+ # assert_equal 'foo', offer.comments
39
+ end
40
+
41
+ end
@@ -0,0 +1,19 @@
1
+ require 'rubygems'
2
+ require 'test/unit'
3
+ begin
4
+ require 'shoulda'
5
+ rescue LoadError
6
+ puts "Shoulda not available. Install it with: sudo gem install thoughtbot-shoulda -s http://gems.github.com"
7
+ end
8
+ begin
9
+ require 'mocha'
10
+ rescue LoadError
11
+ puts "Mocha not available. Install it with: sudo gem install mocha"
12
+ end
13
+
14
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
15
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
16
+ require 'campusbooks'
17
+
18
+ class Test::Unit::TestCase
19
+ end
metadata ADDED
@@ -0,0 +1,106 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: campusbooks
3
+ version: !ruby/object:Gem::Version
4
+ hash: 23
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 2
9
+ - 0
10
+ version: 0.2.0
11
+ platform: ruby
12
+ authors:
13
+ - Marshall Roch
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2009-08-31 00:00:00 -07:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: httparty
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ hash: 3
30
+ segments:
31
+ - 0
32
+ version: "0"
33
+ type: :runtime
34
+ version_requirements: *id001
35
+ - !ruby/object:Gem::Dependency
36
+ name: isbn-tools
37
+ prerelease: false
38
+ requirement: &id002 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ hash: 3
44
+ segments:
45
+ - 0
46
+ version: "0"
47
+ type: :runtime
48
+ version_requirements: *id002
49
+ description: A Ruby library for accessing the CampusBooks.com API
50
+ email: marshall@mroch.com
51
+ executables: []
52
+
53
+ extensions: []
54
+
55
+ extra_rdoc_files:
56
+ - README.rdoc
57
+ - LICENSE
58
+ files:
59
+ - README.rdoc
60
+ - VERSION.yml
61
+ - lib/campusbooks/base.rb
62
+ - lib/campusbooks/book.rb
63
+ - lib/campusbooks/offer.rb
64
+ - lib/campusbooks.rb
65
+ - test/base_test.rb
66
+ - test/book_test.rb
67
+ - test/offer_test.rb
68
+ - test/test_helper.rb
69
+ - LICENSE
70
+ has_rdoc: true
71
+ homepage: http://github.com/mroch/campusbooks
72
+ licenses: []
73
+
74
+ post_install_message:
75
+ rdoc_options:
76
+ - --inline-source
77
+ - --charset=UTF-8
78
+ require_paths:
79
+ - lib
80
+ required_ruby_version: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ">="
84
+ - !ruby/object:Gem::Version
85
+ hash: 3
86
+ segments:
87
+ - 0
88
+ version: "0"
89
+ required_rubygems_version: !ruby/object:Gem::Requirement
90
+ none: false
91
+ requirements:
92
+ - - ">="
93
+ - !ruby/object:Gem::Version
94
+ hash: 3
95
+ segments:
96
+ - 0
97
+ version: "0"
98
+ requirements: []
99
+
100
+ rubyforge_project:
101
+ rubygems_version: 1.3.7
102
+ signing_key:
103
+ specification_version: 2
104
+ summary: CampusBooks API for Ruby
105
+ test_files: []
106
+