barcodevalidation 1.0.0 → 2.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: 522d7b61575d8c85f1db57f9ccbefcfa07965ffa
4
- data.tar.gz: cd612cf9d41691e9b44003fd581c60b80771d73e
2
+ SHA256:
3
+ metadata.gz: d0ddfbb1e0066701228173d80f24f18eca5bf195e4cb0ba84d1a2b7cff1f306b
4
+ data.tar.gz: 21fd5a0a5eb2876b5b764c49d0ae2a4130a2cd4710e0ee3784b56221f5d0c895
5
5
  SHA512:
6
- metadata.gz: 7b16df4b9a082951160a1c1e9a06f8947304ae3413224e9521fa57441fefa15184fc58586a2f0e6f63c7cbaa2b220725f13243b7a2aa9f80c25d05bd81440f77
7
- data.tar.gz: 7e328aa855eaf1b4d52c61e91abc085747b90961ec1021a403f0affbb8699c5286aed4e70966631870561b8e90973bf7f66e40842a12f08cddf98fbb7b1f58f1
6
+ metadata.gz: eac5d8884e82da6c0f57b1042887d8337a6f1bebb91062b068919f42513e90a869edfd048389fd4529a08537a326a582dcd9d0110e327d8dd1726cd93eebb0fb
7
+ data.tar.gz: 8448952e7fa2e83336f67de3af3b6b1f3cee49d57ed180df5402c4d9b85136fa332ee345b4c4a8c024be909d709125e29d7ca42c0df228e4a5013b0d4c6e4d4c
@@ -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,107 @@ 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(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
+
50
+ bad = BarcodeValidation.scan(937_179_004_162)
51
+ # => #<BarcodeValidation::GTIN(937179004162)>
52
+ bad.valid? # => false
53
+ bad.check_digit # => #<BarcodeValidation::GTIN::CheckDigit(2) invalid: expected 7>
54
+ bad.check_digit.valid? # => false
55
+ bad.check_digit.actual # => #<BarcodeValidation::Digit(2)>
56
+ bad.check_digit.expected # => #<BarcodeValidation::Digit(7)>
57
+ ```
58
+
59
+
60
+
61
+ Development
62
+ -----------
63
+
64
+ Download the code from GitHub:
65
+
66
+ ```
67
+ git clone git@github.com:marketplacer/barcodevalidation.git
68
+ ```
69
+
70
+ Set up dependencies using Bundler:
71
+
72
+ ```
73
+ cd barcodevalidation
74
+ bin/setup
75
+ ```
76
+
77
+ Start the interactive development console:
78
+
79
+ ```
80
+ bin/console
81
+ ```
82
+
83
+ Run a build:
84
+
85
+ ```
86
+ bin/rake
87
+ ```
88
+
89
+ #### Code Quality Checks
90
+
91
+ Rubocop is used to enforce coding standards.
92
+
93
+ ```
94
+ bin/rubocop
95
+ bin/rubocop --help
96
+ ```
97
+
98
+
99
+
100
+ Continuous Integration
101
+ ----------------------
102
+
103
+ Code is automatically tested with each push, on both Travis CI and
104
+ Marketplacer's internal Buildkite.
105
+
106
+
107
+
108
+ Project Structure
109
+ -----------------
110
+ This project's structure is inspired by the Bundler skeleton for a new
111
+ Gem, created using `bundler gem barcodevalidation`.
112
+
113
+ * `.bundle/config`: Configuration for Bundler
114
+ * `.ruby-version`: Gives rvm, rbenv, chruby etc. a Ruby version to use
115
+ * `Gemfile`: Lists RubyGem dependencies, to be installed by Bundler
116
+ * `Rakefile`: Defines Rake tasks
117
+ * `bin/`: Contains binstubs, useful for development tasks
118
+ * `bundle`: Runs Bundler, in the correct way
119
+ * `console`: development console (equiv. to `bin/bundle exec pry`)
120
+ * `rake`: Runs Rake (equivalent to `bin/bundle exec rake`)
121
+ * `rubocop`: Runs Rubocop (equivalent to `bin/bundle exec rubocop`)
122
+ * `setup`: Sets up the project to be ready for development
123
+ * `config/boot.rb`: Prepares dependencies before loading the library
124
+ * `lib/`: Source files; this directory is added to Ruby's load path
125
+ * `script/ci`: The script run by Buildkite to start a build
126
+
127
+
128
+
129
+ License
130
+ -------
131
+
132
+ This project is licensed under the [MIT License]. See [LICENSE.md] for
133
+ the full text.
26
134
 
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
135
+ [MIT License]: <https://opensource.org/licenses/MIT>
136
+ [LICENSE.md]: <https://github.com/marketplacer/barcodevalidation/blob/master/LICENSE.md>
@@ -1,25 +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
9
- spec.authors = ["Alan Harper"]
10
- spec.email = ["alan@aussiegeek.net"]
11
- spec.summary = %q{Barcode validation library}
12
- spec.description = %q{Simple barcode validator. Just verifies that barcode checksum is valid}
13
- spec.homepage = ""
10
+ spec.version = BarcodeValidation::VERSION
11
+ spec.authors = ["Marketplacer"]
12
+ spec.email = ["it@marketplacer.com"]
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"]
20
27
 
21
- spec.add_development_dependency "bundler", "~> 1.6"
22
- spec.add_development_dependency "rake"
23
- spec.add_development_dependency "minitest"
24
- spec.add_development_dependency "codeclimate-test-reporter"
28
+ spec.add_runtime_dependency "adamantium"
25
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
- require "barcodevalidation/version"
1
+ # frozen_string_literal: true
2
2
 
3
- module Barcodevalidation
4
- def self.valid?(barcode)
5
- barcode = barcode.to_s
6
- return false unless [8, 10, 12, 13].include?(barcode.length)
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"
9
+ require "barcodevalidation/version"
7
10
 
8
- parts = barcode.rjust(18, '0').chars.map(&:to_i)
9
- checksum = parts.pop
11
+ module BarcodeValidation
12
+ class << self
13
+ def scan(input)
14
+ GTIN.new(sanitize(input))
15
+ end
10
16
 
11
- calculated_checksum = 0
12
- parts.each_with_index do |part, index|
13
- if index % 2 == 0
14
- calculated_checksum += (part * 3)
15
- else
16
- calculated_checksum += part
17
+ def scan!(input)
18
+ scan(input).tap do |result|
19
+ raise InvalidGTINError, input unless result.valid?
17
20
  end
18
21
  end
19
22
 
20
- calculated_checksum = ((calculated_checksum.to_f / 10).ceil * 10) - calculated_checksum
21
- checksum == calculated_checksum
23
+ private
22
24
 
23
- rescue ArgumentError
24
- false #we only accept numeric barcodes
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,26 @@
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
+ end
26
+ 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.0"
1
+ # frozen_string_literal: true
2
+
3
+ module BarcodeValidation
4
+ VERSION = "2.3.0"
3
5
  end
metadata CHANGED
@@ -1,113 +1,79 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: barcodevalidation
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 2.3.0
5
5
  platform: ruby
6
6
  authors:
7
- - Alan Harper
8
- autorequire:
9
- bindir: bin
7
+ - Marketplacer
8
+ autorequire:
9
+ bindir: exe
10
10
  cert_chain: []
11
- date: 2016-03-17 00:00:00.000000000 Z
11
+ date: 2020-10-28 00:00:00.000000000 Z
12
12
  dependencies:
13
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.6'
20
- type: :development
21
- prerelease: false
22
- version_requirements: !ruby/object:Gem::Requirement
23
- requirements:
24
- - - "~>"
25
- - !ruby/object:Gem::Version
26
- version: '1.6'
27
- - !ruby/object:Gem::Dependency
28
- name: rake
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
14
+ name: adamantium
43
15
  requirement: !ruby/object:Gem::Requirement
44
16
  requirements:
45
17
  - - ">="
46
18
  - !ruby/object:Gem::Version
47
19
  version: '0'
48
- type: :development
20
+ type: :runtime
49
21
  prerelease: false
50
22
  version_requirements: !ruby/object:Gem::Requirement
51
23
  requirements:
52
24
  - - ">="
53
25
  - !ruby/object:Gem::Version
54
26
  version: '0'
55
- - !ruby/object:Gem::Dependency
56
- name: codeclimate-test-reporter
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'
69
- description: Simple barcode validator. Just verifies that barcode checksum is valid
27
+ description: A RubyGem to parse and validate barcodes
70
28
  email:
71
- - alan@aussiegeek.net
29
+ - it@marketplacer.com
72
30
  executables: []
73
31
  extensions: []
74
32
  extra_rdoc_files: []
75
33
  files:
76
- - ".gitignore"
77
- - ".travis.yml"
78
- - Gemfile
79
- - LICENSE.txt
34
+ - LICENSE.md
80
35
  - README.md
81
- - Rakefile
82
36
  - barcodevalidation.gemspec
37
+ - config/boot.rb
83
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
84
54
  - lib/barcodevalidation/version.rb
85
- - test/minitest_helper.rb
86
- - test/test_barcodevalidation.rb
87
- homepage: ''
55
+ homepage: https://github.com/marketplacer/barcodevalidation
88
56
  licenses:
89
57
  - MIT
90
58
  metadata: {}
91
- post_install_message:
59
+ post_install_message:
92
60
  rdoc_options: []
93
61
  require_paths:
94
62
  - lib
95
63
  required_ruby_version: !ruby/object:Gem::Requirement
96
64
  requirements:
97
- - - ">="
65
+ - - "~>"
98
66
  - !ruby/object:Gem::Version
99
- version: '0'
67
+ version: '2.5'
100
68
  required_rubygems_version: !ruby/object:Gem::Requirement
101
69
  requirements:
102
70
  - - ">="
103
71
  - !ruby/object:Gem::Version
104
72
  version: '0'
105
73
  requirements: []
106
- rubyforge_project:
107
- rubygems_version: 2.5.1
108
- signing_key:
74
+ rubyforge_project:
75
+ rubygems_version: 2.7.6.2
76
+ signing_key:
109
77
  specification_version: 4
110
- summary: Barcode validation library
111
- test_files:
112
- - test/minitest_helper.rb
113
- - 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,4 +0,0 @@
1
- source 'https://rubygems.org'
2
-
3
- # Specify your gem's dependencies in barcodevalidation.gemspec
4
- gemspec
@@ -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,7 +0,0 @@
1
- require "codeclimate-test-reporter"
2
- CodeClimate::TestReporter.start
3
-
4
- $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
5
- require 'barcodevalidation'
6
-
7
- require 'minitest/autorun'
@@ -1,38 +0,0 @@
1
- require 'minitest_helper'
2
-
3
- class TestBarcodevalidation < MiniTest::Test
4
- def test_that_it_has_a_version_number
5
- refute_nil ::Barcodevalidation::VERSION
6
- end
7
-
8
- def test_valid_barcodes
9
- [
10
- 937179004167,
11
- '937179004167',
12
- 9312631133233,
13
- '0753759137885'
14
- ].each { |barcode| assert Barcodevalidation.valid?(barcode), barcode }
15
- end
16
-
17
- def test_invalid_barcodes
18
- [
19
- 144793, #too short
20
- 1234567890123, #invalid check digit
21
- 50140424, #invalid check digit
22
- 5420056646861,
23
- 10004336,
24
- '48cm',
25
- 123,
26
- 1, #make sure only valid length barcodes are accepted
27
- 22,
28
- 333,
29
- 4444,
30
- 55555,
31
- 666666,
32
- 777777,
33
- 99999999,
34
- 12345678901,
35
- 123456789012345
36
- ].each { |barcode| refute Barcodevalidation.valid?(barcode), barcode }
37
- end
38
- end