Module: IbanBic

Defined in:
lib/iban_bic/core.rb,
lib/iban_bic/engine.rb,
lib/iban_bic/random.rb,
lib/iban_bic/version.rb,
lib/iban_bic/configuration.rb,
lib/generators/iban_bic/install_generator.rb

Defined Under Namespace

Classes: Configuration, Engine, InstallGenerator

Constant Summary collapse

VERSION =
"1.0.1"

Class Method Summary collapse

Class Method Details

.bicsObject



127
128
129
# File 'lib/iban_bic/core.rb', line 127

def bics
  configuration.static_bics? ? static_bics : dynamic_bics
end

.calculate_bic(iban) ⇒ Object



88
89
90
91
92
93
94
# File 'lib/iban_bic/core.rb', line 88

def calculate_bic(iban)
  country = iban[0..1]
  parts = parse(iban)
  return nil unless parts&.fetch(:bank, nil)

  bics.dig(country, parts[:bank])
end

.calculate_check(iban) ⇒ Object



57
58
59
60
61
62
63
64
65
# File 'lib/iban_bic/core.rb', line 57

def calculate_check(iban)
  98 - "#{iban[4..-1]}#{iban[0..3]}".each_char.map do |char|
    case char
    when "0".."9" then char
    when "A".."Z" then (char.ord - 55).to_s
    else raise ArgumentError, "Invalid IBAN format"
    end
  end .join.to_i % 97
end

.calculate_valid_country_check_iban(iban) ⇒ Object



75
76
77
78
79
80
81
82
# File 'lib/iban_bic/core.rb', line 75

def calculate_valid_country_check_iban(iban)
  validator = country_validators[iban[0..1]]
  return iban unless validator

  parts = parse(iban)
  validator.call(parts)
  parts.values.join
end

.clear_cacheObject



96
97
98
99
# File 'lib/iban_bic/core.rb', line 96

def clear_cache
  @cached_variables.each { |variable| instance_variable_set(variable, nil) }
  @cached_variables.clear
end

.configurationObject



12
13
14
# File 'lib/iban_bic/core.rb', line 12

def configuration
  @configuration ||= Configuration.new
end

.configureObject



16
17
18
# File 'lib/iban_bic/core.rb', line 16

def configure
  configuration.instance_eval(&Proc.new)
end

.country_validatorsObject



8
9
10
# File 'lib/iban_bic/core.rb', line 8

def country_validators
  @country_validators ||= {}
end

.dynamic_bicsObject



140
141
142
143
144
145
146
147
148
149
150
# File 'lib/iban_bic/core.rb', line 140

def dynamic_bics
  @dynamic_bics ||= begin
    @cached_variables << :@dynamic_bics
    ret = {}
    Bic.find_each do |bic|
      ret[bic.country] = {} unless ret[bic.country]
      ret[bic.country][bic.bank_code] = bic.bic
    end
    ret.freeze
  end
end

.fix(iban) ⇒ Object



25
26
27
28
29
30
31
32
33
34
35
36
# File 'lib/iban_bic/core.rb', line 25

def fix(iban)
  # Fixed check IBAN parts (countries where IBAN check is always the same) must be fixed before parsing
  iban, fixed_iban_check = fix_fixed_iban_check(iban)

  parts = parse(iban)
  return unless parts

  iban = calculate_valid_country_check_iban(iban)
  iban = fix_iban_check(iban) unless fixed_iban_check

  iban
end

.fix_fixed_iban_check(iban) ⇒ Object



38
39
40
41
42
43
44
# File 'lib/iban_bic/core.rb', line 38

def fix_fixed_iban_check(iban)
  return [iban, false] unless tags[iban[0..1]].member?(:fixed_iban_check)

  result = iban.dup
  result[2..3] = /\(\?\<iban_check>([^\)]*)\)/.match(iban_meta[iban[0..1]]["parts"])[1]
  [result, true]
end

.fix_iban_check(iban) ⇒ Object



46
47
48
49
50
51
# File 'lib/iban_bic/core.rb', line 46

