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

Constants included from Helpers

Helpers::STDNUMPAT

Class Method Summary collapse

Methods included from Helpers

extractNumber, 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]


164
165
166
167
168
169
170
171
172
173
# File 'lib/library_stdnums.rb', line 164

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?



56
57
58
# File 'lib/library_stdnums.rb', line 56

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



66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
# File 'lib/library_stdnums.rb', line 66

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.



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

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] == '978'

  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



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

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 = '978' + 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



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

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



98
99
100
101
102
103
104
# File 'lib/library_stdnums.rb', line 98

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 true
end