ibandit 1.13.0 → 1.15.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/.rubocop.yml +1 -1
- data/CHANGELOG.md +9 -0
- data/bin/build_structure_file.rb +221 -114
- data/config/locales/da.yml +7 -0
- data/config/locales/de.yml +7 -0
- data/config/locales/en.yml +7 -0
- data/config/locales/es.yml +7 -0
- data/config/locales/fr.yml +7 -0
- data/config/locales/it.yml +9 -1
- data/config/locales/nb.yml +7 -0
- data/config/locales/nl.yml +7 -0
- data/config/locales/pt.yml +7 -0
- data/config/locales/sl.yml +7 -0
- data/config/locales/sv.yml +7 -0
- data/data/raw/IBANSTRUCTURE.xml +1134 -292
- data/data/raw/IBAN_Registry.txt +51 -48
- data/data/raw/pseudo_ibans.yml +52 -0
- data/data/raw/structure_additions.yml +29 -1
- data/data/structures.yml +524 -25
- data/lib/ibandit/constants.rb +5 -1
- data/lib/ibandit/iban.rb +13 -13
- data/lib/ibandit/iban_assembler.rb +1 -1
- data/lib/ibandit/local_details_cleaner.rb +7 -7
- data/lib/ibandit/sweden/local_details_converter.rb +1 -1
- data/lib/ibandit/version.rb +1 -1
- data/lib/ibandit.rb +1 -1
- data/spec/ibandit/iban_assembler_spec.rb +48 -0
- data/spec/ibandit/iban_spec.rb +375 -2212
- data/spec/spec_helper.rb +6 -44
- metadata +4 -3
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: 15eee0ef8f82ced114c7aedc52a70c88ab69877928356200917723e0416af1a8
         | 
| 4 | 
            +
              data.tar.gz: a1d8b2feda3f775c0c25f481f58194e5e9dab9af2e8d8406007697e96564d178
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: a728382a2bb8e522ca8cb547938052f9fdf84dc1d81388e07f6465705c81ea61ad1b0a1cfd84deac1cc5a9f6d873ca98c9f510d1526f07ffff48fa9e746c08fa
         | 
| 7 | 
            +
              data.tar.gz: 3a5d6917918b1744b9c4dd86651f6099acea270a4b1029b2f7cbc18b25bdd832271b9780e35c8141bcc8273736859698bb1b0893a3688833d4690e3480486c8e
         | 
    
        data/.rubocop.yml
    CHANGED
    
    
    
        data/CHANGELOG.md
    CHANGED
    
    | @@ -1,3 +1,12 @@ | |
| 1 | 
            +
            ## 1.15.0 - March 28, 2023
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            - Improve the error messages that are generated
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            ## 1.14.0 - March 28, 2023
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            - Update IBAN registry #233
         | 
| 8 | 
            +
            - Add GL and FO to the IBAN constructor for local details
         | 
| 9 | 
            +
             | 
| 1 10 | 
             
            ## 1.13.0 - March 6, 2023
         | 
| 2 11 |  | 
| 3 12 | 
             
            - Update BLZ data - BLZ_20230306
         | 
    
        data/bin/build_structure_file.rb
    CHANGED
    
    | @@ -1,6 +1,8 @@ | |
| 1 1 | 
             
            #!/usr/bin/env ruby
         | 
| 2 2 | 
             
            # frozen_string_literal: true
         | 
| 3 3 |  | 
| 4 | 
            +
            # rubocop:disable Layout/LineLength
         | 
| 5 | 
            +
             | 
| 4 6 | 
             
            # Script for parsing the IBAN registry (IBAN_Registry.txt) and IBAN structures
         | 
| 5 7 | 
             
            # (IBANSTRUCTURE.xml) files from SWIFT.
         | 
| 6 8 | 
             
            require "csv"
         | 
| @@ -22,143 +24,240 @@ end | |
| 22 24 |  | 
| 23 25 | 
             
            class Report
         | 
| 24 26 | 
             
              include SAXMachine
         | 
| 25 | 
            -
              elements " | 
| 27 | 
            +
              elements "ibanstructure_v2", as: :countries, class: Country
         | 
| 26 28 | 
             
            end
         | 
| 27 29 |  | 
| 28 | 
            -
             | 
| 29 | 
            -
             | 
| 30 | 
            -
             | 
| 31 | 
            -
             | 
| 32 | 
            -
             | 
| 33 | 
            -
             | 
| 34 | 
            -
                 | 
| 35 | 
            -
             | 
| 36 | 
            -
             | 
| 37 | 
            -
             | 
| 38 | 
            -
             | 
| 39 | 
            -
             | 
| 40 | 
            -
             | 
| 41 | 
            -
             | 
| 42 | 
            -
             | 
| 43 | 
            -
                 | 
| 30 | 
            +
            class IbanRegistryTextFile
         | 
| 31 | 
            +
              attr_accessor :lines, :registry
         | 
| 32 | 
            +
             | 
