barcodevalidation 2.5.0 → 2.6.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
2
  SHA256:
3
- metadata.gz: f1472674218493f67abaf42f2c94c4009ca1aabb07180cee0bfd9ef3c6c2fed5
4
- data.tar.gz: f8aa280b1ca3ad091d13c4a1391d7598b82cbcd5db3d9a3c92c65cdb4ce2407b
3
+ metadata.gz: ba3b5afd4aee1020e30233ec636f17390d4ce3b0683f485e26811d84afe9e7e5
4
+ data.tar.gz: 1c533193d00fad326a78342876b42f15b5a4534d0cd4c47451962687c2dce95e
5
5
  SHA512:
6
- metadata.gz: 87096371c819a9efa4f2493edf47ae2d21cccb16922e9b1661aa11de5fcf82aab7a2031ba8ec2660d6026003f905488c793d996c65bc21ab3e0fd44255e672f4
7
- data.tar.gz: 7eaebe15a7d9ff6c8922b46ec6c1cea2b392235c5b2d245038456ae10c3e72618c5b20c465f1f13094cda06fae3aa123dd3c1fdd189c8f717e9fa04875c6c390
6
+ metadata.gz: f295608b02b3ce172d58b45572db6f1c0d566d55fa9277b59c1ba34098503d1bc9513cbb00c785169ff342a242c29c5398771bc578d23ce348c69984c90e84fe
7
+ data.tar.gz: 5784a212986f8973bd2e7d5bcfc473c0b61c9c92c194d966f554e86dedbf92943cf7766a89debe4ee0428967ab6e138b87b8b309a79c85b0fbdcc3b766ae31ac
data/README.md CHANGED
@@ -63,6 +63,46 @@ bad.to_all_valid # => []
63
63
  ```
64
64
 
65
65
 
66
+ Custom GTINs
67
+ ------------
68
+
69
+ If the standard GTINs provided are not enough for your needs, you can implement your own by subclassing `BarcodeValidation::GTIN::Base` or any of its subclasses. If your custom class overlaps with a default class or one of your other custom classes, you can declare `prioritize_before <other class>` to re-order their evaluation order.
70
+
71
+ An example:
72
+
73
+ ```ruby
74
+ # A custom class that handles any length GTIN as long as it starts with "123".
75
+ # Note that we must still provide a VALID_LENGTH to allow transcoding to other GTINs by zero-padding.
76
+ # Due to this inheriting from Base, it is automatically registered and added to the end of the list of classes to check if it `handles?` an input.
77
+ class MyCustomGTIN < BarcodeValidation::GTIN::Base
78
+ VALID_LENGTH = 20
79
+
80
+ def self.handles?(input)
81
+ input.start_with?("123") && input.length <= VALID_LENGTH
82
+ end
83
+
84
+ # Custom validity check
85
+ def valid?
86
+ self.class.handles?(input) && check_digit.valid?
87
+ end
88
+ end
89
+
90
+ # A custom implementation of GTIN13, which addresses a subset of the GTIN13 range.
91
+ class MyCustomGTIN13 < BarcodeValidation::GTIN::GTIN13
92
+ # Ensure we get a chance to handle GTINs before our parent,
93
+ # so we can handle the subset we care about and have our parent handle the rest.
94
+ prioritize_before BarcodeValidation::GTIN::GTIN13
95
+
96
+ def self.handles?(input)
97
+ input.start_with?("123") && super
98
+ end
99
+
100
+ def valid?
101
+ input.start_with?("123") && super
102
+ end
103
+ end
104
+ ```
105
+
66
106
 
67
107
  Development
68
108
  -----------
@@ -19,6 +19,34 @@ module BarcodeValidation
19
19
  BarcodeValidation::InvalidGTIN.new(input, error: e)
20
20
  end
21
21
 
22
+ # Does this class (potentially) handle a GTIN that matches the input?
23
+ # Subclasses can choose to implement their own logic. The default is to look at +VALID_LENGTH+ and use that to match the length of the input the class handles.
24
+ def self.handles?(input)
25
+ return false unless const_defined?(:VALID_LENGTH)
26
+
27
+ input.length == self::VALID_LENGTH
28
+ end
29
+
30
+ # Upon inheritance, register the subclass so users of the library can dynamically add more GTINs in their own code.
31
+ def self.inherited(subclass)
32
+ BarcodeValidation::GTIN.append_gtin_class(subclass)
33
+ end
34
+
35
+ # Ensure this class is earlier in the GTIN classes list than +other_gtin_class+ and thus will get asked earlier if it handles a GTIN.
36
+ def self.prioritize_before(other_gtin_class)
37
+ raise ArgumentError, "The class you want to prioritize before is not a registered prioritized GTIN class." unless GTIN.gtin_class?(other_gtin_class)
38
+
39
+ GTIN.reprioritize_before(self, other_gtin_class)
40
+ end
41
+
42
+ # This class is abstract and should not be included in the list of GTIN classes that actually implement a GTIN.
43
+ def self.abstract_class
44
+ BarcodeValidation::GTIN.remove_gtin_class(self)
45
+ end
46
+
47
+ # GTIN::Base is an abstract class. See GTIN8/12/13/14 for implementations of actual GTINs.
48
+ abstract_class
49
+
22
50
  def valid?
23
51
  valid_length == length && check_digit.valid?
24
52
  end
@@ -2,27 +2,62 @@
2
2
 
3
3
  require "forwardable"
4
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
5
 
12
6
  module BarcodeValidation
7
+ # GTIN is responsible for wrapping input in an appropriate GTIN::Base sub-class.
8
+ # An important part of this involves managing the prioritized list of GTIN classes we use for handling input.
9
+ # The methods implemented here are used by GTIN::Base to manage this list and prioritize classes.
13
10
  module GTIN
14
11
  class << self
15
12
  def new(input)
16
13
  (class_for_input(input) || BarcodeValidation::InvalidGTIN).new(input)
17
14
  end
18
15
 
16
+ # Adds the provided class to the back of the list of prioritized GTIN classes.
17
+ def append_gtin_class(gtin_class)
18
+ prioritized_gtin_classes.push(gtin_class) unless gtin_class?(gtin_class)
19
+ nil
20
+ end
21
+
22
+ # Ensure the provided class is removed from the list of prioritized GTIN classes.
23
+ def remove_gtin_class(gtin_class)
24
+ prioritized_gtin_classes.delete(gtin_class)
25
+ nil
26
+ end
27
+
28
+ # Is this a registered prioritized GTIN class?
29
+ # @return [true, false]
30
+ def gtin_class?(gtin_class)
31
+ prioritized_gtin_classes.include?(gtin_class)
32
+ end
33
+
34
+ # @param [Class] high_priority_class The higher priority GTIN class you want to move before the low priority class
35
+ # @param [Class] low_priority_class The low priority GTIN class that the high priority one is moved before
36
+ def reprioritize_before(high_priority_class, low_priority_class)
37
+ low_priority_index = prioritized_gtin_classes.index(low_priority_class)
38
+ remove_gtin_class(high_priority_class)
39
+ prioritized_gtin_classes.insert(low_priority_index, high_priority_class)
40
+ nil
41
+ end
42
+
19
43
  private
20
44
 
45
+ def prioritized_gtin_classes
46
+ @prioritized_gtin_classes ||= []
47
+ end
48
+
21
49
  def class_for_input(input)
22
- [GTIN8, GTIN12, GTIN13, GTIN14].find do |klass|
23
- input.to_s.size == klass::VALID_LENGTH
24
- end
50
+ input = input.to_s.freeze
51
+ prioritized_gtin_classes.find { |klass| klass.handles?(input) }
25
52
  end
26
53
  end
27
54
  end
28
55
  end
56
+
57
+ # Load GTIN implementations after we have our registration setup
58
+ require_relative "gtin/base"
59
+ require_relative "gtin/check_digit"
60
+ require_relative "gtin/gtin8"
61
+ require_relative "gtin/gtin12"
62
+ require_relative "gtin/gtin13"
63
+ require_relative "gtin/gtin14"
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module BarcodeValidation
4
- VERSION = "2.5.0"
4
+ VERSION = "2.6.0"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: barcodevalidation
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.5.0
4
+ version: 2.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Marketplacer
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-08-30 00:00:00.000000000 Z
11
+ date: 2022-09-29 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: A RubyGem to parse and validate barcodes
14
14
  email: