lisbn 0.2.4 → 0.3.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 8fa75ed8a6e119ea7c617805974f13001ec8c138
4
- data.tar.gz: e0eda6505a9276ec0e853e3ebe4f28fea3b3b63c
2
+ SHA256:
3
+ metadata.gz: 775f300f160de6abd661522d46324737767b6b833788a6100bbe2a919b0389e1
4
+ data.tar.gz: 814805f91620600eca86134a2bc6bce92a62ba958b3bcdf126620a0cfc81420b
5
5
  SHA512:
6
- metadata.gz: d87d6a6cf62296f315b9ed195eb79ddf5cc4fce259d84e7fd662ee1f8a64b0da43f48a95af12e92fa93c45a4e44ad9087adea14bf7698fc2bc8f7fbad1f821bb
7
- data.tar.gz: d7cda1db814e7615a191c036211bf673ab247917b2ee2ab8579cc6e54a3a506dd86e1afc7107fe626c21cc2f53c318dbf61e85ce767b1974e61a9d1ab95e07b2
6
+ metadata.gz: a9a6de31ee4669739e39f77705c4019569368c115152dfa811d71215f5a61aa7e59ebe20ca4abc4c472c5cb358fdb1dd16b6f5ff7d23202053f3222fe81a101c
7
+ data.tar.gz: 8804bee7122817fdd1c25af7fa01289eac805d363e654fc4c0b558c8955d731c0405e121a63949b1611b6e1a3930eb0f673647e39cef8170ed14fa0463f10447
@@ -0,0 +1,11 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.5
4
+ deploy:
5
+ provider: rubygems
6
+ api_key:
7
+ secure: fAmrDgaEj29FTiwB/Iy4pX+QiLHTo4MbUw1JeUqMAK/RgDlx0OnTK7J25hfZYScb2tr7xliooC4abQAIzzdrT8J1Pb4qp53G4pwiVcbvf+bXWHJDZDGxNAeGDsvB4EEHhPWJCajIOkx7qEf1+R7Je82MjppeqC0EXx+AO3tDTfQ=
8
+ gem: lisbn
9
+ on:
10
+ tags: true
11
+ repo: ragalie/lisbn
data/README.md CHANGED
@@ -1,5 +1,7 @@
1
1
  # Lisbn
2
2
 
3
+ [![Build Status](https://travis-ci.org/ragalie/lisbn.svg?branch=master)](https://travis-ci.org/ragalie/lisbn)
4
+
3
5
  Lisbn (pronounced "Lisbon") is a wrapper around String that adds methods for manipulating
4
6
  [ISBNs](http://en.wikipedia.org/wiki/International_Standard_Book_Number).
5
7
 
@@ -58,3 +60,9 @@ Then run:
58
60
  3. Commit your changes (`git commit -am 'Added some feature'`)
59
61
  4. Push to the branch (`git push origin my-new-feature`)
60
62
  5. Create new Pull Request
63
+
64
+ ## Releasing
65
+
66
+ 1. Update the version in lisbn.gemspec using [semver](https://semver.org).
67
+ 2. Tag the version update commit as `vX.X.X` on the master branch.
68
+ 3. Push to github.
data/Rakefile CHANGED
@@ -3,5 +3,11 @@ require "bundler/gem_tasks"
3
3
 
4
4
  Dir["tasks/**/*.rake"].each { |ext| load ext }
5
5
 
6
- require 'rspec/core/rake_task'
7
- RSpec::Core::RakeTask.new('spec')
6
+ begin
7
+ require 'rspec/core/rake_task'
8
+ RSpec::Core::RakeTask.new('spec')
9
+
10
+ task :default => :spec
11
+ rescue LoadError
12
+ # nop
13
+ end
@@ -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
@@ -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
@@ -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.4"
15
+ gem.version = "0.3.0"
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
@@ -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
@@ -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.4
4
+ version: 0.3.0
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-26 00:00:00.000000000 Z
11
+ date: 2019-01-05 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
@@ -62,6 +90,7 @@ extra_rdoc_files: []
62
90
  files:
63
91
  - ".gitignore"
64
92
  - ".rspec"
93
+ - ".travis.yml"
65
94
  - Gemfile
66
95
  - LICENSE
67
96
  - README.md
@@ -95,8 +124,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
95
124
  - !ruby/object:Gem::Version
96
125
  version: '0'
97
126
  requirements: []
98
- rubyforge_project:
99
- rubygems_version: 2.5.2
127
+ rubygems_version: 3.0.2
100
128
  signing_key:
101
129
  specification_version: 4
102
130
  summary: Provides methods for converting between ISBN-10 and ISBN-13, checking validity