bookland 2.0.0 → 3.0.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: f62422a2d6bb33379862e355d5fc372afc75aea1
4
+ data.tar.gz: 47be6f9d863d31e9ce5edc605fac48338e09e88a
5
+ SHA512:
6
+ metadata.gz: 401687a31df67958367e50699e0a574f26f0370eb4c5edf684828446492261f9101aac55d4f0d9c22cd5f85f985534cc075d63cbbfc89c9074c6a189621c9680
7
+ data.tar.gz: 2e53af118ccd411f724a17fc74548cdfa0df3898a03c10ccedf2068de0680097fb6ba16e1a22e35ed0e44586ccf0c62dadea787edec2b26aede85987cd3143ee
data/.travis.yml CHANGED
@@ -1,7 +1,5 @@
1
1
  rvm:
2
- - 1.8.7
3
- - 1.9.2
2
+ - 2.0.0
4
3
  - 1.9.3
5
- - jruby
6
- - rbx
7
- - ree
4
+ - jruby-19mode
5
+ - rbx-19mode
data/README.md CHANGED
@@ -1,14 +1,11 @@
1
1
  # Bookland
2
2
 
3
- [![travis] [1]] [2]
4
-
5
- [Bookland] [3] provides ISBN and EAN classes in Ruby.
3
+ [Bookland][bo] provides ISBN and ASIN classes, which should come in handy when trading books online.
6
4
 
7
5
  ## Installation
8
6
 
9
- ```ruby
10
- # Gemfile
11
- gem 'bookland', '~> 2.0.0.beta'
7
+ ```bash
8
+ gem install bookland
12
9
  ```
13
10
 
14
11
  ## Usage
@@ -16,19 +13,9 @@ gem 'bookland', '~> 2.0.0.beta'
16
13
  ```ruby
17
14
  include 'bookland'
18
15
 
