sec_id 5.2.0 → 6.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/.yardopts +6 -0
- data/CHANGELOG.md +24 -0
- data/MIGRATION.md +101 -0
- data/README.md +200 -17
- data/lib/sec_id/active_model.rb +144 -0
- data/lib/sec_id/base.rb +33 -1
- data/lib/sec_id/bic/country_codes.rb +46 -0
- data/lib/sec_id/bic.rb +123 -0
- data/lib/sec_id/cei.rb +19 -7
- data/lib/sec_id/cfi/attribute_set.rb +49 -0
- data/lib/sec_id/cfi/classification.rb +107 -0
- data/lib/sec_id/cfi/field.rb +56 -0
- data/lib/sec_id/cfi/tables.rb +1033 -0
- data/lib/sec_id/cfi.rb +138 -208
- data/lib/sec_id/cik.rb +13 -0
- data/lib/sec_id/concerns/checkable.rb +2 -2
- data/lib/sec_id/concerns/generatable.rb +71 -0
- data/lib/sec_id/concerns/normalizable.rb +1 -0
- data/lib/sec_id/concerns/validatable.rb +14 -3
- data/lib/sec_id/cusip.rb +18 -7
- data/lib/sec_id/deep_freeze.rb +18 -0
- data/lib/sec_id/detector.rb +28 -7
- data/lib/sec_id/dti.rb +104 -0
- data/lib/sec_id/figi.rb +18 -0
- data/lib/sec_id/fisn.rb +31 -0
- data/lib/sec_id/iban/country_rules.rb +7 -6
- data/lib/sec_id/iban.rb +19 -1
- data/lib/sec_id/isin.rb +20 -15
- data/lib/sec_id/lei.rb +13 -0
- data/lib/sec_id/occ.rb +21 -0
- data/lib/sec_id/railtie.rb +14 -0
- data/lib/sec_id/scanner.rb +2 -6
- data/lib/sec_id/sedol.rb +16 -0
- data/lib/sec_id/valoren.rb +13 -0
- data/lib/sec_id/version.rb +2 -1
- data/lib/sec_id/wkn.rb +16 -0
- data/lib/sec_id.rb +29 -4
- data/sec_id.gemspec +11 -5
- data/sig/manifest.yaml +8 -0
- data/sig/sec_id/base.rbs +72 -0
- data/sig/sec_id/bic/country_codes.rbs +5 -0
- data/sig/sec_id/bic.rbs +30 -0
- data/sig/sec_id/cei.rbs +26 -0
- data/sig/sec_id/cfi/attribute_set.rbs +68 -0
- data/sig/sec_id/cfi/classification.rbs +23 -0
- data/sig/sec_id/cfi/field.rbs +337 -0
- data/sig/sec_id/cfi/tables.rbs +68 -0
- data/sig/sec_id/cfi.rbs +56 -0
- data/sig/sec_id/cik.rbs +19 -0
- data/sig/sec_id/concerns/checkable.rbs +41 -0
- data/sig/sec_id/concerns/generatable.rbs +26 -0
- data/sig/sec_id/concerns/normalizable.rbs +34 -0
- data/sig/sec_id/concerns/validatable.rbs +42 -0
- data/sig/sec_id/cusip.rbs +29 -0
- data/sig/sec_id/deep_freeze.rbs +6 -0
- data/sig/sec_id/detector.rbs +35 -0
- data/sig/sec_id/dti.rbs +27 -0
- data/sig/sec_id/errors.rbs +28 -0
- data/sig/sec_id/figi.rbs +31 -0
- data/sig/sec_id/fisn.rbs +24 -0
- data/sig/sec_id/iban/country_rules.rbs +10 -0
- data/sig/sec_id/iban.rbs +54 -0
- data/sig/sec_id/isin.rbs +40 -0
- data/sig/sec_id/lei.rbs +33 -0
- data/sig/sec_id/occ.rbs +45 -0
- data/sig/sec_id/scanner.rbs +46 -0
- data/sig/sec_id/sedol.rbs +34 -0
- data/sig/sec_id/valoren.rbs +29 -0
- data/sig/sec_id/version.rbs +3 -0
- data/sig/sec_id/wkn.rbs +15 -0
- data/sig/sec_id.rbs +58 -0
- metadata +55 -7
- data/lib/sec_id/concerns/identifier_metadata.rb +0 -56
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
module SecID
|
|
2
|
+
class CFI < Base
|
|
3
|
+
# ISO 10962:2021 CFI code tables.
|
|
4
|
+
#
|
|
5
|
+
# @api private
|
|
6
|
+
module Tables
|
|
7
|
+
# `{ letter => [value_symbol, value_label] }` for one attribute position.
|
|
8
|
+
# Values are typed loosely: the `[symbol, label]` tuple literals widen to
|
|
9
|
+
# `Array[Symbol | String]` under `Hash#freeze`, and `map(&:first)` on them feeds
|
|
10
|
+
# Field domains (Array[Symbol]) — untyped keeps both sides consistent.
|
|
11
|
+
type value_map = Hash[String, untyped]
|
|
12
|
+
|
|
13
|
+
# A group definition and the (loosely-typed, deeply-nested) group table.
|
|
14
|
+
type group_def = Hash[Symbol, untyped]
|
|
15
|
+
|
|
16
|
+
NA: nil
|
|
17
|
+
|
|
18
|
+
FORM: value_map
|
|
19
|
+
VOTING: value_map
|
|
20
|
+
OWNERSHIP: value_map
|
|
21
|
+
PAYMENT: value_map
|
|
22
|
+
PREF_REDEMPTION: value_map
|
|
23
|
+
PREF_INCOME: value_map
|
|
24
|
+
DEBT_GUARANTEE: value_map
|
|
25
|
+
DEBT_REDEMPTION: value_map
|
|
26
|
+
DEBT_INTEREST_FZVK: value_map
|
|
27
|
+
DEBT_INTEREST_FZV: value_map
|
|
28
|
+
STRUCTURED_DISTRIBUTION: value_map
|
|
29
|
+
STRUCTURED_UNDERLYING: value_map
|
|
30
|
+
WARRANT_UNDERLYING: value_map
|
|
31
|
+
EXERCISE_STYLE: value_map
|
|
32
|
+
CIV_CLOSED_OPEN: value_map
|
|
33
|
+
CIV_DISTRIBUTION: value_map
|
|
34
|
+
CIV_ASSETS: value_map
|
|
35
|
+
CIV_SECURITY_FULL: value_map
|
|
36
|
+
CIV_SECURITY_SHORT: value_map
|
|
37
|
+
OPTION_STYLE: value_map
|
|
38
|
+
OPTION_UNDERLYING: value_map
|
|
39
|
+
STANDARDIZED: value_map
|
|
40
|
+
COMMODITY_ASSETS: value_map
|
|
41
|
+
RETURN_TRIGGER: value_map
|
|
42
|
+
H_OPTION_STYLE: value_map
|
|
43
|
+
H_VALUATION: value_map
|
|
44
|
+
DELIVERY_CP: value_map
|
|
45
|
+
DELIVERY_PN: value_map
|
|
46
|
+
DELIVERY_PCN: value_map
|
|
47
|
+
DELIVERY_CPE: value_map
|
|
48
|
+
H_DELIVERY: value_map
|
|
49
|
+
H_DELIVERY_N: value_map
|
|
50
|
+
H_DELIVERY_NA: value_map
|
|
51
|
+
FWD_TRIGGER_CSF: value_map
|
|
52
|
+
FWD_TRIGGER_SF: value_map
|
|
53
|
+
FWD_TRIGGER_CF: value_map
|
|
54
|
+
|
|
55
|
+
# `{ letter => [category_symbol, category_label] }`. Typed loosely (widening tuple
|
|
56
|
+
# values; generation also indexes with nilable `.keys.sample` results).
|
|
57
|
+
CATEGORIES: Hash[untyped, untyped]
|
|
58
|
+
|
|
59
|
+
# `{ cat_letter => { grp_letter => group_def } }` (typed loosely, as above).
|
|
60
|
+
GROUPS: Hash[untyped, untyped]
|
|
61
|
+
|
|
62
|
+
ED_REDEMPTION_RULE: Hash[Symbol, untyped]
|
|
63
|
+
|
|
64
|
+
def self.ed_rule_applies?: (untyped category_code, untyped group_code, untyped letters) -> bool
|
|
65
|
+
def self.group: (untyped category_code, untyped group_code) -> untyped
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
data/sig/sec_id/cfi.rbs
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
module SecID
|
|
2
|
+
# Classification of Financial Instruments (CFI) — ISO 10962:2021.
|
|
3
|
+
class CFI < Base
|
|
4
|
+
FULL_NAME: String
|
|
5
|
+
ID_LENGTH: Integer
|
|
6
|
+
EXAMPLE: String
|
|
7
|
+
VALID_CHARS_REGEX: ::Regexp
|
|
8
|
+
ID_REGEX: ::Regexp
|
|
9
|
+
|
|
10
|
+
# Derived semantic maps (letter => symbol).
|
|
11
|
+
CATEGORIES: Hash[String, Symbol]
|
|
12
|
+
GROUPS: Hash[String, Hash[String, Symbol]]
|
|
13
|
+
|
|
14
|
+
def self.categories: () -> Hash[String, Symbol]
|
|
15
|
+
def self.groups_for: (String category_code) -> Hash[String, Symbol]?
|
|
16
|
+
|
|
17
|
+
# Used unguarded as non-nil after validation (indexed into the tables); typed loosely
|
|
18
|
+
# so static Steep and runtime RBS::Test (which sees nil for invalid) agree.
|
|
19
|
+
attr_reader category_code: untyped
|
|
20
|
+
attr_reader group_code: untyped
|
|
21
|
+
attr_reader attr1: untyped
|
|
22
|
+
attr_reader attr2: untyped
|
|
23
|
+
attr_reader attr3: untyped
|
|
24
|
+
attr_reader attr4: untyped
|
|
25
|
+
|
|
26
|
+
def initialize: (SecID::input cfi) -> void
|
|
27
|
+
def category: () -> Symbol?
|
|
28
|
+
def group: () -> Symbol?
|
|
29
|
+
def decode: () -> Classification?
|
|
30
|
+
def to_s: () -> String
|
|
31
|
+
|
|
32
|
+
private def self.generate_body: (Random random) -> String
|
|
33
|
+
private def self.sample_attribute: (untyped position, Random random) -> String
|
|
34
|
+
private def self.enforce_ed_rule: (untyped category_code, untyped group_code, untyped letters, Random random) -> void
|
|
35
|
+
|
|
36
|
+
private
|
|
37
|
+
|
|
38
|
+
def components: () -> Hash[Symbol, untyped]
|
|
39
|
+
def valid_format?: () -> bool
|
|
40
|
+
def detect_errors: () -> Array[Symbol]
|
|
41
|
+
def validation_message: (Symbol code) -> String?
|
|
42
|
+
def valid_category?: () -> bool
|
|
43
|
+
def valid_group?: () -> bool
|
|
44
|
+
def valid_attributes?: () -> bool
|
|
45
|
+
# `[position, letter]` pairs; typed loosely since the tuple literals widen.
|
|
46
|
+
def attribute_violations: () -> Array[untyped]
|
|
47
|
+
def compute_attribute_violations: () -> Array[untyped]
|
|
48
|
+
def permitted_attribute?: (untyped position, String letter) -> bool
|
|
49
|
+
def ed_rule_violations: () -> Array[untyped]
|
|
50
|
+
def ed_rule_applies?: () -> bool
|
|
51
|
+
def attribute_letters: () -> Array[String]
|
|
52
|
+
def attribute_error_message: () -> String
|
|
53
|
+
|
|
54
|
+
@attribute_violations: Array[untyped]
|
|
55
|
+
end
|
|
56
|
+
end
|
data/sig/sec_id/cik.rbs
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
module SecID
|
|
2
|
+
# Central Index Key (CIK).
|
|
3
|
+
class CIK < Base
|
|
4
|
+
FULL_NAME: String
|
|
5
|
+
# Typed loosely: `#normalized` does `ID_LENGTH.max` and Range#max is nilable in RBS.
|
|
6
|
+
ID_LENGTH: untyped
|
|
7
|
+
EXAMPLE: String
|
|
8
|
+
VALID_CHARS_REGEX: ::Regexp
|
|
9
|
+
ID_REGEX: ::Regexp
|
|
10
|
+
|
|
11
|
+
attr_reader padding: String?
|
|
12
|
+
|
|
13
|
+
def initialize: (SecID::input cik) -> void
|
|
14
|
+
def normalized: () -> String
|
|
15
|
+
def normalize!: () -> self
|
|
16
|
+
def to_s: () -> String
|
|
17
|
+
private def self.generate_body: (Random random) -> String
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
module SecID
|
|
2
|
+
# Provides check-digit validation and calculation for identifiers with a check digit.
|
|
3
|
+
module Checkable : SecID::Base
|
|
4
|
+
CHAR_TO_DIGITS: Hash[String, Integer | Array[Integer]]
|
|
5
|
+
CHAR_TO_DIGIT: Hash[String, Integer]
|
|
6
|
+
|
|
7
|
+
def self.included: (Module base) -> void
|
|
8
|
+
|
|
9
|
+
attr_reader check_digit: (Integer | String)?
|
|
10
|
+
|
|
11
|
+
# Class methods added when Checkable is included.
|
|
12
|
+
module ClassMethods : SecID::_IdentifierClass
|
|
13
|
+
def restore: (SecID::input id_without_check_digit) -> String
|
|
14
|
+
def restore!: (SecID::input id_without_check_digit) -> Base
|
|
15
|
+
def check_digit: (SecID::input id) -> (Integer | String)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def valid?: () -> bool
|
|
19
|
+
def restore: () -> String
|
|
20
|
+
def restore!: () -> self
|
|
21
|
+
def calculate_check_digit: () -> (Integer | String)
|
|
22
|
+
def to_s: () -> String
|
|
23
|
+
|
|
24
|
+
private
|
|
25
|
+
|
|
26
|
+
def luhn_sum_double_add_double: (Array[Integer] digits) -> Integer
|
|
27
|
+
def luhn_sum_indexed: (Array[Integer] digits) -> Integer
|
|
28
|
+
def luhn_sum_standard: (Array[Integer] digits) -> Integer
|
|
29
|
+
def reversed_digits_single: (untyped id) -> Array[Integer]
|
|
30
|
+
def reversed_digits_multi: (untyped id) -> Array[Integer]
|
|
31
|
+
def error_codes: () -> Array[Symbol]
|
|
32
|
+
def check_digit_width: () -> Integer
|
|
33
|
+
def validation_message: (Symbol code) -> String?
|
|
34
|
+
def validate_format_for_calculation!: () -> void
|
|
35
|
+
def mod10: (Integer sum) -> Integer
|
|
36
|
+
def div10mod10: (Integer number) -> Integer
|
|
37
|
+
def mod97: (String numeric_string) -> Integer
|
|
38
|
+
|
|
39
|
+
@check_digit: (Integer | String)?
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
module SecID
|
|
2
|
+
# Provides generation of new, format-valid identifiers for use as test fixtures.
|
|
3
|
+
module Generatable
|
|
4
|
+
ALPHA: Array[String]
|
|
5
|
+
DIGITS: Array[String]
|
|
6
|
+
ALPHANUMERIC: Array[String]
|
|
7
|
+
|
|
8
|
+
def self.included: (Module base) -> void
|
|
9
|
+
|
|
10
|
+
# The class-object surface Generatable's methods call once extended.
|
|
11
|
+
interface _GeneratableClass
|
|
12
|
+
def new: (SecID::input) -> Base
|
|
13
|
+
def has_check_digit?: () -> bool
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# Class methods added when Generatable is included.
|
|
17
|
+
module ClassMethods : SecID::Generatable::_GeneratableClass
|
|
18
|
+
def generate: (?random: Random) -> Base
|
|
19
|
+
|
|
20
|
+
private
|
|
21
|
+
|
|
22
|
+
def generate_body: (Random _random) -> String
|
|
23
|
+
def random_string: (Array[String] charset, Integer length, random: Random) -> String
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
module SecID
|
|
2
|
+
# Host surface Normalizable's instance methods call through `self`.
|
|
3
|
+
interface _NormalizableHost
|
|
4
|
+
def identifier: () -> String?
|
|
5
|
+
def valid?: () -> bool
|
|
6
|
+
def validate!: () -> void
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
# Provides normalization and display-formatting methods for identifier types.
|
|
10
|
+
#
|
|
11
|
+
# `ClassMethods#normalize`/`#to_pretty_s` read `self::SEPARATORS` (polymorphic
|
|
12
|
+
# constant dispatch); the extend-module `self` can't be typed as `singleton(Base)`,
|
|
13
|
+
# so that access resolves via the relaxed UnknownConstant diagnostic (see Steepfile).
|
|
14
|
+
module Normalizable : SecID::_NormalizableHost
|
|
15
|
+
SEPARATORS: ::Regexp
|
|
16
|
+
|
|
17
|
+
def self.included: (Module base) -> void
|
|
18
|
+
|
|
19
|
+
# Class methods added when Normalizable is included.
|
|
20
|
+
module ClassMethods : SecID::_IdentifierClass
|
|
21
|
+
def normalize: (_ToS id) -> String
|
|
22
|
+
def to_pretty_s: (_ToS id) -> String?
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def normalized: () -> String
|
|
26
|
+
alias normalize normalized
|
|
27
|
+
def normalize!: () -> self
|
|
28
|
+
def to_pretty_s: () -> String?
|
|
29
|
+
def to_s: () -> String
|
|
30
|
+
def to_str: () -> String
|
|
31
|
+
|
|
32
|
+
@full_id: String
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
module SecID
|
|
2
|
+
# Host surface Validatable's instance methods call through `self`. The refined
|
|
3
|
+
# `class` return lets `self.class::ID_LENGTH` and the class metadata resolve.
|
|
4
|
+
interface _ValidatableHost
|
|
5
|
+
def identifier: () -> String?
|
|
6
|
+
def full_id: () -> String
|
|
7
|
+
def class: () -> singleton(SecID::Base)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
# Provides validation methods for identifier types.
|
|
11
|
+
module Validatable : SecID::_ValidatableHost
|
|
12
|
+
ERROR_MAP: Hash[Symbol, singleton(SecID::Error)]
|
|
13
|
+
|
|
14
|
+
def self.included: (Module base) -> void
|
|
15
|
+
|
|
16
|
+
# Class methods added when Validatable is included.
|
|
17
|
+
module ClassMethods : SecID::_IdentifierClass
|
|
18
|
+
def valid?: (SecID::input id) -> bool
|
|
19
|
+
def validate: (SecID::input id) -> Base
|
|
20
|
+
def validate!: (SecID::input id) -> Base
|
|
21
|
+
def error_class_for: (Symbol code) -> singleton(SecID::Error)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def valid?: () -> bool
|
|
25
|
+
def validate: () -> self
|
|
26
|
+
def errors: () -> Errors
|
|
27
|
+
def validate!: () -> self
|
|
28
|
+
|
|
29
|
+
private
|
|
30
|
+
|
|
31
|
+
def valid_format?: () -> bool
|
|
32
|
+
def error_codes: () -> Array[Symbol]
|
|
33
|
+
def detect_errors: () -> Array[Symbol]
|
|
34
|
+
def valid_length?: () -> bool
|
|
35
|
+
def valid_characters?: () -> bool
|
|
36
|
+
def check_digit_width: () -> Integer
|
|
37
|
+
def validation_message: (Symbol code) -> String?
|
|
38
|
+
def build_error: (Symbol code, String? message) -> Errors::detail
|
|
39
|
+
|
|
40
|
+
@errors: Errors
|
|
41
|
+
end
|
|
42
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
module SecID
|
|
2
|
+
# Committee on Uniform Securities Identification Procedures (CUSIP).
|
|
3
|
+
class CUSIP < 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
|
+
|
|
13
|
+
# `#cins?` indexes `cusip6[0]` (nilable even for a non-nil String); typed loosely.
|
|
14
|
+
attr_reader cusip6: untyped
|
|
15
|
+
attr_reader issue: String?
|
|
16
|
+
|
|
17
|
+
def initialize: (SecID::input cusip) -> void
|
|
18
|
+
def to_pretty_s: () -> String?
|
|
19
|
+
def calculate_check_digit: () -> Integer
|
|
20
|
+
def self.check_digit: (SecID::input id) -> Integer
|
|
21
|
+
private def self.generate_body: (Random random) -> String
|
|
22
|
+
def to_isin: (String country_code) -> ISIN
|
|
23
|
+
def cins?: () -> bool
|
|
24
|
+
|
|
25
|
+
private
|
|
26
|
+
|
|
27
|
+
def components: () -> Hash[Symbol, untyped]
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
module SecID
|
|
2
|
+
# Detects which identifier types match a given string.
|
|
3
|
+
#
|
|
4
|
+
# @api private
|
|
5
|
+
class Detector
|
|
6
|
+
type priority = Array[Integer | Float | nil]
|
|
7
|
+
|
|
8
|
+
def initialize: (Array[singleton(Base)] identifier_list) -> void
|
|
9
|
+
def call: (SecID::input str) -> Array[Symbol]
|
|
10
|
+
def matches?: (SecID::input str) -> bool
|
|
11
|
+
def first_match: (SecID::input str) -> Base?
|
|
12
|
+
|
|
13
|
+
private
|
|
14
|
+
|
|
15
|
+
def filter_candidates: (String upcased) -> Array[singleton(Base)]
|
|
16
|
+
def validate_and_sort: (String input, Array[untyped] candidates) -> Array[Symbol]
|
|
17
|
+
def precompute: () -> void
|
|
18
|
+
def build_discriminator_sets: () -> void
|
|
19
|
+
def build_length_table: () -> void
|
|
20
|
+
def build_priority_table: () -> void
|
|
21
|
+
def build_key_table: () -> void
|
|
22
|
+
def stage1_special_chars: (String upcased) -> Array[singleton(Base)]?
|
|
23
|
+
def stage2_length: (Integer length) -> Array[singleton(Base)]
|
|
24
|
+
def stage3_charset: (String upcased, Array[singleton(Base)] candidates) -> Array[singleton(Base)]
|
|
25
|
+
def accepts_char?: (singleton(Base) klass, String char) -> bool
|
|
26
|
+
|
|
27
|
+
@classes: Array[singleton(Base)]
|
|
28
|
+
@slash_types: Array[singleton(Base)]
|
|
29
|
+
@space_only_types: Array[singleton(Base)]
|
|
30
|
+
@special_types: Array[singleton(Base)]
|
|
31
|
+
@candidates_by_length: Hash[Integer, Array[singleton(Base)]]
|
|
32
|
+
@priority_for: Hash[singleton(Base), priority]
|
|
33
|
+
@key_for: Hash[singleton(Base), Symbol]
|
|
34
|
+
end
|
|
35
|
+
end
|
data/sig/sec_id/dti.rbs
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
module SecID
|
|
2
|
+
# Digital Token Identifier (DTI, ISO 24165).
|
|
3
|
+
class DTI < 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
|
+
GRANDFATHERED_CODES: Hash[String, String]
|
|
16
|
+
|
|
17
|
+
def initialize: (SecID::input dti) -> void
|
|
18
|
+
def calculate_check_digit: () -> String
|
|
19
|
+
private def self.generate_body: (Random random) -> String
|
|
20
|
+
|
|
21
|
+
private
|
|
22
|
+
|
|
23
|
+
def components: () -> Hash[Symbol, untyped]
|
|
24
|
+
def grandfathered_check_digit: (untyped base) -> String?
|
|
25
|
+
def iso7064_mod31_30_check_char: (untyped base) -> String
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
module SecID
|
|
2
|
+
# Immutable value object representing validation errors for an identifier.
|
|
3
|
+
class Errors
|
|
4
|
+
# A single error entry. `{ error:, message: }` in the source, but `Hash#freeze`
|
|
5
|
+
# in `build_error` widens the record literal, so it is modelled as a Hash.
|
|
6
|
+
type detail = Hash[Symbol, untyped]
|
|
7
|
+
|
|
8
|
+
attr_reader details: Array[detail]
|
|
9
|
+
|
|
10
|
+
def initialize: (Array[detail] errors) -> void
|
|
11
|
+
|
|
12
|
+
def messages: () -> Array[String?]
|
|
13
|
+
|
|
14
|
+
def any?: () -> bool
|
|
15
|
+
|
|
16
|
+
def empty?: () -> bool
|
|
17
|
+
|
|
18
|
+
alias none? empty?
|
|
19
|
+
|
|
20
|
+
def size: () -> Integer
|
|
21
|
+
|
|
22
|
+
def each: () { (detail) -> void } -> Array[detail]
|
|
23
|
+
|
|
24
|
+
def to_a: () -> Array[String?]
|
|
25
|
+
|
|
26
|
+
def as_json: (*untyped) -> Array[detail]
|
|
27
|
+
end
|
|
28
|
+
end
|
data/sig/sec_id/figi.rbs
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
module SecID
|
|
2
|
+
# Financial Instrument Global Identifier (FIGI).
|
|
3
|
+
class FIGI < 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
|
+
RESTRICTED_PREFIXES: Set[String]
|
|
13
|
+
GENERATE_CHARSET: Array[String]
|
|
14
|
+
|
|
15
|
+
attr_reader prefix: String?
|
|
16
|
+
attr_reader random_part: String?
|
|
17
|
+
|
|
18
|
+
def initialize: (SecID::input figi) -> void
|
|
19
|
+
def to_pretty_s: () -> String?
|
|
20
|
+
def calculate_check_digit: () -> Integer
|
|
21
|
+
def self.check_digit: (SecID::input id) -> Integer
|
|
22
|
+
private def self.generate_body: (Random random) -> String
|
|
23
|
+
|
|
24
|
+
private
|
|
25
|
+
|
|
26
|
+
def components: () -> Hash[Symbol, untyped]
|
|
27
|
+
def valid_format?: () -> bool
|
|
28
|
+
def detect_errors: () -> Array[Symbol]
|
|
29
|
+
def validation_message: (Symbol code) -> String?
|
|
30
|
+
end
|
|
31
|
+
end
|
data/sig/sec_id/fisn.rbs
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
module SecID
|
|
2
|
+
# Financial Instrument Short Name (FISN).
|
|
3
|
+
class FISN < Base
|
|
4
|
+
FULL_NAME: String
|
|
5
|
+
ID_LENGTH: ::Range[Integer]
|
|
6
|
+
EXAMPLE: String
|
|
7
|
+
VALID_CHARS_REGEX: ::Regexp
|
|
8
|
+
SEPARATORS: ::Regexp
|
|
9
|
+
ID_REGEX: ::Regexp
|
|
10
|
+
FISN_CHARSET: Array[String]
|
|
11
|
+
|
|
12
|
+
attr_reader issuer: String?
|
|
13
|
+
attr_reader description: String?
|
|
14
|
+
|
|
15
|
+
def initialize: (SecID::input fisn) -> void
|
|
16
|
+
def to_s: () -> String
|
|
17
|
+
private def self.generate_body: (Random random) -> String
|
|
18
|
+
private def self.generate_part: (Integer length, Random random) -> String
|
|
19
|
+
|
|
20
|
+
private
|
|
21
|
+
|
|
22
|
+
def components: () -> Hash[Symbol, untyped]
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
module SecID
|
|
2
|
+
class IBAN < Base
|
|
3
|
+
# `{ length: Integer, format: Regexp, components?: {name => [start, length]} }`, but
|
|
4
|
+
# the nested literal infers as a broad Hash, so it is modelled loosely.
|
|
5
|
+
type rule = Hash[Symbol, untyped]
|
|
6
|
+
|
|
7
|
+
COUNTRY_RULES: Hash[String, rule]
|
|
8
|
+
LENGTH_ONLY_COUNTRIES: Hash[String, Integer]
|
|
9
|
+
end
|
|
10
|
+
end
|
data/sig/sec_id/iban.rbs
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
module SecID
|
|
2
|
+
# International Bank Account Number (IBAN).
|
|
3
|
+
class IBAN < Base
|
|
4
|
+
include Checkable
|
|
5
|
+
extend Checkable::ClassMethods
|
|
6
|
+
|
|
7
|
+
FULL_NAME: String
|
|
8
|
+
ID_LENGTH: ::Range[Integer]
|
|
9
|
+
EXAMPLE: String
|
|
10
|
+
VALID_CHARS_REGEX: ::Regexp
|
|
11
|
+
ID_REGEX: ::Regexp
|
|
12
|
+
NUMERIC_COUNTRY_RULES: Array[[String, rule]]
|
|
13
|
+
|
|
14
|
+
def self.supported_countries: () -> Array[String]
|
|
15
|
+
|
|
16
|
+
# country_code/bban are used unguarded after validation; typed loosely so static
|
|
17
|
+
# Steep and runtime RBS::Test (which sees nil for invalid) agree.
|
|
18
|
+
attr_reader country_code: untyped
|
|
19
|
+
attr_reader bban: untyped
|
|
20
|
+
# Optional BBAN components; typed loosely so `#components` (which conditionally
|
|
21
|
+
# assigns them into an inferred hash) type-checks.
|
|
22
|
+
attr_reader bank_code: untyped
|
|
23
|
+
attr_reader branch_code: untyped
|
|
24
|
+
attr_reader account_number: untyped
|
|
25
|
+
attr_reader national_check: untyped
|
|
26
|
+
|
|
27
|
+
def initialize: (SecID::input iban) -> void
|
|
28
|
+
def restore: () -> String
|
|
29
|
+
def calculate_check_digit: () -> Integer
|
|
30
|
+
def self.check_digit: (SecID::input id) -> Integer
|
|
31
|
+
private def self.generate_body: (Random random) -> String
|
|
32
|
+
def valid_bban_format?: () -> bool
|
|
33
|
+
def country_rule: () -> rule?
|
|
34
|
+
def known_country?: () -> bool
|
|
35
|
+
def to_s: () -> String
|
|
36
|
+
def to_pretty_s: () -> String?
|
|
37
|
+
|
|
38
|
+
private
|
|
39
|
+
|
|
40
|
+
def components: () -> Hash[Symbol, untyped]
|
|
41
|
+
def check_digit_width: () -> Integer
|
|
42
|
+
def valid_format?: () -> bool
|
|
43
|
+
def detect_errors: () -> Array[Symbol]
|
|
44
|
+
def validation_message: (Symbol code) -> String?
|
|
45
|
+
def extract_check_digit_and_bban: (String rest) -> void
|
|
46
|
+
def expected_bban_length_for_country: () -> Integer?
|
|
47
|
+
def check_digits?: (untyped rest, Integer? expected_bban_length) -> bool
|
|
48
|
+
def extract_bban_components: () -> void
|
|
49
|
+
def valid_bban_length_only?: () -> bool
|
|
50
|
+
def numeric_string_for_check: () -> String
|
|
51
|
+
|
|
52
|
+
self.@supported_countries: Array[String]
|
|
53
|
+
end
|
|
54
|
+
end
|
data/sig/sec_id/isin.rbs
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
module SecID
|
|
2
|
+
# International Securities Identification Number (ISIN).
|
|
3
|
+
class ISIN < 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
|
+
CGS_COUNTRY_CODES: Set[String]
|
|
13
|
+
NSIN_COUNTRY_TYPES: Hash[String, Symbol]
|
|
14
|
+
|
|
15
|
+
# Used unguarded as non-nil after validation (indexed/looked-up); typed loosely
|
|
16
|
+
# so both static Steep and runtime RBS::Test (which sees nil for invalid) agree.
|
|
17
|
+
attr_reader country_code: untyped
|
|
18
|
+
attr_reader nsin: untyped
|
|
19
|
+
|
|
20
|
+
def initialize: (SecID::input isin) -> void
|
|
21
|
+
def to_pretty_s: () -> String?
|
|
22
|
+
def calculate_check_digit: () -> Integer
|
|
23
|
+
def self.check_digit: (SecID::input id) -> Integer
|
|
24
|
+
private def self.generate_body: (Random random) -> String
|
|
25
|
+
def to_cusip: () -> CUSIP
|
|
26
|
+
def cgs?: () -> bool
|
|
27
|
+
def sedol?: () -> bool
|
|
28
|
+
def wkn?: () -> bool
|
|
29
|
+
def valoren?: () -> bool
|
|
30
|
+
def to_sedol: () -> SEDOL
|
|
31
|
+
def to_wkn: () -> WKN
|
|
32
|
+
def to_valoren: () -> Valoren
|
|
33
|
+
def nsin_type: () -> Symbol
|
|
34
|
+
def to_nsin: () -> (CUSIP | SEDOL | WKN | Valoren | String | nil)
|
|
35
|
+
|
|
36
|
+
private
|
|
37
|
+
|
|
38
|
+
def components: () -> Hash[Symbol, untyped]
|
|
39
|
+
end
|
|
40
|
+
end
|
data/sig/sec_id/lei.rbs
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
module SecID
|
|
2
|
+
# Legal Entity Identifier (LEI).
|
|
3
|
+
class LEI < 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
|
+
|
|
13
|
+
attr_reader lou_id: String?
|
|
14
|
+
attr_reader reserved: String?
|
|
15
|
+
attr_reader entity_id: String?
|
|
16
|
+
|
|
17
|
+
# Used unguarded after validation (`#numeric_identifier`); typed loosely so static
|
|
18
|
+
# Steep and runtime RBS::Test (which sees nil for invalid) agree.
|
|
19
|
+
def identifier: () -> untyped
|
|
20
|
+
|
|
21
|
+
def initialize: (SecID::input lei) -> void
|
|
22
|
+
def to_pretty_s: () -> String?
|
|
23
|
+
def calculate_check_digit: () -> Integer
|
|
24
|
+
def self.check_digit: (SecID::input id) -> Integer
|
|
25
|
+
private def self.generate_body: (Random random) -> String
|
|
26
|
+
|
|
27
|
+
private
|
|
28
|
+
|
|
29
|
+
def components: () -> Hash[Symbol, untyped]
|
|
30
|
+
def check_digit_width: () -> Integer
|
|
31
|
+
def numeric_identifier: () -> String
|
|
32
|
+
end
|
|
33
|
+
end
|
data/sig/sec_id/occ.rbs
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
module SecID
|
|
2
|
+
# OCC Option Symbol.
|
|
3
|
+
class OCC < Base
|
|
4
|
+
FULL_NAME: String
|
|
5
|
+
ID_LENGTH: ::Range[Integer]
|
|
6
|
+
EXAMPLE: String
|
|
7
|
+
VALID_CHARS_REGEX: ::Regexp
|
|
8
|
+
SEPARATORS: ::Regexp
|
|
9
|
+
ID_REGEX: ::Regexp
|
|
10
|
+
|
|
11
|
+
# Used unguarded as non-nil after validation; typed loosely so static Steep and
|
|
12
|
+
# runtime RBS::Test (which sees nil for invalid) agree.
|
|
13
|
+
attr_reader underlying: untyped
|
|
14
|
+
attr_reader date_str: untyped
|
|
15
|
+
attr_reader type: untyped
|
|
16
|
+
attr_reader strike_mills: untyped
|
|
17
|
+
|
|
18
|
+
def self.generate: (?random: Random) -> OCC
|
|
19
|
+
# build/compose accept any Numeric strike (e.g. Rational) and a String or Symbol type.
|
|
20
|
+
def self.build: (underlying: untyped, date: String | Date, type: untyped, strike: Integer | Float | Rational | String) -> OCC
|
|
21
|
+
def self.compose_symbol: (untyped underlying, untyped date_str, untyped type, untyped strike_mills) -> String
|
|
22
|
+
|
|
23
|
+
def initialize: (SecID::input symbol) -> void
|
|
24
|
+
def normalized: () -> String
|
|
25
|
+
def valid?: () -> bool
|
|
26
|
+
def date: () -> Date?
|
|
27
|
+
alias date_obj date
|
|
28
|
+
def strike: () -> Float?
|
|
29
|
+
def to_s: () -> String
|
|
30
|
+
def to_pretty_s: () -> String?
|
|
31
|
+
|
|
32
|
+
private
|
|
33
|
+
|
|
34
|
+
# `Integer | Float | Rational` (not `Numeric`, which lacks `#*` in RBS) so the
|
|
35
|
+
# `when Numeric then strike * 1000` branch type-checks; String is the 8-digit form.
|
|
36
|
+
def self.normalize_strike_mills: (Integer | Float | Rational | String strike) -> String
|
|
37
|
+
|
|
38
|
+
def components: () -> Hash[Symbol, untyped]
|
|
39
|
+
def error_codes: () -> Array[Symbol]
|
|
40
|
+
def validation_message: (Symbol code) -> String?
|
|
41
|
+
|
|
42
|
+
@date: Date?
|
|
43
|
+
@strike: Float?
|
|
44
|
+
end
|
|
45
|
+
end
|