| 33 | 
            +
              FILE_ELEMENTS = [
         | 
| 34 | 
            +
                # 0 Data element
         | 
| 35 | 
            +
                # 1 Name of country
         | 
| 36 | 
            +
                # 2 IBAN prefix country code (ISO 3166)
         | 
| 37 | 
            +
                COUNTRY_CODE = 2,
         | 
| 38 | 
            +
                # 3 Country code includes other countries/territories
         | 
| 39 | 
            +
                # 4 SEPA country
         | 
| 40 | 
            +
                # 5 SEPA country also includes
         | 
| 41 | 
            +
                # 6 Domestic account number example
         | 
| 42 | 
            +
                DOMESTIC_ACCOUNT_NUMBER_EXAMPLE = 6,
         | 
| 43 | 
            +
                # 7 BBAN
         | 
| 44 | 
            +
                # 8 BBAN structure
         | 
| 45 | 
            +
                BBAN_STRUCTURE = 8,
         | 
| 46 | 
            +
                # 9 BBAN length
         | 
| 47 | 
            +
                # 10 Bank identifier position within the BBAN
         | 
| 48 | 
            +
                BANK_IDENTIFIER_POSITION = 10,
         | 
| 49 | 
            +
                # 11 Bank identifier pattern
         | 
| 50 | 
            +
                BANK_IDENTIFIER_PATTERN = 11,
         | 
| 51 | 
            +
                # 12 Branch identifier position within the BBAN
         | 
| 52 | 
            +
                BRANCH_IDENTIFIER_POSITION = 12,
         | 
| 53 | 
            +
                # 13 Branch identifier pattern
         | 
| 54 | 
            +
                BRANCH_IDENTIFIER_PATTERN = 13,
         | 
| 55 | 
            +
                # 14 Bank identifier example
         | 
| 56 | 
            +
                # 15 Branch identifier example
         | 
| 57 | 
            +
                # 16 BBAN example
         | 
| 58 | 
            +
                BBAN_EXAMPLE = 16,
         | 
| 59 | 
            +
                # 17 IBAN
         | 
| 60 | 
            +
                # 18 IBAN structure
         | 
| 61 | 
            +
                # 19 IBAN length
         | 
| 62 | 
            +
                # 20 Effective date
         | 
| 63 | 
            +
                # 21 IBAN electronic format example
         | 
| 64 | 
            +
                IBAN_EXAMPLE = 21,
         | 
| 65 | 
            +
              ].freeze
         | 
| 66 | 
            +
             | 
| 67 | 
            +
              def self.call(path = "../data/raw/IBAN_Registry.txt")
         | 
| 68 | 
            +
                lines = CSV.read(
         | 
| 69 | 
            +
                  File.expand_path(path, __dir__),
         | 
| 70 | 
            +
                  col_sep: "\t",
         | 
| 71 | 
            +
                  headers: true,
         | 
| 72 | 
            +
                  encoding: Encoding::ISO_8859_1,
         | 
| 73 | 
            +
                ).to_a.transpose.tap(&:shift)
         | 
| 74 | 
            +
             | 
| 75 | 
            +
                new(lines).tap(&:parse)
         | 
| 44 76 | 
             
              end
         | 
| 45 | 
            -
             | 
| 46 | 
            -
             | 
| 47 | 
            -
             | 
| 48 | 
            -
             | 
| 49 | 
            -
              # 0 Data element
         | 
| 50 | 
            -
              # 1 Name of country
         | 
| 51 | 
            -
              # 2 IBAN prefix country code (ISO 3166)
         | 
| 52 | 
            -
              COUNTRY_CODE = 2,
         | 
| 53 | 
            -
              # 3 Country code includes other countries/territories
         | 
| 54 | 
            -
              # 4 SEPA country
         | 
| 55 | 
            -
              # 5 SEPA country also includes
         | 
| 56 | 
            -
              # 6 Domestic account number example
         | 
| 57 | 
            -
              # 7 BBAN
         | 
| 58 | 
            -
              # 8 BBAN structure
         | 
| 59 | 
            -
              BBAN_STRUCTURE = 8,
         | 
| 60 | 
            -
              # 9 BBAN length
         | 
| 61 | 
            -
              # 10 Bank identifier position within the BBAN
         | 
| 62 | 
            -
              # 11 Bank identifier pattern
         | 
| 63 | 
            -
              BANK_IDENTIFIER_PATTERN = 11,
         | 
| 64 | 
            -
              # 12 Branch identifier position within the BBAN
         | 
| 65 | 
            -
              # 13 Branch identifier pattern
         | 
| 66 | 
            -
              BRANCH_IDENTIFIER_PATTERN = 13,
         | 
| 67 | 
            -
              # 14 Bank identifier example
         | 
| 68 | 
            -
              # 15 Branch identifier example
         | 
| 69 | 
            -
              # 16 BBAN example
         | 
| 70 | 
            -
              # 17 IBAN
         | 
| 71 | 
            -
              # 18 IBAN structure
         | 
| 72 | 
            -
              # 19 IBAN length
         | 
