As of the beginning of 2007, ISBN10 is dead. Now we’re in a world that allows “979” prefixes, though the following code doesn’t expect them yet…
Here’s some stuff to turn your 10-digit ISBNs into 13-digit ISBNs, naively assuming “978”, following an the API post doing the same from LibraryThing. There’s another one at isbn.org for humans.
Code from O’Reilly’s internal stuff:
module Isbn def self.dash_isbn(isbn) raise ArgumentError.new("ISBN argument must be string") unless isbn.is_a?(String) if isbn.length == 10 return isbn[/^./] + "-" + isbn[1..3] + "-" + isbn[4..8] + "-" + isbn[/.$/] elsif isbn.length == 13 return isbn[0..2] + "-" + isbn[3].chr + "-" + isbn[4..6] + "-" + isbn[7..11] + "-" + isbn[/.$/] else raise ArgumentError.new("ISBN must be 10 or 13 characters") end end def self.isbn10toisbn13(isbn) raise ArgumentError.new("ISBN argument must be string") unless isbn.is_a?(String) raise ArgumentError.new("ISBN must be of length 10") unless isbn.length == 10 prefix = "978" isbn12 = prefix + isbn[0...-1] return isbn12 + check_digit_13(isbn12).to_s end def self.check_digit_13(isbn_12) # http://www.barcodeisland.com/ean13.phtml # need to subtract remainder from 10 # and do exemption for zero LMS 08.29.2006 raise ArgumentError.new("ISBN must be of length 12") unless isbn_12.length == 12 sum = 0 odds = 0 evens = 0 isbn_12.scan(/\d/).each_with_index {|d, i| if (i % 2) == 0 evens = evens + (d.to_i * 1) else odds = odds + (d.to_i * 3) end } sum = evens + odds digit = sum % 10 if digit.zero? return 0 else return 10 - digit end end end # of module Isbns
The last test method relies on my database, which you won’t have. Replace it with something else you trust or drop it.
#!/usr/bin/env ruby require 'test/unit' require 'pdb' require 'isbn' class IsbnTest < Test::Unit::TestCase def setup @isbn10 = "059610123X" @isbn13 = "978059610123X" end def test_dash_isbn # must be a String assert_raise ArgumentError do Isbn.dash_isbn(123) end # must be 10 or 13 characters assert_raise ArgumentError do Isbn.dash_isbn("123") end assert_equal("0-596-10123-X", Isbn.dash_isbn(@isbn10)) assert_equal("978-0-596-10123-X", Isbn.dash_isbn(@isbn13)) end def test_isbn10toisbn13 # must be a String assert_raise ArgumentError do Isbn.isbn10toisbn13(123) end # must be 10 characters assert_raise ArgumentError do Isbn.isbn10toisbn13(@isbn13) end assert_equal("9780596101237", Isbn.isbn10toisbn13(@isbn10)) end def test_check_digit_13 # must be 12 characters assert_raise ArgumentError do Isbn.check_digit_13(@isbn13) end assert_equal(7, Isbn.check_digit_13(@isbn13[0..-2])) assert_equal(0, Isbn.check_digit_13("123456789018")) end def test_isbn13 ["0596008627", "1565929470", "0596002734", "0596004001", "0596527357", "0596101635", "0596005059", "0596527063", "1565926374", "0596526946", "1565926420", "0596101805", "059652742X", "156592455X", "0596006446", "0596008473", "0596009607", "0596100582", "0596100493", "0596004427", "1565925890", "1565927141", "059651610X"].each {|isbn| puts "Testing #{isbn}" assert_equal(PDB::ProdDB.new(isbn).isbn13, Isbn.isbn10toisbn13(isbn), "Bad checksum!") } end end