addressing 0.1.1 → 0.3.1
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 +4 -4
- data/CHANGELOG.md +15 -0
- data/README.md +18 -2
- data/data/country/zh.json +1 -1
- data/lib/addressing/address_format.rb +21 -0
- data/lib/addressing/field_override.rb +33 -0
- data/lib/addressing/lazy_subdivisions.rb +5 -0
- data/lib/addressing/model.rb +110 -0
- data/lib/addressing/version.rb +1 -1
- data/lib/addressing.rb +8 -0
- metadata +4 -3
- data/lib/addressing/address_format_validator.rb +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 70ce82947444306a38c71f41034dbc93a842d06125f66d2288ab212b663af42c
|
4
|
+
data.tar.gz: 69a1dc6eb190e4d1dca977df29cf3d6c3fe8b2c87334d8a919e1f7022f57bdb2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6e8be1a338edaa1a0f39ac942b04786a7c0e88937c148c48ffe851b52b79dfcebb235e6a31800c1ad0c862b26be8ac255469bf3682fdb73e86b11f9d898e18f4
|
7
|
+
data.tar.gz: c4473163b7243a66c8846e77d6f6d267af3c3a33f3b483aa2ef2098d3dd8942885dcb7044e0bc15f2a3a889b79453ea658ad8cf3ea503c54770aa1725ced5315
|
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,21 @@
|
|
2
2
|
|
3
3
|
All notable changes to `addressing` will be documented in this file.
|
4
4
|
|
5
|
+
## 0.3.1 (04-04-2022)
|
6
|
+
|
7
|
+
- Break with both subdivisions and parents when subdivision field is empty
|
8
|
+
- Only retrieve field if it exists on model
|
9
|
+
|
10
|
+
## 0.3.0 (04-04-2022)
|
11
|
+
|
12
|
+
- Allow field validation to be overridden
|
13
|
+
- Only verify address when one of the field changes
|
14
|
+
- Allow used address fields to be configured
|
15
|
+
|
16
|
+
## 0.2.0 (25-02-2022)
|
17
|
+
|
18
|
+
- Add ActiveRecord validations
|
19
|
+
|
5
20
|
## 0.1.1 (21-02-2022)
|
6
21
|
|
7
22
|
- Fix typo in DE custom format
|
data/README.md
CHANGED
@@ -172,6 +172,24 @@ p formatter.format(address, origin_country: "FR")
|
|
172
172
|
# ÉTATS-UNIS - UNITED STATES
|
173
173
|
```
|
174
174
|
|
175
|
+
### Validating addresses
|
176
|
+
|
177
|
+
For Active Record models, use:
|
178
|
+
|
179
|
+
```rb
|
180
|
+
class User < ApplicationRecord
|
181
|
+
validates_address_format
|
182
|
+
end
|
183
|
+
```
|
184
|
+
|
185
|
+
For performance, the address is only verified if at least one of the fields changes. Set your own condition with:
|
186
|
+
|
187
|
+
```rb
|
188
|
+
class User < ApplicationRecord
|
189
|
+
validates_address if: -> { something_changed? }, ...
|
190
|
+
end
|
191
|
+
```
|
192
|
+
|
175
193
|
## Changelog
|
176
194
|
|
177
195
|
Please see [CHANGELOG](CHANGELOG.md) for more information on what has changed recently.
|
@@ -203,5 +221,3 @@ Feel free to open an issue to get feedback on your idea before spending too much
|
|
203
221
|
## License
|
204
222
|
|
205
223
|
The MIT License (MIT). Please see [License File](LICENSE.md) for more information.
|
206
|
-
|
207
|
-
https://github.com/countries/countries/blob/eddb4af3889e5c8b66d897f9789d43c4a1ee0598/spec/thread_safety_spec.rb
|
data/data/country/zh.json
CHANGED
@@ -35,7 +35,6 @@
|
|
35
35
|
"MK": "北马其顿",
|
36
36
|
"BJ": "贝宁",
|
37
37
|
"BE": "比利时",
|
38
|
-
"PE": "秘鲁",
|
39
38
|
"IS": "冰岛",
|
40
39
|
"PR": "波多黎各",
|
41
40
|
"PL": "波兰",
|
@@ -149,6 +148,7 @@
|
|
149
148
|
"MN": "蒙古",
|
150
149
|
"MS": "蒙特塞拉特",
|
151
150
|
"BD": "孟加拉国",
|
151
|
+
"PE": "秘鲁",
|
152
152
|
"FM": "密克罗尼西亚",
|
153
153
|
"MM": "缅甸",
|
154
154
|
"MD": "摩尔多瓦",
|
@@ -141,4 +141,25 @@ module Addressing
|
|
141
141
|
fields & used_fields
|
142
142
|
end
|
143
143
|
end
|
144
|
+
|
145
|
+
class AddressFormatHelper
|
146
|
+
class << self
|
147
|
+
# Gets the required fields.
|
148
|
+
#
|
149
|
+
# Applies field overrides to the required fields
|
150
|
+
# specified by the address format.
|
151
|
+
def required_fields(address_format, field_overrides)
|
152
|
+
required_fields = address_format.required_fields
|
153
|
+
required_fields = required_fields - field_overrides.optional_fields
|
154
|
+
required_fields = required_fields - field_overrides.hidden_fields
|
155
|
+
|
156
|
+
if field_overrides.required_fields
|
157
|
+
required_fields = required_fields + field_overrides.required_fields
|
158
|
+
required_fields = required_fields.uniq
|
159
|
+
end
|
160
|
+
|
161
|
+
required_fields
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
144
165
|
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Addressing
|
4
|
+
class FieldOverride < Enum
|
5
|
+
HIDDEN = "hidden"
|
6
|
+
OPTIONAL = "optional"
|
7
|
+
REQUIRED = "required"
|
8
|
+
end
|
9
|
+
|
10
|
+
class FieldOverrides
|
11
|
+
attr_reader :hidden_fields, :optional_fields, :required_fields
|
12
|
+
|
13
|
+
def initialize(definition)
|
14
|
+
AddressField.assert_all_exist(definition.keys)
|
15
|
+
FieldOverride.assert_all_exist(definition.values)
|
16
|
+
|
17
|
+
@hidden_fields = []
|
18
|
+
@optional_fields = []
|
19
|
+
@required_fields = []
|
20
|
+
|
21
|
+
definition.each do |field, override|
|
22
|
+
case override
|
23
|
+
when FieldOverride::HIDDEN
|
24
|
+
@hidden_fields << field
|
25
|
+
when FieldOverride::OPTIONAL
|
26
|
+
@optional_fields << field
|
27
|
+
when FieldOverride::REQUIRED
|
28
|
+
@required_fields << field
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,110 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Addressing
|
4
|
+
module Model
|
5
|
+
def validates_address_format(
|
6
|
+
fields: [:country_code, :administrative_area, :locality, :dependent_locality, :postal_code, :sorting_code, :address_line1, :address_line2, :organization, :given_name, :additional_name, :family_name, :locale], field_overrides: nil, **options)
|
7
|
+
fields = Array(fields)
|
8
|
+
field_overrides ||= FieldOverrides.new({})
|
9
|
+
|
10
|
+
options[:if] ||= -> { fields.any? { |f| changes.key?(f.to_s) } } unless options[:unless]
|
11
|
+
|
12
|
+
class_eval do
|
13
|
+
validate :verify_address_format, **options
|
14
|
+
|
15
|
+
define_method :verify_address_format do
|
16
|
+
values = fields.each_with_object({}) { |f, v| v[f] = send(f) if self.respond_to?(f) }
|
17
|
+
address = Address.new(**values)
|
18
|
+
|
19
|
+
return unless address.country_code.present?
|
20
|
+
|
21
|
+
address_format = AddressFormat.get(address.country_code)
|
22
|
+
address_format.used_fields
|
23
|
+
|
24
|
+
return unless address.country_code.present?
|
25
|
+
|
26
|
+
address_format = AddressFormat.get(address.country_code)
|
27
|
+
address_format.used_fields
|
28
|
+
|
29
|
+
# Validate the presence of required fields.
|
30
|
+
AddressFormatHelper::required_fields(address_format, field_overrides).each do |required_field|
|
31
|
+
next unless address.send(required_field).blank?
|
32
|
+
|
33
|
+
errors.add(required_field, "should not be blank")
|
34
|
+
end
|
35
|
+
|
36
|
+
used_fields = address_format.used_fields - field_overrides.hidden_fields
|
37
|
+
|
38
|
+
# Validate the absence of unused fields.
|
39
|
+
unused_fields = AddressField.all.values - used_fields
|
40
|
+
unused_fields.each do |unused_field|
|
41
|
+
next if address.send(unused_field).blank?
|
42
|
+
|
43
|
+
errors.add(unused_field, "should be blank")
|
44
|
+
end
|
45
|
+
|
46
|
+
# Validate subdivisions.
|
47
|
+
subdivisions = verify_subdivisions(address, address_format, field_overrides)
|
48
|
+
|
49
|
+
# Validate postal code.
|
50
|
+
verify_postal_code(address.postal_code, subdivisions, address_format) if used_fields.include?(AddressField::POSTAL_CODE)
|
51
|
+
end
|
52
|
+
|
53
|
+
define_method :verify_subdivisions do |address, address_format, field_overrides|
|
54
|
+
# No predefined subdivisions exist, nothing to validate against.
|
55
|
+
return [] if address_format.subdivision_depth < 1
|
56
|
+
|
57
|
+
subdivisions, _parents = address_format.used_subdivision_fields.each_with_index.inject([[], []]) do |(subdivisions, parents), (field, index)|
|
58
|
+
# The field is empty or validation is disabled.
|
59
|
+
break [subdivisions, parents] if address.send(field).blank? || field_overrides.hidden_fields.include?(field)
|
60
|
+
|
61
|
+
parents << (index > 0 ? address.send(address_format.used_subdivision_fields[index - 1]) : address_format.country_code)
|
62
|
+
subdivision = Subdivision.get(address.send(field), parents)
|
63
|
+
if subdivision.nil?
|
64
|
+
errors.add(field, "should be valid")
|
65
|
+
break [subdivisions, parents]
|
66
|
+
end
|
67
|
+
|
68
|
+
subdivisions << subdivision
|
69
|
+
# No predefined subdivisions below this level, stop here.
|
70
|
+
break [subdivisions, parents] if subdivision.children.empty?
|
71
|
+
|
72
|
+
[subdivisions, parents]
|
73
|
+
end
|
74
|
+
|
75
|
+
subdivisions
|
76
|
+
end
|
77
|
+
|
78
|
+
define_method :verify_postal_code do |postal_code, subdivisions, address_format|
|
79
|
+
# Nothing to validate.
|
80
|
+
return if postal_code.blank?
|
81
|
+
|
82
|
+
full_pattern, start_pattern = subdivisions.inject([address_format.postal_code_pattern, nil]) do |(full_pattern, start_pattern), subdivision|
|
83
|
+
pattern = subdivision.postal_code_pattern
|
84
|
+
next [full_pattern, start_pattern] if pattern.blank?
|
85
|
+
next [pattern, start_pattern] if subdivision.postal_code_pattern_type == PatternType::FULL
|
86
|
+
|
87
|
+
[full_pattern, pattern]
|
88
|
+
end
|
89
|
+
|
90
|
+
if full_pattern
|
91
|
+
# The pattern must match the provided value completely.
|
92
|
+
match = postal_code.match(Regexp.new(full_pattern.gsub("\\\\", "\\").to_s, "i"))
|
93
|
+
if match.nil? || match[0] != postal_code
|
94
|
+
errors.add(AddressField::POSTAL_CODE, "should be valid")
|
95
|
+
return
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
if start_pattern
|
100
|
+
# The pattern must match the start of the provided value.
|
101
|
+
match = postal_code.match(Regexp.new(start_pattern.gsub("\\\\", "\\").to_s, "i"))
|
102
|
+
if match.nil? || postal_code.index(match[0]) != 0
|
103
|
+
errors.add(AddressField::POSTAL_CODE, "should be valid")
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
data/lib/addressing/version.rb
CHANGED
data/lib/addressing.rb
CHANGED
@@ -12,6 +12,7 @@ require "addressing/administrative_area_type"
|
|
12
12
|
require "addressing/country"
|
13
13
|
require "addressing/default_formatter"
|
14
14
|
require "addressing/dependent_locality_type"
|
15
|
+
require "addressing/field_override"
|
15
16
|
require "addressing/lazy_subdivisions"
|
16
17
|
require "addressing/locale"
|
17
18
|
require "addressing/locality_type"
|
@@ -28,3 +29,10 @@ module Addressing
|
|
28
29
|
|
29
30
|
class UnknownLocaleError < Error; end
|
30
31
|
end
|
32
|
+
|
33
|
+
if defined?(ActiveSupport.on_load)
|
34
|
+
ActiveSupport.on_load(:active_record) do
|
35
|
+
require "addressing/model"
|
36
|
+
extend Addressing::Model
|
37
|
+
end
|
38
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: addressing
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Robin van der Vleuten
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-04-04 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description:
|
14
14
|
email: robinvdvleuten@gmail.com
|
@@ -684,15 +684,16 @@ files:
|
|
684
684
|
- lib/addressing/address.rb
|
685
685
|
- lib/addressing/address_field.rb
|
686
686
|
- lib/addressing/address_format.rb
|
687
|
-
- lib/addressing/address_format_validator.rb
|
688
687
|
- lib/addressing/administrative_area_type.rb
|
689
688
|
- lib/addressing/country.rb
|
690
689
|
- lib/addressing/default_formatter.rb
|
691
690
|
- lib/addressing/dependent_locality_type.rb
|
692
691
|
- lib/addressing/enum.rb
|
692
|
+
- lib/addressing/field_override.rb
|
693
693
|
- lib/addressing/lazy_subdivisions.rb
|
694
694
|
- lib/addressing/locale.rb
|
695
695
|
- lib/addressing/locality_type.rb
|
696
|
+
- lib/addressing/model.rb
|
696
697
|
- lib/addressing/pattern_type.rb
|
697
698
|
- lib/addressing/postal_code_type.rb
|
698
699
|
- lib/addressing/postal_label_formatter.rb
|
File without changes
|