lisbn 0.2.3 → 0.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/.github/workflows/push.yml +32 -0
- data/.github/workflows/ruby.yml +30 -0
- data/README.md +8 -0
- data/Rakefile +8 -2
- data/data/RangeMessage.xml +804 -178
- data/data/ranges.yml +632 -124
- data/lib/lisbn/cache_method.rb +1 -1
- data/lib/lisbn/lisbn.rb +53 -21
- data/lisbn.gemspec +3 -1
- data/spec/cache_method_spec.rb +19 -6
- data/spec/lisbn_spec.rb +89 -30
- data/spec/spec_helper.rb +0 -1
- metadata +33 -4
data/lib/lisbn/cache_method.rb
CHANGED
@@ -5,7 +5,7 @@ class Lisbn < String
|
|
5
5
|
alias_method method + "_without_cache", method
|
6
6
|
define_method method do |*args, &blk|
|
7
7
|
@cache ||= {}
|
8
|
-
@cache[[method, self]] ||= send(method + "_without_cache", *args, &blk)
|
8
|
+
@cache[[method, args, blk, self]] ||= send(method + "_without_cache", *args, &blk)
|
9
9
|
end
|
10
10
|
end
|
11
11
|
end
|
data/lib/lisbn/lisbn.rb
CHANGED
@@ -17,8 +17,10 @@ class Lisbn < String
|
|
17
17
|
end
|
18
18
|
|
19
19
|
def isbn_with_dash
|
20
|
-
if valid_isbn_13? && parts
|
21
|
-
|
20
|
+
if valid_isbn_13? && parts5 = parts(5)
|
21
|
+
parts5.join("-")
|
22
|
+
elsif valid_isbn_10? && parts4 = parts(4)
|
23
|
+
parts4.join("-")
|
22
24
|
elsif isbn.length > 3
|
23
25
|
isbn[0..-2] + "-" + isbn[-1]
|
24
26
|
else
|
@@ -45,18 +47,21 @@ class Lisbn < String
|
|
45
47
|
'978' + isbn[0..-2] + isbn_13_checksum
|
46
48
|
end
|
47
49
|
|
48
|
-
# Returns an Array with the 'parts' of the ISBN
|
50
|
+
# Returns an Array with the 'parts' of the ISBN in left-to-right order.
|
49
51
|
# The parts of an ISBN are as follows:
|
50
|
-
# - GS1 prefix
|
52
|
+
# - GS1 prefix (only for ISBN-13)
|
51
53
|
# - Group identifier
|
52
54
|
# - Prefix/publisher code
|
53
55
|
# - Item number
|
54
56
|
# - Check digit
|
55
57
|
#
|
56
58
|
# Returns nil if the ISBN is not valid.
|
59
|
+
# Returns nil if parts argument is 4 but ISBN-10 does not exist
|
57
60
|
# Returns nil if the group and prefix cannot be identified.
|
58
|
-
def parts
|
61
|
+
def parts(parts = 5)
|
62
|
+
raise ArgumentError, "Parts must be either 4 or 5." unless parts == 4 || parts == 5
|
59
63
|
return unless isbn13
|
64
|
+
return if parts == 4 && !isbn10
|
60
65
|
|
61
66
|
group = prefix = nil
|
62
67
|
|
@@ -80,36 +85,59 @@ class Lisbn < String
|
|
80
85
|
return unless group && prefix
|
81
86
|
|
82
87
|
prefix = sprintf("%0#{prefix[:length]}d", prefix[:number])
|
83
|
-
|
88
|
+
|
89
|
+
if parts == 4
|
90
|
+
[group[3..-1], prefix, isbn10[(group[3..-1].length + prefix.length)..-2], isbn10[-1..-1]]
|
91
|
+
else
|
92
|
+
[group[0..2], group[3..-1], prefix, isbn13[(group.length + prefix.length)..-2], isbn13[-1..-1]]
|
93
|
+
end
|
84
94
|
end
|
85
95
|
|
86
96
|
def isbn_10_checksum
|
87
97
|
base = isbn.length == 13 ? isbn[3..-2] : isbn[0..-2]
|
88
98
|
|
89
|
-
|
90
|
-
|
91
|
-
|
99
|
+
sum = base[0].to_i * 10 +
|
100
|
+
base[1].to_i * 9 +
|
101
|
+
base[2].to_i * 8 +
|
102
|
+
base[3].to_i * 7 +
|
103
|
+
base[4].to_i * 6 +
|
104
|
+
base[5].to_i * 5 +
|
105
|
+
base[6].to_i * 4 +
|
106
|
+
base[7].to_i * 3 +
|
107
|
+
base[8].to_i * 2
|
108
|
+
|
109
|
+
remainder = sum % 11
|
92
110
|
|
93
|
-
remainder = products.inject(0) {|m, v| m + v} % 11
|
94
111
|
case remainder
|
95
112
|
when 0
|
96
|
-
0
|
113
|
+
"0"
|
97
114
|
when 1
|
98
|
-
|
115
|
+
"X"
|
99
116
|
else
|
100
|
-
11 - remainder
|
101
|
-
end
|
117
|
+
(11 - remainder).to_s
|
118
|
+
end
|
102
119
|
end
|
103
120
|
|
104
121
|
def isbn_13_checksum
|
105
122
|
base = (isbn.length == 13 ? '' : '978') + isbn[0..-2]
|
106
123
|
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
124
|
+
sum = (
|
125
|
+
base[1].to_i +
|
126
|
+
base[3].to_i +
|
127
|
+
base[5].to_i +
|
128
|
+
base[7].to_i +
|
129
|
+
base[9].to_i +
|
130
|
+
base[11].to_i
|
131
|
+
) * 3 +
|
132
|
+
base[0].to_i +
|
133
|
+
base[2].to_i +
|
134
|
+
base[4].to_i +
|
135
|
+
base[6].to_i +
|
136
|
+
base[8].to_i +
|
137
|
+
base[10].to_i +
|
138
|
+
base[12].to_i
|
139
|
+
|
140
|
+
(10 - sum % 10).to_s[-1]
|
113
141
|
end
|
114
142
|
|
115
143
|
cache_method :isbn, :valid?, :isbn10, :isbn13, :parts, :isbn_10_checksum, :isbn_13_checksum
|
@@ -126,5 +154,9 @@ private
|
|
126
154
|
isbn[-1..-1] == isbn_13_checksum
|
127
155
|
end
|
128
156
|
|
129
|
-
RANGES =
|
157
|
+
RANGES = if Gem::Version.new(Psych::VERSION) >= Gem::Version.new('4.0.0')
|
158
|
+
YAML::load_file(File.dirname(__FILE__) + "/../../data/ranges.yml", permitted_classes: [Range, Symbol])
|
159
|
+
else
|
160
|
+
YAML::load_file(File.dirname(__FILE__) + "/../../data/ranges.yml")
|
161
|
+
end
|
130
162
|
end
|
data/lisbn.gemspec
CHANGED
@@ -12,9 +12,11 @@ Gem::Specification.new do |gem|
|
|
12
12
|
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
13
13
|
gem.name = "lisbn"
|
14
14
|
gem.require_paths = ["lib"]
|
15
|
-
gem.version = "0.2
|
15
|
+
gem.version = "0.3.2"
|
16
16
|
|
17
17
|
gem.add_dependency "nori", "~> 2.0"
|
18
18
|
gem.add_dependency "nokogiri"
|
19
|
+
gem.add_development_dependency "multi_json"
|
20
|
+
gem.add_development_dependency "rake"
|
19
21
|
gem.add_development_dependency "rspec"
|
20
22
|
end
|
data/spec/cache_method_spec.rb
CHANGED
@@ -3,8 +3,8 @@ require 'spec_helper'
|
|
3
3
|
class String
|
4
4
|
extend Lisbn::CacheMethod
|
5
5
|
|
6
|
-
def with_excitement!
|
7
|
-
self + "!"
|
6
|
+
def with_excitement!(how_much = 1)
|
7
|
+
self + "!" * how_much
|
8
8
|
end
|
9
9
|
|
10
10
|
cache_method :with_excitement!
|
@@ -14,14 +14,27 @@ describe "cache_method" do
|
|
14
14
|
subject { String.new("awesomeness") }
|
15
15
|
|
16
16
|
it "evaluates the method the first time but not subsequent times" do
|
17
|
-
subject.
|
17
|
+
expect(subject).to receive(:+).with("!").once.and_call_original
|
18
18
|
subject.with_excitement!
|
19
|
-
subject.with_excitement
|
19
|
+
subject.with_excitement!
|
20
|
+
end
|
21
|
+
|
22
|
+
it "reevaluates the method if the arguments change" do
|
23
|
+
expect(subject).to receive(:+).with("!")
|
24
|
+
expect(subject).to receive(:+).with("!!")
|
25
|
+
subject.with_excitement!
|
26
|
+
subject.with_excitement!(2)
|
27
|
+
end
|
28
|
+
|
29
|
+
it "reevaluates the method if the block changes" do
|
30
|
+
expect(subject).to receive(:+).twice.and_call_original
|
31
|
+
subject.with_excitement! { "cats" }
|
32
|
+
subject.with_excitement! { "dogs" }
|
20
33
|
end
|
21
34
|
|
22
35
|
it "reevaluates the method if the object's hash changes" do
|
23
|
-
subject.with_excitement
|
36
|
+
expect(subject.with_excitement!).to eq("awesomeness!")
|
24
37
|
subject.replace("more awesomeness")
|
25
|
-
subject.with_excitement
|
38
|
+
expect(subject.with_excitement!).to eq("more awesomeness!")
|
26
39
|
end
|
27
40
|
end
|
data/spec/lisbn_spec.rb
CHANGED
@@ -4,54 +4,54 @@ describe "Lisbn" do
|
|
4
4
|
describe "#isbn" do
|
5
5
|
it "converts the string to just digits and X" do
|
6
6
|
isbn = Lisbn.new("9487-028asdfasdf878X7")
|
7
|
-
isbn.isbn.
|
7
|
+
expect(isbn.isbn).to eq("9487028878X7")
|
8
8
|
end
|
9
9
|
end
|
10
10
|
|
11
11
|
describe "#valid?" do
|
12
12
|
it "recognizes a valid ISBN10" do
|
13
13
|
isbn = Lisbn.new("0123456789")
|
14
|
-
isbn.valid
|
14
|
+
expect(isbn.valid?).to be true
|
15
15
|
end
|
16
16
|
|
17
17
|
it "recognizes a valid ISBN10 with X checksum" do
|
18
18
|
isbn = Lisbn.new("160459411X")
|
19
|
-
isbn.valid
|
19
|
+
expect(isbn.valid?).to be true
|
20
20
|
end
|
21
21
|
|
22
22
|
it "recognizes a valid ISBN10 with 0 checksum" do
|
23
23
|
isbn = Lisbn.new("0679405070")
|
24
|
-
isbn.valid
|
24
|
+
expect(isbn.valid?).to be true
|
25
25
|
end
|
26
26
|
|
27
27
|
it "recognizes an invalid ISBN10" do
|
28
28
|
isbn = Lisbn.new("0123546789")
|
29
|
-
isbn.valid
|
29
|
+
expect(isbn.valid?).to be false
|
30
30
|
end
|
31
31
|
|
32
32
|
it "recognizes a valid ISBN13" do
|
33
33
|
isbn = Lisbn.new("9780000000002")
|
34
|
-
isbn.valid
|
34
|
+
expect(isbn.valid?).to be true
|
35
35
|
end
|
36
36
|
|
37
37
|
it "recognizes a valid ISBN13 with 0 checksum" do
|
38
38
|
isbn = Lisbn.new("9780062870780")
|
39
|
-
isbn.valid
|
39
|
+
expect(isbn.valid?).to be true
|
40
40
|
end
|
41
41
|
|
42
42
|
it "recognizes an invalid ISBN13" do
|
43
43
|
isbn = Lisbn.new("9780000000003")
|
44
|
-
isbn.valid
|
44
|
+
expect(isbn.valid?).to be false
|
45
45
|
end
|
46
46
|
|
47
47
|
it "returns false for improperly-formatted ISBNs" do
|
48
48
|
isbn = Lisbn.new("97800000X0002")
|
49
|
-
isbn.valid
|
49
|
+
expect(isbn.valid?).to be false
|
50
50
|
end
|
51
51
|
|
52
52
|
it "regards anything not 10 or 13 digits as invalid" do
|
53
53
|
isbn = Lisbn.new("")
|
54
|
-
isbn.valid
|
54
|
+
expect(isbn.valid?).to be false
|
55
55
|
end
|
56
56
|
end
|
57
57
|
|
@@ -69,8 +69,16 @@ describe "Lisbn" do
|
|
69
69
|
context "with a 10-digit ISBN" do
|
70
70
|
let(:isbn) { "1402780591" }
|
71
71
|
|
72
|
+
it "returns the isbn with dashes between the parts" do
|
73
|
+
expect(subject.isbn_with_dash).to eq("1-4027-8059-1")
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
context "with an invalid 9-digit ISBN" do
|
78
|
+
let(:isbn) { "402780591" }
|
79
|
+
|
72
80
|
it "returns the isbn with a dash before the checkdigit" do
|
73
|
-
expect(subject.isbn_with_dash).to eq("
|
81
|
+
expect(subject.isbn_with_dash).to eq("40278059-1")
|
74
82
|
end
|
75
83
|
end
|
76
84
|
|
@@ -87,25 +95,25 @@ describe "Lisbn" do
|
|
87
95
|
subject { Lisbn.new("9780000000002") }
|
88
96
|
|
89
97
|
it "returns nil if invalid" do
|
90
|
-
subject.
|
91
|
-
subject.isbn10.
|
98
|
+
allow(subject).to receive(:valid?) { false }
|
99
|
+
expect(subject.isbn10).to be_nil
|
92
100
|
end
|
93
101
|
|
94
102
|
it "returns nil if the ISBN is 13-digits and isn't in the 978 GS1" do
|
95
103
|
lisbn = Lisbn.new("9790000000003")
|
96
|
-
lisbn.
|
97
|
-
lisbn.isbn10.
|
104
|
+
allow(lisbn).to receive(:valid?) { true }
|
105
|
+
expect(lisbn.isbn10).to be_nil
|
98
106
|
end
|
99
107
|
|
100
108
|
it "computes the ISBN10 checksum" do
|
101
|
-
subject.isbn10.
|
109
|
+
expect(subject.isbn10).to eq("0000000000")
|
102
110
|
end
|
103
111
|
|
104
112
|
it "returns the isbn if it's 10 digits" do
|
105
113
|
lisbn = Lisbn.new("0000000000")
|
106
|
-
lisbn.
|
107
|
-
lisbn.
|
108
|
-
lisbn.isbn10.
|
114
|
+
allow(lisbn).to receive(:valid?) { true }
|
115
|
+
expect(lisbn).not_to receive(:isbn_10_checksum)
|
116
|
+
expect(lisbn.isbn10).to eq("0000000000")
|
109
117
|
end
|
110
118
|
end
|
111
119
|
|
@@ -113,19 +121,19 @@ describe "Lisbn" do
|
|
113
121
|
subject { Lisbn.new("0000000000") }
|
114
122
|
|
115
123
|
it "returns nil if invalid" do
|
116
|
-
subject.
|
117
|
-
subject.isbn13.
|
124
|
+
allow(subject).to receive(:valid?) { false }
|
125
|
+
expect(subject.isbn13).to be_nil
|
118
126
|
end
|
119
127
|
|
120
128
|
it "computes the ISBN13 checksum" do
|
121
|
-
subject.isbn13.
|
129
|
+
expect(subject.isbn13).to eq("9780000000002")
|
122
130
|
end
|
123
131
|
|
124
132
|
it "returns the isbn if it's 13 digits" do
|
125
133
|
lisbn = Lisbn.new("9780000000002")
|
126
|
-
lisbn.
|
127
|
-
lisbn.
|
128
|
-
lisbn.isbn13.
|
134
|
+
allow(lisbn).to receive(:valid?) { true }
|
135
|
+
expect(lisbn).not_to receive(:isbn_13_checksum)
|
136
|
+
expect(lisbn.isbn13).to eq("9780000000002")
|
129
137
|
end
|
130
138
|
end
|
131
139
|
|
@@ -133,23 +141,74 @@ describe "Lisbn" do
|
|
133
141
|
subject { Lisbn.new("9780000000002") }
|
134
142
|
|
135
143
|
it "splits into the right groups" do
|
136
|
-
subject.parts.
|
144
|
+
expect(subject.parts).to eq(["978", "0", "00", "000000", "2"])
|
137
145
|
end
|
138
146
|
|
139
147
|
it "works with long groups" do
|
140
148
|
lisbn = Lisbn.new("9786017002015")
|
141
|
-
lisbn.parts.
|
149
|
+
expect(lisbn.parts).to eq(["978", "601", "7002", "01", "5"])
|
150
|
+
end
|
151
|
+
|
152
|
+
it "should raise ArgumentError for anything other than 4 or 5" do
|
153
|
+
expect { subject.parts(3) }.to raise_error(ArgumentError)
|
154
|
+
end
|
155
|
+
|
156
|
+
it "splits into the right groups with number argument" do
|
157
|
+
expect(subject.parts(5)).to eq(["978", "0", "00", "000000", "2"])
|
142
158
|
end
|
143
159
|
|
144
160
|
it "returns nil if it can't find a valid group" do
|
145
161
|
lisbn = Lisbn.new("9780100000002")
|
146
|
-
lisbn.parts.
|
162
|
+
expect(lisbn.parts).to be_nil
|
163
|
+
end
|
164
|
+
|
165
|
+
it "uses the correct check digit if provided an isbn10" do
|
166
|
+
lisbn = Lisbn.new("0906212731")
|
167
|
+
expect(lisbn.parts).to eq(["978", "0", "906212", "73", "8"])
|
168
|
+
end
|
169
|
+
|
170
|
+
context "4 parts variant" do
|
171
|
+
it "splits isbn10 for parts with argument" do
|
172
|
+
lisbn = Lisbn.new("832100928X")
|
173
|
+
expect(lisbn.parts(4)).to eq(["83", "210", "0928", "X"])
|
174
|
+
end
|
175
|
+
|
176
|
+
it "works correctly for publisher identifier (CRC Press)" do
|
177
|
+
lisbn = Lisbn.new("0849304768")
|
178
|
+
expect(lisbn.parts(4)).to eq(["0", "8493", "0476", "8"])
|
179
|
+
end
|
180
|
+
|
181
|
+
it "works correctly with long publisher identifier (Tarquin Publications)" do
|
182
|
+
lisbn = Lisbn.new("0906212731")
|
183
|
+
expect(lisbn.parts(4)).to eq(["0", "906212", "73", "1"])
|
184
|
+
end
|
185
|
+
|
186
|
+
it "uses the correct check digit if provided an isbn13" do
|
187
|
+
lisbn = Lisbn.new("9780906212738")
|
188
|
+
expect(lisbn.parts(4)).to eq(["0", "906212", "73", "1"])
|
189
|
+
end
|
190
|
+
|
191
|
+
it "splits isbn10 for parts for initial isbn13" do
|
192
|
+
lisbn = Lisbn.new("9786017002015")
|
193
|
+
expect(lisbn.parts(4)).to eq(["601", "7002", "01", "5"])
|
194
|
+
end
|
195
|
+
|
196
|
+
it 'returns nil if ISBN-10 equivalent doesnt exists' do
|
197
|
+
lisbn = Lisbn.new("979-11-86178-14-0")
|
198
|
+
expect(lisbn.parts(4)).to be_nil
|
199
|
+
end
|
200
|
+
|
201
|
+
it "returns nil if it can't find a valid group" do
|
202
|
+
lisbn = Lisbn.new("9780100000002")
|
203
|
+
expect(lisbn.parts(4)).to be_nil
|
204
|
+
end
|
147
205
|
end
|
148
206
|
end
|
149
207
|
|
150
208
|
describe "ranges" do
|
151
209
|
it "skips over invalid '0-length' ranges" do
|
152
|
-
Lisbn::RANGES.values.flatten.map {|v| v[:length]}
|
210
|
+
range_lengths = Lisbn::RANGES.values.flatten.map {|v| v[:length]}
|
211
|
+
expect(range_lengths).not_to include(0)
|
153
212
|
end
|
154
213
|
end
|
155
214
|
|
@@ -157,7 +216,7 @@ describe "Lisbn" do
|
|
157
216
|
subject { Lisbn.new("9780000000002") }
|
158
217
|
|
159
218
|
it "#splits" do
|
160
|
-
subject.split("7").
|
219
|
+
expect(subject.split("7")).to eq(["9", "80000000002"])
|
161
220
|
end
|
162
221
|
end
|
163
222
|
end
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: lisbn
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2
|
4
|
+
version: 0.3.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mike Ragalie
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2022-01-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: nori
|
@@ -38,6 +38,34 @@ dependencies:
|
|
38
38
|
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: multi_json
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rake
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
41
69
|
- !ruby/object:Gem::Dependency
|
42
70
|
name: rspec
|
43
71
|
requirement: !ruby/object:Gem::Requirement
|
@@ -60,6 +88,8 @@ executables: []
|
|
60
88
|
extensions: []
|
61
89
|
extra_rdoc_files: []
|
62
90
|
files:
|
91
|
+
- ".github/workflows/push.yml"
|
92
|
+
- ".github/workflows/ruby.yml"
|
63
93
|
- ".gitignore"
|
64
94
|
- ".rspec"
|
65
95
|
- Gemfile
|
@@ -95,8 +125,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
95
125
|
- !ruby/object:Gem::Version
|
96
126
|
version: '0'
|
97
127
|
requirements: []
|
98
|
-
|
99
|
-
rubygems_version: 2.6.14
|
128
|
+
rubygems_version: 3.3.3
|
100
129
|
signing_key:
|
101
130
|
specification_version: 4
|
102
131
|
summary: Provides methods for converting between ISBN-10 and ISBN-13, checking validity
|