Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Publication ranges #5

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 16 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,26 @@ You can convert it to ISBN-10 or ISBN-13:
> isbn.isbn13
=> "9780000000002"

And you can break it up into its GS1 prefix, group identifier, prefix/publisher code,
You can break it up into its GS1 prefix, group identifier, prefix/publisher code,
item number and check digit:

> isbn.parts
=> ["978", "0", "00", "000000", "2"]


You can generate the complete range of ISBNs for a registrant element, using the publisher_range object:

> isbn.publisher_range.isbn13s
=> ["9786017002008", "9786017002015", "9786017002022", .. "9786017002992"]

You can create a publication range object directly:

> Lisbn::PublicationRange.new("9786017002008")

You can see the range as a string representation:

> Lisbn::PublicationRange.new("9786017002008").to_s
=> "978-601-7002-00-8..978-601-7002-99-2"

## Updating

You can update the ISBN ranges by replacing the RangeMessage.xml file with an
Expand Down
1 change: 1 addition & 0 deletions lib/lisbn.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@
require_relative "lisbn/cache_method"
require_relative "lisbn/lisbn"
require_relative "lisbn/ranges"
require_relative "lisbn/publication_range"
10 changes: 10 additions & 0 deletions lib/lisbn/lisbn.rb
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,16 @@ def isbn13
'978' + isbn[0..-2] + isbn_13_checksum
end

def isbn13_checksum_corrected
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems like most of the methods use isbn_13 rather than isbn13. My preference would be to standardize on isbn_13 (and isbn_10), and to open a separate PR to rename the anomalous isbn13 method.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A better name for this might also be something like isbn_13_with_corrected_checksum that makes clear that an ISBN is being returned, and not a checksum.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed

return nil unless isbn.length == 13
isbn[0..-2] + isbn_13_checksum
end

def publication_range
return unless isbn13
PublicationRange.new(isbn13)
end

# Returns an Array with the 'parts' of the ISBN-13 in left-to-right order.
# The parts of an ISBN are as follows:
# - GS1 prefix
Expand Down
57 changes: 57 additions & 0 deletions lib/lisbn/publication_range.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
class Lisbn < String
class PublicationRange
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This mechanism is a bit hard to understand, but I think from_prefix is basically:

seed_isbn13.parts[0..2].join + "0" * (12 - prefix.size) + checksum

and to_prefix is:

seed_isbn13.parts[0..2].join + "9" * (12 - prefix.size) + checksum

Is it easier to implement and think about by manipulating the parts (as a string), rather than doing the integer multiplication approach?

include Enumerable
def initialize(seed_isbn13)
@seed_isbn13 = Lisbn.new(seed_isbn13)
end

def parts
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The naming of this method is confusing. Maybe registration_parts?

seed_isbn13.parts[0..2]
end

def prefix
parts.join
end

def to_s
"#{Lisbn.new(from).isbn_with_dash}..#{Lisbn.new(to).isbn_with_dash}"
end

def number_of_publications
10 ** (13 - prefix.size - 1)
end

def publication_numbers
(0..(number_of_publications-1))
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would be best to add spaces around the - sign like you do in other places in this class.

end

def each
(from_prefix..to_prefix).each do |isbn|
yield Lisbn.new((isbn*10).to_s).isbn13_checksum_corrected
end
end

private
attr_reader :seed_isbn13

def multiplier
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method seems to have the same return value as the number_of_publications method. Should we pick one?

(10 ** (12 - prefix.size))
end

def from_prefix
prefix.to_i * multiplier
end

def to_prefix
(prefix.to_i+1) * multiplier - 1
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Spaces around operator here too.

end

def from
Lisbn.new((from_prefix*10).to_s).isbn13_checksum_corrected
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Spaces around operator here too.

end

def to
Lisbn.new((to_prefix*10).to_s).isbn13_checksum_corrected
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Spaces around operator here too.

end
end
end
145 changes: 144 additions & 1 deletion spec/lisbn_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,16 @@
lisbn.should_not_receive(:isbn_13_checksum)
lisbn.isbn13.should == "9780000000002"
end

it "provides a corrected checksum" do
lisbn = Lisbn.new("9780000000001")
lisbn.isbn13_checksum_corrected.should == "9780000000002"
end

it "can generate a publication range" do
lisbn = Lisbn.new("9786017002015")
lisbn.publication_range.to_s.should == "978-601-7002-00-8..978-601-7002-99-2"
end
end

describe "#parts" do
Expand All @@ -147,6 +157,138 @@
end
end

describe "#publication_range" do
subject { Lisbn::PublicationRange.new("9786017002015") }

it "returns a PublicationRange object" do
subject.class.should == Lisbn::PublicationRange
end

it "returns the three parts of a PublicationRange" do
subject.parts.should == ["978", "601", "7002"]
end

it "returns the number of publication in the range" do
subject.number_of_publications.should == 100
end

it "returns the range of publication numbers" do
subject.publication_numbers.should == (0..99)
end

it "returns a string representation of the range of ISBN13s" do
subject.to_s.should == "978-601-7002-00-8..978-601-7002-99-2"
end

it "returns an enumerable of isbns" do
subject.min.should == "9786017002008"
subject.max.should == "9786017002992"

subject.map{|x| x}.should == [
"9786017002008",
"9786017002015",
"9786017002022",
"9786017002039",
"9786017002046",
"9786017002053",
"9786017002060",
"9786017002077",
"9786017002084",
"9786017002091",
"9786017002107",
"9786017002114",
"9786017002121",
"9786017002138",
"9786017002145",
"9786017002152",
"9786017002169",
"9786017002176",
"9786017002183",
"9786017002190",
"9786017002206",
"9786017002213",
"9786017002220",
"9786017002237",
"9786017002244",
"9786017002251",
"9786017002268",
"9786017002275",
"9786017002282",
"9786017002299",
"9786017002305",
"9786017002312",
"9786017002329",
"9786017002336",
"9786017002343",
"9786017002350",
"9786017002367",
"9786017002374",
"9786017002381",
"9786017002398",
"9786017002404",
"9786017002411",
"9786017002428",
"9786017002435",
"9786017002442",
"9786017002459",
"9786017002466",
"9786017002473",
"9786017002480",
"9786017002497",
"9786017002503",
"9786017002510",
"9786017002527",
"9786017002534",
"9786017002541",
"9786017002558",
"9786017002565",
"9786017002572",
"9786017002589",
"9786017002596",
"9786017002602",
"9786017002619",
"9786017002626",
"9786017002633",
"9786017002640",
"9786017002657",
"9786017002664",
"9786017002671",
"9786017002688",
"9786017002695",
"9786017002701",
"9786017002718",
"9786017002725",
"9786017002732",
"9786017002749",
"9786017002756",
"9786017002763",
"9786017002770",
"9786017002787",
"9786017002794",
"9786017002800",
"9786017002817",
"9786017002824",
"9786017002831",
"9786017002848",
"9786017002855",
"9786017002862",
"9786017002879",
"9786017002886",
"9786017002893",
"9786017002909",
"9786017002916",
"9786017002923",
"9786017002930",
"9786017002947",
"9786017002954",
"9786017002961",
"9786017002978",
"9786017002985",
"9786017002992"
]
end
end

describe "ranges" do
it "skips over invalid '0-length' ranges" do
Lisbn::RANGES.values.flatten.map {|v| v[:length]}.should_not include(0)
Expand All @@ -157,7 +299,8 @@
subject { Lisbn.new("9780000000002") }

it "#splits" do
subject.split("7").should == ["9", "80000000002"]
subject.split("7").should == ["9",
"80000000002"]
end
end
end