postman_paf 0.3.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 +7 -0
- data/.github/workflows/gem-push.yml +48 -0
- data/.github/workflows/gem-test.yml +22 -0
- data/.gitignore +17 -0
- data/.rspec +3 -0
- data/.rubocop.yml +36 -0
- data/CHANGELOG.md +5 -0
- data/CODE_OF_CONDUCT.md +84 -0
- data/Gemfile +6 -0
- data/LICENSE.txt +21 -0
- data/README.md +174 -0
- data/Rakefile +12 -0
- data/bin/console +15 -0
- data/bin/setup +8 -0
- data/lib/postman_paf/converter.rb +65 -0
- data/lib/postman_paf/exceptions/exceptions.rb +29 -0
- data/lib/postman_paf/exceptions/last_part_exceptions.rb +36 -0
- data/lib/postman_paf/exceptions/rule_3_exceptions.rb +35 -0
- data/lib/postman_paf/exceptions/rule_5_and_7_exceptions.rb +24 -0
- data/lib/postman_paf/exceptions/rule_6_exceptions.rb +48 -0
- data/lib/postman_paf/exceptions/which_exception.rb +103 -0
- data/lib/postman_paf/printable_address.rb +35 -0
- data/lib/postman_paf/rules/address_builder.rb +30 -0
- data/lib/postman_paf/rules/building_number.rb +35 -0
- data/lib/postman_paf/rules/rule_1.rb +27 -0
- data/lib/postman_paf/rules/rule_2.rb +23 -0
- data/lib/postman_paf/rules/rule_3.rb +45 -0
- data/lib/postman_paf/rules/rule_4.rb +24 -0
- data/lib/postman_paf/rules/rule_5.rb +35 -0
- data/lib/postman_paf/rules/rule_6.rb +69 -0
- data/lib/postman_paf/rules/rule_7.rb +33 -0
- data/lib/postman_paf/rules/rules.rb +71 -0
- data/lib/postman_paf/rules/which_rule.rb +40 -0
- data/lib/postman_paf/validator.rb +65 -0
- data/lib/postman_paf/version.rb +5 -0
- data/lib/postman_paf.rb +32 -0
- data/postman_paf.gemspec +53 -0
- metadata +210 -0
@@ -0,0 +1,48 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module PostmanPAF
|
4
|
+
module Exceptions
|
5
|
+
module WhichException
|
6
|
+
RULE6_PREMISE_ELEMENTS = %w[buildingName subBuildingName].freeze
|
7
|
+
|
8
|
+
# Checks if the whole buildingName String contains an Exception I,
|
9
|
+
# Exception II or Exception III. Then checks if last part of the
|
10
|
+
# buildingName String (AKA numeric part) contains an exception.
|
11
|
+
# Finally checks if the whole subBuildingName String contains an
|
12
|
+
# Exception I, Exception II or Exception III.
|
13
|
+
# @param paf_address [Hash] to be converted.
|
14
|
+
# @return [Symbol] the Rule 6 conversion exception(s) to apply to
|
15
|
+
# the address based on criteria met.
|
16
|
+
def self.exception_to_apply_rule6(paf_address:)
|
17
|
+
RULE6_PREMISE_ELEMENTS.each_with_object([]) do |premise_element, exceptions|
|
18
|
+
exception = if contains_digit_as_first_and_last?(paf_address[premise_element])
|
19
|
+
:exception_i
|
20
|
+
elsif contains_digit_as_first_and_penultimate_and_alpha_as_last?(paf_address[premise_element])
|
21
|
+
:exception_ii
|
22
|
+
elsif contains_one_alpha_character?(paf_address[premise_element])
|
23
|
+
:exception_iii
|
24
|
+
elsif premise_element == BUILDING_NAME
|
25
|
+
# Checks buildingName ONLY for numeric part exception - no numeric part
|
26
|
+
# exceptions have been found for subBuildingName in test data.
|
27
|
+
building_name_parts = paf_address[BUILDING_NAME].split(' ')
|
28
|
+
if building_name_parts.size > 1
|
29
|
+
last_part = building_name_parts.last
|
30
|
+
if last_part.match?(/\d/)
|
31
|
+
PostmanPAF::Exceptions::WhichException.last_part_exception_to_apply(paf_address: paf_address, last_part: last_part)
|
32
|
+
else
|
33
|
+
:no_exception
|
34
|
+
end
|
35
|
+
else
|
36
|
+
:no_exception
|
37
|
+
end
|
38
|
+
else
|
39
|
+
:no_exception
|
40
|
+
end
|
41
|
+
|
42
|
+
premise_element_exception = "#{SimpleSymbolize.snakeize(premise_element)}_#{exception}".to_sym
|
43
|
+
exceptions << premise_element_exception
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module PostmanPAF
|
4
|
+
module Exceptions
|
5
|
+
module WhichException
|
6
|
+
# Exception I.
|
7
|
+
# @param address_data [String] buildingName or subBuildingName data.
|
8
|
+
# @return [Boolean] if first and last characters are numeric.
|
9
|
+
# @example
|
10
|
+
# contains_digit_as_first_and_last?("1") #=> true
|
11
|
+
# contains_digit_as_first_and_last?("1-2") #=> true
|
12
|
+
# contains_digit_as_first_and_last?("1/2") #=> true
|
13
|
+
# contains_digit_as_first_and_last?("1 Example House 2") #=> true
|
14
|
+
# contains_digit_as_first_and_last?("1 Example House") #=> false
|
15
|
+
def self.contains_digit_as_first_and_last?(address_data)
|
16
|
+
address_data.match?(/^\d(.*\d)?$/)
|
17
|
+
end
|
18
|
+
|
19
|
+
# Exception II.
|
20
|
+
# @param address_data [String] buildingName or subBuildingName data.
|
21
|
+
# @return [Boolean] if first and penultimate characters are numeric and
|
22
|
+
# last character is alphabetic. Case insensitive.
|
23
|
+
# @example
|
24
|
+
# contains_digit_as_first_and_penultimate_and_alpha_as_last?("1A") #=> true
|
25
|
+
# contains_digit_as_first_and_penultimate_and_alpha_as_last?("12A") #=> true
|
26
|
+
# contains_digit_as_first_and_penultimate_and_alpha_as_last?("1 Example 2A") #=> true
|
27
|
+
# contains_digit_as_first_and_penultimate_and_alpha_as_last?("1") #=> false
|
28
|
+
# contains_digit_as_first_and_penultimate_and_alpha_as_last?("15 A2") #=> false
|
29
|
+
def self.contains_digit_as_first_and_penultimate_and_alpha_as_last?(address_data)
|
30
|
+
return false unless address_data.length >= 2
|
31
|
+
|
32
|
+
first, *middle, last = address_data.chars
|
33
|
+
|
34
|
+
first.match?(/[[:digit:]]/) &&
|
35
|
+
(middle.empty? || middle.last.match?(/[[:digit:]]/)) &&
|
36
|
+
last.match?(/[[:alpha:]]/)
|
37
|
+
end
|
38
|
+
|
39
|
+
# Exception III.
|
40
|
+
# @param address_data [String] buildingName or subBuildingName data.
|
41
|
+
# @return [Boolean] if one alphabetic character only. Case insensitive.
|
42
|
+
# @example
|
43
|
+
# contains_one_alpha_character?("A") #=> true
|
44
|
+
# contains_one_alpha_character?("b") #=> true
|
45
|
+
# contains_one_alpha_character?("Z") #=> true
|
46
|
+
# contains_one_alpha_character?("1") #=> false
|
47
|
+
def self.contains_one_alpha_character?(address_data)
|
48
|
+
return false unless address_data.length.eql? 1
|
49
|
+
|
50
|
+
address_data.match?(/^[a-zA-Z]$/)
|
51
|
+
end
|
52
|
+
|
53
|
+
# Exception to Rule.
|
54
|
+
# @param address_data [String] buildingName.
|
55
|
+
# @return [Boolean] if last part (i.e. numeric part) contains a number
|
56
|
+
# between 0 and 9999.
|
57
|
+
# @example
|
58
|
+
# contains_digit_between_0_and_9999?("Example 0") #=> true
|
59
|
+
# contains_digit_between_0_and_9999?("Example 14") #=> true
|
60
|
+
# contains_digit_between_0_and_9999?("Example 9999") #=> true
|
61
|
+
# contains_digit_between_0_and_9999?("Example 10000") #=> false
|
62
|
+
def self.contains_digit_between_0_and_9999?(address_data)
|
63
|
+
address_data.match?(/ \d{1,4}$/)
|
64
|
+
end
|
65
|
+
|
66
|
+
# Exception IV.
|
67
|
+
# @param address_data [String] buildingName.
|
68
|
+
# @return [Boolean] if last part (i.e. numeric range or a numeric alpha
|
69
|
+
# suffix) is prefixed by an addressing keyword. Case insensitive.
|
70
|
+
# @example
|
71
|
+
# contains_address_keyword?("UNIT 1") #=> true
|
72
|
+
# contains_address_keyword?("BLOCKS 1-2") #=> true
|
73
|
+
# contains_address_keyword?("FLAT 12A") #=> true
|
74
|
+
# contains_address_keyword?("shops 2-4") #=> true
|
75
|
+
# contains_address_keyword?("STALLS") #=> false
|
76
|
+
def self.contains_address_keyword?(address_data)
|
77
|
+
last_part = address_data.split(' ').last
|
78
|
+
|
79
|
+
['BACK OF', 'BLOCK', 'BLOCKS', 'BUILDING', 'FLAT', 'MAISONETTE', 'MAISONETTES', 'REAR OF', 'SHOP', 'SHOPS', 'STALL',
|
80
|
+
'STALLS', 'SUITE', 'SUITES', 'UNIT', 'UNITS'].each do |keyword|
|
81
|
+
regex = "(^|\\s)#{keyword} #{last_part.upcase}$"
|
82
|
+
return true if address_data.upcase.match?(regex)
|
83
|
+
end
|
84
|
+
false
|
85
|
+
end
|
86
|
+
|
87
|
+
# Exception V.
|
88
|
+
# @param address_data [String] buildingName.
|
89
|
+
# @return [Boolean] if penultimate part (i.e. word in a buildingName) is
|
90
|
+
# followed by a whitespace and completed by numerics with decimals or
|
91
|
+
# forward slashes.
|
92
|
+
# @example
|
93
|
+
# contains_digits_with_decimals_or_forward_slashes?("Example 1.2") #=> true
|
94
|
+
# contains_digits_with_decimals_or_forward_slashes?("Example 85/1") #=> true
|
95
|
+
# contains_digits_with_decimals_or_forward_slashes?("Example 7:8") #=> false
|
96
|
+
def self.contains_digits_with_decimals_or_forward_slashes?(address_data)
|
97
|
+
last_part = address_data.split(' ').last
|
98
|
+
|
99
|
+
last_part.match?(%r{^\d+[.|/]\d+$})
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module PostmanPAF
|
4
|
+
# Getter and setter class for variables of the converted address.
|
5
|
+
# @attr line1 [String] converted.
|
6
|
+
# @attr line2 [String] converted.
|
7
|
+
# @attr line3 [String] converted.
|
8
|
+
# @attr line4 [String] converted.
|
9
|
+
# @attr line5 [String] the postTown of an address. Not converted.
|
10
|
+
# @attr country [String] not converted.
|
11
|
+
# @attr postcode [String] not converted.
|
12
|
+
# @attr language [String] not converted.
|
13
|
+
# @attr dps [String] the delivery point suffix, a unique 2-digit
|
14
|
+
# code for each delivery point in a postcode. Not converted.
|
15
|
+
class PrintableAddress
|
16
|
+
attr_accessor :line1, :line2, :line3, :line4, :line5, :country, :postcode, :language, :dps
|
17
|
+
|
18
|
+
# Converts PrintableAddress object to JSON Hash representation
|
19
|
+
# without ActiveSupport.
|
20
|
+
# @return [Hash] converted address data as JSON Hash.
|
21
|
+
def as_json
|
22
|
+
{
|
23
|
+
'line1' => @line1,
|
24
|
+
'line2' => @line2,
|
25
|
+
'line3' => @line3,
|
26
|
+
'line4' => @line4,
|
27
|
+
'line5' => @line5,
|
28
|
+
'postcode' => @postcode,
|
29
|
+
'country' => @country,
|
30
|
+
'language' => @language,
|
31
|
+
'dps' => @dps
|
32
|
+
}
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module PostmanPAF
|
4
|
+
module Rules
|
5
|
+
module BuildAddress
|
6
|
+
# Builds PrintableAddress object and returns attributes as JSON.
|
7
|
+
# @param paf_address [Hash] to be converted.
|
8
|
+
# @param lines [Array<String>] the converted lines of address data.
|
9
|
+
# Lines with an Integer value are type converted to a String.
|
10
|
+
# Lines with a value of nil are removed before converted address
|
11
|
+
# is returned.
|
12
|
+
def self.build_printable_address(paf_address:, lines:)
|
13
|
+
printable_address = PrintableAddress.new
|
14
|
+
|
15
|
+
lines.each_with_index do |line, index|
|
16
|
+
line_number = index + 1
|
17
|
+
line = line.to_s if line.is_a?(Integer)
|
18
|
+
printable_address.send("line#{line_number}=", line) unless line_number.eql?(6) || line_number.eql?(7)
|
19
|
+
end
|
20
|
+
|
21
|
+
printable_address.postcode = paf_address[POSTCODE].slice(0..7)
|
22
|
+
printable_address.country = paf_address[COUNTRY]
|
23
|
+
printable_address.language = paf_address[LANGUAGE]
|
24
|
+
printable_address.dps = paf_address[DPS]
|
25
|
+
|
26
|
+
printable_address.as_json.compact
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module PostmanPAF
|
4
|
+
module Rules
|
5
|
+
module ApplyRule
|
6
|
+
# Places buildingNumber in converted printable format address depending
|
7
|
+
# on thoroughfare and locality elements present in the PAF address.
|
8
|
+
# @param data [Array<String>] the converted lines of address data.
|
9
|
+
# @param paf_address [Hash] to be converted.
|
10
|
+
# @param number [String] the building number to be placed in the
|
11
|
+
# converted address.
|
12
|
+
# @return data [Array<String>] the updated converted lines of
|
13
|
+
# address data with the building number added.
|
14
|
+
def self.add_building_number(data:, paf_address:, number:)
|
15
|
+
if paf_address[DEPENDENT_THOROUGHFARE_NAME]
|
16
|
+
data << "#{number} #{paf_address[DEPENDENT_THOROUGHFARE_NAME]}"
|
17
|
+
data << paf_address[THOROUGHFARE_NAME]
|
18
|
+
data << paf_address[DOUBLE_DEPENDENT_LOCALITY]
|
19
|
+
data << paf_address[DEPENDENT_LOCALITY]
|
20
|
+
elsif paf_address[THOROUGHFARE_NAME]
|
21
|
+
data << "#{number} #{paf_address[THOROUGHFARE_NAME]}"
|
22
|
+
data << paf_address[DOUBLE_DEPENDENT_LOCALITY]
|
23
|
+
data << paf_address[DEPENDENT_LOCALITY]
|
24
|
+
elsif paf_address[DOUBLE_DEPENDENT_LOCALITY]
|
25
|
+
data << "#{number} #{paf_address[DOUBLE_DEPENDENT_LOCALITY]}"
|
26
|
+
data << paf_address[DEPENDENT_LOCALITY]
|
27
|
+
elsif paf_address[DEPENDENT_LOCALITY]
|
28
|
+
data << "#{number} #{paf_address[DEPENDENT_LOCALITY]}"
|
29
|
+
else
|
30
|
+
data << number
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module PostmanPAF
|
4
|
+
module Rules
|
5
|
+
module ApplyRule
|
6
|
+
# Applies conversion Rule 1 to the PAF address.
|
7
|
+
# Rule 1 conversion criteria: organisationName.
|
8
|
+
# Will also apply as a default if organisationName,
|
9
|
+
# subBuildingName, buildingName + buildingNumber NOT
|
10
|
+
# present. Exceptions are not applicable.
|
11
|
+
# @param paf_address [Hash] to be converted.
|
12
|
+
# @return data [Array<String>] the converted lines of address data.
|
13
|
+
def self.apply_rule1(paf_address:)
|
14
|
+
data = []
|
15
|
+
|
16
|
+
data << paf_address[ORGANISATION_NAME]
|
17
|
+
data << paf_address[DEPARTMENT_NAME]
|
18
|
+
data << "PO BOX #{paf_address[PO_BOX_NUMBER]}" if paf_address[PO_BOX_NUMBER]
|
19
|
+
|
20
|
+
data << paf_address[DEPENDENT_THOROUGHFARE_NAME]
|
21
|
+
data << paf_address[THOROUGHFARE_NAME]
|
22
|
+
data << paf_address[DOUBLE_DEPENDENT_LOCALITY]
|
23
|
+
data << paf_address[DEPENDENT_LOCALITY]
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module PostmanPAF
|
4
|
+
module Rules
|
5
|
+
module ApplyRule
|
6
|
+
# Applies conversion Rule 2 to the PAF address.
|
7
|
+
# Rule 2 conversion criteria: buildingNumber OR
|
8
|
+
# organisationName + buildingNumber. Exceptions
|
9
|
+
# are not applicable.
|
10
|
+
# @param paf_address [Hash] to be converted.
|
11
|
+
# @return data [Array<String>] the converted lines of address data.
|
12
|
+
def self.apply_rule2(paf_address:)
|
13
|
+
data = []
|
14
|
+
|
15
|
+
data << paf_address[ORGANISATION_NAME]
|
16
|
+
data << paf_address[DEPARTMENT_NAME]
|
17
|
+
data << "PO BOX #{paf_address[PO_BOX_NUMBER]}" if paf_address[PO_BOX_NUMBER]
|
18
|
+
|
19
|
+
PostmanPAF::Rules::ApplyRule.add_building_number(data: data, paf_address: paf_address, number: paf_address[BUILDING_NUMBER])
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module PostmanPAF
|
4
|
+
module Rules
|
5
|
+
module ApplyRule
|
6
|
+
# Applies conversion Rule 3 to the PAF address. Rule 3 conversion
|
7
|
+
# criteria: buildingName OR organisationName + buildingName.
|
8
|
+
# Exceptions can apply to buildingName.
|
9
|
+
# @param paf_address [Hash] to be converted.
|
10
|
+
# @param exception [Symbol] the exception to be applied during
|
11
|
+
# conversion.
|
12
|
+
# @return data [Array<String>] the converted lines of address data.
|
13
|
+
def self.apply_rule3(paf_address:, exception:)
|
14
|
+
data = []
|
15
|
+
|
16
|
+
data << paf_address[ORGANISATION_NAME]
|
17
|
+
data << paf_address[DEPARTMENT_NAME]
|
18
|
+
data << "PO BOX #{paf_address[PO_BOX_NUMBER]}" if paf_address[PO_BOX_NUMBER]
|
19
|
+
|
20
|
+
case exception
|
21
|
+
when :exception_i, :exception_ii, :exception_iii
|
22
|
+
if paf_address[DEPENDENT_THOROUGHFARE_NAME]
|
23
|
+
data << "#{paf_address[BUILDING_NAME]} #{paf_address[DEPENDENT_THOROUGHFARE_NAME]}"
|
24
|
+
data << paf_address[THOROUGHFARE_NAME]
|
25
|
+
else
|
26
|
+
data << "#{paf_address[BUILDING_NAME]} #{paf_address[THOROUGHFARE_NAME]}"
|
27
|
+
end
|
28
|
+
when :exception_i_numeric_part, :exception_ii_numeric_part
|
29
|
+
*name, number = paf_address[BUILDING_NAME].split(' ')
|
30
|
+
data << name.join(' ')
|
31
|
+
PostmanPAF::Rules::ApplyRule.add_building_number(data: data, paf_address: paf_address, number: number)
|
32
|
+
else
|
33
|
+
# Applies if :exception_to_rule, :exception_iv, :exception_v or :no_exception i.e. buildingName is not split
|
34
|
+
data << paf_address[BUILDING_NAME]
|
35
|
+
data << paf_address[DEPENDENT_THOROUGHFARE_NAME]
|
36
|
+
data << paf_address[THOROUGHFARE_NAME]
|
37
|
+
end
|
38
|
+
|
39
|
+
data << paf_address[DOUBLE_DEPENDENT_LOCALITY] unless data.include?(paf_address[DOUBLE_DEPENDENT_LOCALITY])
|
40
|
+
data << paf_address[DEPENDENT_LOCALITY] unless data.include?(paf_address[DEPENDENT_LOCALITY])
|
41
|
+
data
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module PostmanPAF
|
4
|
+
module Rules
|
5
|
+
module ApplyRule
|
6
|
+
# Applies conversion Rule 4 to the PAF address.
|
7
|
+
# Rule 4 conversion criteria: buildingName + buildingNumber OR
|
8
|
+
# organisationName + buildingName + buildingNumber. Exceptions
|
9
|
+
# are not applicable.
|
10
|
+
# @param paf_address [Hash] to be converted.
|
11
|
+
# @return data [Array<String>] the converted lines of address data.
|
12
|
+
def self.apply_rule4(paf_address:)
|
13
|
+
data = []
|
14
|
+
|
15
|
+
data << paf_address[ORGANISATION_NAME]
|
16
|
+
data << paf_address[DEPARTMENT_NAME]
|
17
|
+
data << "PO BOX #{paf_address[PO_BOX_NUMBER]}" if paf_address[PO_BOX_NUMBER]
|
18
|
+
|
19
|
+
data << paf_address[BUILDING_NAME]
|
20
|
+
PostmanPAF::Rules::ApplyRule.add_building_number(data: data, paf_address: paf_address, number: paf_address[BUILDING_NUMBER])
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module PostmanPAF
|
4
|
+
module Rules
|
5
|
+
module ApplyRule
|
6
|
+
# Applies conversion Rule 5 to the PAF address. Rule 5 conversion
|
7
|
+
# criteria: subBuildingName + buildingNumber OR organisationName
|
8
|
+
# + subBuildingName + buildingNumber. Exceptions can apply to
|
9
|
+
# subBuildingName ONLY.
|
10
|
+
# @param paf_address [Hash] to be converted.
|
11
|
+
# @param exception [Symbol] the exception to be applied during
|
12
|
+
# conversion.
|
13
|
+
# @return data [Array<String>] the converted lines of address data.
|
14
|
+
def self.apply_rule5(paf_address:, exception:)
|
15
|
+
data = []
|
16
|
+
|
17
|
+
data << paf_address[ORGANISATION_NAME]
|
18
|
+
data << paf_address[DEPARTMENT_NAME]
|
19
|
+
data << "PO BOX #{paf_address[PO_BOX_NUMBER]}" if paf_address[PO_BOX_NUMBER]
|
20
|
+
|
21
|
+
case exception
|
22
|
+
when :exception_i, :exception_ii
|
23
|
+
number = "#{paf_address[SUB_BUILDING_NAME]} #{paf_address[BUILDING_NUMBER]}"
|
24
|
+
PostmanPAF::Rules::ApplyRule.add_building_number(data: data, paf_address: paf_address, number: number)
|
25
|
+
when :exception_iii
|
26
|
+
number = "#{paf_address[BUILDING_NUMBER]}#{paf_address[SUB_BUILDING_NAME]}"
|
27
|
+
PostmanPAF::Rules::ApplyRule.add_building_number(data: data, paf_address: paf_address, number: number)
|
28
|
+
else
|
29
|
+
data << paf_address[SUB_BUILDING_NAME]
|
30
|
+
PostmanPAF::Rules::ApplyRule.add_building_number(data: data, paf_address: paf_address, number: paf_address[BUILDING_NUMBER])
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module PostmanPAF
|
4
|
+
module Rules
|
5
|
+
module ApplyRule
|
6
|
+
SUB_BUILDING_NAME_EXCEPTIONS = %i[sub_building_name_exception_i sub_building_name_exception_ii sub_building_name_exception_iii].freeze
|
7
|
+
|
8
|
+
# Applies conversion Rule 6 to the PAF address. Rule 6 conversion
|
9
|
+
# criteria: subBuildingName + buildingName OR organisationName
|
10
|
+
# + subBuildingName + buildingName. Exceptions can apply to
|
11
|
+
# subBuildingName AND/OR buildingName.
|
12
|
+
# @param paf_address [Hash] to be converted.
|
13
|
+
# @param exceptions [Array<Symbol>] the exceptions to be applied
|
14
|
+
# during conversion.
|
15
|
+
# @return data [Array<String>] the converted lines of address data.
|
16
|
+
def self.apply_rule6(paf_address:, exceptions:)
|
17
|
+
building_name_exception = exceptions.first
|
18
|
+
sub_building_name_exception = exceptions.last
|
19
|
+
|
20
|
+
data = []
|
21
|
+
|
22
|
+
data << paf_address[ORGANISATION_NAME]
|
23
|
+
data << paf_address[DEPARTMENT_NAME]
|
24
|
+
data << "PO BOX #{paf_address[PO_BOX_NUMBER]}" if paf_address[PO_BOX_NUMBER]
|
25
|
+
|
26
|
+
case building_name_exception
|
27
|
+
when :building_name_exception_i, :building_name_exception_ii, :building_name_exception_iii
|
28
|
+
# Applies regardless of sub_building_name_exception.
|
29
|
+
if paf_address[DEPENDENT_THOROUGHFARE_NAME]
|
30
|
+
data << paf_address[SUB_BUILDING_NAME]
|
31
|
+
data << "#{paf_address[BUILDING_NAME]} #{paf_address[DEPENDENT_THOROUGHFARE_NAME]}"
|
32
|
+
data << paf_address[THOROUGHFARE_NAME]
|
33
|
+
else
|
34
|
+
data << paf_address[SUB_BUILDING_NAME]
|
35
|
+
data << "#{paf_address[BUILDING_NAME]} #{paf_address[THOROUGHFARE_NAME]}"
|
36
|
+
end
|
37
|
+
when :building_name_exception_i_numeric_part, :building_name_exception_ii_numeric_part
|
38
|
+
if SUB_BUILDING_NAME_EXCEPTIONS.include?(sub_building_name_exception)
|
39
|
+
*name, number = paf_address[BUILDING_NAME].split(' ')
|
40
|
+
data << "#{paf_address[SUB_BUILDING_NAME]} #{name.join(" ")}"
|
41
|
+
PostmanPAF::Rules::ApplyRule.add_building_number(data: data, paf_address: paf_address, number: number)
|
42
|
+
else
|
43
|
+
*name, number = paf_address[BUILDING_NAME].split(' ')
|
44
|
+
data << paf_address[SUB_BUILDING_NAME]
|
45
|
+
data << name.join(' ')
|
46
|
+
PostmanPAF::Rules::ApplyRule.add_building_number(data: data, paf_address: paf_address, number: number)
|
47
|
+
end
|
48
|
+
else
|
49
|
+
# Applies if :building_name_exception_to_rule, :building_name_exception_iv, :building_name_exception_v or :building_name_no_exception
|
50
|
+
# i.e. buildingName is not split
|
51
|
+
if SUB_BUILDING_NAME_EXCEPTIONS.include?(sub_building_name_exception)
|
52
|
+
data << "#{paf_address[SUB_BUILDING_NAME]} #{paf_address[BUILDING_NAME]}"
|
53
|
+
data << paf_address[DEPENDENT_THOROUGHFARE_NAME]
|
54
|
+
data << paf_address[THOROUGHFARE_NAME]
|
55
|
+
else
|
56
|
+
data << paf_address[SUB_BUILDING_NAME]
|
57
|
+
data << paf_address[BUILDING_NAME]
|
58
|
+
data << paf_address[DEPENDENT_THOROUGHFARE_NAME]
|
59
|
+
data << paf_address[THOROUGHFARE_NAME]
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
data << paf_address[DOUBLE_DEPENDENT_LOCALITY] unless data.include?(paf_address[DOUBLE_DEPENDENT_LOCALITY])
|
64
|
+
data << paf_address[DEPENDENT_LOCALITY] unless data.include?(paf_address[DEPENDENT_LOCALITY])
|
65
|
+
data
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module PostmanPAF
|
4
|
+
module Rules
|
5
|
+
module ApplyRule
|
6
|
+
# Applies conversion Rule 7 to the PAF address. Rule 7 conversion
|
7
|
+
# criteria: subBuildingName + buildingName + buildingNumber OR
|
8
|
+
# organisationName + subBuildingName + buildingName +
|
9
|
+
# buildingNumber. Exceptions can apply to subBuildingName ONLY.
|
10
|
+
# @param paf_address [Hash] to be converted.
|
11
|
+
# @param exception [Symbol] the exception to be applied during
|
12
|
+
# conversion.
|
13
|
+
# @return data [Array<String>] the converted lines of address data.
|
14
|
+
def self.apply_rule7(paf_address:, exception:)
|
15
|
+
data = []
|
16
|
+
|
17
|
+
data << paf_address[ORGANISATION_NAME]
|
18
|
+
data << paf_address[DEPARTMENT_NAME]
|
19
|
+
data << "PO BOX #{paf_address[PO_BOX_NUMBER]}" if paf_address[PO_BOX_NUMBER]
|
20
|
+
|
21
|
+
case exception
|
22
|
+
when :exception_i, :exception_ii, :exception_iii
|
23
|
+
data << "#{paf_address[SUB_BUILDING_NAME]} #{paf_address[BUILDING_NAME]}"
|
24
|
+
else
|
25
|
+
data << paf_address[SUB_BUILDING_NAME]
|
26
|
+
data << paf_address[BUILDING_NAME]
|
27
|
+
end
|
28
|
+
|
29
|
+
PostmanPAF::Rules::ApplyRule.add_building_number(data: data, paf_address: paf_address, number: paf_address[BUILDING_NUMBER])
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module PostmanPAF
|
4
|
+
module Rules
|
5
|
+
# PAF address elements:
|
6
|
+
ORGANISATION_NAME = 'organisationName'
|
7
|
+
DEPARTMENT_NAME = 'departmentName'
|
8
|
+
PO_BOX_NUMBER = 'poBoxNumber'
|
9
|
+
BUILDING_NUMBER = 'buildingNumber'
|
10
|
+
BUILDING_NAME = 'buildingName'
|
11
|
+
SUB_BUILDING_NAME = 'subBuildingName'
|
12
|
+
THOROUGHFARE_NAME = 'thoroughfareName'
|
13
|
+
DEPENDENT_THOROUGHFARE_NAME = 'dependentThoroughfareName'
|
14
|
+
DEPENDENT_LOCALITY = 'dependentLocality'
|
15
|
+
DOUBLE_DEPENDENT_LOCALITY = 'doubleDependentLocality'
|
16
|
+
POST_TOWN = 'postTown'
|
17
|
+
POSTCODE = 'postcode'
|
18
|
+
COUNTRY = 'country'
|
19
|
+
LANGUAGE = 'language'
|
20
|
+
DPS = 'dps'
|
21
|
+
# Only the presence of subBuildingName, buildingName and
|
22
|
+
# buildingNumber determine which Rule applies.
|
23
|
+
ADDRESS_ELEMENTS_FOR_RULE = %w[subBuildingName buildingName buildingNumber].freeze
|
24
|
+
|
25
|
+
# Identifies address elements found in PAF address and returns
|
26
|
+
# applicable rule.
|
27
|
+
# @param paf_address [Hash] to be converted.
|
28
|
+
# @return [Symbol] the conversion rule to apply to the address
|
29
|
+
# based on address elements found.
|
30
|
+
def self.which_rule(paf_address:)
|
31
|
+
found_premise_elements = []
|
32
|
+
|
33
|
+
paf_address.each do |key, value|
|
34
|
+
# to_s is used to handle an Integer value in the PAF address.
|
35
|
+
found_premise_elements << key if ADDRESS_ELEMENTS_FOR_RULE.include?(key) && !value.to_s.empty?
|
36
|
+
end
|
37
|
+
|
38
|
+
PostmanPAF::Rules::WhichRule.rule_to_apply(premise_elements: found_premise_elements)
|
39
|
+
end
|
40
|
+
|
41
|
+
# Applies the applicable rule and exception (if applicable) to
|
42
|
+
# create the converted printable address data. Rule 1
|
43
|
+
# applies for a PAF address containing an organisationName,
|
44
|
+
# but also applies when defaulting to Rule 1 for a PAF address
|
45
|
+
# that does not contain: organisationName, subBuildingName,
|
46
|
+
# buildingName or buildingNumber.
|
47
|
+
# @param rule [Symbol] the conversion rule to be applied to the
|
48
|
+
# address.
|
49
|
+
# @param paf_address [Hash] to be converted.
|
50
|
+
# @param exception [Symbol] applied during conversion.
|
51
|
+
# @return [Array] converted address data.
|
52
|
+
def self.apply_rule(rule:, paf_address:, exception:)
|
53
|
+
case rule
|
54
|
+
when :rule2
|
55
|
+
PostmanPAF::Rules::ApplyRule.apply_rule2(paf_address: paf_address)
|
56
|
+
when :rule3
|
57
|
+
PostmanPAF::Rules::ApplyRule.apply_rule3(paf_address: paf_address, exception: exception)
|
58
|
+
when :rule4
|
59
|
+
PostmanPAF::Rules::ApplyRule.apply_rule4(paf_address: paf_address)
|
60
|
+
when :rule5
|
61
|
+
PostmanPAF::Rules::ApplyRule.apply_rule5(paf_address: paf_address, exception: exception)
|
62
|
+
when :rule6
|
63
|
+
PostmanPAF::Rules::ApplyRule.apply_rule6(paf_address: paf_address, exceptions: exception)
|
64
|
+
when :rule7
|
65
|
+
PostmanPAF::Rules::ApplyRule.apply_rule7(paf_address: paf_address, exception: exception)
|
66
|
+
else
|
67
|
+
PostmanPAF::Rules::ApplyRule.apply_rule1(paf_address: paf_address)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module PostmanPAF
|
4
|
+
module Rules
|
5
|
+
module WhichRule
|
6
|
+
RULE_02 = %w[buildingNumber].freeze
|
7
|
+
RULE_03 = %w[buildingName].freeze
|
8
|
+
RULE_04 = %w[buildingName buildingNumber].freeze
|
9
|
+
RULE_05 = %w[buildingNumber subBuildingName].freeze
|
10
|
+
RULE_06 = %w[buildingName subBuildingName].freeze
|
11
|
+
RULE_07 = %w[buildingName buildingNumber subBuildingName].freeze
|
12
|
+
|
13
|
+
# Matches address elements found in PAF address to criteria for
|
14
|
+
# applicable Royal Mail rule. Rule 1 is defaulted to if
|
15
|
+
# subBuildingName, buildingName and buildingNumber are NOT
|
16
|
+
# present.
|
17
|
+
# @param premise_elements [Array<String>] the premise elements
|
18
|
+
# found in the PAF address.
|
19
|
+
# @return [Symbol] the applicable Royal Mail conversion rule.
|
20
|
+
def self.rule_to_apply(premise_elements:)
|
21
|
+
case premise_elements.sort
|
22
|
+
when RULE_02
|
23
|
+
:rule2
|
24
|
+
when RULE_03
|
25
|
+
:rule3
|
26
|
+
when RULE_04
|
27
|
+
:rule4
|
28
|
+
when RULE_05
|
29
|
+
:rule5
|
30
|
+
when RULE_06
|
31
|
+
:rule6
|
32
|
+
when RULE_07
|
33
|
+
:rule7
|
34
|
+
else
|
35
|
+
:rule1
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|