Class: Worldwide::Region
- Inherits:
-
Object
- Object
- Worldwide::Region
- Defined in:
- lib/worldwide/region.rb
Constant Summary collapse
- REQUIRED =
When faced with the question, “Is a postal code required in this country?”, we treat the answer as a tri-state configuration item. “Recommended” means that we recommend that it be provided, but you may still leave the zip field blank.
"required"- RECOMMENDED =
"recommended"- OPTIONAL =
"optional"- INSPECTION_FIELDS =
The default ‘.inspect` isn’t a good fit for Region, because it can end up dumping a lot of info as it walks the hierarchy of descendants. So, instead, we provide our own ‘.inspect` that only shows a restricted subset of the object’s fields.
[ :alpha_three, :building_number_required, :currency, :example_city, :flag, :format, :group, :group_name, :cldr_code, :iso_code, :languages, :neighbours, :numeric_three, :week_start_day, :unit_system, :zip_autofill_enabled, :zip_example, :zip_regex, :zip_requirement, ]
Instance Attribute Summary collapse
-
#alpha_three ⇒ Object
readonly
ISO-3166 three-letter code for this region, if there is one.
-
#building_number_may_be_in_address2 ⇒ Object
In some countries, an address may have the building number in address2.
-
#building_number_required ⇒ Object
In some countries, every address must have a building number.
-
#cldr_code ⇒ Object
readonly
The CLDR code for this region.
-
#code_alternates ⇒ Object
Alternate codes which may be used to designate this region.
-
#currency ⇒ Object
The suggested currency for use in this region.
-
#example_city ⇒ Object
A major city in the given region that can be used as an example.
-
#flag ⇒ Object
Unicode codepoints for this region’s flag emoji.
-
#format ⇒ Object
Hash of strings denoting how to format an address in this region.
-
#group ⇒ Object
The string that results from appending “ Countries” to the adjectival form of the #group_name.
-
#group_name ⇒ Object
The continent that this region is part of.
-
#hide_provinces_from_addresses ⇒ Object
If this flag is set, then we support provinces “under the hood” for this country, but we do not show them as part of a formatted address.
-
#iso_code ⇒ Object
readonly
The ISO-3166-2 code for this region (e.g. “CA”, “CA-ON”) or, if there is no alpha-2 code defined for this region, a numeric code (e.g. “001”).
-
#languages ⇒ Object
Languages that are commonly used in this region.
-
#legacy_code ⇒ Object
readonly
The code used by the legacy Shopify ecosystem for this region.
-
#legacy_name ⇒ Object
readonly
The name used by the legacy Shopify ecosystem for this region.
-
#neighbours ⇒ Object
iso_code values of regions (subdivisions) within the same country that border this region.
-
#numeric_three ⇒ Object
readonly
The ISO-3166-1 three-digit code for this region (returned as a string to preserve leading zeroes), e.g., “003”.
-
#parents ⇒ Object
A region may have more than one parent.
-
#partial_zip_regex ⇒ Object
Some countries have a multi-part postal code, and we may in some cases encounter only the first part.
-
#phone_number_prefix ⇒ Object
The telephone country dialing code for this region.
-
#province_optional ⇒ Object
If true, then the province is optional for addresses in this region.
-
#tags ⇒ Object
tags that help us group the region, e.g.
-
#tax_name ⇒ Object
readonly
Value Added Tax (Sales Tax) name Note that this should really be translated; showing this untranslated name to users is a bad idea.
-
#tax_rate ⇒ Object
readonly
“generic” VAT tax rate on “most” goods.
-
#timezone ⇒ Object
If the region is within a single timezone, its Olson name will be given here.
-
#timezones ⇒ Object
If the region spans multiple timezones (and it has postal codes), then this attribute will contain a hash table mapping from timezone name to a list of postal code prefixes.
-
#unit_system ⇒ Object
The measurement system in use in this region.
-
#use_zone_code_as_short_name ⇒ Object
true iff zone.iso_code should be returned as the .short_name for zones of this region.
-
#week_start_day ⇒ Object
Day of the week (English language string) on which the week is considered to start in this region.
-
#zip_autofill_enabled ⇒ Object
Some regions have only a single postal code value.
-
#zip_example ⇒ Object
An example of a valid postal code for this region.
-
#zip_prefixes ⇒ Object
A list of character sequences with which a postal code in this region may start.
-
#zip_regex ⇒ Object
A regular expression which postal codes in this region must match.
-
#zip_requirement ⇒ Object
Is a zip value required in this region? (Possible values: “optional”, “recommended”, “required”).
-
#zips_crossing_provinces ⇒ Object
Hash of zips that are valid for more than one province.
-
#zones ⇒ Object
readonly
Regions that are sub-regions of this region.
Instance Method Summary collapse
-
#add_zone(region) ⇒ Object
Relationships.
-
#associated_country ⇒ Object
Attributes.
-
#autofill_zip ⇒ Object
The value with which to autofill the zip, if this region has zip autofill active; otherwise, nil.
-
#city_required? ⇒ Boolean
Does this region require cities to be specified?.
-
#continent? ⇒ Boolean
Is this Region a continent?.
-
#country? ⇒ Boolean
Is this Region considered a “country” (top-level political entity “country or region”) in the view of the legacy Shopify ecosystem?.
- #deprecated? ⇒ Boolean
-
#field(key:) ⇒ Object
An Worldwide::Field that can be used to ask about the field, including labels, error messages, and an autofill value if there is one.
-
#full_name(locale: I18n.locale) ⇒ Object
A user-facing name in the currently-active locale’s language.
-
#has_zip? ⇒ Boolean
Does this region have postal codes?.
-
#initialize(alpha_three: nil, continent: false, country: false, deprecated: false, cldr_code: nil, iso_code: nil, legacy_code: nil, legacy_name: nil, numeric_three: nil, province: false, short_name: nil, tax_name: nil, tax_rate: 0.0, use_zone_code_as_short_name: false) ⇒ Region
constructor
A new instance of Region.
- #inspect ⇒ Object
-
#province? ⇒ Boolean
Is this Region considered a “province” (political subdivision of a “country”)?.
-
#province_optional? ⇒ Boolean
are zones optional for this region?.
-
#short_name ⇒ Object
A short-form name for this region, if there is a conventional short form.
-
#valid_zip?(zip, partial_match: false) ⇒ Boolean
is the given postal code value valid for this region?.
-
#zip_autofill ⇒ Object
If the Region has an autofill zip, return the value that will be autofilled Otherwise, return nil.
-
#zip_required? ⇒ Boolean
is a postal code required for this region?.
-
#zone(code: nil, name: nil, zip: nil) ⇒ Object
returns a Region that is a child of this Region.
Constructor Details
#initialize(alpha_three: nil, continent: false, country: false, deprecated: false, cldr_code: nil, iso_code: nil, legacy_code: nil, legacy_name: nil, numeric_three: nil, province: false, short_name: nil, tax_name: nil, tax_rate: 0.0, use_zone_code_as_short_name: false) ⇒ Region
Returns a new instance of Region.
190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 |
# File 'lib/worldwide/region.rb', line 190 def initialize( alpha_three: nil, continent: false, country: false, deprecated: false, cldr_code: nil, iso_code: nil, legacy_code: nil, legacy_name: nil, numeric_three: nil, province: false, short_name: nil, tax_name: nil, tax_rate: 0.0, use_zone_code_as_short_name: false ) if iso_code.nil? && numeric_three.nil? raise ArgumentError, "At least one of iso_code: and numeric_three: must be provided" end @alpha_three = alpha_three&.to_s&.upcase @continent = continent @country = country @deprecated = deprecated @cldr_code = cldr_code @iso_code = iso_code&.to_s&.upcase @legacy_code = legacy_code @legacy_name = legacy_name @numeric_three = numeric_three&.to_s @province = province @short_name = short_name @tax_name = tax_name @tax_rate = tax_rate @use_zone_code_as_short_name = use_zone_code_as_short_name @building_number_required = false @building_number_may_be_in_address2 = false @currency = nil @flag = nil @format = {} @group = nil @group_name = nil @languages = [] @neighbours = [] @partial_zip_regex = nil @phone_number_prefix = nil = [] @timezone = nil @timezones = {} @unit_system = nil @week_start_day = nil @zip_autofill_enabled = false @zip_example = nil @zip_prefixes = [] @zip_regex = nil @parents = [].to_set @zones = [] end |
Instance Attribute Details
#alpha_three ⇒ Object (readonly)
ISO-3166 three-letter code for this region, if there is one. Otherwise, nil.
43 44 45 |
# File 'lib/worldwide/region.rb', line 43 def alpha_three @alpha_three end |
#building_number_may_be_in_address2 ⇒ Object
In some countries, an address may have the building number in address2. If we are allowed to have a building number in address2, then this will be true.
52 53 54 |
# File 'lib/worldwide/region.rb', line 52 def building_number_may_be_in_address2 @building_number_may_be_in_address2 end |
#building_number_required ⇒ Object
In some countries, every address must have a building number. In others (e.g., GB), some addresses rely on just a building name, not a number. If we require a building number in an address, then this will be true.
48 49 50 |
# File 'lib/worldwide/region.rb', line 48 def building_number_required @building_number_required end |
#cldr_code ⇒ Object (readonly)
The CLDR code for this region.
90 91 92 |
# File 'lib/worldwide/region.rb', line 90 def cldr_code @cldr_code end |
#code_alternates ⇒ Object
Alternate codes which may be used to designate this region
55 56 57 |
# File 'lib/worldwide/region.rb', line 55 def code_alternates @code_alternates end |
#currency ⇒ Object
The suggested currency for use in this region. Note that this may not always be the official currency. E.g., we return USD for VE, not VED.
60 61 62 |
# File 'lib/worldwide/region.rb', line 60 def currency @currency end |
#example_city ⇒ Object
A major city in the given region that can be used as an example
63 64 65 |
# File 'lib/worldwide/region.rb', line 63 def example_city @example_city end |
#flag ⇒ Object
Unicode codepoints for this region’s flag emoji
66 67 68 |
# File 'lib/worldwide/region.rb', line 66 def flag @flag end |
#format ⇒ Object
Hash of strings denoting how to format an address in this region. The format is described in shopify.engineering/handling-addresses-from-all-around-the-world
- address1: a street address (address line 1, with a buliding nmuber and street name)
- address1_with_unit: address line 1 including a subpremise (unit, apartment, etc.)
- edit: the fields to present on an address input form
- show: how to arrange the fields when formatting an address for display
74 75 76 |
# File 'lib/worldwide/region.rb', line 74 def format @format end |
#group ⇒ Object
The string that results from appending “ Countries” to the adjectival form of the #group_name
79 80 81 |
# File 'lib/worldwide/region.rb', line 79 def group @group end |
#group_name ⇒ Object
The continent that this region is part of.
82 83 84 |
# File 'lib/worldwide/region.rb', line 82 def group_name @group_name end |
#hide_provinces_from_addresses ⇒ Object
If this flag is set, then we support provinces “under the hood” for this country, but we do not show them as part of a formatted address. If the province is missing, we will auto-infer it based on the zip (note that this auto-inference may be wrong for some addresses near a border).
87 88 89 |
# File 'lib/worldwide/region.rb', line 87 def hide_provinces_from_addresses @hide_provinces_from_addresses end |
#iso_code ⇒ Object (readonly)
The ISO-3166-2 code for this region (e.g. “CA”, “CA-ON”) or, if there is no alpha-2 code defined for this region, a numeric code (e.g. “001”).
94 95 96 |
# File 'lib/worldwide/region.rb', line 94 def iso_code @iso_code end |
#languages ⇒ Object
Languages that are commonly used in this region. Note that this may not be the same as the languages that are officially recognized there. We present them in alphabetical order by language code.
99 100 101 |
# File 'lib/worldwide/region.rb', line 99 def languages @languages end |
#legacy_code ⇒ Object (readonly)
The code used by the legacy Shopify ecosystem for this region. E.g., for MX-CMX it will return “DF”. This code should never be shown in the user interface. This is the code that was traditionally returned by “country_db”.
105 106 107 |
# File 'lib/worldwide/region.rb', line 105 def legacy_code @legacy_code end |
#legacy_name ⇒ Object (readonly)
The name used by the legacy Shopify ecosystem for this region. E.g., “Sao Tome And Principe” for “ST”. This name should never be shown in the user interface. This name is the name that was traditionally returned by “country_db”.
111 112 113 |
# File 'lib/worldwide/region.rb', line 111 def legacy_name @legacy_name end |
#neighbours ⇒ Object
iso_code values of regions (subdivisions) within the same country that border this region. E.g., for CA-ON, the neighbouring zones are CA-MB, CA-NU and CA-QC.
115 116 117 |
# File 'lib/worldwide/region.rb', line 115 def neighbours @neighbours end |
#numeric_three ⇒ Object (readonly)
The ISO-3166-1 three-digit code for this region (returned as a string to preserve leading zeroes), e.g., “003”.
119 120 121 |
# File 'lib/worldwide/region.rb', line 119 def numeric_three @numeric_three end |
#parents ⇒ Object
A region may have more than one parent. For example, Puerto Rico (PR/US-PR) is associated with both the US and the Caribbean (029)
39 40 41 |
# File 'lib/worldwide/region.rb', line 39 def parents @parents end |
#partial_zip_regex ⇒ Object
Some countries have a multi-part postal code, and we may in some cases encounter only the first part. E.g., the GB code ‘SW1A 1AA` has a first part (outward code) of `SW1A`. When validating such a partial postal code, it must match this regular expression.
124 125 126 |
# File 'lib/worldwide/region.rb', line 124 def partial_zip_regex @partial_zip_regex end |
#phone_number_prefix ⇒ Object
The telephone country dialing code for this region
127 128 129 |
# File 'lib/worldwide/region.rb', line 127 def phone_number_prefix @phone_number_prefix end |
#province_optional ⇒ Object
If true, then the province is optional for addresses in this region.
188 189 190 |
# File 'lib/worldwide/region.rb', line 188 def province_optional @province_optional end |
#tags ⇒ Object
tags that help us group the region, e.g. “EU-member”
145 146 147 |
# File 'lib/worldwide/region.rb', line 145 def end |
#tax_name ⇒ Object (readonly)
Value Added Tax (Sales Tax) name Note that this should really be translated; showing this untranslated name to users is a bad idea.
139 140 141 |
# File 'lib/worldwide/region.rb', line 139 def tax_name @tax_name end |
#tax_rate ⇒ Object (readonly)
“generic” VAT tax rate on “most” goods
142 143 144 |
# File 'lib/worldwide/region.rb', line 142 def tax_rate @tax_rate end |
#timezone ⇒ Object
If the region is within a single timezone, its Olson name will be given here.
148 149 150 |
# File 'lib/worldwide/region.rb', line 148 def timezone @timezone end |
#timezones ⇒ Object
If the region spans multiple timezones (and it has postal codes), then this attribute will contain a hash table mapping from timezone name to a list of postal code prefixes. We can use this information to determine the timezone for a given postal code.
153 154 155 |
# File 'lib/worldwide/region.rb', line 153 def timezones @timezones end |
#unit_system ⇒ Object
The measurement system in use in this region.
160 161 162 |
# File 'lib/worldwide/region.rb', line 160 def unit_system @unit_system end |
#use_zone_code_as_short_name ⇒ Object
true iff zone.iso_code should be returned as the .short_name for zones of this region
163 164 165 |
# File 'lib/worldwide/region.rb', line 163 def use_zone_code_as_short_name @use_zone_code_as_short_name end |
#week_start_day ⇒ Object
Day of the week (English language string) on which the week is considered to start in this region. E.g., “sunday”
157 158 159 |
# File 'lib/worldwide/region.rb', line 157 def week_start_day @week_start_day end |
#zip_autofill_enabled ⇒ Object
Some regions have only a single postal code value. In such cases, we can autofill the zip field with the value from zip_example.
167 168 169 |
# File 'lib/worldwide/region.rb', line 167 def zip_autofill_enabled @zip_autofill_enabled end |
#zip_example ⇒ Object
An example of a valid postal code for this region
170 171 172 |
# File 'lib/worldwide/region.rb', line 170 def zip_example @zip_example end |
#zip_prefixes ⇒ Object
A list of character sequences with which a postal code in this region may start.
176 177 178 |
# File 'lib/worldwide/region.rb', line 176 def zip_prefixes @zip_prefixes end |
#zip_regex ⇒ Object
A regular expression which postal codes in this region must match.
179 180 181 |
# File 'lib/worldwide/region.rb', line 179 def zip_regex @zip_regex end |
#zip_requirement ⇒ Object
Is a zip value required in this region? (Possible values: “optional”, “recommended”, “required”)
173 174 175 |
# File 'lib/worldwide/region.rb', line 173 def zip_requirement @zip_requirement end |
#zips_crossing_provinces ⇒ Object
Hash of zips that are valid for more than one province
182 183 184 |
# File 'lib/worldwide/region.rb', line 182 def zips_crossing_provinces @zips_crossing_provinces end |
#zones ⇒ Object (readonly)
Regions that are sub-regions of this region.
185 186 187 |
# File 'lib/worldwide/region.rb', line 185 def zones @zones end |
Instance Method Details
#add_zone(region) ⇒ Object
Relationships
256 257 258 259 260 261 |
# File 'lib/worldwide/region.rb', line 256 def add_zone(region) return if @zones.include?(region) region.parents << self @zones.append(region) end |
#associated_country ⇒ Object
Attributes
265 266 267 268 269 |
# File 'lib/worldwide/region.rb', line 265 def associated_country return self if country? parent_country end |
#autofill_zip ⇒ Object
The value with which to autofill the zip, if this region has zip autofill active; otherwise, nil.
273 274 275 |
# File 'lib/worldwide/region.rb', line 273 def autofill_zip zip_example if @zip_autofill_enabled end |
#city_required? ⇒ Boolean
Does this region require cities to be specified?
278 279 280 |
# File 'lib/worldwide/region.rb', line 278 def city_required? field(key: :city).autofill(locale: :en).nil? end |
#continent? ⇒ Boolean
Is this Region a continent?
283 284 285 |
# File 'lib/worldwide/region.rb', line 283 def continent? @continent end |
#country? ⇒ Boolean
Is this Region considered a “country” (top-level political entity “country or region”) in the view of the legacy Shopify ecosystem?
289 290 291 |
# File 'lib/worldwide/region.rb', line 289 def country? @country end |
#deprecated? ⇒ Boolean
293 294 295 |
# File 'lib/worldwide/region.rb', line 293 def deprecated? @deprecated end |
#field(key:) ⇒ Object
An Worldwide::Field that can be used to ask about the field, including labels, error messages, and an autofill value if there is one.
299 300 301 302 303 |
# File 'lib/worldwide/region.rb', line 299 def field(key:) return nil unless country? Worldwide::Fields.field(country_code: iso_code, field_key: key) end |
#full_name(locale: I18n.locale) ⇒ Object
A user-facing name in the currently-active locale’s language.
306 307 308 309 310 311 312 313 |
# File 'lib/worldwide/region.rb', line 306 def full_name(locale: I18n.locale) lookup_code = cldr_code if /^[0-9]+$/.match?(lookup_code) || lookup_code.length < 3 Worldwide::Cldr.t("territories.#{lookup_code}", locale: locale, default: legacy_name) else Worldwide::Cldr.t("subdivisions.#{lookup_code}", locale: locale, default: legacy_name) end end |
#has_zip? ⇒ Boolean
Does this region have postal codes?
316 317 318 |
# File 'lib/worldwide/region.rb', line 316 def has_zip? !!format["show"]&.include?("{zip}") end |
#inspect ⇒ Object
250 251 252 |
# File 'lib/worldwide/region.rb', line 250 def inspect "#<#{self.class.name}:#{object_id} #{inspected_fields}>" end |
#province? ⇒ Boolean
Is this Region considered a “province” (political subdivision of a “country”)?
321 322 323 |
# File 'lib/worldwide/region.rb', line 321 def province? @province end |
#province_optional? ⇒ Boolean
are zones optional for this region?
395 396 397 |
# File 'lib/worldwide/region.rb', line 395 def province_optional? province_optional || !@zones&.any?(&:province?) end |
#short_name ⇒ Object
A short-form name for this region, if there is a conventional short form. E.g., returns “ON” for “CA-ON”, but “Tokyo” for “JP-13”.
327 328 329 |
# File 'lib/worldwide/region.rb', line 327 def short_name @short_name || full_name end |
#valid_zip?(zip, partial_match: false) ⇒ Boolean
is the given postal code value valid for this region?
386 387 388 389 390 391 392 |
# File 'lib/worldwide/region.rb', line 386 def valid_zip?(zip, partial_match: false) normalized = Zip.normalize( country_code: province? && associated_country.iso_code ? associated_country.iso_code : iso_code, zip: zip, ) valid_normalized_zip?(normalized, partial_match: partial_match) end |
#zip_autofill ⇒ Object
If the Region has an autofill zip, return the value that will be autofilled Otherwise, return nil
372 373 374 |
# File 'lib/worldwide/region.rb', line 372 def zip_autofill return zip_example if zip_autofill_enabled end |
#zip_required? ⇒ Boolean
is a postal code required for this region?
377 378 379 380 381 382 383 |
# File 'lib/worldwide/region.rb', line 377 def zip_required? if zip_requirement.nil? !zip_regex.nil? else REQUIRED == zip_requirement end end |
#zone(code: nil, name: nil, zip: nil) ⇒ Object
returns a Region that is a child of this Region
332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 |
# File 'lib/worldwide/region.rb', line 332 def zone(code: nil, name: nil, zip: nil) count = 0 count += 1 unless code.nil? count += 1 unless name.nil? count += 1 unless zip.nil? unless count == 1 # More than one of code, name, or zip was given raise ArgumentError, "Must specify exactly one of code:, name: or zip:." end if Worldwide::Util.present?(code) search_code = code.to_s.upcase alt_search_code = "#{search_code[0..1]}-#{search_code[2..-1]}" zones.find do |region| [search_code, alt_search_code].any? do |candidate| candidate == subdivision_code(region.iso_code) || candidate == region.alpha_three || candidate == region.iso_code || candidate == region.legacy_code || candidate == region.numeric_three || region&.code_alternates&.any?(candidate) end end elsif Worldwide::Util.present?(name) search_name = name.upcase zones.find do |region| search_name == region.legacy_name.upcase || search_name == region.full_name.upcase || search_name == I18n.with_locale(:en) { region.full_name.upcase } end else # Worldwide::Util.present?(zip) zone_by_normalized_zip(Zip.normalize(country_code: iso_code, zip: zip)) end || Worldwide.unknown_region end |