| 73 | 
            -
              # 20 Effective date
         | 
| 74 | 
            -
              # 21 IBAN electronic format example
         | 
| 75 | 
            -
            ].freeze
         | 
| 76 | 
            -
             | 
| 77 | 
            -
            def get_bban_formats(iban_registry_file)
         | 
| 78 | 
            -
              iban_registry_file.each_with_object({}) do |line, hash|
         | 
| 79 | 
            -
                bban_structure = line[BBAN_STRUCTURE].strip
         | 
| 80 | 
            -
             | 
| 81 | 
            -
                bank_code_structure = line[BANK_IDENTIFIER_PATTERN].strip
         | 
| 82 | 
            -
                branch_code_structure = line[BRANCH_IDENTIFIER_PATTERN]&.strip
         | 
| 83 | 
            -
             | 
| 84 | 
            -
                bank_code_structure = "" if bank_code_structure == "N/A"
         | 
| 85 | 
            -
             | 
| 86 | 
            -
                country_code = line[COUNTRY_CODE].strip
         | 
| 87 | 
            -
                hash[country_code] = convert_swift_convention(bban_structure,
         | 
| 88 | 
            -
                                                              bank_code_structure,
         | 
| 89 | 
            -
                                                              branch_code_structure)
         | 
| 77 | 
            +
             | 
| 78 | 
            +
              def initialize(lines)
         | 
| 79 | 
            +
                @lines = lines
         | 
| 80 | 
            +
                @registry = {}
         | 
| 90 81 | 
             
              end
         | 
| 91 | 
            -
            end
         | 
| 92 82 |  | 
| 93 | 
            -
             | 
| 94 | 
            -
             | 
| 95 | 
            -
             | 
| 96 | 
            -
             | 
| 97 | 
            -
             | 
| 98 | 
            -
             | 
| 99 | 
            -
             | 
| 100 | 
            -
             | 
| 101 | 
            -
             | 
| 102 | 
            -
             | 
| 103 | 
            -
             | 
| 104 | 
            -
             | 
| 105 | 
            -
             | 
| 106 | 
            -
             | 
| 107 | 
            -
             | 
| 108 | 
            -
             | 
| 109 | 
            -
             | 
| 110 | 
            -
             | 
| 111 | 
            -
             | 
| 112 | 
            -
             | 
| 113 | 
            -
             | 
| 114 | 
            -
             | 
| 115 | 
            -
             | 
| 116 | 
            -
             | 
| 117 | 
            -
               | 
| 83 | 
            +
              def parse
         | 
| 84 | 
            +
                lines.each do |line|
         | 
| 85 | 
            +
                  country_code = clean_string(line[COUNTRY_CODE])
         | 
| 86 | 
            +
             | 
| 87 | 
            +
                  bban_details = convert_swift_convention(
         | 
| 88 | 
            +
                    country_code: country_code,
         | 
| 89 | 
            +
                    bban_structure: clean_string(line[BBAN_STRUCTURE]),
         | 
| 90 | 
            +
                    bank_code_structure: clean_string(line[BANK_IDENTIFIER_PATTERN]),
         | 
| 91 | 
            +
                    branch_code_structure: clean_string(line[BRANCH_IDENTIFIER_PATTERN]),
         | 
| 92 | 
            +
                    bank_identifier_position: clean_string(line[BANK_IDENTIFIER_POSITION]),
         | 
| 93 | 
            +
                    branch_identifier_position: clean_string(line[BRANCH_IDENTIFIER_POSITION]),
         | 
| 94 | 
            +
                  ) || {}
         | 
| 95 | 
            +
             | 
| 96 | 
            +
                  registry[country_code] = {
         | 
| 97 | 
            +
                    iban_example: clean_string(line[IBAN_EXAMPLE]),
         | 
| 98 | 
            +
                    bban_example: clean_string(line[BBAN_EXAMPLE]),
         | 
| 99 | 
            +
                    domestic_account_number_example: clean_string(line[DOMESTIC_ACCOUNT_NUMBER_EXAMPLE]),
         | 
| 100 | 
            +
                    **bban_details,
         | 
| 101 | 
            +
                  }.compact
         | 
| 102 | 
            +
                end
         | 
| 103 | 
            +
              end
         | 
| 104 | 
            +
             | 
| 105 | 
            +
              private
         | 
| 106 | 
            +
             | 
| 107 | 
            +
              def clean_string(string)
         | 
| 108 | 
            +
                return nil if string.nil?
         | 
| 109 | 
            +
             | 
| 110 | 
            +
                string.strip!
         | 
| 111 | 
            +
                return nil if string == "N/A"
         | 
| 112 | 
            +
             | 
| 113 | 
            +
                string
         | 
| 114 | 
            +
              end
         | 
| 115 | 
            +
             | 
| 116 | 
            +
              # IBAN Registry has BBAN format (which seems to be accurate), and Bank
         | 
| 117 | 
            +
              # identifier length, which contains something roughly like the format for the
         | 
