sec_id 4.4.1 → 5.1.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.
data/lib/sec_id/isin.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module SecId
3
+ module SecID
4
4
  # International Securities Identification Number (ISIN) - a 12-character alphanumeric code
5
5
  # that uniquely identifies a security globally.
6
6
  #
@@ -9,13 +9,18 @@ module SecId
9
9
  # @see https://en.wikipedia.org/wiki/International_Securities_Identification_Number
10
10
  #
11
11
  # @example Validate an ISIN
12
- # SecId::ISIN.valid?('US5949181045') #=> true
12
+ # SecID::ISIN.valid?('US5949181045') #=> true
13
13
  #
14
14
  # @example Restore check digit
15
- # SecId::ISIN.restore!('US594918104') #=> 'US5949181045'
15
+ # SecID::ISIN.restore!('US594918104') #=> #<SecID::ISIN>
16
16
  class ISIN < Base
17
17
  include Checkable
18
18
 
19
+ FULL_NAME = 'International Securities Identification Number'
20
+ ID_LENGTH = 12
21
+ EXAMPLE = 'US5949181045'
22
+ VALID_CHARS_REGEX = /\A[A-Z0-9]+\z/
23
+
19
24
  # Regular expression for parsing ISIN components.
20
25
  ID_REGEX = /\A
