Class: ISO::IBAN
- Inherits:
-
Object
- Object
- ISO::IBAN
- Includes:
- Comparable
- Defined in:
- lib/iso/iban/no_autoload.rb,
lib/iso/iban/invalid.rb,
lib/iso/iban/version.rb,
lib/iso/iban/specification.rb
Overview
IBAN - ISO 13616-1
Usage
require 'iso/iban'
ISO::IBAN.valid?('CH35 1234 5987 6543 2109 A') # => true
ISO::IBAN.validate('CH37 1234 5987 6543 2109 A') # => [:invalid_checksum]
ISO::IBAN.generate('CH', '12345', '987') # => #<ISO::IBAN CH76 1234 5000 0000 0098 7>
iban = ISO::IBAN.parse('CH35 1234 5987 6543 2109 A') # => #<ISO::IBAN CH35 1234 5987 6543 2109 A>
iban = ISO::IBAN.new('CH351234598765432109A') # => #<ISO::IBAN CH35 1234 5987 6543 2109 A>
iban.formatted # => "CH35 1234 5987 6543 2109 A"
iban.compact # => "CH351234598765432109A"
iban.country # => "CH"
iban.checksum_digits # => "35"
iban.bank_code # => "12345"
iban.account_code # => "98765432109A"
iban.valid? # => true
iban.validate # => []
General IBAN Information
What is an IBAN?
IBAN stands for International Bank Account Number. It is the ISO 13616 international standard for numbering bank accounts. In 2006, the International Organization for Standardization (ISO) designated SWIFT as the Registration Authority for ISO 13616.Use
The IBAN facilitates the communication and processing of cross-border transactions. It allows exchanging account identification details in a machine-readable form.
The ISO 13616 IBAN Standard
Structure
The IBAN structure is defined in ISO 13616-1 and consists of a two-letter ISO 3166-1 country code, followed by two check digits and up to thirty alphanumeric characters for a BBAN (Basic Bank Account Number) which has a fixed length per country and, included within it, a bank identifier with a fixed position and a fixed length per country. The check digits are calculated based on the scheme defined in ISO/IEC 7064 (MOD97-10).Terms and definitions
- Bank identifier: The identifier that uniquely identifies the financial
institution and, when appropriate, the branch of that financial institution
servicing an account.
- BBAN: basic bank account number: The identifier that uniquely identifies
an individual account, at a specific financial institution, in a particular
country. The BBAN includes a bank identifier of the financial institution
servicing that account.
- IBAN: international bank account number: The expanded version of the basic bank account number (BBAN), intended for use internationally. The IBAN uniquely identifies an individual account, at a specific financial institution, in a particular country.
- Bank identifier: The identifier that uniquely identifies the financial
institution and, when appropriate, the branch of that financial institution
servicing an account.
Submitters
Nationally-agreed, ISO13616-compliant IBAN formats are submitted to the registration authority exclusively by the National Standards Body or the National Central Bank of the country.
Defined Under Namespace
Classes: Invalid, Specification
Constant Summary collapse
- Version =
Note:
require 'iso/iban' loads the version.
The version of the sorting gem.
Gem::Version.new("0.1.3")
- CharacterCodes =
Character code translation used to convert an IBAN into its numeric (digits-only) form
Hash[('0'..'9').zip('0'..'9')+('a'..'z').zip(10..35)+('A'..'Z').zip(10..35)]
- UpperAlpha =
All uppercase letters
[*'A'..'Z']
- LowerAlpha =
All lowercase letters
[*'a'..'z']
- Digits =
All digits
[*'0'..'9']
- AlphaNumeric =
All uppercase letters, lowercase letters and digits
[*'A'..'Z', *'a'..'z', *'0'..'9']
Instance Attribute Summary collapse
-
#compact ⇒ String
readonly
The standard form of the IBAN for machine communication, without spaces, encoded in Encoding::BINARY.
-
#country ⇒ String
readonly
The ISO-3166 2-letter country code (first and second character).
-
#specification ⇒ ISO::IBAN::Specification
readonly
The specification for this IBAN (determined by its country).
Class Method Summary collapse
-
.generate(country, *components) ⇒ Object
Generate an IBAN from country code and components, automatically filling in the checksum.
-
.load_specifications(spec_file = nil) ⇒ self
Load the IBAN specifications file, which determines how the IBAN for any given country looks.
-
.numerify(string) ⇒ String
Converts a String into its digits-only form, i.e.
-
.parse(iban_number) ⇒ ISO::IBAN
An IBAN instance representing the passed IBAN number.
-
.parse!(iban_number) ⇒ ISO::IBAN
Like ISO::IBAN.parse, but raises an ISO::IBAN::Invalid exception if the IBAN is invalid.
-
.random(*countries) ⇒ ISO::IBAN
A random, valid IBAN.
-
.specification(a2_country_code, *default, &default_block) ⇒ ISO::IBAN::Specification
The specification for the given country.
-
.specifications ⇒ Hash<String => ISO::IBAN::Specification>
A hash with the country (ISO3166 2-letter) as key and the specification for that country as value.
-
.strip(iban) ⇒ String
The IBAN in compact form, all whitespace and dashes stripped.
-
.valid?(iban) ⇒ true, false
Whether the IBAN is valid.
-
.validate(iban) ⇒ Array<Symbol>
An array with a code of all validation errors, empty if valid.
Instance Method Summary collapse
-
#<=>(other) ⇒ -1, ...
See Object#<=>.
-
#account_code ⇒ String
The account code part of the IBAN.
-
#bank_code ⇒ String?
The bank code part of the IBAN, nil if not applicable.
-
#bban ⇒ String
The BBAN of the IBAN (everything except the country code and check digits).
-
#branch_code ⇒ String?
The branch code part of the IBAN, nil if not applicable.
-
#calculated_check_digits ⇒ String
The check-digits as calculated from the IBAN.
-
#checksum_digits ⇒ String
The checksum digits in the IBAN (character 3 & 4).
-
#eql?(other) ⇒ true, false
Whether two ISO::IBANs are equal.
-
#formatted ⇒ String
The IBAN in its formatted form, which is more human readable than the compact form.
-
#hash ⇒ Integer
A hash value, see Object#hash.
-
#initialize(iban) ⇒ IBAN
constructor
A new instance of IBAN.
-
#inspect ⇒ Object
See Object#inspect.
-
#invalid_characters(input_encoding = nil) ⇒ Array
An Array with all invalid characters.
-
#numeric ⇒ Integer?
IBAN in its numeric form, i.e.
-
#to_a ⇒ Array
The individual IBAN components as defined by the SWIFT specification.
-
#to_s ⇒ String
The compact form of the IBAN as a String.
-
#update_checksum! ⇒ self
Requires that the checksum digits were left as '??', replaces them with the proper checksum.
-
#valid? ⇒ true, false
Whether the IBAN is valid.
-
#valid_characters? ⇒ true, false
Whether IBAN consists only of valid characters.
-
#valid_checksum? ⇒ true, false
Whether the checksum of the IBAN is valid.
-
#valid_country? ⇒ true, false
Whether the country of the IBAN is valid.
-
#valid_format? ⇒ true, false
Whether the format of the IBAN is valid.
-
#valid_length? ⇒ true, false
Whether the length of the IBAN is valid.
-
#validate ⇒ Array<Symbol>
Error codes:.
Constructor Details
#initialize(iban) ⇒ IBAN
Returns a new instance of IBAN.
280 281 282 283 284 285 286 |
# File 'lib/iso/iban/no_autoload.rb', line 280 def initialize(iban) raise ArgumentError, "String expected for iban, but got #{iban.class}" unless iban.is_a?(String) @compact = iban.b.upcase @country = @compact[0,2] @specification = self.class.specification(@country, nil) end |
Instance Attribute Details
#compact ⇒ String (readonly)
Returns The standard form of the IBAN for machine communication, without spaces, encoded in Encoding::BINARY.
270 271 272 |
# File 'lib/iso/iban/no_autoload.rb', line 270 def compact @compact end |
#country ⇒ String (readonly)
Returns The ISO-3166 2-letter country code (first and second character).
273 274 275 |
# File 'lib/iso/iban/no_autoload.rb', line 273 def country @country end |
#specification ⇒ ISO::IBAN::Specification (readonly)
Returns The specification for this IBAN (determined by its country).
276 277 278 |
# File 'lib/iso/iban/no_autoload.rb', line 276 def specification @specification end |
Class Method Details
.generate(country, *components) ⇒ Object
generate
will pad all segments with zeros, which means it will generate invalid
IBANs if you provide too short segments which are alphabetic only.
For example, ISO::IBAN.generate('BG', 'A', '2', 'C')
generates an invalid IBAN.
Generate an IBAN from country code and components, automatically filling in the checksum.
218 219 220 221 222 223 224 225 |
# File 'lib/iso/iban/no_autoload.rb', line 218 def self.generate(country, *components) spec = specification(country) justified = spec.component_lengths.zip(components).map { |length, component| component.rjust(length, "0") } iban = new(country+'??'+justified.join('')) iban.update_checksum! iban end |
.load_specifications(spec_file = nil) ⇒ self
Using require 'iso/iban'
will automatically invoke this method.
If you do not wish this behavior, require 'iso/iban/no_autoload'
instead.
Load the IBAN specifications file, which determines how the IBAN for any given country looks.
It will use the following sources in this order (first one which exists wins)
- Path passed as
spec_file
parameter - Path provided by the env variable
IBAN_SPECIFICATIONS
- The file
../data/iso-iban/specs.yaml
relative to the lib dir - The Gem datadir path
115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 |
# File 'lib/iso/iban/no_autoload.rb', line 115 def self.load_specifications(spec_file=nil) if spec_file then # do nothing elsif ENV['IBAN_SPECIFICATIONS'] then spec_file = ENV['IBAN_SPECIFICATIONS'] else spec_file = File.('../../../../data/iso-iban/specs.yaml', __FILE__) if !File.file?(spec_file) && defined?(Gem) && Gem.datadir('iso-iban') spec_file = Gem.datadir('iso-iban')+'/specs.yaml' end end if spec_file && File.file?(spec_file) @specifications = ISO::IBAN::Specification.load_yaml(spec_file) elsif spec_file raise "Could not load IBAN specifications, specs file #{spec_file.inspect} does not exist or can't be read." else raise "Could not load IBAN specifications, no specs file found." end self end |
.numerify(string) ⇒ String
Converts a String into its digits-only form, i.e. all characters a-z are replaced with their corresponding digit sequences, according to the IBAN specification.
261 262 263 264 265 266 267 |
# File 'lib/iso/iban/no_autoload.rb', line 261 def self.numerify(string) string.downcase.gsub(/\D/) { |char| CharacterCodes.fetch(char) { raise ArgumentError, "The string contains an invalid character #{char.inspect}" } }.to_i end |
.parse(iban_number) ⇒ ISO::IBAN
Returns An IBAN instance representing the passed IBAN number.
201 202 203 |
# File 'lib/iso/iban/no_autoload.rb', line 201 def self.parse(iban_number) new(strip(iban_number || "")) end |
.parse!(iban_number) ⇒ ISO::IBAN
Like ISO::IBAN.parse, but raises an ISO::IBAN::Invalid exception if the IBAN is invalid.
189 190 191 192 193 194 |
# File 'lib/iso/iban/no_autoload.rb', line 189 def self.parse!(iban_number) iban = parse(iban_number) raise Invalid.new(iban) unless iban.valid? iban end |
.random(*countries) ⇒ ISO::IBAN
Returns A random, valid IBAN.
231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 |
# File 'lib/iso/iban/no_autoload.rb', line 231 def self.random(*countries) countries = specifications.keys if countries.empty? country = countries.sample account = specification(country).iban_structure.scan(/([A-Z]+)|(\d+)(!?)([nac])/).map { |exact, length, fixed, code| if exact exact elsif code == 'a' Array.new(length.to_i) { UpperAlpha.sample }.join('') elsif code == 'c' Array.new(length.to_i) { AlphaNumeric.sample }.join('') elsif code == 'e' ' '*length.to_i elsif code == 'n' Array.new(length.to_i) { Digits.sample }.join('') end }.join('') account[2,2] = '??' iban = new(account) iban.update_checksum! iban end |
.specification(a2_country_code, *default, &default_block) ⇒ ISO::IBAN::Specification
Returns The specification for the given country.
149 150 151 |
# File 'lib/iso/iban/no_autoload.rb', line 149 def self.specification(a2_country_code, *default, &default_block) specifications.fetch(a2_country_code, *default, &default_block) end |
.specifications ⇒ Hash<String => ISO::IBAN::Specification>
Returns A hash with the country (ISO3166 2-letter) as key and the specification for that country as value.
140 141 142 |
# File 'lib/iso/iban/no_autoload.rb', line 140 def self.specifications @specifications || raise("No specifications have been loaded yet - Check the docs for ISO::IBAN::load_specifications.") end |
.strip(iban) ⇒ String
Returns The IBAN in compact form, all whitespace and dashes stripped.
178 179 180 |
# File 'lib/iso/iban/no_autoload.rb', line 178 def self.strip(iban) iban.delete("\n\r\t -") end |
.valid?(iban) ⇒ true, false
Returns Whether the IBAN is valid.
See #validate for details.
159 160 161 |
# File 'lib/iso/iban/no_autoload.rb', line 159 def self.valid?(iban) parse(iban).valid? end |
.validate(iban) ⇒ Array<Symbol>
Returns An array with a code of all validation errors, empty if valid.
See #validate for details.
169 170 171 |
# File 'lib/iso/iban/no_autoload.rb', line 169 def self.validate(iban) parse(iban).validate end |
Instance Method Details
#<=>(other) ⇒ -1, ...
See Object#<=>
425 426 427 |
# File 'lib/iso/iban/no_autoload.rb', line 425 def <=>(other) other.respond_to?(:compact) ? @compact <=> other.compact : nil end |
#account_code ⇒ String
Returns The account code part of the IBAN.
373 374 375 |
# File 'lib/iso/iban/no_autoload.rb', line 373 def account_code @compact[((@specification.branch_position_to || @specification.bank_position_to || 3)+1)..-1] end |
#bank_code ⇒ String?
Returns The bank code part of the IBAN, nil if not applicable.
355 356 357 358 359 360 361 |
# File 'lib/iso/iban/no_autoload.rb', line 355 def bank_code if @specification && @specification.bank_position_from && @specification.bank_position_to @compact[@specification.bank_position_from..@specification.bank_position_to] else nil end end |
#bban ⇒ String
Returns The BBAN of the IBAN (everything except the country code and check digits).
350 351 352 |
# File 'lib/iso/iban/no_autoload.rb', line 350 def bban @compact[4..-1] end |
#branch_code ⇒ String?
Returns The branch code part of the IBAN, nil if not applicable.
364 365 366 367 368 369 370 |
# File 'lib/iso/iban/no_autoload.rb', line 364 def branch_code if @specification && @specification.branch_position_from && @specification.branch_position_to @compact[@specification.branch_position_from..@specification.branch_position_to] else nil end end |
#calculated_check_digits ⇒ String
Returns The check-digits as calculated from the IBAN.
443 444 445 |
# File 'lib/iso/iban/no_autoload.rb', line 443 def calculated_check_digits "%02d" % (98-(self.class.numerify(bban+@country)*100)%97) end |
#checksum_digits ⇒ String
Returns The checksum digits in the IBAN (character 3 & 4).
345 346 347 |
# File 'lib/iso/iban/no_autoload.rb', line 345 def checksum_digits @compact[2,2] end |
#eql?(other) ⇒ true, false
Returns Whether two ISO::IBANs are equal. Comparison is based on class and IBAN number.
450 451 452 |
# File 'lib/iso/iban/no_autoload.rb', line 450 def eql?(other) self.class.equal?(other.class) && self == other end |
#formatted ⇒ String
Returns The IBAN in its formatted form, which is more human readable than the compact form.
293 294 295 |
# File 'lib/iso/iban/no_autoload.rb', line 293 def formatted @_formatted ||= @compact.gsub(/.{4}(?=.)/, '\0 ') end |
#hash ⇒ Integer
Returns A hash value, see Object#hash.
456 457 458 |
# File 'lib/iso/iban/no_autoload.rb', line 456 def hash [self.class, @compact].hash end |
#inspect ⇒ Object
See Object#inspect
461 462 463 |
# File 'lib/iso/iban/no_autoload.rb', line 461 def inspect sprintf "#<%p %s>", self.class, formatted end |
#invalid_characters(input_encoding = nil) ⇒ Array
Returns An Array with all invalid characters.
389 390 391 392 393 |
# File 'lib/iso/iban/no_autoload.rb', line 389 def invalid_characters(input_encoding=nil) iban = input_encoding ? @compact.dup.force_encoding(input_encoding) : @compact iban.gsub(/[A-Z0-9?]*/i, '').chars.to_a.uniq # to_a is for ruby <= 2.0 where String#chars returns an Enumerator end |
#numeric ⇒ Integer?
Returns IBAN in its numeric form, i.e. all characters a-z are replaced with their corresponding
digit sequences.
Will return nil if the IBAN is shorter than 5 characters (which makes it invalid).
301 302 303 |
# File 'lib/iso/iban/no_autoload.rb', line 301 def numeric @compact.size < 5 ? nil : self.class.numerify(@compact[4..-1]+@compact[0,4]) end |
#to_a ⇒ Array
This method is experimental. It might change or be removed in future versions!
Returns The individual IBAN components as defined by the SWIFT specification. An empty array if this IBAN does not have a specification.
476 477 478 479 480 |
# File 'lib/iso/iban/no_autoload.rb', line 476 def to_a @_components ||= @specification ? @compact.match(@specification.iban_regex).captures : [] @_components.dup end |
#to_s ⇒ String
Returns The compact form of the IBAN as a String.
466 467 468 |
# File 'lib/iso/iban/no_autoload.rb', line 466 def to_s @compact.dup end |
#update_checksum! ⇒ self
Requires that the checksum digits were left as '??', replaces them with the proper checksum.
433 434 435 436 437 438 439 440 |
# File 'lib/iso/iban/no_autoload.rb', line 433 def update_checksum! raise "Checksum digit placeholders missing" unless @compact[2,2] == '??' @compact[2,2] = calculated_check_digits @_formatted = nil self end |
#valid? ⇒ true, false
Returns Whether the IBAN is valid. See #validate for details.
308 309 310 |
# File 'lib/iso/iban/no_autoload.rb', line 308 def valid? valid_characters? && valid_country? && valid_checksum? && valid_length? && valid_format? end |
#valid_characters? ⇒ true, false
Returns Whether IBAN consists only of valid characters.
396 397 398 |
# File 'lib/iso/iban/no_autoload.rb', line 396 def valid_characters? @compact =~ /\A[A-Z]{2}(?:\d\d|\?\?)[A-Z0-9]*\z/in ? true : false end |
#valid_checksum? ⇒ true, false
Returns Whether the checksum of the IBAN is valid.
416 417 418 419 420 |
# File 'lib/iso/iban/no_autoload.rb', line 416 def valid_checksum? numerified = numeric() numerified && (numerified % 97 == 1) end |
#valid_country? ⇒ true, false
Returns Whether the country of the IBAN is valid.
401 402 403 |
# File 'lib/iso/iban/no_autoload.rb', line 401 def valid_country? @specification ? true : false end |
#valid_format? ⇒ true, false
Returns Whether the format of the IBAN is valid.
406 407 408 |
# File 'lib/iso/iban/no_autoload.rb', line 406 def valid_format? @specification && @specification.iban_regex =~ @compact ? true : false end |
#valid_length? ⇒ true, false
Returns Whether the length of the IBAN is valid.
411 412 413 |
# File 'lib/iso/iban/no_autoload.rb', line 411 def valid_length? @specification && @compact.size == @specification.iban_length ? true : false end |
#validate ⇒ Array<Symbol>
The class method validate uses parse, which means it will strip whitespace and
dashes from the IBAN.
#initialize on the other hand expects the IBAN in compact format and will not strip
those characters.
Error codes:
- :invalid_characters
- :invalid_country
- :invalid_checksum
- :invalid_length
- :invalid_format
Invalid characters means that the IBAN contains characters which are not in the set of A-Za-z0-9. See #invalid_characters.
Invalid country means the country is unknown (character 1 & 2 in the IBAN).
Invalid checksum means the two check digits (character 3 & 4 in the IBAN).
Invalid length means the IBAN does not comply with the length specified for the country of that IBAN.
Invalid format means the IBAN does not comply with the format specified for the country of that IBAN.
333 334 335 336 337 338 339 340 341 342 |
# File 'lib/iso/iban/no_autoload.rb', line 333 def validate errors = [] errors << :invalid_characters unless valid_characters? errors << :invalid_country unless valid_country? errors << :invalid_checksum unless valid_characters? && valid_checksum? errors << :invalid_length unless valid_length? errors << :invalid_format unless valid_format? errors end |