| 118 | 
            +
              # bank code and usually the branch code where applicable. This is a best attempt
         | 
| 119 | 
            +
              # to convert those from weird SWIFT-talk into regexes, and then work out the
         | 
| 120 | 
            +
              # account number format regex by taking the bank and branch code regexes off
         | 
| 121 | 
            +
              # the front of the BBAN format.
         | 
| 122 | 
            +
              #
         | 
| 123 | 
            +
              # This works about 90% of the time, the rest are overridden in
         | 
| 124 | 
            +
              # structure_additions.yml
         | 
| 125 | 
            +
              def convert_swift_convention( # rubocop:todo Metrics/AbcSize
         | 
| 126 | 
            +
                country_code:,
         | 
| 127 | 
            +
                bban_structure:,
         | 
| 128 | 
            +
                branch_code_structure:,
         | 
| 129 | 
            +
                bank_code_structure: nil,
         | 
| 130 | 
            +
                bank_identifier_position: nil,
         | 
| 131 | 
            +
                branch_identifier_position: nil
         | 
| 132 | 
            +
              )
         | 
| 133 | 
            +
                bban_regex = iban_registry_to_regex(bban_structure)
         | 
| 134 | 
            +
                bank_regex = iban_registry_to_regex(bank_code_structure)
         | 
| 135 | 
            +
                branch_regex = branch_code_structure.nil? ? nil : iban_registry_to_regex(branch_code_structure)
         | 
| 136 | 
            +
             | 
| 137 | 
            +
                bban_ranges = create_bban_ranges(bban_structure)
         | 
| 138 | 
            +
                ranges_to_remove = [
         | 
| 139 | 
            +
                  convert_string_range(bank_identifier_position),
         | 
| 140 | 
            +
                  convert_string_range(branch_identifier_position),
         | 
| 141 | 
            +
                ].compact.uniq
         | 
| 142 | 
            +
                max_bank_details_index = ranges_to_remove.map(&:last).max
         | 
| 143 | 
            +
             | 
| 144 | 
            +
                _, non_bank_identifier_ranges = bban_ranges.partition do |_, range|
         | 
| 145 | 
            +
                  max_bank_details_index >= range.last
         | 
| 146 | 
            +
                end
         | 
| 147 | 
            +
             | 
| 148 | 
            +
                account_number_regex = iban_registry_to_regex(non_bank_identifier_ranges.map(&:first).join)
         | 
| 149 | 
            +
             | 
| 150 | 
            +
                {
         | 
| 151 | 
            +
                  bban_format: bban_regex.source,
         | 
| 152 | 
            +
                  bank_code_format: bank_regex.source,
         | 
| 153 | 
            +
                  branch_code_format: branch_regex&.source,
         | 
| 154 | 
            +
                  account_number_format: account_number_regex.source,
         | 
| 155 | 
            +
                }
         | 
| 156 | 
            +
              rescue StandardError => e
         | 
| 157 | 
            +
                puts "-----------------"
         | 
| 158 | 
            +
                puts "Issue with: #{country_code}"
         | 
| 159 | 
            +
                puts "\t #{e.message}"
         | 
| 160 | 
            +
                puts "\t #{e.backtrace}"
         | 
| 161 | 
            +
                puts "\t -----------------"
         | 
| 162 | 
            +
                puts "\t country_code: #{country_code}"
         | 
| 163 | 
            +
                puts "\t bban_structure: #{bban_structure}"
         | 
| 164 | 
            +
                puts "\t branch_code_structure: #{branch_code_structure}"
         | 
| 165 | 
            +
                puts "\t bank_code_structure: #{bank_code_structure}"
         | 
| 166 | 
            +
                puts "\t bank_identifier_position: #{bank_identifier_position}"
         | 
| 167 | 
            +
                puts "\t branch_identifier_position: #{branch_identifier_position}"
         | 
| 168 | 
            +
              end
         | 
| 169 | 
            +
             | 
| 170 | 
            +
              # Given "4!n4!n12!c" this returns an array that contains the ranges that cover the
         | 
| 171 | 
            +
              # structure. Eg; [["4!n", 0..3]]
         | 
| 172 | 
            +
              def create_bban_ranges(bban_structure)
         | 
| 173 | 
            +
                arr = bban_structure.scan(/((\d+)![anc])/)
         | 
| 174 | 
            +
             | 
| 175 | 
            +
                start = 0
         | 
| 176 | 
            +
             | 
| 177 | 
            +
                arr.each_with_object([]) do |(structure, length), acc|
         | 
| 178 | 
            +
                  end_number = start + length.to_i - 1
         | 
| 179 | 
            +
                  acc.push([structure, start..end_number])
         | 
| 180 | 
            +
                  start = end_number + 1
         | 
| 181 | 
            +
                end
         | 
| 182 | 
            +
              end
         | 
| 183 | 
            +
             | 
| 184 | 
            +
              def convert_string_range(str)
         | 
| 185 | 
            +
                start_val, end_val = str.split("-").map(&:to_i)
         | 
