bookland 2.0.0 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
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