company_number 0.1.1 → 0.1.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0d4b40991721f4eb047e7060a428f3d85593cc4ce3dd15bb427d95ed629cbb37
4
- data.tar.gz: cfedbc59ad70b411b385ba55813e5ebf32247ebaf2b2628f324b3d77799b6aed
3
+ metadata.gz: 15d093084ab43783fcd77f0d6b369c54bf0741e2da3ccb086b329f71b904bee6
4
+ data.tar.gz: 0b6942d8d8c036bcd5bb2a1ced0abe8f04b83e3e02a134651419cd6316e28eed
5
5
  SHA512:
6
- metadata.gz: 7f012c7724dddab12ef370a57d7e5f5d00d6f556cbd5bb4aa5f0b11c33298bcc2eee4a523cce73dbcb1e669c4824d57bd14c8a67780741bb3186b65ed568ac68
7
- data.tar.gz: d51f55008b3cfd58a48e312af82a9538f00e75f6e857b0601d83c684bbfdd30612f031e89ee809811ccc99614e91af1653f761106cda6f00f1c7d34959bab1c4
6
+ metadata.gz: 71f2d3a6a3ef2e6af33562af3c89167113946e8dd993ee2d61c1d44e2049cb773d9ba18477e2f81083aecdf47a0c28cb1ca2e309ccc085b1b3c259d45a1df371
7
+ data.tar.gz: c86a9a62d0fa7194f60dd4ed9191a670a58f8bd4ad111a084df71d0466b889674008473b53fcbf5ab625457e2292db008b857e54c701364e6b64c0f4cf82730f
data/.rubocop.yml CHANGED
@@ -7,6 +7,9 @@ Style/FrozenStringLiteralComment:
7
7
  Style/StringLiterals:
8
8
  Enabled: false
9
9
 
10
+ Style/Documentation:
11
+ Enabled: false
12
+
10
13
  Metrics/BlockLength:
11
14
  Exclude:
12
15
  - spec/**/*
@@ -17,8 +20,19 @@ Metrics/CyclomaticComplexity:
17
20
  Metrics/MethodLength:
18
21
  Max: 20
19
22
 
23
+ Metrics/BlockLength:
24
+ Exclude:
25
+ - '**/*.gemspec'
26
+ - 'spec/**/*'
27
+
20
28
  Layout/LineLength:
21
29
  Max: 80
30
+ Exclude:
31
+ - '**/*.gemspec'
32
+ - 'spec/**/*'
22
33
 
23
34
  Naming/MemoizedInstanceVariableName:
24
35
  EnforcedStyleForLeadingUnderscores: optional
36
+
37
+ Gemspec/RequiredRubyVersion:
38
+ Enabled: false
data/CHANGELOG.md CHANGED
@@ -1,12 +1,22 @@
1
1
  ## Changelog
2
2
 
3
+ ### 0.1.2 - 2022-04-21
4
+ * Features:
5
+ * Add custom configurations - aae0d51
6
+ - custom_dictionary
7
+ - strict_validation
8
+ - excluded_countries
9
+
10
+ * Enhancements:
11
+ * Update RuboCop configuration - dcd9852
12
+
3
13
  ### 0.1.1 - 2022-04-04
4
14
  * Features:
5
15
  * Add dictionary to return the company number metadata - b19c8d9
6
16
 
7
17
  * Deprecations:
8
- * Remove `regexp` attr_reader (moved to metadata) - #3
9
- * Remove `countries` attr_reader to use `CompanyNumber::Number#valid_countries` - #3
18
+ * Remove `regexp` attr_reader (moved to metadata)
19
+ * Remove `countries` attr_reader to use `CompanyNumber::Number#valid_countries`
10
20
 
11
21
  * Bug fixes:
12
22
  * Fix `CompanyNumber::Number#to_s` method not to return trailing whitespace when country code is not filled in - 9b4f3c53
data/README.md CHANGED
@@ -33,12 +33,9 @@ company_number = CompanyNumber.parse('123456789', :fr)
33
33
  Then you can run validation methods
34
34
 
35
35
  ```ruby
36
- company_number.valid?
37
- # => true
38
- company_number.valid_country?
39
- # => true
40
- company_number.valid_for_country?(:at)
41
- # => false
36
+ company_number.valid? # => true
37
+ company_number.valid_country? # => true
38
+ company_number.valid_for_country?(:at) # => false
42
39
  ```
43
40
 
44
41
  You can also fetch valid countries
@@ -82,6 +79,95 @@ CompanyNumber.dictionary
82
79
  # => {:at=>{:country=>"Austria", :name=>"Firmenbuchnummer", :regexp=>"^([a-zA-Z]{2}\\d{1,6}|\\d{1,6})[A-Z]$", :pattern=>"2 letters + 6 numbers + 1 letter (LLXXXXXXL)", :variations=>"1-6 numbers + 1 letter (XXXXXXL)"}, ...}