21
26
  (?<identifier>
@@ -71,6 +76,13 @@ module SecId
71
76
  @check_digit = isin_parts[:check_digit]&.to_i
72
77
  end
73
78
 
79
+ # @return [String, nil]
80
+ def to_pretty_s
81
+ return nil unless valid?
82
+
83
+ "#{country_code} #{nsin} #{check_digit}"
84
+ end
85
+
74
86
  # @return [Integer] the calculated check digit (0-9)
75
87
  # @raise [InvalidFormatError] if the ISIN format is invalid
76
88
  def calculate_check_digit
@@ -130,6 +142,13 @@ module SecId
130
142
  Valoren.new(nsin)
131
143
  end
132
144
 
145
+ private
146
+
147
+ # @return [Hash]
148
+ def components = { country_code:, nsin:, check_digit: }
149
+
150
+ public
151
+
133
152
  # Returns the type of NSIN embedded in this ISIN.
134
153
  #
135
154
  # @return [Symbol] :cusip, :sedol, :wkn, :valoren, or :generic
@@ -148,9 +167,9 @@ module SecId
148
167
 
149
168
  case nsin_type
150
169
  when :cusip then to_cusip
151
- when :sedol then SEDOL.new(nsin[2..])
152
- when :wkn then WKN.new(nsin[3..])
153
- when :valoren then Valoren.new(nsin)
170
+ when :sedol then to_sedol
171
+ when :wkn then to_wkn
172
+ when :valoren then to_valoren
154
173
  else nsin # :generic - return raw string
155
174
  end
156
175
  end
data/lib/sec_id/lei.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module SecId
3
+ module SecID
4
4
  # Legal Entity Identifier (LEI) - a 20-character alphanumeric code that
5
5
  # uniquely identifies legal entities participating in financial transactions.
6
6
  #
@@ -10,13 +10,18 @@ module SecId
10
10
  # @see https://www.gleif.org/en/about-lei/iso-17442-the-lei-code-structure
11
11
  #
12
12
  # @example Validate a LEI
13
- # SecId::LEI.valid?('529900T8BM49AURSDO55') #=> true
13
+ # SecID::LEI.valid?('529900T8BM49AURSDO55') #=> true
14
14
  #
15
15
  # @example Calculate check digit
16
- # SecId::LEI.check_digit('529900T8BM49AURSDO') #=> 55
16
+ # SecID::LEI.check_digit('529900T8BM49AURSDO') #=> 55
17
17
  class LEI < Base
18
18
  include Checkable
19
19
 
20
+ FULL_NAME = 'Legal Entity Identifier'
21
+ ID_LENGTH = 20
22
+ EXAMPLE = '7LTWFZYICNSX8D621K86'
23
+ VALID_CHARS_REGEX = /\A[0-9A-Z]+\z/
24
+
20
25
  # Regular expression for parsing LEI components.
21
26
  ID_REGEX = /\A
22
27
  (?<identifier>
@@ -45,6 +50,13 @@ module SecId
45
50
  @check_digit = lei_parts[:check_digit]&.to_i
46
51
  end
47
52
 
53
+ # @return [String, nil]
54
+ def to_pretty_s
55
+ return nil unless valid?
56
+
57
+ to_s.scan(/.{1,4}/).join(' ')
58
+ end
59
+
48
60
  # @return [Integer] the calculated 2-digit check digit (1-98)
49
61
  # @raise [InvalidFormatError] if the LEI format is invalid
50
62
  def calculate_check_digit
@@ -52,14 +64,15 @@ module SecId
52
64
  mod97("#{numeric_identifier}00")
53
65
  end
54
66
 
55
- # @return [String]
56
- def to_s
57
- return full_number unless check_digit
67
+ private
58
68
 
59
- "#{identifier}#{check_digit.to_s.rjust(2, '0')}"
60
- end
69
+ # @return [Hash]
70
+ def components = { lou_id:, reserved:, entity_id:, check_digit: }
61
71
 
62
- private
72
+ # @return [Integer]
73
+ def check_digit_width
74
+ 2
75
+ end
63
76
 
64
77
  # @return [String] the numeric string representation
65
78
  def numeric_identifier
data/lib/sec_id/occ.rb CHANGED
@@ -2,24 +2,28 @@
2
2
 
3
3
  require 'date'
4
4
 
5
- module SecId
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. The {#has_check_digit?} method returns false
10
- # and validation includes both format and date parseability checks.
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
- # SecId::OCC.valid?('AAPL 210917C00150000') #=> true
16
+ # SecID::OCC.valid?('AAPL 210917C00150000') #=> true
17
17
  #
18
18
  # @example Build an OCC symbol from components
19
- # occ = SecId::OCC.build(underlying: 'AAPL', date: '2021-09-17', type: 'C', strike: 150.0)
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
- include Normalizable
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 String && /\A\d{8}\z/
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, upcase: false)
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] if the OCC symbol is invalid
106
- def normalize!
107
- raise InvalidFormatError, "OCC '#{full_number}' is invalid and cannot be normalized!" unless valid?
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,53 @@ module SecId
116
117
 
117
118
  # @return [Date, nil] the parsed date or nil if invalid
118
119
  def date
119
- return nil unless date_str
120
+ return @date if defined?(@date)
121
+ return unless date_str
120
122
 
121
- @date ||= Date.strptime(date_str, '%y%m%d')
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 ||= strike_mills.to_i / 1000.0
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
- full_number
138
+ full_id
139
+ end
140
+
141
+ # @return [String, nil]
142
+ def to_pretty_s
143
+ return nil unless valid?
144
+
145
+ "#{underlying} #{date_str} #{type} #{strike_mills}"
135
146
  end
136
- alias to_str to_s
137
147
 
138
- # @deprecated Use {#full_number} instead
148
+ private
149
+
150
+ # @return [Hash]
151
+ def components = { underlying:, date_str:, type:, strike_mills: }
152
+
153
+ # @return [Array<Symbol>]
154
+ def error_codes
155
+ return detect_errors unless valid_format?
156
+ return [:invalid_date] if date.nil?
157
+
158
+ []
159
+ end
160
+
161
+ # @param code [Symbol]
139
162
  # @return [String]
140
- def full_symbol
141
- full_number
163
+ def validation_message(code)
164
+ return "Date '#{date_str}' cannot be parsed" if code == :invalid_date
165
+
166
+ super
142
167
  end
143
168
  end
144
169
  end
data/lib/sec_id/sedol.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module SecId
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
- # SecId::SEDOL.valid?('B19GKT4') #=> true
13
+ # SecID::SEDOL.valid?('B19GKT4') #=> true
14
14
  #
15
15
  # @example Calculate check digit
16
- # SecId::SEDOL.check_digit('B19GKT') #=> 4
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
- sedol_with_check_digit = "#{identifier}#{check_digit || calculate_check_digit}"
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)
@@ -60,6 +62,9 @@ module SecId
60
62
 
