Class: Identifiers::ISBN
- Inherits:
-
Object
- Object
- Identifiers::ISBN
- Defined in:
- lib/identifiers/isbn.rb
Constant Summary collapse
- ISBN_13_REGEXP =
/ \b ( 97[89] # ISBN (GS1) Bookland prefix ([\p{Pd}\p{Zs}])? # Optional hyphenation (?: \d # Digit \2? # Optional hyphenation ){9} \d # Check digit ) \b /x- ISBN_10_REGEXP =
/ (?<! # Don't match a hyphenated or spaced ISBN-13 97[89] [\p{Pd}\p{Zs}] ) \b ( \d{1,5} # Registration group identifier ([\p{Pd}\p{Zs}])? # Optional hyphenation (?: \d # Digit \2? # Optional hyphenation ){4,8} [\dX] # Check digit ) \b /x- ISBN_A_REGEXP =
%r{ \b (?<=10\.) # Directory indicator (always 10) 97[89]\. # ISBN (GS1) Bookland prefix \d{2,8} # ISBN registration group element and publisher prefix / # Prefix/suffix divider \d{1,7} # ISBN title enumerator and check digit \b }x
Class Method Summary collapse
- .digits_of(isbn) ⇒ Object
- .extract(str) ⇒ Object
- .extract_isbn_as(str) ⇒ Object
- .extract_ten_digit_isbns(str) ⇒ Object
- .extract_thirteen_digit_isbns(str) ⇒ Object
- .isbn_13_check_digit(isbn) ⇒ Object
- .valid_isbn_10?(isbn) ⇒ Boolean
- .valid_isbn_13?(isbn) ⇒ Boolean
Class Method Details
.digits_of(isbn) ⇒ Object
103 104 105 |
# File 'lib/identifiers/isbn.rb', line 103 def self.digits_of(isbn) isbn.to_s.each_char.map { |char| char == 'X' ? 10 : Integer(char) }.to_enum end |
.extract(str) ⇒ Object
43 44 45 |
# File 'lib/identifiers/isbn.rb', line 43 def self.extract(str) extract_isbn_as(str) + extract_thirteen_digit_isbns(str) + extract_ten_digit_isbns(str) end |
.extract_isbn_as(str) ⇒ Object
47 48 49 |
# File 'lib/identifiers/isbn.rb', line 47 def self.extract_isbn_as(str) extract_thirteen_digit_isbns(str.to_s.scan(ISBN_A_REGEXP).join("\n").tr('/.', '')) end |
.extract_ten_digit_isbns(str) ⇒ Object
60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 |
# File 'lib/identifiers/isbn.rb', line 60 def self.extract_ten_digit_isbns(str) str .to_s .scan(ISBN_10_REGEXP) .select { |isbn, hyphen| !hyphen || isbn.count(hyphen) == 3 } .map { |isbn, hyphen| isbn.delete(hyphen.to_s) } .select { |isbn| valid_isbn_10?(isbn) } .map { |isbn| isbn.chop! isbn.prepend('978') isbn << isbn_13_check_digit(isbn).to_s isbn } end |
.extract_thirteen_digit_isbns(str) ⇒ Object
51 52 53 54 55 56 57 58 |
# File 'lib/identifiers/isbn.rb', line 51 def self.extract_thirteen_digit_isbns(str) str .to_s .scan(ISBN_13_REGEXP) .select { |isbn, hyphen| !hyphen || isbn.count(hyphen) == 4 } .map { |isbn, hyphen| isbn.delete(hyphen.to_s) } .select { |isbn| valid_isbn_13?(isbn) } end |
.isbn_13_check_digit(isbn) ⇒ Object
76 77 78 79 80 81 82 83 84 85 |
# File 'lib/identifiers/isbn.rb', line 76 def self.isbn_13_check_digit(isbn) sum = digits_of(isbn).zip([1, 3].cycle).map { |digit, weight| digit * weight }.reduce(:+) check_digit = 10 - (sum % 10) if check_digit == 10 0 else check_digit end end |
.valid_isbn_10?(isbn) ⇒ Boolean
95 96 97 98 99 100 101 |
# File 'lib/identifiers/isbn.rb', line 95 def self.valid_isbn_10?(isbn) return false unless String(isbn).length == 10 && isbn =~ ISBN_10_REGEXP result = digits_of(isbn).with_index.map { |digit, weight| digit * weight.succ }.reduce(:+) (result % 11).zero? end |
.valid_isbn_13?(isbn) ⇒ Boolean
87 88 89 90 91 92 93 |
# File 'lib/identifiers/isbn.rb', line 87 def self.valid_isbn_13?(isbn) return false unless String(isbn).length == 13 && isbn =~ ISBN_13_REGEXP result = digits_of(isbn).zip([1, 3].cycle).map { |digit, weight| digit * weight }.reduce(:+) (result % 10).zero? end |