| 186 | 
            +
                (start_val - 1)..(end_val - 1)
         | 
| 187 | 
            +
              rescue StandardError
         | 
| 188 | 
            +
                nil
         | 
| 189 | 
            +
              end
         | 
| 190 | 
            +
             | 
| 191 | 
            +
              def iban_registry_to_regex(swift_string)
         | 
| 192 | 
            +
                regex = swift_string.
         | 
| 193 | 
            +
                  gsub(/(\d+)!n/, '\\d{\1}').
         | 
| 194 | 
            +
                  gsub(/(\d+)!a/, '[A-Z]{\1}').
         | 
| 195 | 
            +
                  gsub(/(\d+)!c/, '[A-Z0-9]{\1}')
         | 
| 196 | 
            +
                Regexp.new(regex)
         | 
| 197 | 
            +
              end
         | 
| 118 198 | 
             
            end
         | 
| 119 199 |  | 
| 120 | 
            -
             | 
| 121 | 
            -
               | 
| 122 | 
            -
             | 
| 123 | 
            -
             | 
| 124 | 
            -
                 | 
| 200 | 
            +
            class IbanStructureFile
         | 
| 201 | 
            +
              attr_accessor :report, :iban_registry_file
         | 
| 202 | 
            +
             | 
| 203 | 
            +
              def self.call(iban_registry_file, path: "../data/raw/IBANSTRUCTURE.xml")
         | 
| 204 | 
            +
                iban_structures_file = File.read(File.expand_path(path, __dir__))
         | 
| 205 | 
            +
                new(iban_registry_file:, iban_structures_file:).parse
         | 
| 206 | 
            +
              end
         | 
| 207 | 
            +
             | 
| 208 | 
            +
              def initialize(iban_registry_file:, iban_structures_file:)
         | 
| 209 | 
            +
                @iban_registry_file = iban_registry_file
         | 
| 210 | 
            +
                @report = Report.parse(iban_structures_file)
         | 
| 211 | 
            +
              end
         | 
| 212 | 
            +
             | 
| 213 | 
            +
              def parse # rubocop:todo Metrics/AbcSize
         | 
| 214 | 
            +
                report.countries.each_with_object({}) do |country, hash|
         | 
| 215 | 
            +
                  country_bban = iban_registry_file.registry[country.country_code] || {}
         | 
| 216 | 
            +
             | 
| 217 | 
            +
                  hash[country.country_code] = {
         | 
| 218 | 
            +
                    bank_code_position: country.bank_code_position.to_i,
         | 
| 219 | 
            +
                    bank_code_length: country.bank_code_length.to_i,
         | 
| 220 | 
            +
                    branch_code_position: country.branch_code_position.to_i,
         | 
| 221 | 
            +
                    branch_code_length: country.branch_code_length.to_i,
         | 
| 222 | 
            +
                    account_number_position: country.account_number_position.to_i,
         | 
| 223 | 
            +
                    account_number_length: country.account_number_length.to_i,
         | 
| 224 | 
            +
                    total_length: country.total_length.to_i,
         | 
| 225 | 
            +
                    national_id_length: country.national_id_length.to_i,
         | 
| 226 | 
            +
                    **country_bban,
         | 
| 227 | 
            +
                  }
         | 
| 228 | 
            +
                end
         | 
| 229 | 
            +
              end
         | 
| 125 230 | 
             
            end
         | 
| 126 231 |  | 
| 127 232 | 
             
            def merge_structures(structures, additions)
         | 
| 128 233 | 
             
              additions.each_pair do |key, value|
         | 
| 129 | 
            -
                structures[key].merge!(value) if structures.include?(key)
         | 
| 234 | 
            +
                structures[key].merge!(value).compact! if structures.include?(key)
         | 
| 130 235 | 
             
              end
         | 
| 131 236 |  | 
| 132 237 | 
             
              structures
         | 
| 133 238 | 
             
            end
         | 
| 134 239 |  | 
| 240 | 
            +
            def load_yaml_file(path)
         | 
| 241 | 
            +
              YAML.safe_load(
         | 
| 242 | 
            +
                File.read(File.expand_path(path, __dir__)),
         | 
| 243 | 
            +
                permitted_classes: [Range, Symbol, Regexp],
         | 
| 244 | 
            +
              )
         | 
| 245 | 
            +
            end
         | 
| 246 | 
            +
             | 
| 135 247 | 
             
            # Only parse the files if this file is run as an executable (not required in,
         | 
| 136 248 | 
             
            # as it is in the specs)
         | 
| 137 249 | 
             
            if __FILE__ == $PROGRAM_NAME
         | 
| 138 | 
            -
               | 
| 139 | 
            -
                File.expand_path("../data/raw/IBAN_Registry.txt", __dir__),
         | 
| 140 | 
            -
                col_sep: "\t",
         | 
| 141 | 
            -
                headers: true,
         | 
| 142 | 
            -
                encoding: Encoding::ISO_8859_1,
         | 
| 143 | 
            -
              ).to_a.transpose
         | 
