From e1d14dc1db1b52041a3ce01fcfdbc059c43d27f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Seitz?= Date: Tue, 3 Jun 2025 17:44:15 +0200 Subject: [PATCH 1/3] update ruby version and replace bank-contact with iban-tools --- .ruby-version | 2 +- Gemfile.lock | 24 ++++++++++----------- girocode.gemspec | 2 +- lib/girocode.rb | 2 +- lib/girocode/code.rb | 50 ++++++++++++++++++++++---------------------- 5 files changed, 40 insertions(+), 40 deletions(-) diff --git a/.ruby-version b/.ruby-version index b502146..6cb9d3d 100644 --- a/.ruby-version +++ b/.ruby-version @@ -1 +1 @@ -3.0.2 +3.4.3 diff --git a/Gemfile.lock b/Gemfile.lock index 6867842..fa4c1e7 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -2,27 +2,27 @@ PATH remote: . specs: girocode (0.2.0) - bank-contact + iban-tools rqrcode GEM remote: https://rubygems.org/ specs: - bank-contact (0.0.6) chunky_png (1.4.0) - docile (1.4.0) - minitest (5.14.4) - rake (13.0.6) - rqrcode (2.1.0) + docile (1.4.1) + iban-tools (1.2.1) + minitest (5.25.5) + rake (13.3.0) + rqrcode (3.1.0) chunky_png (~> 1.0) - rqrcode_core (~> 1.0) - rqrcode_core (1.2.0) - simplecov (0.21.2) + rqrcode_core (~> 2.0) + rqrcode_core (2.0.0) + simplecov (0.22.0) docile (~> 1.1) simplecov-html (~> 0.11) simplecov_json_formatter (~> 0.1) - simplecov-html (0.12.3) - simplecov_json_formatter (0.1.3) + simplecov-html (0.13.1) + simplecov_json_formatter (0.1.4) PLATFORMS ruby @@ -34,4 +34,4 @@ DEPENDENCIES simplecov BUNDLED WITH - 2.2.22 + 2.6.8 diff --git a/girocode.gemspec b/girocode.gemspec index c8cd13d..e6c480f 100644 --- a/girocode.gemspec +++ b/girocode.gemspec @@ -17,5 +17,5 @@ Gem::Specification.new do |s| s.require_paths = ['lib'] s.add_dependency 'rqrcode' - s.add_dependency 'bank-contact' + s.add_dependency 'iban-tools' end diff --git a/lib/girocode.rb b/lib/girocode.rb index cf1775a..6f8b99a 100644 --- a/lib/girocode.rb +++ b/lib/girocode.rb @@ -1,5 +1,5 @@ require 'bigdecimal' -require 'bank/contact' +require 'iban-tools' require 'rqrcode' require_relative 'girocode/version' diff --git a/lib/girocode/code.rb b/lib/girocode/code.rb index 9b41b2d..bf2c887 100644 --- a/lib/girocode/code.rb +++ b/lib/girocode/code.rb @@ -1,13 +1,13 @@ module Girocode class Error < StandardError; end - + class Code ATTRIBUTES = %i[bic name iban currency amount purpose creditor_reference reference bto_info] attr_reader *ATTRIBUTES - + MAX_PAYLOAD_BYTES = 331 AMOUNT_RANGE = BigDecimal('0.01')..BigDecimal('999999999.99') - + def initialize(**attrs) if keys = attrs.keys - ATTRIBUTES and not keys.empty? raise ArgumentError, "Illegal attributes #{keys.inspect}" @@ -19,17 +19,17 @@ module Girocode raise ArgumentError, "either creditor reference or reference may be set" if creditor_reference? && reference? raise ArgumentError, "payload too long" if payload.bytesize > MAX_PAYLOAD_BYTES end - + def bic=(value) if value.nil? @bic = nil + elsif value.match? /\A[A-Z0-9]{4}([A-Z]{2})([A-Z0-9]{2})([A-Z0-9]{3})?\z/ + @bic = value else - bic = Bank::BIC.new(value) - raise ArgumentError, "Invalid BIC #{value.inspect}" unless bic.valid? - @bic = bic.to_s + raise ArgumentError, "Invalid BIC #{value.inspect}" end end - + def name=(value) value = value.strip raise ArgumentError, 'name is required' unless value @@ -37,81 +37,81 @@ module Girocode raise ArgumentError, 'Illegal name' if value.include?("\n") || value.include?("\r") @name = value end - + def iban=(value) - iban = Bank::IBAN.new(value) - raise ArgumentError, "Invalid IBAN #{value.inspect}" unless iban.valid? - @iban = iban.to_s + raise ArgumentError, "Invalid IBAN #{value.inspect}" unless IBANTools::IBAN.valid?(value) + + @iban = value end - + def currency=(value) value = value.to_s.upcase raise ArgumentError, "Invalid currency" unless value.match?(/\A[A-Z]{3}\z/) @currency = value end - + def amount=(value) raise ArgumentError, 'amount is required' unless value value = BigDecimal(value, Float::DIG + 1) raise ArgumentError, "invalid amount #{value.inspect}" unless AMOUNT_RANGE.cover?(value) @amount = value end - + def purpose=(value) unless value.nil? raise ArgumentError, "invalid purpose #{value.inspect}" unless value.match?(/\A[A-z0-9]{0,4}\z/) end @purpose = value end - + def creditor_reference=(value) unless value.nil? raise ArgumentError, "invalid creditor reference #{value.inspect}" if value.include?("\n") || value.include?("\r") || value.size > 35 end @creditor_reference = value end - + def reference=(value) unless value.nil? raise ArgumentError, "invalid reference #{value.inspect}" if value.include?("\n") || value.include?("\r") || value.size > 140 end @reference = value end - + def bto_info=(value) unless value.nil? raise ArgumentError, "invalid bto_info #{value.inspect}" if value.include?("\n") || value.include?("\r") || value.size > 70 end @bto_info = value end - + ATTRIBUTES.each do |attr| define_method("#{attr}?") do value = instance_variable_get("@#{attr}") value.respond_to?(:empty?) ? !value.empty? : !!value end end - + def payload ['BCD', '002', '1', 'SCT', bic, name, iban,formatted_amount, purpose, creditor_reference || reference, bto_info].map(&:to_s).join("\n") end - + def to_qrcode RQRCode::QRCode.new(payload, level: :m, mode: :byte_8bit) end - + def to_ascii to_qrcode.to_s end - + %i[png svg html ansi].each do |format| define_method("to_#{format}") { |*args| to_qrcode.public_send("as_#{format}", *args) } end - + private - + def formatted_amount "#{currency}#{amount.round(2).to_s('F')}" if currency? && amount end From 8d93f295cfbd16bb8d8f8ba25d0ec56bbccbddee Mon Sep 17 00:00:00 2001 From: Matthias Grosser Date: Wed, 4 Jun 2025 00:20:19 +0200 Subject: [PATCH 2/3] Inline BIC validation from bank-contact Fix bundler --- CHANGELOG.md | 6 ++-- Gemfile.lock | 7 ++--- girocode.gemspec | 1 + lib/girocode.rb | 1 + lib/girocode/bic.rb | 67 +++++++++++++++++++++++++++++++++++++++++ lib/girocode/code.rb | 6 ++-- lib/girocode/version.rb | 2 +- test/girocode_test.rb | 12 ++++++-- 8 files changed, 89 insertions(+), 13 deletions(-) create mode 100644 lib/girocode/bic.rb diff --git a/CHANGELOG.md b/CHANGELOG.md index b63f8c8..9b5e297 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,5 @@ -## 0.2.0 +## 1.0.0 -- support Ruby 2.7+ +- Drop bank-contact, use iban-tools (@Joerg-Seitz) +- Inline BIC validation from bank-contact +- Support Ruby 3.4 diff --git a/Gemfile.lock b/Gemfile.lock index fa4c1e7..2e70728 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,13 +1,15 @@ PATH remote: . specs: - girocode (0.2.0) + girocode (1.0.0) + bigdecimal iban-tools rqrcode GEM remote: https://rubygems.org/ specs: + bigdecimal (3.2.1) chunky_png (1.4.0) docile (1.4.1) iban-tools (1.2.1) @@ -32,6 +34,3 @@ DEPENDENCIES minitest rake simplecov - -BUNDLED WITH - 2.6.8 diff --git a/girocode.gemspec b/girocode.gemspec index e6c480f..409af57 100644 --- a/girocode.gemspec +++ b/girocode.gemspec @@ -16,6 +16,7 @@ Gem::Specification.new do |s| s.files = Dir['{lib}/**/*.rb', 'LICENSE', 'README.md', 'CHANGELOG.md'] s.require_paths = ['lib'] + s.add_dependency 'bigdecimal' s.add_dependency 'rqrcode' s.add_dependency 'iban-tools' end diff --git a/lib/girocode.rb b/lib/girocode.rb index 6f8b99a..8b6da7a 100644 --- a/lib/girocode.rb +++ b/lib/girocode.rb @@ -3,6 +3,7 @@ require 'iban-tools' require 'rqrcode' require_relative 'girocode/version' +require_relative 'girocode/bic' require_relative 'girocode/code' module Girocode diff --git a/lib/girocode/bic.rb b/lib/girocode/bic.rb new file mode 100644 index 0000000..53911ab --- /dev/null +++ b/lib/girocode/bic.rb @@ -0,0 +1,67 @@ +# derived from bank-contact/bic by Kevin + +module Girocode + class BIC + REGEX = /\A([A-Z]{4})([A-Z]{2})([A-Z0-9]{2})([A-Z0-9]{3})?\z/.freeze + + def self.valid?(code) + new(code).valid? + end + + def initialize(code) + @code = code.to_s.gsub(/\s+/, '').upcase + end + + def bank_code + @code[0..3] + end + + def country_code + @code[4..5] + end + + def location_code + @code[6..7] + end + + def branch_code + @code[8..10] + end + + def to_s(formatted = false) + formatted ? to_formatted_str : @code + end + + def to_formatted_str + "#{bank_code} #{country_code} #{location_code} #{branch_code}".strip + end + + def test? + location_code[1] == '0' + end + + def passive? + location_code[1] == '1' + end + + def reverse_billing? + location_code[1] == '2' + end + + def valid? + valid_format? && valid_location_code? && valid_branch_code? + end + + def valid_format? + REGEX.match?(@code) + end + + def valid_location_code? + !location_code.start_with?('0', '1') && !location_code.end_with?('O') + end + + def valid_branch_code? + branch_code.empty? || branch_code == 'XXX' || !branch_code.start_with?('X') + end + end +end diff --git a/lib/girocode/code.rb b/lib/girocode/code.rb index bf2c887..7b08e86 100644 --- a/lib/girocode/code.rb +++ b/lib/girocode/code.rb @@ -23,10 +23,10 @@ module Girocode def bic=(value) if value.nil? @bic = nil - elsif value.match? /\A[A-Z0-9]{4}([A-Z]{2})([A-Z0-9]{2})([A-Z0-9]{3})?\z/ - @bic = value else - raise ArgumentError, "Invalid BIC #{value.inspect}" + bic = BIC.new(value) + raise ArgumentError, "Invalid BIC #{value.inspect}" unless bic.valid? + @bic = bic.to_s end end diff --git a/lib/girocode/version.rb b/lib/girocode/version.rb index 4f2cb4f..e7654b9 100644 --- a/lib/girocode/version.rb +++ b/lib/girocode/version.rb @@ -1,3 +1,3 @@ module Girocode - VERSION = "0.2.0" + VERSION = "1.0.0" end diff --git a/test/girocode_test.rb b/test/girocode_test.rb index b223857..f77b169 100644 --- a/test/girocode_test.rb +++ b/test/girocode_test.rb @@ -2,7 +2,7 @@ require_relative 'test_helper' class GirocodeTest < Minitest::Test def test_that_it_has_a_version_number - refute_nil ::Girocode::VERSION + refute_nil Girocode::VERSION end def test_girocode @@ -10,9 +10,15 @@ class GirocodeTest < Minitest::Test code = Girocode.new(**attrs) assert_equal data(:data), code.to_ascii end - + + def test_bic + assert_raises ArgumentError do + Girocode.new(bic: 'FOOBAR', name: 'Franz Mustermänn', iban: 'DE71110220330123456789', currency: :eur, amount: 12.3, purpose: 'GDDS', creditor_reference: 'RF18539007547034') + end + end + private - + def data(name) Pathname(__dir__).join("#{name}.txt").read end From 560aff2283c99051ed906b9e9cdfb9311f3f8f8e Mon Sep 17 00:00:00 2001 From: Matthias Grosser Date: Wed, 4 Jun 2025 00:22:52 +0200 Subject: [PATCH 3/3] Drop Ruby 2.7 --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index e37b858..30fa999 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -13,7 +13,7 @@ jobs: timeout-minutes: 5 strategy: matrix: - ruby-version: ['2.7', '3.0', '3.1', '3.2', '3.3'] + ruby-version: ['3.0', '3.1', '3.2', '3.3', '3.4'] steps: - uses: actions/checkout@v2