61
63
  private
62
64
 
65
+ # @return [Hash]
66
+ def components = { check_digit: }
67
+
63
68
  # NOTE: Not idiomatic Ruby, but optimized for performance.
64
69
  #
65
70
  # @return [Integer] the weighted sum
@@ -1,24 +1,26 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module SecId
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. The {#has_check_digit?} method
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
- # SecId::Valoren.valid?('3886335') #=> true
16
- # SecId::Valoren.valid?('003886335') #=> true
14
+ # SecID::Valoren.valid?('3886335') #=> true
15
+ # SecID::Valoren.valid?('003886335') #=> true
17
16
  #
18
17
  # @example Normalize a Valoren to 9 digits
19
- # SecId::Valoren.normalize!('3886335') #=> '003886335'
18
+ # SecID::Valoren.normalize('3886335') #=> '003886335'
20
19
  class Valoren < Base
21
- include Normalizable
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
@@ -38,6 +40,13 @@ module SecId
38
40
  @identifier = valoren_parts[:identifier]
39
41
  end
40
42
 
43
+ # @return [String, nil]
44
+ def to_pretty_s
45
+ return nil unless valid?
46
+
47
+ identifier.reverse.scan(/.{1,3}/).join(' ').reverse
48
+ end
49
+
41
50
  # @param country_code [String] the ISO 3166-1 alpha-2 country code (default: 'CH')
42
51
  # @return [ISIN] a new ISIN instance with calculated check digit
43
52
  # @raise [InvalidFormatError] if the country code is not CH or LI
@@ -46,29 +55,27 @@ module SecId
46
55
  raise InvalidFormatError, "'#{country_code}' is not a valid Valoren country code!"
47
56
  end
48
57
 
49
- normalize!
50
- isin = ISIN.new(country_code + full_number)
51
- isin.restore!
52
- isin
58
+ ISIN.new(country_code + normalized).restore!
53
59
  end
54
60
 
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
61
  # @return [String] the normalized 9-digit Valoren
59
- # @raise [InvalidFormatError] if the Valoren format is invalid
60
- def normalize!
61
- raise InvalidFormatError, "Valoren '#{full_number}' is invalid and cannot be normalized!" unless valid_format?
62
+ # @raise [InvalidFormatError]
63
+ def normalized
64
+ validate!
65
+ @identifier.rjust(self.class::ID_LENGTH.max, '0')
66
+ end
62
67
 
63
- @full_number = @identifier.rjust(9, '0')
64
- @padding = @full_number[0, 9 - @identifier.length]
65
- @full_number
68
+ # @return [self]
69
+ # @raise [InvalidFormatError]
70
+ def normalize!
71
+ super
72
+ @padding = @full_id[0, self.class::ID_LENGTH.max - @identifier.length]
73
+ self
66
74
  end
67
75
 
68
76
  # @return [String]
69
77
  def to_s
70
- full_number
78
+ full_id
71
79
  end
72
- alias to_str to_s
73
80
  end
74
81
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module SecId
4
- VERSION = '4.4.1'
3
+ module SecID
4
+ VERSION = '5.1.0'
5
5
  end
data/lib/sec_id/wkn.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module SecId
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
- # SecId::WKN.valid?('514000') #=> true
14
- # SecId::WKN.valid?('CBK100') #=> true
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 '#{full_number}' is invalid!" unless valid_format?
39
+ raise InvalidFormatError, "WKN '#{full_id}' is invalid!" unless valid_format?
35
40
 
36
- isin = ISIN.new("#{country_code}000#{identifier}")
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 = SecId::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.1.0'
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.4.1
4
+ version: 5.1.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.1.0
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.4
71
+ rubygems_version: 4.0.6
64
72
  specification_version: 4
65
73
  summary: Validate securities identification numbers with ease!
66
74
  test_files: []