| 144 | 
            -
             | 
| 145 | 
            -
              iban_registry_file.shift
         | 
| 146 | 
            -
             | 
| 147 | 
            -
              iban_structures_file = File.read(
         | 
| 148 | 
            -
                File.expand_path("../data/raw/IBANSTRUCTURE.xml", __dir__),
         | 
| 149 | 
            -
              )
         | 
| 250 | 
            +
              old_file = load_yaml_file("../data/structures.yml")
         | 
| 150 251 |  | 
| 151 | 
            -
               | 
| 152 | 
            -
             | 
| 153 | 
            -
                iban_registry_file,
         | 
| 154 | 
            -
              )
         | 
| 252 | 
            +
              iban_registry_file = IbanRegistryTextFile.call
         | 
| 253 | 
            +
              iban_structures = IbanStructureFile.call(iban_registry_file)
         | 
| 155 254 |  | 
| 156 | 
            -
              structure_additions =  | 
| 157 | 
            -
                File.read(File.expand_path("../data/raw/structure_additions.yml", __dir__)),
         | 
| 158 | 
            -
                permitted_classes: [Range, Symbol],
         | 
| 159 | 
            -
              )
         | 
| 255 | 
            +
              structure_additions = load_yaml_file("../data/raw/structure_additions.yml")
         | 
| 160 256 |  | 
| 161 257 | 
             
              complete_structures = merge_structures(iban_structures, structure_additions)
         | 
| 258 | 
            +
              pseudo_ibans = load_yaml_file("../data/raw/pseudo_ibans.yml")
         | 
| 259 | 
            +
             | 
| 260 | 
            +
              complete_structures.merge!(pseudo_ibans)
         | 
| 162 261 |  | 
| 163 262 | 
             
              output_file_path = File.expand_path(
         | 
| 164 263 | 
             
                "../data/structures.yml",
         | 
| @@ -166,4 +265,12 @@ if __FILE__ == $PROGRAM_NAME | |
| 166 265 | 
             
              )
         | 
| 167 266 |  | 
| 168 267 | 
             
              File.open(output_file_path, "w") { |f| f.write(complete_structures.to_yaml) }
         | 
| 268 | 
            +
             | 
| 269 | 
            +
              new_countries = old_file.keys.to_set ^ complete_structures.keys.to_set
         | 
| 270 | 
            +
              puts "New countries:"
         | 
| 271 | 
            +
              new_countries.each do |country|
         | 
| 272 | 
            +
                puts "#{country} #{complete_structures[country][:iban_example]} #{complete_structures[country][:domestic_account_number_example]}"
         | 
| 273 | 
            +
              end
         | 
| 169 274 | 
             
            end
         | 
| 275 | 
            +
             | 
| 276 | 
            +
            # rubocop:enable Layout/LineLength
         | 
    
        data/config/locales/da.yml
    CHANGED
    
    | @@ -10,3 +10,10 @@ da: | |
| 10 10 | 
             
                invalid_format: "Uventet format for en IBAN fra %{country_code}."
         | 
| 11 11 | 
             
                is_invalid: "er ugyldig"
         | 
| 12 12 | 
             
                does_not_support_payments: "understøtter ikke betalinger"
         | 
| 13 | 
            +
                has_invalid_format: "ugyldigt format"
         | 
| 14 | 
            +
                failed_checksum_test: "bestod ikke kontrolsumtesten"
         | 
| 15 | 
            +
                failed_modulus_check: "bestod ikke moduluskontrollen"
         | 
| 16 | 
            +
                has_invalid_length: "ugyldig længde"
         | 
| 17 | 
            +
                bank_code_does_not_exist: "bankkoden findes ikke"
         | 
| 18 | 
            +
                has_invalid_clearing_code_length: "længden på clearingskoden er ugyldig"
         | 
| 19 | 
            +
                has_invalid_serial_number: "ugyldigt serienummer"
         | 
    
        data/config/locales/de.yml
    CHANGED
    
    | @@ -10,3 +10,10 @@ de: | |
| 10 10 | 
             
                invalid_format: "Unerwartetes Format für eine %{country_code}-IBAN."
         | 
| 11 11 | 
             
                is_invalid: "ist ungültig"
         | 
| 12 12 | 
             
                does_not_support_payments: "unterstützt keine Zahlungen"
         | 
| 13 | 
            +
                has_invalid_format: "Format ist ungültig"
         | 
| 14 | 
            +
                failed_checksum_test: "Prüfsummentest nicht bestanden"
         | 
| 15 | 
            +
                failed_modulus_check: "Modulprüfung nicht bestanden"
         | 
| 16 | 
            +
                has_invalid_length: "Länge ist ungültig"
         | 
| 17 | 
            +
                bank_code_does_not_exist: "Bankleitzahl existiert nicht"
         | 
| 18 | 
            +
                has_invalid_clearing_code_length: "Länge des Verrechnungscodes ist ungültig"
         | 
