sec_id 4.4.1 → 5.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 +49 -3
- data/MIGRATION.md +257 -0
- data/README.md +234 -142
- data/lib/sec_id/base.rb +14 -38
- data/lib/sec_id/cei.rb +7 -2
- data/lib/sec_id/cfi.rb +38 -12
- data/lib/sec_id/cik.rb +21 -18
- data/lib/sec_id/concerns/checkable.rb +56 -14
- data/lib/sec_id/concerns/identifier_metadata.rb +56 -0
- data/lib/sec_id/concerns/normalizable.rb +42 -16
- data/lib/sec_id/concerns/validatable.rb +158 -0
- data/lib/sec_id/cusip.rb +10 -8
- data/lib/sec_id/detector.rb +156 -0
- data/lib/sec_id/errors.rb +67 -0
- data/lib/sec_id/figi.rb +30 -10
- data/lib/sec_id/fisn.rb +10 -4
- data/lib/sec_id/iban/country_rules.rb +4 -2
- data/lib/sec_id/iban.rb +44 -12
- data/lib/sec_id/isin.rb +11 -6
- data/lib/sec_id/lei.rb +12 -9
- data/lib/sec_id/occ.rb +40 -25
- data/lib/sec_id/sedol.rb +9 -7
- data/lib/sec_id/valoren.rb +22 -22
- data/lib/sec_id/version.rb +2 -2
- data/lib/sec_id/wkn.rb +10 -7
- data/lib/sec_id.rb +127 -6
- data/sec_id.gemspec +6 -3
- metadata +11 -3
data/lib/sec_id/occ.rb
CHANGED
|
@@ -2,24 +2,28 @@
|
|
|
2
2
|
|
|
3
3
|
require 'date'
|
|
4
4
|
|
|
5
|
-
module
|
|
5
|
+
module SecID
|
|
6
6
|
# OCC Option Symbol - standardized option symbol format used by Option Clearing Corporation.
|
|
7
7
|
# Format: 6-char underlying (padded) + 6-char date (YYMMDD) + type (C/P) + 8-digit strike (in mills).
|
|
8
8
|
#
|
|
9
|
-
# @note OCC identifiers have no check digit
|
|
10
|
-
# and
|
|
9
|
+
# @note OCC identifiers have no check digit and validation includes both format
|
|
10
|
+
# and date parseability checks.
|
|
11
11
|
#
|
|
12
12
|
# @see https://en.wikipedia.org/wiki/Option_symbol#The_OCC_Option_Symbol
|
|
13
13
|
# @see https://web.archive.org/web/20120507220143/http://www.theocc.com/components/docs/initiatives/symbology/symbology_initiative_v1_8.pdf
|
|
14
14
|
#
|
|
15
15
|
# @example Validate an OCC symbol
|
|
16
|
-
#
|
|
16
|
+
# SecID::OCC.valid?('AAPL 210917C00150000') #=> true
|
|
17
17
|
#
|
|
18
18
|
# @example Build an OCC symbol from components
|
|
19
|
-
# occ =
|
|
19
|
+
# occ = SecID::OCC.build(underlying: 'AAPL', date: '2021-09-17', type: 'C', strike: 150.0)
|
|
20
20
|
# occ.to_s #=> 'AAPL 210917C00150000'
|
|
21
21
|
class OCC < Base
|
|
22
|
-
|
|
22
|
+
FULL_NAME = 'OCC Option Symbol'
|
|
23
|
+
ID_LENGTH = (16..21)
|
|
24
|
+
EXAMPLE = 'AAPL 210917C00150000'
|
|
25
|
+
VALID_CHARS_REGEX = /\A[A-Z0-9 ]+\z/
|
|
26
|
+
SEPARATORS = /-/
|
|
23
27
|
|
|
24
28
|
# Regular expression for parsing OCC symbol components.
|
|
25
29
|
ID_REGEX = /\A
|
|
@@ -81,7 +85,7 @@ module SecId
|
|
|
81
85
|
case strike
|
|
82
86
|
when Numeric
|
|
83
87
|
format('%08d', (strike * 1000).to_i)
|
|
84
|
-
when
|
|
88
|
+
when /\A\d{8}\z/
|
|
85
89
|
strike
|
|
86
90
|
else
|
|
87
91
|
raise ArgumentError, 'Strike must be numeric or an 8-char string!'
|
|
@@ -91,7 +95,7 @@ module SecId
|
|
|
91
95
|
|
|
92
96
|
# @param symbol [String] the OCC symbol string to parse
|
|
93
97
|
def initialize(symbol)
|
|
94
|
-
symbol_parts = parse(symbol
|
|
98
|
+
symbol_parts = parse(symbol)
|
|
95
99
|
@identifier = symbol_parts[:initial]
|
|
96
100
|
@underlying = symbol_parts[:underlying]
|
|
97
101
|
@date_str = symbol_parts[:date]
|
|
@@ -99,14 +103,11 @@ module SecId
|
|
|
99
103
|
@strike_mills = symbol_parts[:strike_mills]
|
|
100
104
|
end
|
|
101
105
|
|
|
102
|
-
# Normalizes the OCC symbol to standard format with 6-char padded underlying and 8-digit strike.
|
|
103
|
-
#
|
|
104
106
|
# @return [String] the normalized OCC symbol
|
|
105
|
-
# @raise [InvalidFormatError]
|
|
106
|
-
def
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
@full_number = self.class.compose_symbol(underlying, date_str, type, strike_mills)
|
|
107
|
+
# @raise [InvalidFormatError, InvalidStructureError]
|
|
108
|
+
def normalized
|
|
109
|
+
validate!
|
|
110
|
+
self.class.compose_symbol(underlying, date_str, type, strike_mills)
|
|
110
111
|
end
|
|
111
112
|
|
|
112
113
|
# @return [Boolean]
|
|
@@ -116,29 +117,43 @@ module SecId
|
|
|
116
117
|
|
|
117
118
|
# @return [Date, nil] the parsed date or nil if invalid
|
|
118
119
|
def date
|
|
119
|
-
return
|
|
120
|
+
return @date if defined?(@date)
|
|
121
|
+
return unless date_str
|
|
120
122
|
|
|
121
|
-
@date
|
|
123
|
+
@date = Date.strptime(date_str, '%y%m%d')
|
|
122
124
|
rescue ArgumentError
|
|
123
|
-
nil
|
|
125
|
+
@date = nil
|
|
124
126
|
end
|
|
125
127
|
alias date_obj date
|
|
126
128
|
|
|
127
|
-
# @return [Float] strike price in dollars
|
|
129
|
+
# @return [Float, nil] strike price in dollars
|
|
128
130
|
def strike
|
|
129
|
-
@strike
|
|
131
|
+
return @strike if defined?(@strike)
|
|
132
|
+
|
|
133
|
+
@strike = strike_mills&.then { |m| m.to_i / 1000.0 }
|
|
130
134
|
end
|
|
131
135
|
|
|
132
136
|
# @return [String]
|
|
133
137
|
def to_s
|
|
134
|
-
|
|
138
|
+
full_id
|
|
135
139
|
end
|
|
136
|
-
alias to_str to_s
|
|
137
140
|
|
|
138
|
-
|
|
141
|
+
private
|
|
142
|
+
|
|
143
|
+
# @return [Array<Symbol>]
|
|
144
|
+
def error_codes
|
|
145
|
+
return detect_errors unless valid_format?
|
|
146
|
+
return [:invalid_date] if date.nil?
|
|
147
|
+
|
|
148
|
+
[]
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
# @param code [Symbol]
|
|
139
152
|
# @return [String]
|
|
140
|
-
def
|
|
141
|
-
|
|
153
|
+
def validation_message(code)
|
|
154
|
+
return "Date '#{date_str}' cannot be parsed" if code == :invalid_date
|
|
155
|
+
|
|
156
|
+
super
|
|
142
157
|
end
|
|
143
158
|
end
|
|
144
159
|
end
|
data/lib/sec_id/sedol.rb
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
module
|
|
3
|
+
module SecID
|
|
4
4
|
# Stock Exchange Daily Official List (SEDOL) - a 7-character alphanumeric code
|
|
5
5
|
# that identifies securities traded on the London Stock Exchange and other UK exchanges.
|
|
6
6
|
#
|
|
@@ -10,13 +10,18 @@ module SecId
|
|
|
10
10
|
# @see https://en.wikipedia.org/wiki/SEDOL
|
|
11
11
|
#
|
|
12
12
|
# @example Validate a SEDOL
|
|
13
|
-
#
|
|
13
|
+
# SecID::SEDOL.valid?('B19GKT4') #=> true
|
|
14
14
|
#
|
|
15
15
|
# @example Calculate check digit
|
|
16
|
-
#
|
|
16
|
+
# SecID::SEDOL.check_digit('B19GKT') #=> 4
|
|
17
17
|
class SEDOL < Base
|
|
18
18
|
include Checkable
|
|
19
19
|
|
|
20
|
+
FULL_NAME = 'Stock Exchange Daily Official List'
|
|
21
|
+
ID_LENGTH = 7
|
|
22
|
+
EXAMPLE = 'B0YBKJ7'
|
|
23
|
+
VALID_CHARS_REGEX = /\A[0-9BCDFGHJKLMNPQRSTVWXYZ]+\z/
|
|
24
|
+
|
|
20
25
|
# Regular expression for parsing SEDOL components.
|
|
21
26
|
# Excludes vowels (A, E, I, O, U) from valid characters.
|
|
22
27
|
ID_REGEX = /\A
|
|
@@ -45,10 +50,7 @@ module SecId
|
|
|
45
50
|
raise InvalidFormatError, "'#{country_code}' is not a valid SEDOL country code!"
|
|
46
51
|
end
|
|
47
52
|
|
|
48
|
-
|
|
49
|
-
isin = ISIN.new("#{country_code}00#{sedol_with_check_digit}")
|
|
50
|
-
isin.restore!
|
|
51
|
-
isin
|
|
53
|
+
ISIN.new("#{country_code}00#{restore}").restore!
|
|
52
54
|
end
|
|
53
55
|
|
|
54
56
|
# @return [Integer] the calculated check digit (0-9)
|
data/lib/sec_id/valoren.rb
CHANGED
|
@@ -1,24 +1,26 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
module
|
|
3
|
+
module SecID
|
|
4
4
|
# Valoren (Swiss Security Number) - a numeric identifier for securities
|
|
5
5
|
# in Switzerland, Liechtenstein, and Belgium.
|
|
6
6
|
#
|
|
7
7
|
# Format: 5-9 numeric digits
|
|
8
8
|
#
|
|
9
|
-
# @note Valoren identifiers have no check digit
|
|
10
|
-
# returns false and validation is based solely on format.
|
|
9
|
+
# @note Valoren identifiers have no check digit and validation is based solely on format.
|
|
11
10
|
#
|
|
12
11
|
# @see https://en.wikipedia.org/wiki/Valoren_number
|
|
13
12
|
#
|
|
14
13
|
# @example Validate a Valoren
|
|
15
|
-
#
|
|
16
|
-
#
|
|
14
|
+
# SecID::Valoren.valid?('3886335') #=> true
|
|
15
|
+
# SecID::Valoren.valid?('003886335') #=> true
|
|
17
16
|
#
|
|
18
17
|
# @example Normalize a Valoren to 9 digits
|
|
19
|
-
#
|
|
18
|
+
# SecID::Valoren.normalize('3886335') #=> '003886335'
|
|
20
19
|
class Valoren < Base
|
|
21
|
-
|
|
20
|
+
FULL_NAME = 'Valoren Number'
|
|
21
|
+
ID_LENGTH = (5..9)
|
|
22
|
+
EXAMPLE = '3886335'
|
|
23
|
+
VALID_CHARS_REGEX = /\A[0-9]+\z/
|
|
22
24
|
|
|
23
25
|
# Regular expression for parsing Valoren components.
|
|
24
26
|
ID_REGEX = /\A
|
|
@@ -46,29 +48,27 @@ module SecId
|
|
|
46
48
|
raise InvalidFormatError, "'#{country_code}' is not a valid Valoren country code!"
|
|
47
49
|
end
|
|
48
50
|
|
|
49
|
-
|
|
50
|
-
isin = ISIN.new(country_code + full_number)
|
|
51
|
-
isin.restore!
|
|
52
|
-
isin
|
|
51
|
+
ISIN.new(country_code + normalized).restore!
|
|
53
52
|
end
|
|
54
53
|
|
|
55
|
-
# Normalizes the Valoren to a 9-digit zero-padded format.
|
|
56
|
-
# Updates both @full_number and @padding to reflect the normalized state.
|
|
57
|
-
#
|
|
58
54
|
# @return [String] the normalized 9-digit Valoren
|
|
59
|
-
# @raise [InvalidFormatError]
|
|
60
|
-
def
|
|
61
|
-
|
|
55
|
+
# @raise [InvalidFormatError]
|
|
56
|
+
def normalized
|
|
57
|
+
validate!
|
|
58
|
+
@identifier.rjust(self.class::ID_LENGTH.max, '0')
|
|
59
|
+
end
|
|
62
60
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
61
|
+
# @return [self]
|
|
62
|
+
# @raise [InvalidFormatError]
|
|
63
|
+
def normalize!
|
|
64
|
+
super
|
|
65
|
+
@padding = @full_id[0, self.class::ID_LENGTH.max - @identifier.length]
|
|
66
|
+
self
|
|
66
67
|
end
|
|
67
68
|
|
|
68
69
|
# @return [String]
|
|
69
70
|
def to_s
|
|
70
|
-
|
|
71
|
+
full_id
|
|
71
72
|
end
|
|
72
|
-
alias to_str to_s
|
|
73
73
|
end
|
|
74
74
|
end
|
data/lib/sec_id/version.rb
CHANGED
data/lib/sec_id/wkn.rb
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
module
|
|
3
|
+
module SecID
|
|
4
4
|
# Wertpapierkennnummer (WKN) - a 6-character alphanumeric code
|
|
5
5
|
# used to identify securities in Germany.
|
|
6
6
|
#
|
|
@@ -10,9 +10,14 @@ module SecId
|
|
|
10
10
|
# @see https://en.wikipedia.org/wiki/Wertpapierkennnummer
|
|
11
11
|
#
|
|
12
12
|
# @example Validate a WKN
|
|
13
|
-
#
|
|
14
|
-
#
|
|
13
|
+
# SecID::WKN.valid?('514000') #=> true
|
|
14
|
+
# SecID::WKN.valid?('CBK100') #=> true
|
|
15
15
|
class WKN < Base
|
|
16
|
+
FULL_NAME = 'Wertpapierkennnummer'
|
|
17
|
+
ID_LENGTH = 6
|
|
18
|
+
EXAMPLE = '514000'
|
|
19
|
+
VALID_CHARS_REGEX = /\A[0-9A-HJ-NP-Z]+\z/
|
|
20
|
+
|
|
16
21
|
# Regular expression for parsing WKN components.
|
|
17
22
|
# Excludes letters I and O to avoid confusion with 1 and 0.
|
|
18
23
|
ID_REGEX = /\A
|
|
@@ -31,11 +36,9 @@ module SecId
|
|
|
31
36
|
# @raise [InvalidFormatError] if the WKN format is invalid
|
|
32
37
|
def to_isin(country_code = 'DE')
|
|
33
38
|
raise InvalidFormatError, "'#{country_code}' is not a valid WKN country code!" unless country_code == 'DE'
|
|
34
|
-
raise InvalidFormatError, "WKN '#{
|
|
39
|
+
raise InvalidFormatError, "WKN '#{full_id}' is invalid!" unless valid_format?
|
|
35
40
|
|
|
36
|
-
|
|
37
|
-
isin.restore!
|
|
38
|
-
isin
|
|
41
|
+
ISIN.new("#{country_code}000#{identifier}").restore!
|
|
39
42
|
end
|
|
40
43
|
end
|
|
41
44
|
end
|
data/lib/sec_id.rb
CHANGED
|
@@ -1,10 +1,136 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require 'set'
|
|
4
3
|
require 'sec_id/version'
|
|
4
|
+
|
|
5
|
+
module SecID
|
|
6
|
+
# Base error class for all SecID errors.
|
|
7
|
+
class Error < StandardError; end
|
|
8
|
+
|
|
9
|
+
# Raised for invalid format, length, or characters.
|
|
10
|
+
class InvalidFormatError < Error; end
|
|
11
|
+
|
|
12
|
+
# Raised when the check digit does not match the calculated value.
|
|
13
|
+
class InvalidCheckDigitError < Error; end
|
|
14
|
+
|
|
15
|
+
# Raised for type-specific structural errors (invalid prefix, category, group, BBAN, or date).
|
|
16
|
+
class InvalidStructureError < Error; end
|
|
17
|
+
|
|
18
|
+
class << self
|
|
19
|
+
# Looks up an identifier class by its symbol key.
|
|
20
|
+
#
|
|
21
|
+
# @param key [Symbol] identifier type (e.g. :isin, :cusip)
|
|
22
|
+
# @return [Class] the identifier class
|
|
23
|
+
# @raise [ArgumentError] if key is unknown
|
|
24
|
+
def [](key)
|
|
25
|
+
identifier_map.fetch(key) do
|
|
26
|
+
raise ArgumentError, "Unknown identifier type: #{key.inspect}"
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Returns all registered identifier classes in load order.
|
|
31
|
+
#
|
|
32
|
+
# @return [Array<Class>]
|
|
33
|
+
def identifiers
|
|
34
|
+
identifier_list.dup
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Detects all identifier types that match the given string.
|
|
38
|
+
#
|
|
39
|
+
# @param str [String, nil] the identifier string to detect
|
|
40
|
+
# @return [Array<Symbol>] matching type symbols sorted by specificity
|
|
41
|
+
def detect(str)
|
|
42
|
+
detector.call(str)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# Checks whether the string is a valid identifier.
|
|
46
|
+
#
|
|
47
|
+
# @param str [String, nil] the identifier string to validate
|
|
48
|
+
# @param types [Array<Symbol>, nil] restrict to specific types (e.g. [:isin, :cusip])
|
|
49
|
+
# @return [Boolean]
|
|
50
|
+
# @raise [ArgumentError] if any key in types is unknown
|
|
51
|
+
def valid?(str, types: nil)
|
|
52
|
+
return detect(str).any? if types.nil?
|
|
53
|
+
|
|
54
|
+
types.any? { |key| self[key].valid?(str) }
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# Parses a string into the most specific matching identifier instance.
|
|
58
|
+
#
|
|
59
|
+
# @param str [String, nil] the identifier string to parse
|
|
60
|
+
# @param types [Array<Symbol>, nil] restrict to specific types (e.g. [:isin, :cusip])
|
|
61
|
+
# @return [SecID::Base, nil] a valid identifier instance, or nil if no match
|
|
62
|
+
# @raise [ArgumentError] if any key in types is unknown
|
|
63
|
+
def parse(str, types: nil)
|
|
64
|
+
types.nil? ? parse_any(str) : parse_from(str, types)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# Parses a string into the most specific matching identifier instance, raising on failure.
|
|
68
|
+
#
|
|
69
|
+
# @param str [String, nil] the identifier string to parse
|
|
70
|
+
# @param types [Array<Symbol>, nil] restrict to specific types (e.g. [:isin, :cusip])
|
|
71
|
+
# @return [SecID::Base] a valid identifier instance
|
|
72
|
+
# @raise [InvalidFormatError] if no matching identifier type is found
|
|
73
|
+
# @raise [ArgumentError] if any key in types is unknown
|
|
74
|
+
def parse!(str, types: nil)
|
|
75
|
+
parse(str, types: types) || raise(InvalidFormatError, parse_error_message(str, types))
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
private
|
|
79
|
+
|
|
80
|
+
# @param klass [Class] the identifier class to register
|
|
81
|
+
# @return [void]
|
|
82
|
+
def register_identifier(klass)
|
|
83
|
+
key = klass.name.split('::').last.downcase.to_sym
|
|
84
|
+
identifier_map[key] = klass
|
|
85
|
+
identifier_list << klass
|
|
86
|
+
@detector = nil
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
# @return [SecID::Base, nil]
|
|
90
|
+
def parse_any(str)
|
|
91
|
+
key = detect(str).first
|
|
92
|
+
key && self[key].new(str)
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
# @return [SecID::Base, nil]
|
|
96
|
+
def parse_from(str, types)
|
|
97
|
+
types.each do |key|
|
|
98
|
+
instance = self[key].new(str)
|
|
99
|
+
return instance if instance.valid?
|
|
100
|
+
end
|
|
101
|
+
nil
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
# @return [String]
|
|
105
|
+
def parse_error_message(str, types)
|
|
106
|
+
base = "No matching identifier type found for #{str.to_s.strip.inspect}"
|
|
107
|
+
types ? "#{base} among #{types.inspect}" : base
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
# @return [Detector]
|
|
111
|
+
def detector
|
|
112
|
+
@detector ||= Detector.new(identifier_list)
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
# @return [Hash{Symbol => Class}]
|
|
116
|
+
def identifier_map
|
|
117
|
+
@identifier_map ||= {}
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
# @return [Array<Class>]
|
|
121
|
+
def identifier_list
|
|
122
|
+
@identifier_list ||= []
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
require 'sec_id/errors'
|
|
128
|
+
require 'sec_id/concerns/identifier_metadata'
|
|
5
129
|
require 'sec_id/concerns/normalizable'
|
|
130
|
+
require 'sec_id/concerns/validatable'
|
|
6
131
|
require 'sec_id/concerns/checkable'
|
|
7
132
|
require 'sec_id/base'
|
|
133
|
+
require 'sec_id/detector'
|
|
8
134
|
require 'sec_id/isin'
|
|
9
135
|
require 'sec_id/cusip'
|
|
10
136
|
require 'sec_id/sedol'
|
|
@@ -18,8 +144,3 @@ require 'sec_id/valoren'
|
|
|
18
144
|
require 'sec_id/cei'
|
|
19
145
|
require 'sec_id/cfi'
|
|
20
146
|
require 'sec_id/fisn'
|
|
21
|
-
|
|
22
|
-
module SecId
|
|
23
|
-
class Error < StandardError; end
|
|
24
|
-
class InvalidFormatError < Error; end
|
|
25
|
-
end
|
data/sec_id.gemspec
CHANGED
|
@@ -6,7 +6,7 @@ require 'sec_id/version'
|
|
|
6
6
|
|
|
7
7
|
Gem::Specification.new do |spec|
|
|
8
8
|
spec.name = 'sec_id'
|
|
9
|
-
spec.version =
|
|
9
|
+
spec.version = SecID::VERSION
|
|
10
10
|
spec.authors = ['Leonid Svyatov']
|
|
11
11
|
spec.email = ['leonid@svyatov.ru']
|
|
12
12
|
|
|
@@ -17,10 +17,13 @@ Gem::Specification.new do |spec|
|
|
|
17
17
|
spec.homepage = 'https://github.com/svyatov/sec_id'
|
|
18
18
|
spec.license = 'MIT'
|
|
19
19
|
|
|
20
|
-
spec.required_ruby_version = '>= 3.
|
|
20
|
+
spec.required_ruby_version = '>= 3.2.0'
|
|
21
21
|
|
|
22
22
|
spec.require_paths = ['lib']
|
|
23
|
-
spec.files = Dir['lib/**/*.rb'] + %w[CHANGELOG.md LICENSE.txt README.md sec_id.gemspec]
|
|
23
|
+
spec.files = Dir['lib/**/*.rb'] + %w[CHANGELOG.md LICENSE.txt MIGRATION.md README.md sec_id.gemspec]
|
|
24
24
|
|
|
25
25
|
spec.metadata['rubygems_mfa_required'] = 'true'
|
|
26
|
+
spec.metadata['source_code_uri'] = 'https://github.com/svyatov/sec_id'
|
|
27
|
+
spec.metadata['changelog_uri'] = 'https://github.com/svyatov/sec_id/blob/main/CHANGELOG.md'
|
|
28
|
+
spec.metadata['bug_tracker_uri'] = 'https://github.com/svyatov/sec_id/issues'
|
|
26
29
|
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: 5.0.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Leonid Svyatov
|
|
@@ -20,6 +20,7 @@ extra_rdoc_files: []
|
|
|
20
20
|
files:
|
|
21
21
|
- CHANGELOG.md
|
|
22
22
|
- LICENSE.txt
|
|
23
|
+
- MIGRATION.md
|
|
23
24
|
- README.md
|
|
24
25
|
- lib/sec_id.rb
|
|
25
26
|
- lib/sec_id/base.rb
|
|
@@ -27,8 +28,12 @@ files:
|
|
|
27
28
|
- lib/sec_id/cfi.rb
|
|
28
29
|
- lib/sec_id/cik.rb
|
|
29
30
|
- lib/sec_id/concerns/checkable.rb
|
|
31
|
+
- lib/sec_id/concerns/identifier_metadata.rb
|
|
30
32
|
- lib/sec_id/concerns/normalizable.rb
|
|
33
|
+
- lib/sec_id/concerns/validatable.rb
|
|
31
34
|
- lib/sec_id/cusip.rb
|
|
35
|
+
- lib/sec_id/detector.rb
|
|
36
|
+
- lib/sec_id/errors.rb
|
|
32
37
|
- lib/sec_id/figi.rb
|
|
33
38
|
- lib/sec_id/fisn.rb
|
|
34
39
|
- lib/sec_id/iban.rb
|
|
@@ -46,6 +51,9 @@ licenses:
|
|
|
46
51
|
- MIT
|
|
47
52
|
metadata:
|
|
48
53
|
rubygems_mfa_required: 'true'
|
|
54
|
+
source_code_uri: https://github.com/svyatov/sec_id
|
|
55
|
+
changelog_uri: https://github.com/svyatov/sec_id/blob/main/CHANGELOG.md
|
|
56
|
+
bug_tracker_uri: https://github.com/svyatov/sec_id/issues
|
|
49
57
|
rdoc_options: []
|
|
50
58
|
require_paths:
|
|
51
59
|
- lib
|
|
@@ -53,14 +61,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
53
61
|
requirements:
|
|
54
62
|
- - ">="
|
|
55
63
|
- !ruby/object:Gem::Version
|
|
56
|
-
version: 3.
|
|
64
|
+
version: 3.2.0
|
|
57
65
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
58
66
|
requirements:
|
|
59
67
|
- - ">="
|
|
60
68
|
- !ruby/object:Gem::Version
|
|
61
69
|
version: '0'
|
|
62
70
|
requirements: []
|
|
63
|
-
rubygems_version: 4.0.
|
|
71
|
+
rubygems_version: 4.0.6
|
|
64
72
|
specification_version: 4
|
|
65
73
|
summary: Validate securities identification numbers with ease!
|
|
66
74
|
test_files: []
|