83
80
  ```
84
81
 
82
+ ## Configuration
83
+ You can configure your own dictionary using **custom_dictionary**.
84
+ It should be a hash with the country codes as keys and the associated metadata as values.
85
+
86
+ Available metadata keys:
87
+ - country
88
+ - name
89
+ - regexp
90
+ - pattern
91
+ - variations
92
+
93
+ **Example:**
94
+ ```ruby
95
+ CompanyNumber.parse('123456789', :fr).valid? # => true
96
+ CompanyNumber.parse('12345678901234', :fr).valid? # => true
97
+
98
+ CompanyNumber.configure do |config|
99
+ config.custom_dictionary = { fr: { regexp: '^\d{14}$' } }
100
+ end
101
+
102
+ CompanyNumber.parse('123456789', :fr).valid? # => false
103
+ CompanyNumber.parse('12345678901234', :fr).valid? # => true
104
+ ```
105
+
106
+ **strict_validation:**
107
+
108
+ You can also enable strict validation to reject unknow countries:
109
+
110
+ ```ruby
111
+ CompanyNumber.parse('123456789').valid? # => true
112
+ CompanyNumber.parse('123456789', :tt).valid? # => true
113
+
114
+ CompanyNumber.configure do |config|
115
+ config.strict_validation = true
116
+ end
117
+
118
+ CompanyNumber.parse('123456789').valid? # => false
119
+ CompanyNumber.parse('123456789', :tt).valid? # => false
120
+ ```
121
+
122
+ **excluded_countries:**
123
+
124
+ You may want to exclude some countries, this allows you to automatically validate the country's company number when strict validation is not enabled. You can also exclude a country to overwrite all its metadata and define it later in a custom dictionary.
125
+
126
+ **Example:**
127
+ ```ruby
128
+ CompanyNumber.parse('123456789', :be).valid? # => false
129
+
130
+ CompanyNumber.configure do |config|
131
+ config.excluded_countries = [:be]
132
+ end
133
+
134
+ CompanyNumber.parse('123456789', :be).valid? # => true
135
+ ```
136
+
137
+ ## Default dictionary:
138
+
139
+ - `:at` - **Austria** - Firmenbuchnummer
140
+ - `:be` - **Belgium** - Numéro d'entreprise Vestigingseenheidsnummer
141
+ - `:bg` - **Bulgaria** - ЕИК (EIK)/ПИК (PIK) (UIC/PIC)
142
+ - `:hr` - **Croatia** - Matični broj poslovnog subjekta (MBS)
143
+ - `:cy` - **Cyprus** - Αριθμός Μητρώου Εταιρίας Şirket kayıt numarası
144
+ - `:cz` - **Czech** - epublic (Identifikační číslo
145
+ - `:dk` - **Denmark** - CVR-nummer
146
+ - `:ee` - **Estonia** - Kood
147
+ - `:fi` - **Finland** - Y-tunnus FO-nummer
148
+ - `:fr` - **France** - Numéro SIREN ou SIRET
149
+ - `:de` - **Germany** - Nummer der Firma Registernummer
150
+ - `:gr` - **Greece** - Αριθμό Φορολογικού Μητρώου (Α.Φ.Μ.)
151
+ - `:hu` - **Hungary** - Cégjegyzékszáma
152
+ - `:ie` - **Ireland** - Company Number
153
+ - `:is` - **Island** - TIN
154
+ - `:it` - **Italy** - Codice fiscale
155
+ - `:lv` - **Latvia** - Reģistrācijas numurs
156
+ - `:li` - **Liechtenstein** - UID
157
+ - `:lt` - **Lithuania** - Juridinio asmens kodas
158
+ - `:lu` - **Luxembourg** - Numéro d'immatriculation
159
+ - `:mt` - **Malta** - Registration Number
160
+ - `:nl` - **Netherlands** - KvK-nummer
161
+ - `:no` - **Norway** - TIN
162
+ - `:pl` - **Poland** - Numer w Krajowym Rejestrze Sądowym (numer KRS)) NIPC)
163
+ - `:ro` - **Romania** - Număr de ordine în Registrul Comerţului
164
+ - `:sk` - **Slovakia** - Identifikačného čísla Identification number
165
+ - `:si` - **Slovenia** - Matična številka
166
+ - `:es` - **Spain** - Número de identificación fiscal (NIF)
167
+ - `:se` - **Sweden** - Registreringsnummer
168
+ - `:ch` - **Switzerland** - UID
169
+ - `:gb` - **United Kingdom** - Company Number Registration Number
170
+
85
171
  ## Development
86
172
 
87
173
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CompanyNumber
4
+ class Configuration
5
+ attr_reader :excluded_countries,
6
+ :custom_dictionary,
7
+ :strict_validation
8
+
9
+ def initialize
10
+ @excluded_countries = []
11
+ @custom_dictionary = {}
12
+ @strict_validation = nil
13
+ end
14
+
15
+ def dictionary
16
+ @dictionary ||= CompanyNumber::Dictionary.new(@custom_dictionary)
17
+ end
18
+
19
+ def strict_validation?
20
+ !!@strict_validation
21
+ end
22
+
23
+ def custom_dictionary=(value)
24
+ Validation.check_dictionary_structure(value)
25
+
26
+ @dictionary = nil
27
+ @custom_dictionary = value
28
+ end
29
+
30
+ def excluded_countries=(value)
31
+ Validation.check_object_class(value, [Array])
32
+
33
+ @dictionary = nil
34
+ @excluded_countries = value
35
+ end
36
+
37
+ def strict_validation=(value)
38
+ Validation.check_object_class(value, [TrueClass, FalseClass, NilClass])
39
+
40
+ @strict_validation = value
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CompanyNumber
4
+ class Dictionary
5
+ attr_reader :country_codes_metadata, :default_hash
6
+
7
+ def self.default_dictionary_path
8
+ File.join(File.dirname(__FILE__), '../../config/dictionary.yml')
9
+ end
10
+
11
+ def initialize(country_codes_metadata = {})
12
+ @country_codes_metadata = country_codes_metadata
13
+ @default_hash = load_default_hash
14
+
15
+ validate_country_codes_metadata
16
+ end
17
+
18
+ def values
19
+ @_values ||= fetch_values
20
+ end
21
+
22
+ private
23
+
24
+ def fetch_values
25
+ transformed_hash =
26
+ @default_hash.merge(@country_codes_metadata) do |country_code, _, value|
27
+ @default_hash[country_code.downcase].merge(value)
28
+ end
29
+
30
+ transformed_hash.reject do |country_code, _metadata|
31
+ CompanyNumber.configuration.excluded_countries.include?(country_code)
32
+ end
33
+ end
34
+
35
+ def load_default_hash
36
+ YAML.safe_load(
37
+ File.read(self.class.default_dictionary_path),
38
+ symbolize_names: true
39
+ )
40
+ end
41
+
42
+ def validate_country_codes_metadata
43
+ Validation.check_object_class(@country_codes_metadata, [Hash])
44
+
45
+ @country_codes_metadata.each do |country_code, metadata|
46
+ Validation.check_string_format(country_code, /^[A-Za-z]{2}$/)
47
+ Validation.check_country_code_metadata(metadata)
48
+ end
49
+ end
50
+ end
51
+ end
@@ -1,10 +1,13 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module CompanyNumber
2
4
  class Number
3
5
  attr_reader :company_number, :country_code, :metadata
4
6
 
5
7
  def initialize(company_number, country_code = nil)
6
- check_param_type(company_number, [String])
7
- check_param_type(country_code, [NilClass, Symbol, String])
8
+ Validation.check_object_class(company_number, [String])
9
+ Validation.check_object_class(country_code, [NilClass, Symbol, String])
10
+ Validation.check_iso_code_format(country_code)
8
11
 
9
12
  @company_number = company_number
10
13
  @country_code = country_code&.downcase&.to_sym
@@ -28,17 +31,22 @@ module CompanyNumber
28
31
  end
29
32
 
30
33
  def valid?
31
- !valid_country? || valid_for_country?(@country_code)
34
+ if CompanyNumber.strict_validation?
35
+ country_code_present_and_valid_country?
36
+ else
37
+ no_country_code_or_valid_country?
38
+ end
32
39
  end
33
40
 
34
41
  def valid_country?
35
- CompanyNumber.dictionary.keys.include?(@country_code)
42
+ CompanyNumber.dictionary.keys.include?(@country_code) ||
43
+ (!CompanyNumber.strict_validation? && !!@country_code)
36
44
  end
37
45
 
38
46
  def valid_for_country?(country_code)
39
- check_param_type(country_code, [Symbol])
40
-
41
- !!(@company_number =~ country_code_regexp(country_code))
47
+ Validation.check_iso_code_format(country_code)
48
+ regexp = CompanyNumber.dictionary.dig(country_code, :regexp)
49
+ (!CompanyNumber.strict_validation? && !regexp) || valid_code?(regexp)
42
50
  end
43
51
 
44
52
  def valid_countries
@@ -52,17 +60,16 @@ module CompanyNumber
52
60
 
53
61
  private
54
62
 
55
- def country_code_regexp(country_code)
56
- regexp = CompanyNumber.dictionary.dig(country_code, :regexp)
57
-
58
- Regexp.new(regexp) unless regexp.nil?
63
+ def no_country_code_or_valid_country?
64
+ !@country_code || valid_for_country?(@country_code)
59
65
  end
60
66
 
61
- def check_param_type(param, expected_classes = [])
62
- return if expected_classes.include?(param.class)
67
+ def country_code_present_and_valid_country?
68
+ !!@country_code && valid_for_country?(@country_code)
69
+ end
63
70
 
64
- raise ArgumentError,
65
- "Expect class of #{param} to be #{expected_classes.join(', ')}"
71
+ def valid_code?(regexp = nil)
72
+ !!regexp && !!(@company_number =~ Regexp.new(regexp))
66
73
  end
67
74
  end
68
75
  end
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CompanyNumber
4
+ module Validation
5
+ ISO_CODE_REGEXP = /^[A-Za-z]{2}$/.freeze
6
+
7
+ AVAILABLE_METADATA_KEYS = %i[
8
+ variations
9
+ pattern
10
+ country
11
+ regexp
12
+ name
13
+ ].freeze
14
+
15
+ class << self
16
+ def check_object_class(object, expected_classes = [])
17
+ return if expected_classes.include?(object.class)
18
+
19
+ raise ArgumentError,
20
+ "Expect #{object} class to be #{expected_classes.join(', ')}"
21
+ end
22
+
23
+ def check_object_inclusion(object, expected_objects = [])
24
+ return if expected_objects.include?(object)
25
+
26
+ raise ArgumentError,
27
+ "Expect #{object} to be part of #{expected_objects}"
28
+ end
29
+
30
+ def check_string_format(string, regexp)
31
+ return if string =~ regexp
32
+
33
+ raise ArgumentError, "Expect #{string} to match regexp: #{regexp}"
34
+ end
35
+
36
+ def check_iso_code_format(country_code)
37
+ return unless country_code
38
+
39
+ check_object_class(country_code, [Symbol, String])
40
+ check_string_format(country_code.to_s, ISO_CODE_REGEXP)
41
+ end
42
+
43
+ def check_country_code_metadata(metadata)
44
+ metadata.each do |key, value|
45
+ check_object_inclusion(key, AVAILABLE_METADATA_KEYS)
46
+ check_object_class(value, [String])
47
+ end
48
+ end
49
+
50
+ def check_dictionary_structure(value)
51
+ Validation.check_object_class(value, [Hash])
52
+
53
+ value.each do |country_code, metadata|
54
+ Validation.check_object_class(country_code, [Symbol])
55
+ Validation.check_object_class(metadata, [Hash])
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module CompanyNumber
4
- VERSION = "0.1.1"
4
+ VERSION = "0.1.2"
5
5
  end
@@ -2,20 +2,40 @@
2
2
 
3
3
  require "yaml"
4
4
  require_relative "company_number/version"
5
+ require_relative "company_number/validation"
5
6
 
6
7
  module CompanyNumber
7
- autoload :Number, 'company_number/number'
8
+ autoload :Configuration, 'company_number/configuration'
9
+ autoload :Dictionary, 'company_number/dictionary'
10
+ autoload :Number, 'company_number/number'
8
11
 
9
12
  class << self
10
13
  def parse(company_number, country_code = nil)
11
14
  CompanyNumber::Number.new(company_number, country_code)
12
15
  end
13
16
 
17
+ def configuration
18
+ @_configuration ||= CompanyNumber::Configuration.new
19
+ end
20
+
21
+ def configure
22
+ yield configuration
23
+ end
24
+
14
25
  def dictionary
15
- @_dictionary ||= YAML.safe_load(
16
- File.read(File.join(File.dirname(__FILE__), '../config/dictionary.yml')),
17
- symbolize_names: true
18
- )
26
+ configuration.dictionary.values
27
+ end
28
+
29
+ def excluded_countries
30
+ configuration.excluded_countries
31
+ end
32
+
33
+ def custom_dictionary
34
+ configuration.custom_dictionary
35
+ end
36
+
37
+ def strict_validation?
38
+ configuration.strict_validation?
19
39
  end
20
40
  end
21
41
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: company_number
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - victorauthiat
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-04-04 00:00:00.000000000 Z
11
+ date: 2022-04-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -102,7 +102,10 @@ files:
102
102
  - company_number.gemspec
103
103
  - config/dictionary.yml
104
104
  - lib/company_number.rb
105
+ - lib/company_number/configuration.rb
106
+ - lib/company_number/dictionary.rb
105
107
  - lib/company_number/number.rb
108
+ - lib/company_number/validation.rb
106
109
  - lib/company_number/version.rb
107
110
  homepage: https://github.com/victorauthiat/company_number
108
111
  licenses: