lisbn 0.2.3 → 0.3.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
- parts.join("-")
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-13 in left-to-right order.
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
- [group[0..2], group[3..-1], prefix, isbn13[(group.length + prefix.length)..-2], isbn13[-1..-1]]
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
- products = base.each_char.each_with_index.map do |chr, i|
90
- chr.to_i * (10 - i)
91
- end
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
- 'X'
115
+ "X"
99
116
  else
100
- 11 - remainder
101
- end.to_s
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
- products = base.each_char.each_with_index.map do |chr, i|
108
- chr.to_i * (i % 2 == 0 ? 1 : 3)
109
- end
110
-
111
- remainder = products.inject(0) {|m, v| m + v} % 10
112
- (remainder == 0 ? 0 : 10 - remainder).to_s
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 = YAML::load_file(File.dirname(__FILE__) + "/../../data/ranges.yml")
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.3"
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
@@ -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.should_receive(:+).with("!").once.and_return("you got stubbed!")
17
+ expect(subject).to receive(:+).with("!").once.and_call_original
18
18
  subject.with_excitement!
19
- subject.with_excitement!.should == "you got stubbed!"
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!.should == "awesomeness!"
36
+ expect(subject.with_excitement!).to eq("awesomeness!")
24
37
  subject.replace("more awesomeness")
25
- subject.with_excitement!.should == "more awesomeness!"
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.should == "9487028878X7"
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?.should be true
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?.should be true
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?.should be true
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?.should be false
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?.should be true
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?.should be true
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?.should be false
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?.should be false
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?.should be false
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("140278059-1")
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.stub(:valid? => false)
91
- subject.isbn10.should be_nil
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.stub(:valid? => true)
97
- lisbn.isbn10.should be_nil
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.should == "0000000000"
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.stub(:valid? => true)
107
- lisbn.should_not_receive(:isbn_10_checksum)
108
- lisbn.isbn10.should == "0000000000"
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.stub(:valid? => false)
117
- subject.isbn13.should be_nil
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.should == "9780000000002"
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.stub(:valid? => true)
127
- lisbn.should_not_receive(:isbn_13_checksum)
128
- lisbn.isbn13.should == "9780000000002"
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.should == ["978", "0", "00", "000000", "2"]
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.should == ["978", "601", "7002", "01", "5"]
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.should be_nil
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]}.should_not include(0)
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").should == ["9", "80000000002"]
219
+ expect(subject.split("7")).to eq(["9", "80000000002"])
161
220
  end
162
221
  end
163
222
  end
data/spec/spec_helper.rb CHANGED
@@ -1,7 +1,6 @@
1
1
  require 'lisbn'
2
2
 
3
3
  RSpec.configure do |config|
4
- config.treat_symbols_as_metadata_keys_with_true_values = true
5
4
  config.run_all_when_everything_filtered = true
6
5
  config.filter_run :focus
7
6
  end
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.3
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: 2017-12-17 00:00:00.000000000 Z
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
- rubyforge_project:
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