barcodevalidation 1.0.1 → 2.3.1

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: db8ad560ea3e5057b6cbaee32f7d3e4075a1e432
4
- data.tar.gz: a0022217ccfac363462b8bdac2c4e9d4b314d6ab
2
+ SHA256:
3
+ metadata.gz: 69f00057d24894273af1d7404d7152f18067b861c8c0a9c553995cc442328768
4
+ data.tar.gz: 30864684c4ea4a27b44907ba99ba9325109344ff257cb2da3bdd10055a5d0ead
5
5
  SHA512:
6
- metadata.gz: 1130c129b9825032db6054694b393bf58be61f2ce855ed46b56c9b139f94a08498ff5e9f903331b93093af5905241f86190ec418ad53fc3d8413d9a0a7ab476d
7
- data.tar.gz: 8d49c76a546b5b32d886f5fa32f03924c5a2de39c55047497a3e2d7c0f992f32b53a935e8c97b2a798a7c117dee62fc0254f87ebc168170da65e0ecabf8dbc4e
6
+ metadata.gz: d81de8495506f006796a5f40db56b365faf3df44859f954eba74dda4ec17dd18bd86c5f9b51e9e4205b845d1593be82e50f61245e0151b9d52cff9f2e4b5fd6a
7
+ data.tar.gz: 46ca1e1ea7522c114501e8d72c9cbc70eaabae4886d50885a6f620abf0bb28a9ce6f982f9177b0c324fd9aa418b7d0f6558a4923e9eb51e801a350910ee9fc0b
@@ -0,0 +1,23 @@
1
+ MIT License
2
+ ===========
3
+
4
+ Copyright (c) 2016 Marketplacer
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining a
7
+ copy of this software and associated documentation files (the
8
+ "Software"), to deal in the Software without restriction, including
9
+ without limitation the rights to use, copy, modify, merge, publish,
10
+ distribute, sublicense, and/or sell copies of the Software, and to
11
+ permit persons to whom the Software is furnished to do so, subject to
12
+ the following conditions:
13
+
14
+ The above copyright notice and this permission notice shall be included
15
+ in all copies or substantial portions of the Software.
16
+
17
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
21
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
22
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
23
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md CHANGED
@@ -1,14 +1,26 @@
1
- [![Build Status](https://travis-ci.org/exchangegroup/barcodevalidation.svg?branch=master)](https://travis-ci.org/exchangegroup/barcodevalidation)
1
+ barcodevalidation
2
+ =================
2
3
 
3
- # Barcodevalidation
4
+ [![Build Status][travis-badge]][travis]
5
+ [![Gem Version][rubygems-badge]][rubygems]
4
6
 
5
- A simple library to validate barcodes
7
+ [travis]: <https://travis-ci.org/marketplacer/barcodevalidation>
8
+ [travis-badge]: <https://travis-ci.org/marketplacer/barcodevalidation.svg?branch=master>
9
+ [rubygems]: <https://badge.fury.io/rb/barcodevalidation>
10
+ [rubygems-badge]: <https://badge.fury.io/rb/barcodevalidation.svg>
6
11
 
7
- ## Installation
12
+ A RubyGem to parse and validate barcodes.
13
+
14
+
15
+
16
+ Installation
17
+ ------------
8
18
 
9
19
  Add this line to your application's Gemfile:
10
20
 
11
- gem 'barcodevalidation'
21
+ ```ruby
22
+ gem "barcodevalidation"
23
+ ```
12
24
 
13
25
  And then execute:
14
26
 
@@ -18,14 +30,113 @@ Or install it yourself as:
18
30
 
19
31
  $ gem install barcodevalidation
20
32
 
21
- ## Usage
22
33
 
23
- Barcodevalidator.valid?(937179004167)
24
34
 
25
- ## Contributing
35
+ Usage
36
+ -----
37
+
38
+ The main API is `BarcodeValidation.scan`. It accepts a single argument,
39
+ and it's pretty flexible about what you give it.
40
+
41
+ ```ruby
42
+ gtin = BarcodeValidation.scan("937179-004167")
43
+ # => #<BarcodeValidation::GTIN::GTIN12(937179004167)>
44
+ gtin.to_s # => "937179004167"
45
+ gtin.valid? # => true
46
+ gtin.check_digit # => #<BarcodeValidation::GTIN::CheckDigit(7)>
47
+ gtin.first(6) # => #<BarcodeValidation::DigitSequence(937179)>
48
+ gtin.slice(0..5) # => #<BarcodeValidation::DigitSequence(937179)>
49
+ gtin.to_gtin_13 # => #<BarcodeValidation::GTIN::GTIN13(0937179004167)>
50
+ gtin.to_all_valid
51
+ # => [#<BarcodeValidation::GTIN::GTIN12(937179004167)>,
52
+ #<BarcodeValidation::GTIN::GTIN123(0937179004167)>]
53
+
54
+ bad = BarcodeValidation.scan(937_179_004_162)
55
+ # => #<BarcodeValidation::InvalidGTIN(937179004162)>
56
+ bad.valid? # => false
57
+ bad.check_digit # => #<BarcodeValidation::GTIN::CheckDigit(2) invalid: expected 7>
58
+ bad.check_digit.valid? # => false
59
+ bad.check_digit.actual # => #<BarcodeValidation::Digit(2)>
60
+ bad.check_digit.expected # => #<BarcodeValidation::Digit(7)>
61
+ bad.to_gtin_13 # => #<BarcodeValidation::InvalidGTIN(937179004162)>
62
+ bad.to_all_valid # => []
63
+ ```
64
+
65
+
66
+
67
+ Development
68
+ -----------
69
+
70
+ Download the code from GitHub:
71
+
72
+ ```
73
+ git clone git@github.com:marketplacer/barcodevalidation.git
74
+ ```
75
+
76
+ Set up dependencies using Bundler:
77
+
78
+ ```
79
+ cd barcodevalidation
80
+ bin/setup
81
+ ```
82
+
83
+ Start the interactive development console:
84
+
85
+ ```
86
+ bin/console
87
+ ```
88
+
89
+ Run a build:
90
+
91
+ ```
92
+ bin/rake
93
+ ```
94
+
95
+ #### Code Quality Checks
96
+
97
+ Rubocop is used to enforce coding standards.
98
+
99
+ ```
100
+ bin/rubocop
101
+ bin/rubocop --help
102
+ ```
103
+
104
+
105
+
106
+ Continuous Integration
107
+ ----------------------
108
+
109
+ Code is automatically tested with each push, on both Travis CI and
110
+ Marketplacer's internal Buildkite.
111
+
112
+
113
+
114
+ Project Structure
115
+ -----------------
116
+ This project's structure is inspired by the Bundler skeleton for a new
117
+ Gem, created using `bundler gem barcodevalidation`.
118
+
119
+ * `.bundle/config`: Configuration for Bundler
120
+ * `.ruby-version`: Gives rvm, rbenv, chruby etc. a Ruby version to use
121
+ * `Gemfile`: Lists RubyGem dependencies, to be installed by Bundler
122
+ * `Rakefile`: Defines Rake tasks
123
+ * `bin/`: Contains binstubs, useful for development tasks
124
+ * `bundle`: Runs Bundler, in the correct way
125
+ * `console`: development console (equiv. to `bin/bundle exec pry`)
126
+ * `rake`: Runs Rake (equivalent to `bin/bundle exec rake`)
127
+ * `rubocop`: Runs Rubocop (equivalent to `bin/bundle exec rubocop`)
128
+ * `setup`: Sets up the project to be ready for development
129
+ * `config/boot.rb`: Prepares dependencies before loading the library
130
+ * `lib/`: Source files; this directory is added to Ruby's load path
131
+ * `script/ci`: The script run by Buildkite to start a build
132
+
133
+
134
+
135
+ License
136
+ -------
137
+
138
+ This project is licensed under the [MIT License]. See [LICENSE.md] for
139
+ the full text.
26
140
 
27
- 1. Fork it ( https://github.com/exchangegroup/barcodevalidation/fork )
28
- 2. Create your feature branch (`git checkout -b my-new-feature`)
29
- 3. Commit your changes (`git commit -am 'Add some feature'`)
30
- 4. Push to the branch (`git push origin my-new-feature`)
31
- 5. Create a new Pull Request
141
+ [MIT License]: <https://opensource.org/licenses/MIT>
142
+ [LICENSE.md]: <https://github.com/marketplacer/barcodevalidation/blob/master/LICENSE.md>
@@ -1,20 +1,29 @@
1
- # coding: utf-8
2
- lib = File.expand_path('../lib', __FILE__)
1
+ # frozen_string_literal: true
2
+
3
+ lib = File.expand_path("lib", __dir__)
3
4
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
- require 'barcodevalidation/version'
5
+ require "barcodevalidation/version"
5
6
 
6
7
  Gem::Specification.new do |spec|
8
+ spec.required_ruby_version = "~> 2.5"
7
9
  spec.name = "barcodevalidation"
8
- spec.version = Barcodevalidation::VERSION
10
+ spec.version = BarcodeValidation::VERSION
9
11
  spec.authors = ["Marketplacer"]
10
12
  spec.email = ["it@marketplacer.com"]
11
- spec.summary = %q{Barcode validation library}
12
- spec.description = %q{Simple barcode validator. Just verifies that barcode checksum is valid}
13
- spec.homepage = ""
13
+
14
+ spec.summary = "Parses and validates barcodes"
15
+ spec.description = "A RubyGem to parse and validate barcodes"
16
+ spec.homepage = "https://github.com/marketplacer/#{spec.name}"
14
17
  spec.license = "MIT"
15
18
 
16
- spec.files = `git ls-files -z`.split("\x0")
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.files = %w[LICENSE.md README.md barcodevalidation.gemspec
20
+ config/*.rb lib/**/*.rb]
21
+ .flat_map { |pattern| Dir.glob(pattern) }
22
+ .reject { |f| File.directory?(f) }
23
+ spec.bindir = "exe"
24
+ spec.executables = spec.files
25
+ .grep(%r{^exe/}) { |f| File.basename(f) }
19
26
  spec.require_paths = ["lib"]
27
+
28
+ spec.add_runtime_dependency "adamantium"
20
29
  end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This script sets up the common environment for the project
4
+ #
5
+ # Require this file using:
6
+ #
7
+ # require File.expand_path("../config/boot.rb", __FILE__)
8
+ #
9
+ # This would work from any file located in the root of the project.
10
+ # For files that are nested within a subdirectory, use a relative path:
11
+ #
12
+ # # From within foo/bar/baz.rb relative to the root of the project
13
+ # require File.expand_path("../../../config/boot.rb", __FILE__)
14
+ #
15
+ # Then, to all RubyGems in the Gemfile available, use one of:
16
+ #
17
+ # - require "bundler/setup"
18
+ # - Bundler.setup
19
+ #
20
+ # To make only certain groups available, use:
21
+ #
22
+ # Bundler.setup(:default, :ci)
23
+ require "pathname"
24
+ project_root = Pathname.new(__FILE__).parent.parent
25
+
26
+ # Add lib directory to load path
27
+ lib = project_root + "lib"
28
+ $LOAD_PATH.unshift(lib.to_s) unless $LOAD_PATH.include?(lib.to_s)
29
+
30
+ # Tell Bundler explicitly which Gemfile to use
31
+ ENV["BUNDLE_GEMFILE"] ||= (project_root + "Gemfile").to_s
32
+ require "bundler"
@@ -1,26 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "barcodevalidation/mixin"
4
+ require "barcodevalidation/error"
5
+ require "barcodevalidation/digit"
6
+ require "barcodevalidation/digit_sequence"
7
+ require "barcodevalidation/gtin"
8
+ require "barcodevalidation/invalid_gtin"
1
9
  require "barcodevalidation/version"
2
10
 
3
- module Barcodevalidation
4
- def self.valid?(barcode)
5
- barcode = barcode.to_s.strip
6
- # only accept numeric codes
7
- return false unless barcode =~ /^\d+$/
8
- # accept lengths defined at gtin.info
9
- return false unless [8, 12, 13, 14].include?(barcode.length)
10
-
11
- parts = barcode.rjust(18, '0').chars.map(&:to_i)
12
- checksum = parts.pop
13
-
14
- calculated_checksum = 0
15
- parts.each_with_index do |part, index|
16
- if index % 2 == 0
17
- calculated_checksum += (part * 3)
18
- else
19
- calculated_checksum += part
11
+ module BarcodeValidation
12
+ class << self
13
+ def scan(input)
14
+ GTIN.new(sanitize(input))
15
+ end
16
+
17
+ def scan!(input)
18
+ scan(input).tap do |result|
19
+ raise InvalidGTINError, input unless result.valid?
20
20
  end
21
21
  end
22
22
 
23
- calculated_checksum = ((calculated_checksum.to_f / 10).ceil * 10) - calculated_checksum
24
- checksum == calculated_checksum
23
+ private
24
+
25
+ # Strips punctuation
26
+ def sanitize(input)
27
+ return input.gsub(/(\s|[-_])/, "") if input.respond_to? :gsub
28
+
29
+ input
30
+ end
31
+ end
32
+
33
+ class InvalidGTINError < ::ArgumentError
34
+ include Error
35
+
36
+ def initialize(input)
37
+ super "Invalid GTIN #{input.inspect}"
38
+ end
25
39
  end
26
40
  end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "delegate"
4
+ require_relative "error/argument_error_class"
5
+
6
+ module BarcodeValidation
7
+ class Digit < DelegateClass(Integer)
8
+ include Adamantium
9
+ include Mixin::ValueObject
10
+
11
+ INTEGER_CAST_ERRORS = [::ArgumentError, ::TypeError].freeze
12
+
13
+ def initialize(input)
14
+ value = Integer(input)
15
+ raise ::ArgumentError unless (0..9).cover? value
16
+
17
+ super(value)
18
+ rescue *INTEGER_CAST_ERRORS
19
+ raise Digit::ArgumentError, input
20
+ end
21
+
22
+ alias to_i __getobj__
23
+
24
+ ArgumentError = Error::ArgumentErrorClass.new(self)
25
+ end
26
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "forwardable"
4
+ require_relative "error/argument_error_class"
5
+
6
+ module BarcodeValidation
7
+ class DigitSequence < Array
8
+ extend Forwardable
9
+ include Adamantium::Flat
10
+ include Mixin::ValueObject
11
+
12
+ delegate to_s: :join
13
+ delegate cast: "self.class"
14
+
15
+ def self.cast(input)
16
+ input = input.to_s if input.is_a? Integer
17
+ input = input.chars if input.is_a? String
18
+ input
19
+ end
20
+
21
+ def initialize(values)
22
+ values = cast(values)
23
+ raise ArgumentError, values unless values.respond_to? :map
24
+
25
+ super(values.map { |value| BarcodeValidation::Digit.new(value) })
26
+ end
27
+
28
+ def ==(other)
29
+ case other
30
+ when String, Numeric then super(self.class.new(other))
31
+ else super
32
+ end
33
+ end
34
+
35
+ ArgumentError = Error::ArgumentErrorClass.new(DigitSequence)
36
+ end
37
+ end
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "error/argument_error_class"
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "forwardable"
4
+
5
+ module BarcodeValidation
6
+ module Error
7
+ class ArgumentErrorClass < ::ArgumentError
8
+ include BarcodeValidation::Error
9
+ extend Forwardable
10
+
11
+ delegate klass: "self.class"
12
+
13
+ def self.new(klass)
14
+ Class.new(self) { define_singleton_method(:klass) { klass } }
15
+ end
16
+
17
+ def initialize(input)
18
+ super "invalid value for #{klass}(): #{input.inspect}"
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "forwardable"
4
+ require_relative "invalid_gtin"
5
+ require_relative "gtin/base"
6
+ require_relative "gtin/check_digit"
7
+ require_relative "gtin/gtin8"
8
+ require_relative "gtin/gtin12"
9
+ require_relative "gtin/gtin13"
10
+ require_relative "gtin/gtin14"
11
+
12
+ module BarcodeValidation
13
+ module GTIN
14
+ class << self
15
+ def new(input)
16
+ (class_for_input(input) || BarcodeValidation::InvalidGTIN).new(input)
17
+ end
18
+
19
+ private
20
+
21
+ def class_for_input(input)
22
+ [GTIN8, GTIN12, GTIN13, GTIN14].find do |klass|
23
+ input.to_s.size == klass::VALID_LENGTH
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,102 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "forwardable"
4
+
5
+ module BarcodeValidation
6
+ module GTIN
7
+ class Base < BarcodeValidation::DigitSequence
8
+ MODULUS = 10
9
+
10
+ extend Forwardable
11
+
12
+ attr_reader :input
13
+
14
+ def initialize(input)
15
+ @input = input
16
+
17
+ super
18
+ rescue BarcodeValidation::Error => e
19
+ BarcodeValidation::InvalidGTIN.new(input, error: e)
20
+ end
21
+
22
+ def valid?
23
+ valid_length == length && check_digit.valid?
24
+ end
25
+
26
+ def valid_length
27
+ raise(AbstractMethodError, "Concrete classes must define the VALID_LENGTH constant") unless self.class.const_defined?(:VALID_LENGTH)
28
+
29
+ self.class::VALID_LENGTH
30
+ end
31
+
32
+ class AbstractMethodError < StandardError; end
33
+
34
+ def to_all_valid
35
+ [
36
+ to_gtin_8,
37
+ to_gtin_12,
38
+ to_gtin_13,
39
+ to_gtin_14,
40
+ ].select(&:valid?)
41
+ end
42
+
43
+ def to_gtin_8
44
+ is_a?(GTIN8) ? self : transcode_to(GTIN8)
45
+ end
46
+
47
+ def to_gtin_12
48
+ is_a?(GTIN12) ? self : transcode_to(GTIN12)
49
+ end
50
+
51
+ def to_gtin_13
52
+ is_a?(GTIN13) ? self : transcode_to(GTIN13)
53
+ end
54
+
55
+ def to_gtin_14
56
+ is_a?(GTIN14) ? self : transcode_to(GTIN14)
57
+ end
58
+
59
+ private
60
+
61
+ def check_digit
62
+ CheckDigit.new(last, expected: expected_check_digit)
63
+ end
64
+
65
+ def expected_check_digit
66
+ (MODULUS - weighted_checkable_digit_sum) % MODULUS
67
+ end
68
+
69
+ def weighted_checkable_digit_sum
70
+ checkable_digits
71
+ .zip([3, 1].cycle)
72
+ .map { |digit, factor| digit * factor }
73
+ .reduce(&:+)
74
+ end
75
+
76
+ def checkable_digits
77
+ take(length - 1).reverse.map(&:to_i)
78
+ end
79
+
80
+ # Instantiates the given class with the string value of this instance
81
+ # with any leading zeros stripped out, and then zero-padded up to the
82
+ # valid length of the given class. If the resulting string is <> the
83
+ # valid length of the target format, the returned object will be a
84
+ # BarcodeValidation::InvalidGTIN with valid? = false and a meaningful
85
+ # error message.
86
+ def transcode_to(klass)
87
+ gtin = klass.new(format("%0#{klass::VALID_LENGTH}d", to_s.gsub(/^0+/, "")))
88
+
89
+ if gtin.valid?
90
+ gtin
91
+ else
92
+ BarcodeValidation::InvalidGTIN.new(
93
+ input,
94
+ error: klass::ConversionError.new(klass).exception(input),
95
+ )
96
+ end
97
+ end
98
+
99
+ ConversionError = Error::ArgumentErrorClass.new(self)
100
+ end
101
+ end
102
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BarcodeValidation
4
+ module GTIN
5
+ class CheckDigit < DelegateClass(Digit)
6
+ include Adamantium::Flat
7
+ include Mixin::ValueObject
8
+
9
+ attr_reader :actual, :expected
10
+
11
+ def initialize(actual, expected: nil)
12
+ expected = actual if expected.nil?
13
+ @expected = Digit.new(expected)
14
+ @actual = Digit.new(actual)
15
+ super(@actual)
16
+ end
17
+
18
+ def valid?
19
+ actual == expected
20
+ end
21
+
22
+ def inspect
23
+ return super if valid?
24
+
25
+ "#<#{self.class}(#{actual}) invalid: expected #{expected}>"
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BarcodeValidation
4
+ module GTIN
5
+ class GTIN12 < BarcodeValidation::GTIN::Base
6
+ VALID_LENGTH = 12
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BarcodeValidation
4
+ module GTIN
5
+ class GTIN13 < BarcodeValidation::GTIN::Base
6
+ VALID_LENGTH = 13
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BarcodeValidation
4
+ module GTIN
5
+ class GTIN14 < BarcodeValidation::GTIN::Base
6
+ VALID_LENGTH = 14
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BarcodeValidation
4
+ module GTIN
5
+ class GTIN8 < BarcodeValidation::GTIN::Base
6
+ VALID_LENGTH = 8
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "delegate"
4
+
5
+ module BarcodeValidation
6
+ class InvalidGTIN < SimpleDelegator
7
+ def initialize(input, error: nil)
8
+ @error = error
9
+ super(input)
10
+ end
11
+
12
+ def valid?
13
+ false
14
+ end
15
+
16
+ def inspect
17
+ %(#<#{self.class} input=#{super} error="#{error_message}">)
18
+ end
19
+
20
+ def error_message
21
+ return @error.message if @error.respond_to? :message
22
+
23
+ @error.inspect
24
+ end
25
+
26
+ def to_all_valid
27
+ []
28
+ end
29
+
30
+ def to_gtin_8
31
+ self
32
+ end
33
+
34
+ def to_gtin_12
35
+ self
36
+ end
37
+
38
+ def to_gtin_13
39
+ self
40
+ end
41
+
42
+ def to_gtin_14
43
+ self
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "mixin/has_check_digit"
4
+ require_relative "mixin/value_object"
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BarcodeValidation
4
+ module Mixin
5
+ # Wraps #last as a CheckDigit
6
+ module HasCheckDigit
7
+ MODULUS = 10
8
+
9
+ def check_digit
10
+ GTIN::CheckDigit.new(last, expected: expected_check_digit)
11
+ end
12
+
13
+ private
14
+
15
+ def expected_check_digit
16
+ (MODULUS - weighted_checkable_digit_sum) % MODULUS
17
+ end
18
+
19
+ def weighted_checkable_digit_sum
20
+ checkable_digits
21
+ .zip([3, 1].cycle)
22
+ .map { |digit, factor| digit * factor }
23
+ .reduce(&:+)
24
+ end
25
+
26
+ def checkable_digits
27
+ take(length - 1).reverse.map(&:to_i)
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "adamantium"
4
+
5
+ module BarcodeValidation
6
+ module Mixin
7
+ module ValueObject
8
+ def self.included(mod)
9
+ mod.extend ClassMethods
10
+ end
11
+
12
+ module ClassMethods
13
+ # Memoizes return values based on the inputs
14
+ def new(*args)
15
+ (@__new_cache ||= {})[args] ||= super
16
+ end
17
+ end
18
+
19
+ def eql?(other)
20
+ object_id == other.object_id
21
+ end
22
+
23
+ def inspect
24
+ "#<#{description}>"
25
+ end
26
+
27
+ def pretty_print(value)
28
+ value.text inspect
29
+ end
30
+
31
+ private
32
+
33
+ def description
34
+ "#{self.class}(#{self})"
35
+ end
36
+ end
37
+ end
38
+ end
@@ -1,3 +1,5 @@
1
- module Barcodevalidation
2
- VERSION = "1.0.1"
1
+ # frozen_string_literal: true
2
+
3
+ module BarcodeValidation
4
+ VERSION = "2.3.1"
3
5
  end
metadata CHANGED
@@ -1,57 +1,79 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: barcodevalidation
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.1
4
+ version: 2.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Marketplacer
8
- autorequire:
9
- bindir: bin
8
+ autorequire:
9
+ bindir: exe
10
10
  cert_chain: []
11
- date: 2016-03-23 00:00:00.000000000 Z
12
- dependencies: []
13
- description: Simple barcode validator. Just verifies that barcode checksum is valid
11
+ date: 2020-11-05 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: adamantium
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ description: A RubyGem to parse and validate barcodes
14
28
  email:
15
29
  - it@marketplacer.com
16
30
  executables: []
17
31
  extensions: []
18
32
  extra_rdoc_files: []
19
33
  files:
20
- - ".gitignore"
21
- - ".travis.yml"
22
- - Gemfile
23
- - LICENSE.txt
34
+ - LICENSE.md
24
35
  - README.md
25
- - Rakefile
26
36
  - barcodevalidation.gemspec
37
+ - config/boot.rb
27
38
  - lib/barcodevalidation.rb
39
+ - lib/barcodevalidation/digit.rb
40
+ - lib/barcodevalidation/digit_sequence.rb
41
+ - lib/barcodevalidation/error.rb
42
+ - lib/barcodevalidation/error/argument_error_class.rb
43
+ - lib/barcodevalidation/gtin.rb
44
+ - lib/barcodevalidation/gtin/base.rb
45
+ - lib/barcodevalidation/gtin/check_digit.rb
46
+ - lib/barcodevalidation/gtin/gtin12.rb
47
+ - lib/barcodevalidation/gtin/gtin13.rb
48
+ - lib/barcodevalidation/gtin/gtin14.rb
49
+ - lib/barcodevalidation/gtin/gtin8.rb
50
+ - lib/barcodevalidation/invalid_gtin.rb
51
+ - lib/barcodevalidation/mixin.rb
52
+ - lib/barcodevalidation/mixin/has_check_digit.rb
53
+ - lib/barcodevalidation/mixin/value_object.rb
28
54
  - lib/barcodevalidation/version.rb
29
- - test/minitest_helper.rb
30
- - test/test_barcodevalidation.rb
31
- homepage: ''
55
+ homepage: https://github.com/marketplacer/barcodevalidation
32
56
  licenses:
33
57
  - MIT
34
58
  metadata: {}
35
- post_install_message:
59
+ post_install_message:
36
60
  rdoc_options: []
37
61
  require_paths:
38
62
  - lib
39
63
  required_ruby_version: !ruby/object:Gem::Requirement
40
64
  requirements:
41
- - - ">="
65
+ - - "~>"
42
66
  - !ruby/object:Gem::Version
43
- version: '0'
67
+ version: '2.5'
44
68
  required_rubygems_version: !ruby/object:Gem::Requirement
45
69
  requirements:
46
70
  - - ">="
47
71
  - !ruby/object:Gem::Version
48
72
  version: '0'
49
73
  requirements: []
50
- rubyforge_project:
51
- rubygems_version: 2.4.5
52
- signing_key:
74
+ rubyforge_project:
75
+ rubygems_version: 2.7.6.2
76
+ signing_key:
53
77
  specification_version: 4
54
- summary: Barcode validation library
55
- test_files:
56
- - test/minitest_helper.rb
57
- - test/test_barcodevalidation.rb
78
+ summary: Parses and validates barcodes
79
+ test_files: []
data/.gitignore DELETED
@@ -1,22 +0,0 @@
1
- *.gem
2
- *.rbc
3
- .bundle
4
- .config
5
- .yardoc
6
- Gemfile.lock
7
- InstalledFiles
8
- _yardoc
9
- coverage
10
- doc/
11
- lib/bundler/man
12
- pkg
13
- rdoc
14
- spec/reports
15
- test/tmp
16
- test/version_tmp
17
- tmp
18
- *.bundle
19
- *.so
20
- *.o
21
- *.a
22
- mkmf.log
@@ -1,7 +0,0 @@
1
- language: ruby
2
- rvm:
3
- - 2.0
4
- - 2.1.2
5
- addons:
6
- code_climate:
7
- repo_token: 9d0616ce6c97ce19ed8aef10e7a94cf8405ebe59a00551aa7cc9e509ad9c4301
data/Gemfile DELETED
@@ -1,6 +0,0 @@
1
- source 'https://rubygems.org'
2
-
3
- # Specify your gem's dependencies in barcodevalidation.gemspec
4
- gemspec
5
-
6
- gem 'minitest'
@@ -1,22 +0,0 @@
1
- Copyright (c) 2014 The Exchange Group
2
-
3
- MIT License
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining
6
- a copy of this software and associated documentation files (the
7
- "Software"), to deal in the Software without restriction, including
8
- without limitation the rights to use, copy, modify, merge, publish,
9
- distribute, sublicense, and/or sell copies of the Software, and to
10
- permit persons to whom the Software is furnished to do so, subject to
11
- the following conditions:
12
-
13
- The above copyright notice and this permission notice shall be
14
- included in all copies or substantial portions of the Software.
15
-
16
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
- LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
- OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
- WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile DELETED
@@ -1,9 +0,0 @@
1
- require "bundler/gem_tasks"
2
- require "rake/testtask"
3
-
4
- Rake::TestTask.new(:test) do |t|
5
- t.libs << "test"
6
- end
7
-
8
- task :default => :test
9
-
@@ -1,4 +0,0 @@
1
- $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
2
- require 'barcodevalidation'
3
-
4
- require 'minitest/autorun'
@@ -1,35 +0,0 @@
1
- require 'minitest_helper'
2
-
3
- class TestBarcodevalidation < MiniTest::Test
4
- def test_valid_barcodes
5
- [
6
- 937179004167,
7
- '937179004167',
8
- 9312631133233,
9
- '0753759137885'
10
- ].each { |barcode| assert Barcodevalidation.valid?(barcode), barcode }
11
- end
12
-
13
- def test_invalid_barcodes
14
- [
15
- 144793, #too short
16
- 1234567890123, #invalid check digit
17
- 50140424, #invalid check digit
18
- 5420056646861,
19
- 10004336,
20
- '48cm',
21
- 123,
22
- 1, #make sure only valid length barcodes are accepted
23
- 22,
24
- 333,
25
- 4444,
26
- 55555,
27
- 666666,
28
- 777777,
29
- 99999999,
30
- 12345678901,
31
- 123456789012345,
32
- 'BODGYBARCODE'
33
- ].each { |barcode| refute Barcodevalidation.valid?(barcode), barcode }
34
- end
35
- end