company_number 0.1.1 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
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: