sec_id 6.0.0 → 7.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 +4 -4
- data/CHANGELOG.md +21 -0
- data/MIGRATION.md +147 -0
- data/README.md +116 -44
- data/lib/sec_id/active_model.rb +1 -1
- data/lib/sec_id/base.rb +63 -14
- data/lib/sec_id/cei.rb +7 -7
- data/lib/sec_id/cik.rb +1 -1
- data/lib/sec_id/concerns/checkable.rb +90 -46
- data/lib/sec_id/concerns/generatable.rb +5 -5
- data/lib/sec_id/concerns/normalizable.rb +4 -4
- data/lib/sec_id/concerns/validatable.rb +7 -7
- data/lib/sec_id/cusip.rb +8 -8
- data/lib/sec_id/deprecation.rb +26 -0
- data/lib/sec_id/detector.rb +3 -26
- data/lib/sec_id/dti.rb +8 -14
- data/lib/sec_id/figi.rb +9 -9
- data/lib/sec_id/iban.rb +20 -20
- data/lib/sec_id/isin.rb +9 -9
- data/lib/sec_id/lei.rb +10 -10
- data/lib/sec_id/occ.rb +1 -1
- data/lib/sec_id/scanner.rb +17 -22
- data/lib/sec_id/sedol.rb +11 -11
- data/lib/sec_id/upi.rb +76 -0
- data/lib/sec_id/valoren.rb +2 -2
- data/lib/sec_id/version.rb +1 -1
- data/lib/sec_id/wkn.rb +1 -1
- data/lib/sec_id.rb +11 -6
- data/sec_id.gemspec +2 -2
- data/sig/sec_id/base.rbs +15 -4
- data/sig/sec_id/cei.rbs +4 -0
- data/sig/sec_id/concerns/checkable.rbs +17 -7
- data/sig/sec_id/concerns/generatable.rbs +1 -1
- data/sig/sec_id/concerns/validatable.rbs +1 -1
- data/sig/sec_id/cusip.rbs +4 -0
- data/sig/sec_id/deprecation.rbs +6 -0
- data/sig/sec_id/detector.rbs +0 -6
- data/sig/sec_id/dti.rbs +6 -1
- data/sig/sec_id/figi.rbs +4 -0
- data/sig/sec_id/iban.rbs +7 -3
- data/sig/sec_id/isin.rbs +4 -0
- data/sig/sec_id/lei.rbs +5 -1
- data/sig/sec_id/scanner.rbs +2 -4
- data/sig/sec_id/sedol.rbs +4 -0
- data/sig/sec_id/upi.rbs +29 -0
- data/sig/sec_id.rbs +5 -2
- metadata +7 -3
data/lib/sec_id/upi.rb
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module SecID
|
|
4
|
+
# Unique Product Identifier (UPI, ISO 4914) - a 12-character code that identifies
|
|
5
|
+
# OTC derivative products for regulatory reporting, issued by the ANNA Derivatives
|
|
6
|
+
# Service Bureau.
|
|
7
|
+
#
|
|
8
|
+
# Format: fixed 'QZ' prefix + 9-character body + 1 check character, drawn from a
|
|
9
|
+
# 30-symbol alphabet (digits 0-9 plus consonants; vowels and 'Y' never appear).
|
|
10
|
+
# Validated fully offline via ISO 7064 hybrid MOD 31,30 over the 11 preceding characters.
|
|
11
|
+
#
|
|
12
|
+
# @see https://www.anna-dsb.com
|
|
13
|
+
#
|
|
14
|
+
# @example Validate a UPI
|
|
15
|
+
# SecID::UPI.valid?('QZRBG6ZTKS42') #=> true
|
|
16
|
+
#
|
|
17
|
+
# @example Restore check character
|
|
18
|
+
# SecID::UPI.restore('QZRBG6ZTKS4') #=> 'QZRBG6ZTKS42'
|
|
19
|
+
class UPI < Base
|
|
20
|
+
include Checkable
|
|
21
|
+
|
|
22
|
+
# Human-readable name of the standard.
|
|
23
|
+
FULL_NAME = 'Unique Product Identifier'
|
|
24
|
+
# Valid length of a normalized identifier.
|
|
25
|
+
ID_LENGTH = 12
|
|
26
|
+
# A representative valid identifier.
|
|
27
|
+
EXAMPLE = 'QZRBG6ZTKS42'
|
|
28
|
+
# Pattern matching the identifier's permitted character set (digits + consonants, no vowels/Y).
|
|
29
|
+
VALID_CHARS_REGEX = /\A[0-9B-DF-HJ-NP-TV-XZ]+\z/
|
|
30
|
+
|
|
31
|
+
# Regular expression for parsing UPI components: fixed 'QZ' prefix, 9-character body,
|
|
32
|
+
# optional check character.
|
|
33
|
+
ID_REGEX = /\A
|
|
34
|
+
(?<identifier>QZ[0-9B-DF-HJ-NP-TV-XZ]{9})
|
|
35
|
+
(?<checksum>[0-9B-DF-HJ-NP-TV-XZ])?
|
|
36
|
+
\z/x
|
|
37
|
+
|
|
38
|
+
# The 30-symbol UPI alphabet, ordered by check-character value (0-29).
|
|
39
|
+
ALPHABET = '0123456789BCDFGHJKLMNPQRSTVWXZ'.chars.freeze
|
|
40
|
+
|
|
41
|
+
# Maps each alphabet character to its check-character value (0-29).
|
|
42
|
+
ALPHABET_VALUE = ALPHABET.each_with_index.to_h.freeze
|
|
43
|
+
|
|
44
|
+
# Characters valid in a UPI body (same alphabet as VALID_CHARS_REGEX).
|
|
45
|
+
GENERATE_CHARSET = ALPHANUMERIC.grep(VALID_CHARS_REGEX).freeze
|
|
46
|
+
|
|
47
|
+
# @param upi [String] the UPI string to parse
|
|
48
|
+
def initialize(upi)
|
|
49
|
+
upi_parts = parse upi
|
|
50
|
+
@identifier = upi_parts[:identifier]
|
|
51
|
+
@checksum = upi_parts[:checksum]
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# @return [String] the calculated check character
|
|
55
|
+
# @raise [InvalidFormatError] if the UPI format is invalid
|
|
56
|
+
def calculate_checksum
|
|
57
|
+
validate_format_for_calculation!
|
|
58
|
+
mod31_30_check_char(identifier, ALPHABET, ALPHABET_VALUE)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# Generates a random UPI body: the fixed 'QZ' prefix plus 9 characters drawn
|
|
62
|
+
# from the UPI alphabet.
|
|
63
|
+
#
|
|
64
|
+
# @param random [Random] source of randomness
|
|
65
|
+
# @return [String] an 11-character UPI body without check character
|
|
66
|
+
def self.generate_body(random)
|
|
67
|
+
"QZ#{random_string(GENERATE_CHARSET, 9, random: random)}"
|
|
68
|
+
end
|
|
69
|
+
private_class_method :generate_body
|
|
70
|
+
|
|
71
|
+
private
|
|
72
|
+
|
|
73
|
+
# @return [Hash]
|
|
74
|
+
def components = { checksum: }
|
|
75
|
+
end
|
|
76
|
+
end
|
data/lib/sec_id/valoren.rb
CHANGED
|
@@ -6,7 +6,7 @@ module SecID
|
|
|
6
6
|
#
|
|
7
7
|
# Format: 5-9 numeric digits
|
|
8
8
|
#
|
|
9
|
-
# @note Valoren identifiers have no
|
|
9
|
+
# @note Valoren identifiers have no checksum and validation is based solely on format.
|
|
10
10
|
#
|
|
11
11
|
# @see https://en.wikipedia.org/wiki/Valoren_number
|
|
12
12
|
#
|
|
@@ -52,7 +52,7 @@ module SecID
|
|
|
52
52
|
end
|
|
53
53
|
|
|
54
54
|
# @param country_code [String] the ISO 3166-1 alpha-2 country code (default: 'CH')
|
|
55
|
-
# @return [ISIN] a new ISIN instance with calculated
|
|
55
|
+
# @return [ISIN] a new ISIN instance with calculated checksum
|
|
56
56
|
# @raise [InvalidFormatError] if the country code is not CH or LI
|
|
57
57
|
def to_isin(country_code = 'CH')
|
|
58
58
|
unless ISIN_COUNTRY_CODES.include?(country_code)
|
data/lib/sec_id/version.rb
CHANGED
data/lib/sec_id/wkn.rb
CHANGED
|
@@ -38,7 +38,7 @@ module SecID
|
|
|
38
38
|
end
|
|
39
39
|
|
|
40
40
|
# @param country_code [String] the ISO 3166-1 alpha-2 country code (default: 'DE')
|
|
41
|
-
# @return [ISIN] a new ISIN instance with calculated
|
|
41
|
+
# @return [ISIN] a new ISIN instance with calculated checksum
|
|
42
42
|
# @raise [InvalidFormatError] if the country code is not DE
|
|
43
43
|
# @raise [InvalidFormatError] if the WKN format is invalid
|
|
44
44
|
def to_isin(country_code = 'DE')
|
data/lib/sec_id.rb
CHANGED
|
@@ -4,7 +4,7 @@ require 'sec_id/version'
|
|
|
4
4
|
|
|
5
5
|
# Toolkit for securities identifiers — validate, normalize, parse, detect, convert,
|
|
6
6
|
# generate, and classify ISIN, CUSIP, CEI, SEDOL, FIGI, LEI, IBAN, CIK, OCC, WKN,
|
|
7
|
-
# Valoren, CFI, FISN, BIC, and
|
|
7
|
+
# Valoren, CFI, FISN, BIC, DTI, and UPI.
|
|
8
8
|
#
|
|
9
9
|
# @see https://github.com/svyatov/sec_id
|
|
10
10
|
module SecID
|
|
@@ -14,8 +14,12 @@ module SecID
|
|
|
14
14
|
# Raised for invalid format, length, or characters.
|
|
15
15
|
class InvalidFormatError < Error; end
|
|
16
16
|
|
|
17
|
-
# Raised when the
|
|
18
|
-
class
|
|
17
|
+
# Raised when the checksum does not match the calculated value.
|
|
18
|
+
class InvalidChecksumError < Error; end
|
|
19
|
+
|
|
20
|
+
# @deprecated Use {InvalidChecksumError}. Kept as a v7 bridge (same class object,
|
|
21
|
+
# so `rescue` under either name keeps working); removed in v8.
|
|
22
|
+
InvalidCheckDigitError = InvalidChecksumError
|
|
19
23
|
|
|
20
24
|
# Raised for type-specific structural errors (invalid prefix, category, group, BBAN, or date).
|
|
21
25
|
class InvalidStructureError < Error; end
|
|
@@ -85,7 +89,7 @@ module SecID
|
|
|
85
89
|
# @return [Hash] hash with :input and :candidates keys
|
|
86
90
|
def explain(str, types: nil)
|
|
87
91
|
input = str.to_s.strip
|
|
88
|
-
target_keys = types || identifier_list.map
|
|
92
|
+
target_keys = types || identifier_list.map(&:type_key)
|
|
89
93
|
candidates = target_keys.map do |key|
|
|
90
94
|
instance = self[key].new(input)
|
|
91
95
|
{ type: key, valid: instance.valid?, errors: instance.errors.details }
|
|
@@ -143,8 +147,7 @@ module SecID
|
|
|
143
147
|
|
|
144
148
|
# @return [void]
|
|
145
149
|
def register_identifier(klass)
|
|
146
|
-
|
|
147
|
-
identifier_map[key] = klass
|
|
150
|
+
identifier_map[klass.type_key] = klass
|
|
148
151
|
identifier_list << klass
|
|
149
152
|
@detector = nil
|
|
150
153
|
@scanner = nil
|
|
@@ -196,6 +199,7 @@ module SecID
|
|
|
196
199
|
end
|
|
197
200
|
end
|
|
198
201
|
|
|
202
|
+
require 'sec_id/deprecation'
|
|
199
203
|
require 'sec_id/deep_freeze'
|
|
200
204
|
require 'sec_id/errors'
|
|
201
205
|
require 'sec_id/concerns/normalizable'
|
|
@@ -220,6 +224,7 @@ require 'sec_id/cfi'
|
|
|
220
224
|
require 'sec_id/fisn'
|
|
221
225
|
require 'sec_id/bic'
|
|
222
226
|
require 'sec_id/dti'
|
|
227
|
+
require 'sec_id/upi'
|
|
223
228
|
|
|
224
229
|
# Auto-activate the ActiveModel validator inside Rails; a no-op everywhere else (keeps the
|
|
225
230
|
# default require zero-dependency). See SecID::Railtie and lib/sec_id/active_model.rb.
|
data/sec_id.gemspec
CHANGED
|
@@ -13,11 +13,11 @@ Gem::Specification.new do |spec|
|
|
|
13
13
|
spec.summary = 'A Ruby toolkit for securities identifiers — validate, parse, normalize, detect, convert, ' \
|
|
14
14
|
'generate, and classify.'
|
|
15
15
|
spec.description = 'Validate, normalize, parse, convert, generate, and classify securities identifiers. ' \
|
|
16
|
-
'Auto-detect identifier type from any string. Calculate and restore
|
|
16
|
+
'Auto-detect identifier type from any string. Calculate and restore checksums. Generate ' \
|
|
17
17
|
'format-valid identifiers as test fixtures. Decode CFI codes to full ISO 10962:2021 ' \
|
|
18
18
|
'classifications. Includes an opt-in ActiveModel/Rails validator that adds no runtime ' \
|
|
19
19
|
'dependency. Supports ISIN, CUSIP, CEI, SEDOL, FIGI, LEI, IBAN, CIK, OCC, WKN, Valoren, ' \
|
|
20
|
-
'CFI, FISN, BIC, and
|
|
20
|
+
'CFI, FISN, BIC, DTI, and UPI.'
|
|
21
21
|
spec.homepage = 'https://github.com/svyatov/sec_id'
|
|
22
22
|
spec.license = 'MIT'
|
|
23
23
|
|
data/sig/sec_id/base.rbs
CHANGED
|
@@ -33,13 +33,20 @@ module SecID
|
|
|
33
33
|
# RBS forbids narrowing an inherited ivar's type.
|
|
34
34
|
def identifier: () -> String?
|
|
35
35
|
|
|
36
|
+
def self.type_key: () -> Symbol
|
|
37
|
+
# `@api private` in YARD, but public here: Detector and Scanner call it from outside.
|
|
38
|
+
def self.detection_priority: () -> Array[Integer | Float | nil]
|
|
36
39
|
def self.short_name: () -> String
|
|
37
40
|
def self.full_name: () -> String
|
|
38
41
|
def self.id_length: () -> (Integer | ::Range[Integer] | ::Array[Integer])
|
|
39
42
|
def self.length_values: () -> (::Array[Integer] | ::Range[Integer])
|
|
40
43
|
def self.length_specificity: () -> (Integer | Float | nil)
|
|
41
44
|
def self.example: () -> String
|
|
45
|
+
def self.has_checksum?: () -> bool
|
|
46
|
+
|
|
47
|
+
# @deprecated v7 bridge alias for `has_checksum?`; removed in v8.
|
|
42
48
|
def self.has_check_digit?: () -> bool
|
|
49
|
+
|
|
43
50
|
def self.inherited: (singleton(Base) subclass) -> void
|
|
44
51
|
|
|
45
52
|
def initialize: (SecID::input _sec_id_number) -> void
|
|
@@ -49,24 +56,28 @@ module SecID
|
|
|
49
56
|
def hash: () -> Integer
|
|
50
57
|
def to_h: () -> Hash[Symbol, untyped]
|
|
51
58
|
def as_json: (*untyped) -> Hash[Symbol, untyped]
|
|
59
|
+
def deconstruct_keys: (::Array[Symbol]? _keys) -> Hash[Symbol, untyped]
|
|
52
60
|
|
|
53
|
-
#
|
|
61
|
+
# Checksum surface. Only the types that `include Checkable` implement these
|
|
54
62
|
# (they raise/NoMethodError otherwise); declared on Base so `Generatable#generate`
|
|
55
|
-
# and `Checkable::ClassMethods` type-check without narrowing on `
|
|
63
|
+
# and `Checkable::ClassMethods` type-check without narrowing on `has_checksum?`.
|
|
56
64
|
def restore: () -> String
|
|
57
65
|
def restore!: () -> self
|
|
58
|
-
def
|
|
66
|
+
def calculate_checksum: () -> (Integer | String)
|
|
59
67
|
|
|
60
68
|
def comparison_id: () -> String
|
|
61
69
|
|
|
62
70
|
private
|
|
63
71
|
|
|
72
|
+
def components_with_deprecation_bridge: () -> Hash[Symbol, untyped]
|
|
64
73
|
def components: () -> Hash[Symbol, untyped]
|
|
65
74
|
def parse: (SecID::input sec_id_number) -> (::MatchData | ::Hash[Symbol, untyped])
|
|
66
75
|
|
|
67
76
|
@full_id: String
|
|
68
77
|
@identifier: untyped
|
|
69
78
|
self.@short_name: String
|
|
70
|
-
self.@
|
|
79
|
+
self.@has_checksum: bool
|
|
80
|
+
self.@type_key: Symbol
|
|
81
|
+
self.@detection_priority: Array[Integer | Float | nil]
|
|
71
82
|
end
|
|
72
83
|
end
|
data/sig/sec_id/cei.rbs
CHANGED
|
@@ -15,7 +15,11 @@ module SecID
|
|
|
15
15
|
attr_reader entity_id: String?
|
|
16
16
|
|
|
17
17
|
def initialize: (SecID::input cei) -> void
|
|
18
|
+
def calculate_checksum: () -> Integer
|
|
19
|
+
def self.checksum: (SecID::input id) -> Integer
|
|
20
|
+
# @deprecated v7 bridge alias for `calculate_checksum`; removed in v8.
|
|
18
21
|
def calculate_check_digit: () -> Integer
|
|
22
|
+
# @deprecated v7 bridge alias for `checksum`; removed in v8.
|
|
19
23
|
def self.check_digit: (SecID::input id) -> Integer
|
|
20
24
|
private def self.generate_body: (Random random) -> String
|
|
21
25
|
|
|
@@ -1,26 +1,35 @@
|
|
|
1
1
|
module SecID
|
|
2
|
-
# Provides
|
|
2
|
+
# Provides checksum validation and calculation for identifiers with a checksum.
|
|
3
3
|
module Checkable : SecID::Base
|
|
4
4
|
CHAR_TO_DIGITS: Hash[String, Integer | Array[Integer]]
|
|
5
5
|
CHAR_TO_DIGIT: Hash[String, Integer]
|
|
6
6
|
|
|
7
7
|
def self.included: (Module base) -> void
|
|
8
8
|
|
|
9
|
-
attr_reader
|
|
9
|
+
attr_reader checksum: (Integer | String)?
|
|
10
10
|
|
|
11
11
|
# Class methods added when Checkable is included.
|
|
12
12
|
module ClassMethods : SecID::_IdentifierClass
|
|
13
|
-
def restore: (SecID::input
|
|
14
|
-
def restore!: (SecID::input
|
|
13
|
+
def restore: (SecID::input id_without_checksum) -> String
|
|
14
|
+
def restore!: (SecID::input id_without_checksum) -> Base
|
|
15
|
+
def checksum: (SecID::input id) -> (Integer | String)
|
|
16
|
+
|
|
17
|
+
# @deprecated v7 bridge alias for `checksum`; removed in v8.
|
|
15
18
|
def check_digit: (SecID::input id) -> (Integer | String)
|
|
16
19
|
end
|
|
17
20
|
|
|
18
21
|
def valid?: () -> bool
|
|
19
22
|
def restore: () -> String
|
|
20
23
|
def restore!: () -> self
|
|
21
|
-
def
|
|
24
|
+
def calculate_checksum: () -> (Integer | String)
|
|
22
25
|
def to_s: () -> String
|
|
23
26
|
|
|
27
|
+
# @deprecated v7 bridge alias for `checksum`; removed in v8.
|
|
28
|
+
def check_digit: () -> (Integer | String)?
|
|
29
|
+
|
|
30
|
+
# @deprecated v7 bridge alias for `calculate_checksum`; removed in v8.
|
|
31
|
+
def calculate_check_digit: () -> (Integer | String)
|
|
32
|
+
|
|
24
33
|
private
|
|
25
34
|
|
|
26
35
|
def luhn_sum_double_add_double: (Array[Integer] digits) -> Integer
|
|
@@ -29,13 +38,14 @@ module SecID
|
|
|
29
38
|
def reversed_digits_single: (untyped id) -> Array[Integer]
|
|
30
39
|
def reversed_digits_multi: (untyped id) -> Array[Integer]
|
|
31
40
|
def error_codes: () -> Array[Symbol]
|
|
32
|
-
def
|
|
41
|
+
def checksum_width: () -> Integer
|
|
33
42
|
def validation_message: (Symbol code) -> String?
|
|
34
43
|
def validate_format_for_calculation!: () -> void
|
|
35
44
|
def mod10: (Integer sum) -> Integer
|
|
36
45
|
def div10mod10: (Integer number) -> Integer
|
|
37
46
|
def mod97: (String numeric_string) -> Integer
|
|
47
|
+
def mod31_30_check_char: (untyped base, Array[String] alphabet, Hash[String, Integer] alphabet_value) -> String
|
|
38
48
|
|
|
39
|
-
@
|
|
49
|
+
@checksum: (Integer | String)?
|
|
40
50
|
end
|
|
41
51
|
end
|
|
@@ -10,7 +10,7 @@ module SecID
|
|
|
10
10
|
# The class-object surface Generatable's methods call once extended.
|
|
11
11
|
interface _GeneratableClass
|
|
12
12
|
def new: (SecID::input) -> Base
|
|
13
|
-
def
|
|
13
|
+
def has_checksum?: () -> bool
|
|
14
14
|
end
|
|
15
15
|
|
|
16
16
|
# Class methods added when Generatable is included.
|
|
@@ -33,7 +33,7 @@ module SecID
|
|
|
33
33
|
def detect_errors: () -> Array[Symbol]
|
|
34
34
|
def valid_length?: () -> bool
|
|
35
35
|
def valid_characters?: () -> bool
|
|
36
|
-
def
|
|
36
|
+
def checksum_width: () -> Integer
|
|
37
37
|
def validation_message: (Symbol code) -> String?
|
|
38
38
|
def build_error: (Symbol code, String? message) -> Errors::detail
|
|
39
39
|
|
data/sig/sec_id/cusip.rbs
CHANGED
|
@@ -16,7 +16,11 @@ module SecID
|
|
|
16
16
|
|
|
17
17
|
def initialize: (SecID::input cusip) -> void
|
|
18
18
|
def to_pretty_s: () -> String?
|
|
19
|
+
def calculate_checksum: () -> Integer
|
|
20
|
+
def self.checksum: (SecID::input id) -> Integer
|
|
21
|
+
# @deprecated v7 bridge alias for `calculate_checksum`; removed in v8.
|
|
19
22
|
def calculate_check_digit: () -> Integer
|
|
23
|
+
# @deprecated v7 bridge alias for `checksum`; removed in v8.
|
|
20
24
|
def self.check_digit: (SecID::input id) -> Integer
|
|
21
25
|
private def self.generate_body: (Random random) -> String
|
|
22
26
|
def to_isin: (String country_code) -> ISIN
|
data/sig/sec_id/detector.rbs
CHANGED
|
@@ -3,8 +3,6 @@ module SecID
|
|
|
3
3
|
#
|
|
4
4
|
# @api private
|
|
5
5
|
class Detector
|
|
6
|
-
type priority = Array[Integer | Float | nil]
|
|
7
|
-
|
|
8
6
|
def initialize: (Array[singleton(Base)] identifier_list) -> void
|
|
9
7
|
def call: (SecID::input str) -> Array[Symbol]
|
|
10
8
|
def matches?: (SecID::input str) -> bool
|
|
@@ -17,8 +15,6 @@ module SecID
|
|
|
17
15
|
def precompute: () -> void
|
|
18
16
|
def build_discriminator_sets: () -> void
|
|
19
17
|
def build_length_table: () -> void
|
|
20
|
-
def build_priority_table: () -> void
|
|
21
|
-
def build_key_table: () -> void
|
|
22
18
|
def stage1_special_chars: (String upcased) -> Array[singleton(Base)]?
|
|
23
19
|
def stage2_length: (Integer length) -> Array[singleton(Base)]
|
|
24
20
|
def stage3_charset: (String upcased, Array[singleton(Base)] candidates) -> Array[singleton(Base)]
|
|
@@ -29,7 +25,5 @@ module SecID
|
|
|
29
25
|
@space_only_types: Array[singleton(Base)]
|
|
30
26
|
@special_types: Array[singleton(Base)]
|
|
31
27
|
@candidates_by_length: Hash[Integer, Array[singleton(Base)]]
|
|
32
|
-
@priority_for: Hash[singleton(Base), priority]
|
|
33
|
-
@key_for: Hash[singleton(Base), Symbol]
|
|
34
28
|
end
|
|
35
29
|
end
|
data/sig/sec_id/dti.rbs
CHANGED
|
@@ -15,13 +15,18 @@ module SecID
|
|
|
15
15
|
GRANDFATHERED_CODES: Hash[String, String]
|
|
16
16
|
|
|
17
17
|
def initialize: (SecID::input dti) -> void
|
|
18
|
+
def calculate_checksum: () -> String
|
|
19
|
+
def self.checksum: (SecID::input id) -> String
|
|
20
|
+
# @deprecated v7 bridge alias for `calculate_checksum`; removed in v8.
|
|
18
21
|
def calculate_check_digit: () -> String
|
|
22
|
+
# @deprecated v7 bridge alias for `checksum`; removed in v8.
|
|
23
|
+
def self.check_digit: (SecID::input id) -> String
|
|
19
24
|
private def self.generate_body: (Random random) -> String
|
|
20
25
|
|
|
21
26
|
private
|
|
22
27
|
|
|
23
28
|
def components: () -> Hash[Symbol, untyped]
|
|
24
|
-
def
|
|
29
|
+
def grandfathered_checksum: (untyped base) -> String?
|
|
25
30
|
def iso7064_mod31_30_check_char: (untyped base) -> String
|
|
26
31
|
end
|
|
27
32
|
end
|
data/sig/sec_id/figi.rbs
CHANGED
|
@@ -17,7 +17,11 @@ module SecID
|
|
|
17
17
|
|
|
18
18
|
def initialize: (SecID::input figi) -> void
|
|
19
19
|
def to_pretty_s: () -> String?
|
|
20
|
+
def calculate_checksum: () -> Integer
|
|
21
|
+
def self.checksum: (SecID::input id) -> Integer
|
|
22
|
+
# @deprecated v7 bridge alias for `calculate_checksum`; removed in v8.
|
|
20
23
|
def calculate_check_digit: () -> Integer
|
|
24
|
+
# @deprecated v7 bridge alias for `checksum`; removed in v8.
|
|
21
25
|
def self.check_digit: (SecID::input id) -> Integer
|
|
22
26
|
private def self.generate_body: (Random random) -> String
|
|
23
27
|
|
data/sig/sec_id/iban.rbs
CHANGED
|
@@ -26,7 +26,11 @@ module SecID
|
|
|
26
26
|
|
|
27
27
|
def initialize: (SecID::input iban) -> void
|
|
28
28
|
def restore: () -> String
|
|
29
|
+
def calculate_checksum: () -> Integer
|
|
30
|
+
def self.checksum: (SecID::input id) -> Integer
|
|
31
|
+
# @deprecated v7 bridge alias for `calculate_checksum`; removed in v8.
|
|
29
32
|
def calculate_check_digit: () -> Integer
|
|
33
|
+
# @deprecated v7 bridge alias for `checksum`; removed in v8.
|
|
30
34
|
def self.check_digit: (SecID::input id) -> Integer
|
|
31
35
|
private def self.generate_body: (Random random) -> String
|
|
32
36
|
def valid_bban_format?: () -> bool
|
|
@@ -38,13 +42,13 @@ module SecID
|
|
|
38
42
|
private
|
|
39
43
|
|
|
40
44
|
def components: () -> Hash[Symbol, untyped]
|
|
41
|
-
def
|
|
45
|
+
def checksum_width: () -> Integer
|
|
42
46
|
def valid_format?: () -> bool
|
|
43
47
|
def detect_errors: () -> Array[Symbol]
|
|
44
48
|
def validation_message: (Symbol code) -> String?
|
|
45
|
-
def
|
|
49
|
+
def extract_checksum_and_bban: (String rest) -> void
|
|
46
50
|
def expected_bban_length_for_country: () -> Integer?
|
|
47
|
-
def
|
|
51
|
+
def checksum?: (untyped rest, Integer? expected_bban_length) -> bool
|
|
48
52
|
def extract_bban_components: () -> void
|
|
49
53
|
def valid_bban_length_only?: () -> bool
|
|
50
54
|
def numeric_string_for_check: () -> String
|
data/sig/sec_id/isin.rbs
CHANGED
|
@@ -19,7 +19,11 @@ module SecID
|
|
|
19
19
|
|
|
20
20
|
def initialize: (SecID::input isin) -> void
|
|
21
21
|
def to_pretty_s: () -> String?
|
|
22
|
+
def calculate_checksum: () -> Integer
|
|
23
|
+
def self.checksum: (SecID::input id) -> Integer
|
|
24
|
+
# @deprecated v7 bridge alias for `calculate_checksum`; removed in v8.
|
|
22
25
|
def calculate_check_digit: () -> Integer
|
|
26
|
+
# @deprecated v7 bridge alias for `checksum`; removed in v8.
|
|
23
27
|
def self.check_digit: (SecID::input id) -> Integer
|
|
24
28
|
private def self.generate_body: (Random random) -> String
|
|
25
29
|
def to_cusip: () -> CUSIP
|
data/sig/sec_id/lei.rbs
CHANGED
|
@@ -20,14 +20,18 @@ module SecID
|
|
|
20
20
|
|
|
21
21
|
def initialize: (SecID::input lei) -> void
|
|
22
22
|
def to_pretty_s: () -> String?
|
|
23
|
+
def calculate_checksum: () -> Integer
|
|
24
|
+
def self.checksum: (SecID::input id) -> Integer
|
|
25
|
+
# @deprecated v7 bridge alias for `calculate_checksum`; removed in v8.
|
|
23
26
|
def calculate_check_digit: () -> Integer
|
|
27
|
+
# @deprecated v7 bridge alias for `checksum`; removed in v8.
|
|
24
28
|
def self.check_digit: (SecID::input id) -> Integer
|
|
25
29
|
private def self.generate_body: (Random random) -> String
|
|
26
30
|
|
|
27
31
|
private
|
|
28
32
|
|
|
29
33
|
def components: () -> Hash[Symbol, untyped]
|
|
30
|
-
def
|
|
34
|
+
def checksum_width: () -> Integer
|
|
31
35
|
def numeric_identifier: () -> String
|
|
32
36
|
end
|
|
33
37
|
end
|
data/sig/sec_id/scanner.rbs
CHANGED
|
@@ -28,8 +28,8 @@ module SecID
|
|
|
28
28
|
private
|
|
29
29
|
|
|
30
30
|
def precompute: () -> void
|
|
31
|
-
def
|
|
32
|
-
def
|
|
31
|
+
def build_candidate_partitions: () -> void
|
|
32
|
+
def build_length_table: () -> void
|
|
33
33
|
def scan_text: (String input, Array[singleton(Base)] target_classes) { (Match) -> void } -> void
|
|
34
34
|
def identify_candidate: (untyped match_data, Array[singleton(Base)] target_classes) -> Match?
|
|
35
35
|
def try_classes: (String raw, String cleaned, Integer start_pos, Array[singleton(Base)] classes) -> Match?
|
|
@@ -40,7 +40,5 @@ module SecID
|
|
|
40
40
|
@occ_classes: Array[singleton(Base)]
|
|
41
41
|
@simple_classes: Array[singleton(Base)]
|
|
42
42
|
@candidates_by_length: Hash[Integer, Array[singleton(Base)]]
|
|
43
|
-
@priority_for: Hash[singleton(Base), Array[Integer | Float | nil]]
|
|
44
|
-
@key_for: Hash[singleton(Base), Symbol]
|
|
45
43
|
end
|
|
46
44
|
end
|
data/sig/sec_id/sedol.rbs
CHANGED
|
@@ -19,7 +19,11 @@ module SecID
|
|
|
19
19
|
|
|
20
20
|
def initialize: (SecID::input sedol) -> void
|
|
21
21
|
def to_isin: (?String country_code) -> ISIN
|
|
22
|
+
def calculate_checksum: () -> Integer
|
|
23
|
+
def self.checksum: (SecID::input id) -> Integer
|
|
24
|
+
# @deprecated v7 bridge alias for `calculate_checksum`; removed in v8.
|
|
22
25
|
def calculate_check_digit: () -> Integer
|
|
26
|
+
# @deprecated v7 bridge alias for `checksum`; removed in v8.
|
|
23
27
|
def self.check_digit: (SecID::input id) -> Integer
|
|
24
28
|
private def self.generate_body: (Random random) -> String
|
|
25
29
|
|
data/sig/sec_id/upi.rbs
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
module SecID
|
|
2
|
+
# Unique Product Identifier (UPI, ISO 4914).
|
|
3
|
+
class UPI < Base
|
|
4
|
+
include Checkable
|
|
5
|
+
extend Checkable::ClassMethods
|
|
6
|
+
|
|
7
|
+
FULL_NAME: String
|
|
8
|
+
ID_LENGTH: Integer
|
|
9
|
+
EXAMPLE: String
|
|
10
|
+
VALID_CHARS_REGEX: ::Regexp
|
|
11
|
+
ID_REGEX: ::Regexp
|
|
12
|
+
ALPHABET: Array[String]
|
|
13
|
+
ALPHABET_VALUE: Hash[String, Integer]
|
|
14
|
+
GENERATE_CHARSET: Array[String]
|
|
15
|
+
|
|
16
|
+
def initialize: (SecID::input upi) -> void
|
|
17
|
+
def calculate_checksum: () -> String
|
|
18
|
+
def self.checksum: (SecID::input id) -> String
|
|
19
|
+
# @deprecated v7 bridge alias for `calculate_checksum`; removed in v8.
|
|
20
|
+
def calculate_check_digit: () -> String
|
|
21
|
+
# @deprecated v7 bridge alias for `checksum`; removed in v8.
|
|
22
|
+
def self.check_digit: (SecID::input id) -> String
|
|
23
|
+
private def self.generate_body: (Random random) -> String
|
|
24
|
+
|
|
25
|
+
private
|
|
26
|
+
|
|
27
|
+
def components: () -> Hash[Symbol, untyped]
|
|
28
|
+
end
|
|
29
|
+
end
|
data/sig/sec_id.rbs
CHANGED
|
@@ -7,10 +7,13 @@ module SecID
|
|
|
7
7
|
class InvalidFormatError < Error
|
|
8
8
|
end
|
|
9
9
|
|
|
10
|
-
# Raised when the
|
|
11
|
-
class
|
|
10
|
+
# Raised when the checksum does not match the calculated value.
|
|
11
|
+
class InvalidChecksumError < Error
|
|
12
12
|
end
|
|
13
13
|
|
|
14
|
+
# @deprecated v7 bridge constant alias for `InvalidChecksumError` (same class object); removed in v8.
|
|
15
|
+
InvalidCheckDigitError: singleton(InvalidChecksumError)
|
|
16
|
+
|
|
14
17
|
# Raised for type-specific structural errors.
|
|
15
18
|
class InvalidStructureError < Error
|
|
16
19
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: sec_id
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version:
|
|
4
|
+
version: 7.0.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Leonid Svyatov
|
|
@@ -11,10 +11,10 @@ date: 1980-01-02 00:00:00.000000000 Z
|
|
|
11
11
|
dependencies: []
|
|
12
12
|
description: Validate, normalize, parse, convert, generate, and classify securities
|
|
13
13
|
identifiers. Auto-detect identifier type from any string. Calculate and restore
|
|
14
|
-
|
|
14
|
+
checksums. Generate format-valid identifiers as test fixtures. Decode CFI codes
|
|
15
15
|
to full ISO 10962:2021 classifications. Includes an opt-in ActiveModel/Rails validator
|
|
16
16
|
that adds no runtime dependency. Supports ISIN, CUSIP, CEI, SEDOL, FIGI, LEI, IBAN,
|
|
17
|
-
CIK, OCC, WKN, Valoren, CFI, FISN, BIC, and
|
|
17
|
+
CIK, OCC, WKN, Valoren, CFI, FISN, BIC, DTI, and UPI.
|
|
18
18
|
email:
|
|
19
19
|
- leonid@svyatov.ru
|
|
20
20
|
executables: []
|
|
@@ -44,6 +44,7 @@ files:
|
|
|
44
44
|
- lib/sec_id/concerns/validatable.rb
|
|
45
45
|
- lib/sec_id/cusip.rb
|
|
46
46
|
- lib/sec_id/deep_freeze.rb
|
|
47
|
+
- lib/sec_id/deprecation.rb
|
|
47
48
|
- lib/sec_id/detector.rb
|
|
48
49
|
- lib/sec_id/dti.rb
|
|
49
50
|
- lib/sec_id/errors.rb
|
|
@@ -57,6 +58,7 @@ files:
|
|
|
57
58
|
- lib/sec_id/railtie.rb
|
|
58
59
|
- lib/sec_id/scanner.rb
|
|
59
60
|
- lib/sec_id/sedol.rb
|
|
61
|
+
- lib/sec_id/upi.rb
|
|
60
62
|
- lib/sec_id/valoren.rb
|
|
61
63
|
- lib/sec_id/version.rb
|
|
62
64
|
- lib/sec_id/wkn.rb
|
|
@@ -79,6 +81,7 @@ files:
|
|
|
79
81
|
- sig/sec_id/concerns/validatable.rbs
|
|
80
82
|
- sig/sec_id/cusip.rbs
|
|
81
83
|
- sig/sec_id/deep_freeze.rbs
|
|
84
|
+
- sig/sec_id/deprecation.rbs
|
|
82
85
|
- sig/sec_id/detector.rbs
|
|
83
86
|
- sig/sec_id/dti.rbs
|
|
84
87
|
- sig/sec_id/errors.rbs
|
|
@@ -91,6 +94,7 @@ files:
|
|
|
91
94
|
- sig/sec_id/occ.rbs
|
|
92
95
|
- sig/sec_id/scanner.rbs
|
|
93
96
|
- sig/sec_id/sedol.rbs
|
|
97
|
+
- sig/sec_id/upi.rbs
|
|
94
98
|
- sig/sec_id/valoren.rbs
|
|
95
99
|
- sig/sec_id/version.rbs
|
|
96
100
|
- sig/sec_id/wkn.rbs
|