| 19 | 
            +
                has_invalid_serial_number: "Seriennummer ist ungültig"
         | 
    
        data/config/locales/en.yml
    CHANGED
    
    | @@ -10,3 +10,10 @@ en: | |
| 10 10 | 
             
                invalid_format: "Unexpected format for a %{country_code} IBAN."
         | 
| 11 11 | 
             
                is_invalid: "is invalid"
         | 
| 12 12 | 
             
                does_not_support_payments: "does not support payments"
         | 
| 13 | 
            +
                has_invalid_format: "format is invalid"
         | 
| 14 | 
            +
                failed_checksum_test: "did not pass checksum test"
         | 
| 15 | 
            +
                failed_modulus_check: "did not pass modulus check"
         | 
| 16 | 
            +
                has_invalid_length: "length is invalid"
         | 
| 17 | 
            +
                bank_code_does_not_exist: "bank code does not exist"
         | 
| 18 | 
            +
                has_invalid_clearing_code_length: "clearing code length is invalid"
         | 
| 19 | 
            +
                has_invalid_serial_number: "serial number is invalid"
         | 
    
        data/config/locales/es.yml
    CHANGED
    
    | @@ -10,3 +10,10 @@ es: | |
| 10 10 | 
             
                invalid_format: "Formato inesperado para un IBAN de %{country_code}."
         | 
| 11 11 | 
             
                is_invalid: "no es válido"
         | 
| 12 12 | 
             
                does_not_support_payments: "no admite pagos"
         | 
| 13 | 
            +
                has_invalid_format: "formato invalido"
         | 
| 14 | 
            +
                failed_checksum_test: "fallo en suma de control"
         | 
| 15 | 
            +
                failed_modulus_check: "fallo en control de modulo"
         | 
| 16 | 
            +
                has_invalid_length: "tamaño invalido"
         | 
| 17 | 
            +
                bank_code_does_not_exist: "codigo bancario inexistente"
         | 
| 18 | 
            +
                has_invalid_clearing_code_length: "codigo de oficina de oficina de compensación invalido"
         | 
| 19 | 
            +
                has_invalid_serial_number: "número de serie invalido"
         | 
    
        data/config/locales/fr.yml
    CHANGED
    
    | @@ -10,3 +10,10 @@ fr: | |
| 10 10 | 
             
                invalid_format: "Format non attendu pour un IBAN %{country_code}."
         | 
| 11 11 | 
             
                is_invalid: "n'est pas valide"
         | 
| 12 12 | 
             
                does_not_support_payments: "ne prend pas en charge les paiements"
         | 
| 13 | 
            +
                has_invalid_format: "le format n'est pas valide"
         | 
| 14 | 
            +
                failed_checksum_test: "échec du test de la somme de contrôle"
         | 
| 15 | 
            +
                failed_modulus_check: "échec du test de module"
         | 
| 16 | 
            +
                has_invalid_length: "la longueur n'est pas valide"
         | 
| 17 | 
            +
                bank_code_does_not_exist: "le code de la banque n'existe pas"
         | 
| 18 | 
            +
                has_invalid_clearing_code_length: "la longueur du clearing code n'est pas valide"
         | 
| 19 | 
            +
                has_invalid_serial_number: "le numéro de série n'est pas valide"
         | 
    
        data/config/locales/it.yml
    CHANGED
    
    | @@ -9,4 +9,12 @@ it: | |
| 9 9 | 
             
                non_alphanumeric_characters: "Caratteri non alfanumerici trovati: %{characters}"
         | 
| 10 10 | 
             
                invalid_format: "Formato imprevisto per un IBAN %{country_code}."
         | 
| 11 11 | 
             
                is_invalid: "non è valido"
         | 
| 12 | 
            -
                does_not_support_payments: "non supporta i pagamenti"
         | 
| 12 | 
            +
                does_not_support_payments: "non supporta i pagamenti"
         | 
| 13 | 
            +
                has_invalid_format: "formato non valido"
         | 
| 14 | 
            +
                failed_checksum_test: "test del checksum non superato"
         | 
| 15 | 
            +
                failed_modulus_check: "test del modulo non superato"
         | 
| 16 | 
            +
                has_invalid_length: "lunghezza non valida"
         | 
| 17 | 
            +
                bank_code_does_not_exist: "codice banca inesistente"
         | 
| 18 | 
            +
                has_invalid_clearing_code_length: "lunghezza clearing code non valida"
         | 
| 19 | 
            +
                has_invalid_serial_number: "numero di serie non valido"
         | 
| 20 | 
            +
             | 
    
        data/config/locales/nb.yml
    CHANGED
    
    | @@ -10,3 +10,10 @@ nb: | |
| 10 10 | 
             
                invalid_format: "Uventet format for IBAN for %{country_code}."
         | 
| 11 11 | 
             
                is_invalid: "er ikke gyldig"
         | 
| 12 12 | 
             
                does_not_support_payments: "støtter ikke betalinger"
         | 
| 13 | 
            +
                has_invalid_format: "formatet er ugyldig"
         | 