def fix_iban_check(iban)
  result = iban.dup
  result[2..3] = "00"
  result[2..3] = calculate_check(result).to_s.rjust(2, "0")
  result.freeze
end

.has_tags?(iban, searched_tags) ⇒ Boolean

Returns:

  • (Boolean)


53
54
55
# File 'lib/iban_bic/core.rb', line 53

def has_tags?(iban, searched_tags)
  (tags[iban[0..1]] & searched_tags).any?
end

.iban_metaObject



101
102
103
# File 'lib/iban_bic/core.rb', line 101

def iban_meta
  @iban_meta ||= ::YAML.load_file(configuration.iban_meta_path)
end

.parse(iban) ⇒ Object



20
21
22
23
# File 'lib/iban_bic/core.rb', line 20

def parse(iban)
  parts = parser[iban[0..1]]&.match(iban)
  parts ? ActiveSupport::HashWithIndifferentAccess[parts.names.zip(parts.captures)] : nil
end

.parserObject



105
106
107
108
109
110
111
112
113
114
# File 'lib/iban_bic/core.rb', line 105

def parser
  @parser ||= begin
    @cached_variables << :@parser
    Hash[
      iban_meta.map do |country, meta|
        [country, /^(?<country>#{country})#{meta["parts"].delete(" ")}$/]
      end
    ].freeze
  end
end

.random_generatorObject



22
23
24
25
26
27
28
29
30
31
# File 'lib/iban_bic/random.rb', line 22

def random_generator
  @random_generator ||= begin
    @cached_variables << :@random_generator
    Hash[
      iban_meta.map do |country, meta|
        [country, /^#{country}#{meta["parts"].delete(" ").gsub(/\(\?\<\w+\>([^\)]*)\)/, "\\1")}$/]
      end
    ].freeze
  end
end

.random_iban(options = {}) ⇒ Object



8
9
10
11
12
13
14
15
16
17
18
19
20
# File 'lib/iban_bic/random.rb', line 8

def random_iban(options = {})
  country = options[:country]
  searched_tags = options[:tags]
  non_searched_tags = options[:not_tags]

  unless country
    possible_countries = random_generator.keys
    possible_countries -= IbanBic.tags.select { |_country, country_tags| (searched_tags - country_tags).any? } .keys if searched_tags.present?
    possible_countries -= IbanBic.tags.select { |_country, country_tags| (non_searched_tags & country_tags).any? } .keys if non_searched_tags.present?
    country = possible_countries.sample
  end
  IbanBic.fix(random_generator[country].random_example)
end

.static_bicsObject



131
132
133
134
135
136
137
138
# File 'lib/iban_bic/core.rb', line 131

def static_bics
  @static_bics ||= begin
    @cached_variables << :@static_bics
    Hash[Dir.glob(File.join(configuration.static_bics_path, "*.yml")).map do |file|
      [File.basename(file).delete(".yml").upcase, YAML.load_file(file)]
    end].freeze
  end
end

.tagsObject



116
117
118
119
120
121
122
123
124
125
# File 'lib/iban_bic/core.rb', line 116

def tags
  @tags ||= begin
    @cached_variables << :@tags
    Hash[
      iban_meta.map do |country, meta|
        [country, meta["tags"]&.split&.map(&:to_sym) || []]
      end
    ].freeze
  end
end

.valid?(iban) ⇒ Boolean

Returns:

  • (Boolean)


67
68
69
# File 'lib/iban_bic/core.rb', line 67

def valid?(iban)
  valid_check?(iban) && valid_country_check?(iban)
end

.valid_check?(iban) ⇒ Boolean

Returns:

  • (Boolean)


71
72
73
# File 'lib/iban_bic/core.rb', line 71

def valid_check?(iban)
  calculate_check(iban) == 97
end

.valid_country_check?(iban) ⇒ Boolean

Returns:

  • (Boolean)


84
85
86
# File 'lib/iban_bic/core.rb', line 84

def valid_country_check?(iban)
  calculate_valid_country_check_iban(iban) == iban
end