19
- isbn = ISBN.new "9780262011532"
20
- isbn.valid? # => true
21
- isbn10 = isbn.to_isbn_10
22
- isbn10.to_s # => "0262011530"
23
- ```
24
-
25
- Or use utility methods on the class level:
26
-
27
- ```ruby
28
- EAN.valid? '0814916013890' # => true
29
- ISBN.valid? '0814916013890' # => false
16
+ ISBN.valid?('9780262011532') # => true
17
+ ASIN.from_isbn('9780262011532') # => "0262011530"
18
+ ASIN.to_isbn('0262011530') # => "9780262011532"
30
19
  ```
31
20
 
32
- [1]: https://secure.travis-ci.org/hakanensari/bookland.png
33
- [2]: http://travis-ci.org/hakanensari/bookland
34
- [3]: http://en.wikipedia.org/wiki/Bookland
21
+ [bo]: http://en.wikipedia.org/wiki/Bookland
data/bookland.gemspec CHANGED
@@ -1,21 +1,24 @@
1
- # -*- encoding: utf-8 -*-
2
- $:.push File.expand_path('../lib', __FILE__)
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
4
  require 'bookland/version'
4
5
 
5
- Gem::Specification.new do |s|
6
- s.name = 'bookland'
7
- s.version = Bookland::VERSION
8
- s.platform = Gem::Platform::RUBY
9
- s.authors = ['Hakan Ensari']
10
- s.email = 'hakan.ensari@papercavalier.com'
11
- s.homepage = 'https://github.com/hakanensari/bookland'
12
- s.summary = %q{EAN and ISBN classes}
13
- s.description = %q{Bookland provides EAN and ISBN classes.}
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'bookland'
8
+ spec.version = Bookland::VERSION
9
+ spec.authors = ['Hakan Ensari']
10
+ spec.email = 'hakan.ensari@papercavalier.com'
11
+ spec.description = %q{An ISBN toolkit}
12
+ spec.summary = %q{An ISBN toolkit}
13
+ spec.homepage = 'https://github.com/hakanensari/bookland'
14
+ spec.license = 'MIT'
14
15
 
15
- s.add_development_dependency 'rake', '~> 0.9.2'
16
+ spec.files = `git ls-files`.split("\n")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ['lib']
16
20
 
17
- s.files = `git ls-files`.split("\n")
18
- s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
19
- s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
20
- s.require_paths = ['lib']
21
+ spec.add_development_dependency 'bundler', '~> 1.3'
22
+ spec.add_development_dependency 'rake'
23
+ spec.add_development_dependency 'minitest', '~> 5.0'
21
24
  end
data/lib/bookland.rb CHANGED
@@ -1,6 +1,4 @@
1
1
  require 'bookland/identifier'
2
- require 'bookland/invalid_isbn'
3
-
4
2
  require 'bookland/ean'
5
3
  require 'bookland/isbn'
6
- require 'bookland/isbn_10'
4
+ require 'bookland/asin'
@@ -0,0 +1,40 @@
1
+ module Bookland
2
+ class ASIN < Identifier
3
+ WEIGHTS = 10.downto(2).to_a.freeze
4
+
5
+ def self.calculate_checksum_digit(digits)
6
+ sum = digits.map(&:to_i).zip(WEIGHTS).reduce(0) { |a , (i, j)| a + i * j }
7
+
8
+ case checksum_digit = 11 - sum % 11
9
+ when 0..9 then checksum_digit.to_s
10
+ when 10 then 'X'
11
+ when 11 then '0'
12
+ end
13
+ end
14
+
15
+ def self.from_isbn(isbn)
16
+ data_digits = isbn.split('')[3..11]
17
+ checksum_digit = ASIN.calculate_checksum_digit(data_digits)
18
+
19
+ (data_digits << checksum_digit).join
20
+ end
21
+
22
+ def self.to_isbn(asin)
23
+ return if asin[0] == 'B'
24
+
25
+ data_digits = %w(9 7 8) + asin.split('')[0, 9]
26
+ checksum_digit = ISBN.calculate_checksum_digit(data_digits)
27
+
28
+ (data_digits << checksum_digit).join
29
+ end
30
+
31
+ def valid?
32
+ case digits.first
33
+ when 'B'
34
+ digits.size == 10
35
+ else
36
+ digits.size == 10 && super
37
+ end
38
+ end
39
+ end
40
+ end
data/lib/bookland/ean.rb CHANGED
@@ -1,17 +1,14 @@
1
1
  module Bookland
2
- # An International Article Number.
3
2
  class EAN < Identifier
4
- # Calculates the checksum for the 12-digit payload of an EAN.
5
- def self.calculate_checksum(payload)
6
- payload.map! &:to_i
7
- weights = [1, 3] * 6
8
- sum = payload.zip(weights).inject(0) { |a, (i, j)| a + i * j }
3
+ WEIGHTS = ([1, 3] * 6).freeze
9
4
 
5
+ def self.calculate_checksum_digit(digits)
6
+ sum = digits.map(&:to_i).zip(WEIGHTS).reduce(0) { |a, (i, j)| a + i * j }
10
7
  ((10 - sum % 10) % 10).to_s
11
8
  end
12
9
 
13
10
  def valid?
14
- @raw.size == 13 && super
11
+ digits.size == 13 && super
15
12
  end
16
13
  end
17
14
  end
@@ -1,32 +1,33 @@
1
1
  module Bookland
2
- # An abstract unique commercial identifier for a product.
3
2
  class Identifier
4
- def self.calculate_checksum(payload)
5
- raise NotImplementedError
6
- end
7
-
8
3
  def self.valid?(raw)
9
4
  new(raw).valid?
10
5
  end
11
6
 
12
- def initialize(raw)
13
- @raw = raw
7
+ def self.calculate_checksum_digit(data_digits)
8
+ raise NotImplementedError
14
9
  end
15
10
 
16
- def checksum
17
- digits[-1]
11
+ attr :digits
12
+
13
+ def initialize(raw)
14
+ @digits = raw.split('')
18
15
  end
19
16
 
20
- def payload
17
+ def data_digits
21
18
  digits[0...-1]
22
19
  end
23
20
 
21
+ def checksum_digit
22
+ digits[-1]
23
+ end
24
+
24
25
  def to_s
25
- @raw
26
+ digits.join
26
27
  end
27
28
 
28
29
  def valid?
29
- checksum == self.class.calculate_checksum(payload)
30
+ checksum_digit == recalculate_checksum_digit
30
31
  end
31
32
 
32
33
  def ==(other)
@@ -35,8 +36,8 @@ module Bookland
35
36
 
36
37
  private
37
38
 
38
- def digits
39
- @digits ||= @raw.split ''
39
+ def recalculate_checksum_digit
40
+ self.class.calculate_checksum_digit(data_digits)
40
41
  end
41
42
  end
42
43
  end
data/lib/bookland/isbn.rb CHANGED
@@ -1,24 +1,9 @@
1
1
  module Bookland
2
- # An EAN that identifies a book.
3
2
  class ISBN < EAN
4
- # Converts the given ISBN to an ISBN-10.
5
- def self.to_isbn_10(raw)
6
- new(raw).to_isbn_10
7
- end
8
-
9
- # Converts the ISBN to an ISBN-10.
10
- def to_isbn_10
11
- raise InvalidISBN unless valid?
12
-
13
- new_payload = payload[3..11]
14
- new_checksum = ISBN10.calculate_checksum new_payload
15
-
16
- (new_payload << new_checksum).join
17
- end
3
+ PREFIXES = [%w(9 7 8), %w(9 7 9)]
18
4
 
19
- # Whether the ISBN is valid.
20
5
  def valid?
21
- !!@raw.match(/^97[89]/) && super
6
+ PREFIXES.include?(digits[0, 3]) && super
22
7
  end
23
8
  end
24
9
  end
@@ -1,3 +1,3 @@
1
1
  module Bookland
2
- VERSION = '2.0.0'
2
+ VERSION = '3.0.0'
3
3
  end
data/test/asin_test.rb ADDED
@@ -0,0 +1,35 @@
1
+ require 'test_helper'
2
+
3
+ class TestASIN < MiniTest::Test
4
+ def test_validates_isbn_like_asins
5
+ File.open('./test/data/isbns').each do |line|
6
+ asin = line.split.first.chomp
7
+ assert ASIN.valid?(asin)
8
+ end
9
+ end
10
+
11
+ def test_validates_proprietary_asins
12
+ ASIN.valid?('B000J8VLEC')
13
+ end
14
+
15
+ def test_does_not_validate_if_not_10_digits
16
+ refute ASIN.valid?('014310582')
17
+ refute ASIN.valid?('01431058255')
18
+ end
19
+
20
+ def test_does_not_validate_if_checksum_not_correct
21
+ refute ASIN.valid?('0143105820')
22
+ end
23
+
24
+ def test_converts_to_isbn
25
+ assert_equal '9780143105824', ASIN.to_isbn('0143105825')
26
+ end
27
+
28
+ def test_does_not_convert_proprietary_asins
29
+ assert_nil ASIN.to_isbn('B000J8VLEC')
30
+ end
31
+
32
+ def test_converts_to_asin
33
+ assert_equal '0143105825', ASIN.from_isbn('9780143105824')
34
+ end
35
+ end
File without changes
data/test/ean_test.rb ADDED
@@ -0,0 +1,15 @@
1
+ require 'test_helper'
2
+
3
+ class TestEAN < MiniTest::Test
4
+ def test_validates
5
+ assert EAN.valid?('0814916013890')
6
+ end
7
+
8
+ def test_does_not_validate_if_not_13_digits
9
+ refute EAN.valid?('978082647694')
10
+ end
11
+
12
+ def test_does_not_validate_if_checksum_incorrect
13
+ refute EAN.valid?('9780826476940')
14
+ end
15
+ end
@@ -0,0 +1,29 @@
1
+ require 'test_helper'
2
+
3
+ class TestIdentifier < MiniTest::Test
4
+ def setup
5
+ @id = Identifier.new('123')
6
+ end
7
+
8
+ def test_data_digits
9
+ assert_equal %w(1 2), @id.data_digits
10
+ end
11
+
12
+ def test_checksum_digit
13
+ assert_equal '3', @id.checksum_digit
14
+ end
15
+
16
+ def test_to_string
17
+ assert_equal '123', @id.to_s
18
+ end
19
+
20
+ def test_comparison
21
+ assert_equal Identifier.new('1'), Identifier.new('1')
22
+ refute_equal Identifier.new('1'), Identifier.new('2')
23
+ end
24
+
25
+ def test_validation_not_implemented
26
+ assert_raises(NotImplementedError) { Identifier.valid?('123') }
27
+ assert_raises(NotImplementedError) { @id.valid? }
28
+ end
29
+ end
data/test/isbn_test.rb ADDED
@@ -0,0 +1,14 @@
1
+ require 'test_helper'
2
+
3
+ class TestISBN < MiniTest::Test
4
+ def test_validates
5
+ File.open('./test/data/isbns').each do |line|
6
+ isbn = line.split.last.chomp
7
+ assert ISBN.valid?(isbn)
8
+ end
9
+ end
10
+
11
+ def test_does_not_validate_an_ean_that_is_not_a_book
12
+ refute ISBN.valid?('0814916013890')
13
+ end
14
+ end
@@ -0,0 +1,4 @@
1
+ require 'minitest/autorun'
2
+ require 'minitest/pride'
3
+ require 'bookland'
4
+ include Bookland
metadata CHANGED
@@ -1,28 +1,58 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bookland
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.0
5
- prerelease:
4
+ version: 3.0.0
6
5
  platform: ruby
7
6
  authors:
8
7
  - Hakan Ensari
9
8
  autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2012-04-05 00:00:00.000000000 Z
11
+ date: 2013-06-19 00:00:00.000000000 Z
13
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '1.3'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '1.3'
14
27
  - !ruby/object:Gem::Dependency
15
28
  name: rake
16
- requirement: &70194822851880 !ruby/object:Gem::Requirement
17
- none: false
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: minitest
43
+ requirement: !ruby/object:Gem::Requirement
18
44
  requirements:
19
45
  - - ~>
20
46
  - !ruby/object:Gem::Version
21
- version: 0.9.2
47
+ version: '5.0'
22
48
  type: :development
23
49
  prerelease: false
24
- version_requirements: *70194822851880
25
- description: Bookland provides EAN and ISBN classes.
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: '5.0'
55
+ description: An ISBN toolkit
26
56
  email: hakan.ensari@papercavalier.com
27
57
  executables: []
28
58
  extensions: []
@@ -36,38 +66,46 @@ files:
36
66
  - Rakefile
37
67
  - bookland.gemspec
38
68
  - lib/bookland.rb
69
+ - lib/bookland/asin.rb
39
70
  - lib/bookland/ean.rb
40
71
  - lib/bookland/identifier.rb
41
- - lib/bookland/invalid_isbn.rb
42
72
  - lib/bookland/isbn.rb
43
- - lib/bookland/isbn_10.rb
44
73
  - lib/bookland/version.rb
45
- - test/bookland_test.rb
46
- - test/isbns
74
+ - test/asin_test.rb
75
+ - test/data/isbns
76
+ - test/ean_test.rb
77
+ - test/identifier_test.rb
78
+ - test/isbn_test.rb
79
+ - test/test_helper.rb
47
80
  homepage: https://github.com/hakanensari/bookland
48
- licenses: []
81
+ licenses:
82
+ - MIT
83
+ metadata: {}
49
84
  post_install_message:
50
85
  rdoc_options: []
51
86
  require_paths:
52
87
  - lib
53
88
  required_ruby_version: !ruby/object:Gem::Requirement
54
- none: false
55
89
  requirements:
56
- - - ! '>='
90
+ - - '>='
57
91
  - !ruby/object:Gem::Version
58
92
  version: '0'
59
93
  required_rubygems_version: !ruby/object:Gem::Requirement
60
- none: false
61
94
  requirements:
62
- - - ! '>='
95
+ - - '>='
63
96
  - !ruby/object:Gem::Version
64
97
  version: '0'
65
98
  requirements: []
66
99
  rubyforge_project:
67
- rubygems_version: 1.8.11
100
+ rubygems_version: 2.0.2
68
101
  signing_key:
69
- specification_version: 3
70
- summary: EAN and ISBN classes
102
+ specification_version: 4
103
+ summary: An ISBN toolkit
71
104
  test_files:
72
- - test/bookland_test.rb
73
- - test/isbns
105
+ - test/asin_test.rb
106
+ - test/data/isbns
107
+ - test/ean_test.rb
108
+ - test/identifier_test.rb
109
+ - test/isbn_test.rb
110
+ - test/test_helper.rb
111
+ has_rdoc:
@@ -1,4 +0,0 @@
1
- module Bookland
2
- class InvalidISBN < StandardError
3
- end
4
- end
@@ -1,37 +0,0 @@
1
- module Bookland
2
- # The now-obsolete 10-digit ISBN.
3
- class ISBN10 < Identifier
4
- # Calculates the checksum for the 9-digit payload of an ISBN-10.
5
- def self.calculate_checksum(payload)
6
- payload.map! &:to_i
7
- weights = 10.downto(2).to_a
8
- sum = payload.zip(weights).inject(0) { |a , (i, j)| a + i * j }
9
- checksum = 11 - sum % 11
10
-
11
- case checksum
12
- when 0..9 then checksum.to_s
13
- when 10 then 'X'
14
- when 11 then '0'
15
- end
16
- end
17
-
18
- # Converts the given ISBN-10 to an ISBN.
19
- def self.to_isbn(raw)
20
- new(raw).to_isbn
21
- end
22
-
23
- # Converts the ISBN-10 to an ISBN.
24
- def to_isbn
25
- raise InvalidISBN unless valid?
26
-
27
- new_payload = [9, 7, 8] + payload
28
- new_checksum = ISBN.calculate_checksum new_payload
29
-
30
- (new_payload << new_checksum).join
31
- end
32
-
33
- def valid?
34
- @raw.size == 10 && super
35
- end
36
- end
37
- end
@@ -1,101 +0,0 @@
1
- $:.push File.expand_path('../../lib', __FILE__)
2
-
3
- require 'test/unit'
4
- require 'bookland'
5
-
6
- include Bookland
7
-
8
- module Test::Unit::Assertions
9
- def assert_false(object, message = '')
10
- assert_equal false, object, message
11
- end
12
- end
13
-
14
- class TestIdentifier < Test::Unit::TestCase
15
- def setup
16
- @id = Identifier.new '123'
17
- end
18
-
19
- def test_checksum
20
- assert_equal '3', @id.checksum
21
- end
22
-
23
- def test_payload
24
- assert_equal ['1', '2'], @id.payload
25
- end
26
-
27
- def test_comparison
28
- assert Identifier.new('1') == Identifier.new('1')
29
- assert Identifier.new('1') != Identifier.new('2')
30
- end
31
- end
32
-
33
- class TestEAN < Test::Unit::TestCase
34
- def test_validates_an_ean
35
- assert EAN.valid? '0814916013890'
36
- end
37
-
38
- def test_does_not_validate_if_not_13_digits
39
- assert_false EAN.valid?('978082647694')
40
- assert_false EAN.valid?('97808264769444')
41
- end
42
-
43
- def test_does_not_validate_if_checksum_not_correct
44
- assert_false EAN.valid?('9780826476940')
45
- end
46
- end
47
-
48
- class TestISBN < Test::Unit::TestCase
49
- def test_validates_isbns
50
- File.open(File.expand_path('../isbns', __FILE__)).each do |line|
51
- isbn = line.split.last.chomp
52
- assert ISBN.valid? isbn
53
- end
54
- end
55
-
56
- def test_does_not_validate_an_ean_that_is_not_a_book
57
- assert_false ISBN.valid?('0814916013890')
58
- end
59
-
60
- def test_converts_to_isbn_10
61
- isbn = ISBN.new '9780143105824'
62
- assert_equal '0143105825', isbn.to_isbn_10
63
- end
64
-
65
- def test_raises_error_when_converting_invalid_isbn
66
- isbn = ISBN.new '9780143105820'
67
- assert_raise InvalidISBN do
68
- isbn.to_isbn_10
69
- end
70
- end
71
- end
72
-
73
- class TestISBN10 < Test::Unit::TestCase
74
- def test_validates_isbn_10s
75
- File.open(File.expand_path('../isbns', __FILE__)).each do |line|
76
- isbn10 = line.split.first.chomp
77
- assert ISBN10.valid? isbn10
78
- end
79
- end
80
-
81
- def test_converts_to_isbn
82
- isbn10 = ISBN10.new '0143105825'
83
- assert_equal '9780143105824', isbn10.to_isbn
84
- end
85
-
86
- def test_raises_error_when_converting_invalid_isbn10
87
- isbn10 = ISBN10.new '0143105820'
88
- assert_raise InvalidISBN do
89
- isbn10.to_isbn
90
- end
91
- end
92
-
93
- def test_does_not_validate_if_not_13_digits
94
- assert_false EAN.valid?('014310582')
95
- assert_false EAN.valid?('01431058255')
96
- end
97
-
98
- def test_does_not_validate_if_checksum_not_correct
99
- assert_false EAN.valid?('0143105820')
100
- end
101
- end