| 14 | 
            +
                failed_checksum_test: "besto ikke kontrollsumtesten"
         | 
| 15 | 
            +
                failed_modulus_check: "besto ikke tallverdikontrollen"
         | 
| 16 | 
            +
                has_invalid_length: "ugyldig lengde"
         | 
| 17 | 
            +
                bank_code_does_not_exist: "bankkoden eksisterer ikke"
         | 
| 18 | 
            +
                has_invalid_clearing_code_length: "registreringsnummerets lengde er ugyldig"
         | 
| 19 | 
            +
                has_invalid_serial_number: "ugyldig serienummer"
         | 
    
        data/config/locales/nl.yml
    CHANGED
    
    | @@ -10,3 +10,10 @@ nl: | |
| 10 10 | 
             
                invalid_format: "Onverwachte formaat voor een %{country_code} IBAN."
         | 
| 11 11 | 
             
                is_invalid: "is ongeldig"
         | 
| 12 12 | 
             
                does_not_support_payments: "ondersteunt geen betalingen"
         | 
| 13 | 
            +
                has_invalid_format: "indeling is ongeldig"
         | 
| 14 | 
            +
                failed_checksum_test: "checksumtest is mislukt"
         | 
| 15 | 
            +
                failed_modulus_check: "moduluscontrole is mislukt"
         | 
| 16 | 
            +
                has_invalid_length: "lengte is ongeldig"
         | 
| 17 | 
            +
                bank_code_does_not_exist: "bankcode bestaat niet"
         | 
| 18 | 
            +
                has_invalid_clearing_code_length: "lengte clearingcode is ongeldig"
         | 
| 19 | 
            +
                has_invalid_serial_number: "serienummer is ongeldig"
         | 
    
        data/config/locales/pt.yml
    CHANGED
    
    | @@ -10,3 +10,10 @@ pt: | |
| 10 10 | 
             
                invalid_format: "Formato inesperado para um IBAN %{country_code}."
         | 
| 11 11 | 
             
                is_invalid: "é inválido"
         | 
| 12 12 | 
             
                does_not_support_payments: "não suporta pagamentos"
         | 
| 13 | 
            +
                has_invalid_format: "o formato é inválido"
         | 
| 14 | 
            +
                failed_checksum_test: "não passou no teste de verificação de soma"
         | 
| 15 | 
            +
                failed_modulus_check: "não passou na verificação do módulo"
         | 
| 16 | 
            +
                has_invalid_length: "o comprimento é inválido"
         | 
| 17 | 
            +
                bank_code_does_not_exist: "o código do banco não existe"
         | 
| 18 | 
            +
                has_invalid_clearing_code_length: "o comprimento do código de libertação é inválido"
         | 
| 19 | 
            +
                has_invalid_serial_number: "o número de série é inválido"
         | 
    
        data/config/locales/sl.yml
    CHANGED
    
    | @@ -10,3 +10,10 @@ sl: | |
| 10 10 | 
             
                invalid_format: "Nepričakovana oblika zapisa %{country_code} v IBAN."
         | 
| 11 11 | 
             
                is_invalid: "ni veljavno"
         | 
| 12 12 | 
             
                does_not_support_payments: "ne podpira plačil"
         | 
| 13 | 
            +
                has_invalid_format: "oblika zapisa ni veljavna"
         | 
| 14 | 
            +
                failed_checksum_test: "neuspešen preizkus kontrolne vsote"
         | 
| 15 | 
            +
                failed_modulus_check: "neuspešno preverjanje modula"
         | 
| 16 | 
            +
                has_invalid_length: "dolžina ni veljavna"
         | 
| 17 | 
            +
                bank_code_does_not_exist: "koda banke ne obstaja"
         | 
| 18 | 
            +
                has_invalid_clearing_code_length: "dolžina klirinške kode ni veljavna"
         | 
| 19 | 
            +
                has_invalid_serial_number: "serijska številka ni veljavna"
         | 
    
        data/config/locales/sv.yml
    CHANGED
    
    | @@ -10,3 +10,10 @@ sv: | |
| 10 10 | 
             
                invalid_format: "Oväntat format för %{country_code} IBAN."
         | 
| 11 11 | 
             
                is_invalid: "är ogiltig"
         | 
| 12 12 | 
             
                does_not_support_payments: "stödjer inte betalningar"
         | 
| 13 | 
            +
                has_invalid_format: "ogiltigt format"
         | 
| 14 | 
            +
                failed_checksum_test: "felaktig kontrollsumma"
         | 
| 15 | 
            +
                failed_modulus_check: "felaktig modulkontroll"
         | 
| 16 | 
            +
                has_invalid_length: "ogiltig längd"
         | 
| 17 | 
            +
                bank_code_does_not_exist: "bankkoden existerar inte"
         | 
| 18 | 
            +
                has_invalid_clearing_code_length: "clearingnumrets längd är ogiltigt"
         | 
| 19 | 
            +
                has_invalid_serial_number: "ogiltigt serienummer"
         |