mroch-campusbooks 0.1.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/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: 1
@@ -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,20 @@
1
+ Copyright 2006, Thierry Godfroid
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ * The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission.
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
16
+ INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
17
+ PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
18
+ HOLDERS BE 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 WITH THE
20
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,60 @@
1
+ == ISBN-Tools for Ruby
2
+
3
+ This library provides the ability to manipulate ISBN numbers.
4
+ It knows about ISBN-10 and ISBN-13 numbers, has the ability to
5
+ check if they are valid and convert from one format to the other.
6
+ It can, of course, compute the check digit of both formats.
7
+
8
+ Finally, it has the ability to hyphenate ISBN numbers for the
9
+ following group identifiers: 0, 1 and 2. Note that only hyphenation
10
+ methods need to know about ranges, so all others methods (validity,
11
+ checksum computations and number conversions) can be used with ISBN
12
+ numbers from any group.
13
+
14
+ Other ranges could be added on request but I would need samples
15
+ ISBN to check the result.
16
+
17
+ == Usage
18
+
19
+ require 'rubygems'
20
+ require 'isbn/tools'
21
+
22
+ isbn_good = "2800107766"
23
+ isbn_bad = "2810107766"
24
+
25
+ def check_and_hyphenate(isbn)
26
+ if ISBN_Tools.is_valid?(isbn)
27
+ puts ISBN_Tools.hyphenate(isbn)
28
+ else
29
+ cksum = ISBN_Tools.compute_check_digit(isbn)
30
+ puts "Invalid ISBN number [#{isbn}]. Checksum should be #{cksum}"
31
+ end
32
+ end
33
+
34
+ check_and_hyphenate isbn_good # => 2-8001-0776-6
35
+ check_and_hyphenate isbn_bad # => Invalid ISBN number [2810107766]. Checksum should be 9
36
+
37
+ == Copyright
38
+
39
+ Copyright:: 2006, Thierry Godfroid
40
+
41
+ The following sources were used in order to understand ISBN numbers and
42
+ how to manipulate them. No books were harmed in the process.
43
+ - http://www.isbn-international.org
44
+ - "Are You Ready for ISBN-13?" http://www.isbn.org/standards/home/isbn/transition.asp. Note that at the bottom of this page, you can find a link towards a small book "ISBN-13 for Dummies", available as PDF (http://www.bisg.org/isbn-13/ISBN13_For_Dummies.pdf)
45
+ - Structure of an ISBN number http://www.isbn.org/standards/home/isbn/international/html/usm4.htm
46
+
47
+ Ranges information was found at http://www.isbn-international.org/en/identifiers.html.
48
+
49
+ == LICENCE NOTE
50
+
51
+ MIT-Style license. See LICENCE file in this distribution.
52
+
53
+ == Requirements
54
+
55
+ ISBN-Tools requires Ruby 1.8.2 or better.
56
+
57
+ == Known bugs/Limitations
58
+
59
+ - This release code only allows for one-digit groups.
60
+ - See also the TODO file in this distribution
@@ -0,0 +1,173 @@
1
+ #--
2
+ # Copyright 2006, Thierry Godfroid
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ # of this software and associated documentation files (the "Software"), to deal
6
+ # in the Software without restriction, including without limitation the rights
7
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ # copies of the Software, and to permit persons to whom the Software is
9
+ # furnished to do so, subject to the following conditions:
10
+ #
11
+ # * The name of the author may not be used to endorse or promote products derived
12
+ # from this software without specific prior written permission.
13
+ #
14
+ # The above copyright notice and this permission notice shall be included in all
15
+ # copies or substantial portions of the Software.
16
+ #
17
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
18
+ # INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
19
+ # PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
20
+ # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
22
+ # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
+ #++
24
+
25
+ # This module provides all the methods of the ISBN-Tools library.
26
+ # Methods have no state but the library reads the file data/ranges.dat
27
+ # and fills up the RNG hash when loaded.
28
+ module ISBN_Tools
29
+ # Supported groups and associated ranges. Data is read from data/ranges.dat
30
+ # (provided in gem) at module load.
31
+ RNG = {}
32
+
33
+ File.open(File.join(File.dirname(__FILE__), "../../data/ranges.dat")) do |file|
34
+ file.each do |line|
35
+ line.chomp!
36
+ break if line.empty?
37
+ ar_line = line.split(/,/)
38
+ ndx = ar_line.delete_at(0)
39
+ RNG[ndx] = []
40
+ ar_line.each { |item|
41
+ r = item.split(/\.\./)
42
+ RNG[ndx].push(Range.new(r[0],r[1]))
43
+ }
44
+ end
45
+ end
46
+
47
+ # Clear all useless characters from an ISBN number and upcase the 'X' sign when
48
+ # present. Also does the basic check that 'X' must be the last sign of the number,
49
+ # if present. Returns nil if provided string is nil or X is not at the last position.
50
+ #
51
+ # No length check is done: no matter what string is passed in, all characters that
52
+ # not in the range [0-9xX] are removed.
53
+ def ISBN_Tools.cleanup(isbn_)
54
+ isbn_.gsub(/[^0-9xX]/,'').gsub(/x/,'X') unless isbn_.nil? or isbn_.scan(/([xX])/).length > 1
55
+ end
56
+
57
+ # Same as cleanup but alters the argument.
58
+ def ISBN_Tools.cleanup!(isbn_)
59
+ isbn_.replace(cleanup(isbn_))
60
+ end
61
+
62
+ # Check that the value is a valid ISBN-10 number. Returns true if it is, false otherwise.
63
+ # The method will check that the number is exactly 10 digits long and that the tenth digit is
64
+ # the correct checksum for the number.
65
+ def ISBN_Tools.is_valid_isbn10?(isbn_)
66
+ isbn = cleanup(isbn_)
67
+ return false if isbn.nil? or isbn.match(/^[0-9]{9}[0-9X]$/).nil?
68
+ sum = 0;
69
+ 0.upto(9) { |ndx| sum += (isbn[ndx]!= 88 ? isbn[ndx].chr.to_i : 10) * (10-ndx) } # 88 is ascii of X
70
+ sum % 11 == 0
71
+ end
72
+
73
+ # Check that the value is a valid ISBN-13 number. Returns true if it is, false otherwise.
74
+ # The method will check that the number is exactly 13 digits long and that the thirteenth digit is
75
+ # the correct checksum for the number.
76
+ def ISBN_Tools.is_valid_isbn13?(isbn_)
77
+ isbn = cleanup(isbn_)
78
+ return false if isbn.nil? or isbn.length!=13 or isbn.match(/^97[8|9][0-9]{10}$/).nil?
79
+ sum = 0
80
+ 0.upto(12) { |ndx| sum += isbn[ndx].chr.to_i * (ndx % 2 == 0 ? 1 : 3) }
81
+ sum.remainder(10) == 0
82
+ end
83
+
84
+ # Check that an ISBN is valid or not. Returns true if is, false otherwise. This method will
85
+ # first call is_valid_isbn10() and, on failure, try is_valid_isbn13(). Returns true if it is
86
+ # a valid number, false otherwise.
87
+ # This method is handy if you don't want to be bothered by checking the length of your
88
+ # isbn before checking its validity. It is a bit slower since cleanup will be called twice.
89
+ def ISBN_Tools.is_valid?(isbn_)
90
+ is_valid_isbn10?(isbn_) || is_valid_isbn13?(isbn_)
91
+ end
92
+
93
+ # Computes the check digit of an ISBN-10 number. It will ignore the tenth sign if present
94
+ # and accepts a number with only 9 digits. Returns the checksum digit or nil. Please note
95
+ # that the checksum digit of an ISBN-10 may be the character 'X'.
96
+ def ISBN_Tools.compute_isbn10_check_digit(isbn_)
97
+ isbn = cleanup(isbn_)
98
+ return nil if isbn.nil? or isbn.length > 10 or isbn.length < 9
99
+ sum = 0;
100
+ 0.upto(8) { |ndx| sum += isbn[ndx].chr.to_i * (10-ndx) }
101
+ (11-sum) % 11 == 10 ? "X" : ((11-sum) % 11).to_s
102
+ end
103
+
104
+ # Computes the check digit of an ISBN-13 number. It will ignore the thirteenth sign if present
105
+ # and accepts a number with only 12 digits. Returns the checksum digit or nil. Please note
106
+ # that the checksum digit of an ISBN-13 is always in the range [0-9].
107
+ def ISBN_Tools.compute_isbn13_check_digit(isbn_)
108
+ isbn = cleanup(isbn_)
109
+ return nil if isbn.nil? or isbn.length > 13 or isbn.length < 12
110
+ sum = 0
111
+ 0.upto(11) { |ndx| sum += isbn[ndx].chr.to_i * (ndx % 2 == 0 ? 1 : 3) }
112
+ (10-sum.remainder(10)) == 10 ? "0" : (10-sum.remainder(10)).to_s
113
+ end
114
+
115
+ # Compute the check digit of an ISBN number. Try as an ISBN-10 number
116
+ # first, and if it failed, as an ISBN-13 number. Returns the check digit or
117
+ # nil if a processing error occured.
118
+ # This method is a helper for compute_isbn10_check_digit and
119
+ # compute_isbn13_check_digit.
120
+ def ISBN_Tools.compute_check_digit(isbn_)
121
+ compute_isbn10_check_digit(isbn_) || compute_isbn13_check_digit(isbn_)
122
+ end
123
+
124
+ # Convert an ISBN-10 number to its equivalent ISBN-13 number. Returns the converted number or nil
125
+ # if the provided ISBN-10 number is nil or non valid.
126
+ def ISBN_Tools.isbn10_to_isbn13(isbn_)
127
+ isbn = cleanup(isbn_)
128
+ "978" + isbn[0..8] + compute_isbn13_check_digit("978" + isbn[0..8]) unless isbn.nil? or ! is_valid_isbn10?(isbn)
129
+ end
130
+
131
+ # Convert an ISBN-13 number to its equivalent ISBN-10 number. Returns the converted number or nil
132
+ # if the provided ISBN-13 number is nil or non valid. Please note that only ISBN-13 numbers starting
133
+ # with 978 can be converted.
134
+ def ISBN_Tools.isbn13_to_isbn10(isbn_)
135
+ isbn = cleanup(isbn_)
136
+ isbn[3..11] + compute_isbn10_check_digit(isbn[3..11]) unless isbn.nil? or ! is_valid_isbn13?(isbn) or ! isbn_.match(/^978.*/)
137
+ end
138
+
139
+ # Hyphenate a valid ISBN-10 number. Returns nil if the number is invalid or if the group range is
140
+ # unknown. Works only for groups 0,1 and 2.
141
+ def ISBN_Tools.hyphenate_isbn10(isbn_)
142
+ isbn = cleanup(isbn_)
143
+ group = isbn[0..0]
144
+ if RNG.has_key?(group) and is_valid_isbn10?(isbn)
145
+ RNG[group].each { |r| return isbn.sub(Regexp.new("(.{1})(.{#{r.last.length}})(.{#{8-r.last.length}})(.)"),'\1-\2-\3-\4') if r.member?(isbn[1..r.last.length]) }
146
+ end
147
+ end
148
+
149
+ # Hyphenate a valid ISBN-13 number. Returns nil if the number is invalid or if the group range is
150
+ # unknown. Works only for groups 0,1 and 2.
151
+ def ISBN_Tools.hyphenate_isbn13(isbn_)
152
+ isbn = cleanup(isbn_)
153
+ if is_valid_isbn13?(isbn)
154
+ group = isbn[3..3]
155
+ if RNG.has_key?(group)
156
+ RNG[group].each { |r| return isbn.sub(Regexp.new("(.{3})(.{1})(.{#{r.last.length}})(.{#{8-r.last.length}})(.)"),'\1-\2-\3-\4-\5') if r.member?(isbn[1..r.last.length]) }
157
+ end
158
+ end
159
+ end
160
+
161
+ # This method takes an ISBN then tries to hyphenate it as an ISBN 10 then an ISBN 13. A bit slower
162
+ # than calling the right one directly but saves you the length checking. Returns an hyphenated value
163
+ # or nil.
164
+ def ISBN_Tools.hyphenate(isbn_)
165
+ hyphenate_isbn10(isbn_) || hyphenate_isbn13(isbn_)
166
+ end
167
+
168
+ # Same as hyphenate() but alters the argument.
169
+ def ISBN_Tools.hyphenate!(isbn_)
170
+ isbn_.replace(hyphenate(isbn_))
171
+ end
172
+
173
+ 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,79 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: mroch-campusbooks
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Marshall Roch
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-08-27 00:00:00 -07:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: httparty
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: "0"
24
+ version:
25
+ description: A Ruby library for accessing the CampusBooks.com API
26
+ email: marshall@mroch.com
27
+ executables: []
28
+
29
+ extensions: []
30
+
31
+ extra_rdoc_files:
32
+ - README.rdoc
33
+ - LICENSE
34
+ files:
35
+ - README.rdoc
36
+ - VERSION.yml
37
+ - lib/campusbooks
38
+ - lib/campusbooks/base.rb
39
+ - lib/campusbooks/book.rb
40
+ - lib/campusbooks/offer.rb
41
+ - lib/campusbooks.rb
42
+ - lib/isbn
43
+ - lib/isbn/LICENCE
44
+ - lib/isbn/README
45
+ - lib/isbn/tools.rb
46
+ - test/base_test.rb
47
+ - test/book_test.rb
48
+ - test/offer_test.rb
49
+ - test/test_helper.rb
50
+ - LICENSE
51
+ has_rdoc: true
52
+ homepage: http://github.com/mroch/campusbooks
53
+ post_install_message:
54
+ rdoc_options:
55
+ - --inline-source
56
+ - --charset=UTF-8
57
+ require_paths:
58
+ - lib
59
+ required_ruby_version: !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - ">="
62
+ - !ruby/object:Gem::Version
63
+ version: "0"
64
+ version:
65
+ required_rubygems_version: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - ">="
68
+ - !ruby/object:Gem::Version
69
+ version: "0"
70
+ version:
71
+ requirements: []
72
+
73
+ rubyforge_project:
74
+ rubygems_version: 1.2.0
75
+ signing_key:
76
+ specification_version: 2
77
+ summary: CampusBooks API for Ruby
78
+ test_files: []
79
+