diff --git a/lib/lisbn/lisbn.rb b/lib/lisbn/lisbn.rb index 6d25ce0..c6446ff 100644 --- a/lib/lisbn/lisbn.rb +++ b/lib/lisbn/lisbn.rb @@ -6,18 +6,30 @@ def isbn # Returns true if the ISBN is valid, false otherwise. def valid? + case isbn.length + when 10 + valid_isbn_10? + when 13 + valid_isbn_13? + else + false + end + end + + # Returns true if the ISBN is valid, false otherwise. + def valid_checksum? case isbn.length when 10 - valid_isbn_10? + valid_checksum_isbn_10? when 13 - valid_isbn_13? + valid_checksum_isbn_13? else false end end def isbn_with_dash - if valid_isbn_13? && parts + if valid_checksum_isbn_13? && parts parts.join("-") elsif isbn.length > 3 isbn[0..-2] + "-" + isbn[-1] @@ -39,7 +51,7 @@ def isbn10 # Returns a valid ISBN in ISBN-13 format. # Returns nil if the ISBN is invalid. def isbn13 - return unless valid? + return unless valid_checksum? return isbn if isbn.length == 13 '978' + isbn[0..-2] + isbn_13_checksum @@ -138,19 +150,27 @@ def isbn_13_checksum (10 - sum % 10).to_s[-1] end - cache_method :isbn, :valid?, :isbn10, :isbn13, :parts, :isbn_10_checksum, :isbn_13_checksum + cache_method :isbn, :valid?, :valid_checksum?, :isbn10, :isbn13, :parts, :isbn_10_checksum, :isbn_13_checksum private - def valid_isbn_10? + def valid_checksum_isbn_10? return false unless isbn.match(/^[0-9]{9}[0-9X]$/) isbn[-1..-1] == isbn_10_checksum end - def valid_isbn_13? + def valid_checksum_isbn_13? return false unless isbn.match(/^[0-9]{13}$/) isbn[-1..-1] == isbn_13_checksum end + def valid_isbn_10? + !parts(4).blank? + end + + def valid_isbn_13? + !parts.blank? + end + RANGES = YAML::load_file(File.dirname(__FILE__) + "/../../data/ranges.yml") end diff --git a/spec/lisbn_spec.rb b/spec/lisbn_spec.rb index 4beedba..7742213 100644 --- a/spec/lisbn_spec.rb +++ b/spec/lisbn_spec.rb @@ -44,6 +44,16 @@ isbn.valid?.should be false end + it "recognizes an invalid ISBN13 with valid checksum" do + isbn = Lisbn.new("8830114722800") + isbn.valid?.should be false + end + + it "recognizes an invalid ISBN10 with valid checksum" do + isbn = Lisbn.new("8830114722800") + isbn.valid?.should be false + end + it "returns false for improperly-formatted ISBNs" do isbn = Lisbn.new("97800000X0002") isbn.valid?.should be false @@ -55,6 +65,54 @@ end end + + describe "#valid_checksum?" do + it "recognizes a valid checksum for ISBN10 format" do + isbn = Lisbn.new("0123456789") + isbn.valid_checksum?.should be true + end + + it "recognizes a valid checksum for ISBN10 with X" do + isbn = Lisbn.new("160459411X") + isbn.valid_checksum?.should be true + end + + it "recognizes a valid checksum for ISBN10 with 0" do + isbn = Lisbn.new("0679405070") + isbn.valid_checksum?.should be true + end + + it "recognizes an invalid ISBN10 checksum" do + isbn = Lisbn.new("0123546789") + isbn.valid_checksum?.should be false + end + + it "recognizes a valid checksum for ISBN13 format" do + isbn = Lisbn.new("9780000000002") + isbn.valid_checksum?.should be true + end + + it "recognizes a valid checksum for ISBN13 with 0" do + isbn = Lisbn.new("9780062870780") + isbn.valid_checksum?.should be true + end + + it "recognizes an invalid checksum for ISBN13" do + isbn = Lisbn.new("9780000000003") + isbn.valid_checksum?.should be false + end + + it "returns false for improperly-formatted ISBNs" do + isbn = Lisbn.new("97800000X0002") + isbn.valid_checksum?.should be false + end + + it "regards anything not 10 or 13 digits as invalid" do + isbn = Lisbn.new("") + isbn.valid_checksum?.should be false + end + end + describe "#isbn_with_dash" do subject { Lisbn.new(isbn) } @@ -87,13 +145,13 @@ subject { Lisbn.new("9780000000002") } it "returns nil if invalid" do - subject.stub(:valid? => false) + subject.stub(:valid_checksum? => false) subject.isbn10.should be_nil end it "returns nil if the ISBN is 13-digits and isn't in the 978 GS1" do lisbn = Lisbn.new("9790000000003") - lisbn.stub(:valid? => true) + lisbn.stub(:valid_checksum? => true) lisbn.isbn10.should be_nil end @@ -103,7 +161,7 @@ it "returns the isbn if it's 10 digits" do lisbn = Lisbn.new("0000000000") - lisbn.stub(:valid? => true) + lisbn.stub(:valid_checksum? => true) lisbn.should_not_receive(:isbn_10_checksum) lisbn.isbn10.should == "0000000000" end @@ -113,7 +171,7 @@ subject { Lisbn.new("0000000000") } it "returns nil if invalid" do - subject.stub(:valid? => false) + subject.stub(:valid_checksum? => false) subject.isbn13.should be_nil end @@ -123,7 +181,7 @@ it "returns the isbn if it's 13 digits" do lisbn = Lisbn.new("9780000000002") - lisbn.stub(:valid? => true) + lisbn.stub(:valid_checksum? => true) lisbn.should_not_receive(:isbn_13_checksum) lisbn.isbn13.should == "9780000000002" end