Module: StdNum::ISBN

Extended by:
Helpers
Defined in:
lib/library_stdnums.rb

Overview

Validate, convert, and normalize ISBNs (10-digit or 13-digit)

Constant Summary

TEN_TO_THIRTEEN_PREFIX =
'978'.freeze
VALID_THIRTEEN_PREFIX =
/\A97[89]/

Constants included from Helpers

Helpers::STDNUMPAT, Helpers::STDNUMPAT_MULTIPLE

Class Method Summary collapse

Methods included from Helpers

extractNumber, extract_multiple_numbers, reduce_to_basics

Class Method Details

.allNormalizedValues(isbn) ⇒ Array<String,String>?

Return an array of the ISBN13 and ISBN10 (in that order) for the passed in value. You'll only get one value back if it's a 13-digit ISBN that can't be converted to an ISBN10. it can't be recognized.

Examples:

Get the normalized values and index them (if valid) or original value (if not)

norms = StdNum::ISBN.allNormalizedValues(rawisbn)
doc['isbn'] = norms ? norms : [rawisbn]


180
181
182
183
184
185
186
187
188
189
# File 'lib/library_stdnums.rb', line 180

def self.allNormalizedValues isbn
  isbn = reduce_to_basics isbn, [10,13]
  return [] unless isbn
  case isbn.size
  when 10
    return [self.convert_to_13(isbn), isbn]
  when 13
    return [isbn, self.convert_to_10(isbn)].compact
  end
end

.at_least_trying?(isbn) ⇒ Boolean

Does it even look like an ISBN?



71
72
73
# File 'lib/library_stdnums.rb', line 71

def self.at_least_trying? isbn
  reduce_to_basics(isbn, [10,13]) ? true : false
end

.checkdigit(isbn, preprocessed = false) ⇒ String?

Compute check digits for 10 or 13-digit ISBNs. See algorithm at http://en.wikipedia.org/wiki/International_Standard_Book_Number



81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
# File 'lib/library_stdnums.rb', line 81

def self.checkdigit isbn, preprocessed = false
  isbn = reduce_to_basics isbn, [10,13] unless preprocessed
  return nil unless isbn

  checkdigit = 0
  if isbn.size == 10
    digits = isbn[0..8].split(//).map {|i| i.to_i}
    (1..9).each do |i|
      checkdigit += digits[i-1] * i
    end
    checkdigit = checkdigit % 11
    return 'X' if checkdigit == 10
    return checkdigit.to_s
  else # size == 13
    checkdigit = 0
    digits = isbn[0..11].split(//).map {|i| i.to_i}
    6.times do
      checkdigit += digits.shift
      checkdigit += digits.shift * 3
    end
    check = 10 - (checkdigit % 10)
    check = 0 if check == 10
    return check.to_s
  end
end

.convert_to_10(isbn) ⇒ String

Convert to 10 if it's 13 digits and the first three digits are 978. Pass through anything 10-digits, and return nil for everything else.



157
158
159
160
161
162
163
164
165
166
167
168
# File 'lib/library_stdnums.rb', line 157

def self.convert_to_10 isbn
  isbn = reduce_to_basics isbn, [10,13]

  # Already 10 digits? Just return
  return isbn if isbn.size == 10

  # Can't be converted to ISBN-10? Bail
  return nil unless isbn[0..2] == TEN_TO_THIRTEEN_PREFIX

  prefix = isbn[3..11]
  return prefix + self.checkdigit(prefix + '0')
end

.convert_to_13(isbn) ⇒ String?

To convert to an ISBN13, throw a '978' on the front and compute the checkdigit We leave 13-digit numbers alone, figuring they're already ok. NO CHECKSUM CHECK IS DONE FOR 13-DIGIT ISBNS! and return nil on anything that's not the right length



143
144
145
146
147
148
149
150
# File 'lib/library_stdnums.rb', line 143

def self.convert_to_13 isbn
  isbn = reduce_to_basics isbn, [10,13]
  return nil unless isbn
  return nil unless valid?(isbn, true)
  return isbn if isbn.size == 13
  prefix = TEN_TO_THIRTEEN_PREFIX + isbn[0..8]
  return prefix + self.checkdigit(prefix + '0', true)
end

.normalize(rawisbn) ⇒ String?

For an ISBN, normalizing it is the same as converting to ISBN 13 and making sure it's valid



128
129
130
131
132
133
134
135
# File 'lib/library_stdnums.rb', line 128

def self.normalize rawisbn
  isbn = convert_to_13 rawisbn
  if isbn
    return isbn
  else
    return nil
  end
end

.valid?(isbn, preprocessed = false) ⇒ Boolean

Check to see if the checkdigit is correct



113
114
115
116
117
118
119
120
# File 'lib/library_stdnums.rb', line 113

def self.valid? isbn, preprocessed = false
  return nil if isbn.nil?
  isbn = reduce_to_basics(isbn, [10,13]) unless preprocessed
  return nil unless isbn
  return false unless isbn[-1..-1] == self.checkdigit(isbn, true)
  return false unless isbn.size == 10 || valid_isbn13_prefix?(isbn)
  return true
end

.valid_isbn13_prefix?(isbn13) ⇒ Boolean

Checks for a valid ISBN13 prefix ISBN13 always starts with 978 or 979. For example: 1000000000012 has a valid check digit, but is not a valid ISBN13.



196
197
198
# File 'lib/library_stdnums.rb', line 196

def self.valid_isbn13_prefix?(isbn13)
  isbn13.size == 13 and !!VALID_THIRTEEN_PREFIX.match(isbn13)
end