address_concern 2.0.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 54db12d5f83e9438e61c47552eba316511be4cbc69200bee3e51568a10c2c41e
4
+ data.tar.gz: 73a84002eeafb49d0536d2bf5de94391410b3b4d873633ba62f2fd3e42df8ab5
5
+ SHA512:
6
+ metadata.gz: ac7f541ac00b56b64c9a6e8f6cc7a49ee423cce621c90a13173ddc7e4c852883d5f5a2ad14bca967b2d7c7fcc9678a7b8062bb580c30baa43bb656e681b7fed9
7
+ data.tar.gz: 305160aabeca32990a9aa74aa2519b6b58b54c7354985ccbb1677fc1ec370b5c0f104319541834c33865f86079f10d4f45b31342be2d2656e90ade6eb42a85fa
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ lib/**/*.rb
2
+ bin/*
3
+ -
4
+ features/**/*.feature
5
+ LICENSE.txt
data/.gitignore ADDED
@@ -0,0 +1,8 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
5
+ spec/test.log
6
+ .byebug_history
7
+ Gemfile.lock
8
+ tmp/
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --colour
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ ruby-2.7.4
data/CHANGELOG ADDED
@@ -0,0 +1,3 @@
1
+ Tue, Mar 8, 2011
2
+ - - - - - - - - -
3
+ - Initial Release
data/Gemfile ADDED
@@ -0,0 +1,7 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in address_concern.gemspec
4
+ gemspec
5
+
6
+ gem 'pry'
7
+ gem 'byebug'
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ Copyright (c) 2011 Paul Campbell
2
+ Copyright (c) 2011-2018 Tyler Rick
3
+
4
+ Permission is hereby granted, free of charge, to any person obtaining
5
+ a copy of this software and associated documentation files (the
6
+ "Software"), to deal in the Software without restriction, including
7
+ without limitation the rights to use, copy, modify, merge, publish,
8
+ distribute, sublicense, and/or sell copies of the Software, and to
9
+ permit persons to whom the Software is furnished to do so, subject to
10
+ the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be
13
+ included in all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,19 @@
1
+ require 'bundler/gem_tasks'
2
+
3
+ #---------------------------------------------------------------------------------------------------
4
+ require 'rspec/core'
5
+ require 'rspec/core/rake_task'
6
+ RSpec::Core::RakeTask.new(:spec) do |spec|
7
+ spec.pattern = FileList['spec/**/*_spec.rb']
8
+ end
9
+
10
+ desc "Start a console with this version of library loaded"
11
+ task :console do
12
+ require 'bundler/setup'
13
+ require 'address_concern'
14
+ require 'irb'
15
+ ARGV.clear
16
+ IRB.start
17
+ end
18
+
19
+ task :default => :spec
data/Readme.md ADDED
@@ -0,0 +1,231 @@
1
+ # Address Concern
2
+
3
+ A reusable polymorphic `Address` model concern for your Rails apps.
4
+
5
+ # Installation
6
+
7
+ Add `address_concern` to your `Gemfile`:
8
+
9
+ gem 'address_concern'
10
+
11
+ Then run the generator to create your addresses table:
12
+
13
+ rails generate address_concern:install
14
+ rake db:migrate
15
+
16
+ You now have an `Address` model that you can use in your app just as if it were in your `app/models` directory.
17
+
18
+ # Usage
19
+
20
+ ## Base usage
21
+
22
+ ```ruby
23
+ class Address < ApplicationRecord
24
+ include AddressConcern::Address
25
+ end
26
+ ```
27
+
28
+ ## `belongs_to_address`
29
+
30
+ `AddressConcern::AddressAssociations` is automatically included into `ActiveRecord::Base` and
31
+ provides a few macros for defining associations with your app's Address model.
32
+
33
+ ```ruby
34
+ class Person < ApplicationRecord
35
+ belongs_to_address
36
+ end
37
+
38
+ person = Person.new
39
+ person.build_address(address: '...')
40
+ ```
41
+
42
+ ## Multiple addresses on same model
43
+
44
+ ```ruby
45
+ class User < ApplicationRecord
46
+ belongs_to_address :shipping_address
47
+ belongs_to_address :billing_address
48
+ end
49
+
50
+ user = User.new
51
+ shipping_address = user.build_shipping_address(address: '...')
52
+ billing_address = user.build_billing_address( address: '...')
53
+ ```
54
+
55
+ See "Adding an `address` association to your ActiveRecord models" section for more examples of
56
+ configuration your associations.
57
+
58
+
59
+ # Adding an `address` association to your ActiveRecord models
60
+
61
+ You can add an address association (or multiple) to any model that has an address.
62
+
63
+ You can associate with the address via a `belongs_to`, `has_one`, or `has_many` — whichever makes
64
+ the most sense for your use case.
65
+
66
+ You can either use standard ActiveRecord association macros, like this:
67
+
68
+ ```ruby
69
+ class Person < ApplicationRecord
70
+ belongs_to :address
71
+ end
72
+ ```
73
+
74
+ ... or use the provided macros:
75
+
76
+ ## `belongs_to_address`
77
+
78
+ ```ruby
79
+ class Person < ApplicationRecord
80
+ belongs_to_address
81
+ end
82
+
83
+ person = Person.new
84
+ person.build_address(address: '...')
85
+ ```
86
+
87
+ If needed, you can pass a name as well as options for the `belongs_to` and (optional) inverse `has_one`
88
+ associations.
89
+
90
+ ```ruby
91
+ class Child < ApplicationRecord
92
+ belongs_to_address inverse: false
93
+ belongs_to_address :secret_hideout, inverse: {name: :child_for_secret_hideout}
94
+ end
95
+
96
+ child = Child.new
97
+ child.build_secret_hideout(address: '...')
98
+ ```
99
+
100
+ ## `has_address`
101
+
102
+ `has_address` creates a `has_one :address` association:
103
+
104
+ ```ruby
105
+ class Company < ApplicationRecord
106
+ has_address
107
+ end
108
+ ```
109
+
110
+ ```
111
+ company = company.new
112
+ address = company.build_address(address: '...')
113
+ ```
114
+
115
+ This also adds a polymorphic `addressable` association on the Address model (not available if you're
116
+ using `belongs_to :address` on your addressable models):
117
+
118
+ ```ruby
119
+ belongs_to :addressable, :polymorphic => true
120
+ ```
121
+
122
+ ## `has_addresses`
123
+
124
+ `has_addresses` creates a `has_many :addresses` association:
125
+
126
+ ```ruby
127
+ class User < ApplicationRecord
128
+ has_addresses
129
+ end
130
+ ```
131
+
132
+ If you want to have several *individually accessible* addresses associated with a single model (such
133
+ as a separate shipping and billing address), you can do something like this:
134
+
135
+ ```ruby
136
+ class User < ApplicationRecord
137
+ has_addresses :types => [:physical, :shipping, :billing]
138
+ end
139
+ ```
140
+
141
+ Then you can refer to them by name, like this:
142
+
143
+ ```ruby
144
+ shipping_address = user.build_shipping_address(address: 'Some address')
145
+ user.shipping_address # => shipping_address
146
+ ```
147
+
148
+ Note that you aren't *limited* to only the address types you specifically list in your
149
+ `has_addresses` declaration; you can still add and retrieve other addresses using the `has_many
150
+ :addresses` association:
151
+
152
+ ```ruby
153
+ vacation_address = user.addresses.build(address: 'Vacation', :address_type => 'Vacation')
154
+ user.addresses # => [shipping_address, vacation_address]
155
+ ```
156
+
157
+ # Country/state database
158
+
159
+ Country/state data comes from the [`carmen`](https://github.com/carmen-ruby/carmen) gem.
160
+
161
+ - You can set the country either by using the `country=` writer (if you want to use a country name
162
+ as input in your frontend) or the `country_code=` writer (if you want to use a country code as
163
+ input). It will automatically update the other column for you and keep both of them up-to-date.
164
+ - The country name is stored in the `country` attribute (most common use case).
165
+ - Country codes can be optionally get/set via the `country_code2` (ISO 3166-1 alpha-2 codes)
166
+ (aliased as `country_code`) or `country_code3` attributes.
167
+ - Be aware that if the country you entered isn't recognized (in Carmen's database), it will be
168
+ rejected and the country field reset to nil. This should probably be considered a bug and be fixed
169
+ in a later release (using validations instead).
170
+
171
+ Other notes regarding country:
172
+
173
+ - Added some special handling of UK countries, since Carmen doesn't recognize 'England', etc. as
174
+ countries but we want to allow those country names to be stored since they may be a part of the
175
+ address you want to preserve.
176
+
177
+ # View helpers
178
+
179
+ Because this gem depends on [`carmen`](https://github.com/carmen-ruby/carmen), you have access to
180
+ its `country_select` and `state_select` helpers.
181
+
182
+ # Related Projects
183
+
184
+ (Along with some feature/API ideas that we may want to incorporate (pull requests welcome!).)
185
+
186
+ - https://github.com/ankane/mainstreet — A standard US address model for Rails
187
+ - Use `alias_attribute` to map existing field names
188
+ - Add new fields like `original_attributes` and `verification_info`
189
+ - Uses `SmartyStreets` to verify addresses (`valid?` returns false).
190
+ - [`acts_as_address` association macro](https://github.com/ankane/mainstreet/blob/master/lib/mainstreet.rb)
191
+ - [`Address` model generator](https://github.com/ankane/mainstreet/blob/master/lib/generators/mainstreet/address_generator.rb)
192
+ - `acts_as_address` could potentially be included into our `Address` model and both gems used together
193
+
194
+ - https://github.com/yrgoldteeth/whereabouts — A simple rails plugin that adds a polymorphic address model
195
+ - `has_whereabouts :location, {:geocode => true}`
196
+ - `has_whereabouts :location, {:validate => [:city, :state, :zip]}`
197
+ - [`has_whereabouts` association macro](https://github.com/yrgoldteeth/whereabouts/blob/master/lib/whereabouts_methods.rb)
198
+ - [`Address` model generator](https://github.com/yrgoldteeth/whereabouts/blob/master/lib/generators/address/templates/address.rb)
199
+
200
+ - https://github.com/wilbert/addresses — An Address engine to use Country, State, City and Neighborhood models
201
+ - Allows you use these models: `Country`, `State` (belongs to country), `City` (belongs to State), `Neighborhood` (belongs to city), `Address` (Belongs to `Neighborhood` and `City`, because neighborhood is not required)
202
+ - `address.city = Address::City.find(city_id)`
203
+ - `mount Addresses::Engine => "/addresses"`
204
+ - [`Address` model](https://github.com/wilbert/addresses/blob/master/app/models/addresses/address.rb)
205
+
206
+ - https://github.com/huerlisi/has_vcards — Rails plugin providing VCard like contact and address models and helpers
207
+ - [`Address` model](https://github.com/huerlisi/has_vcards/blob/master/app/models/has_vcards/address.rb)
208
+
209
+ Not maintained for 3+ years:
210
+ - https://github.com/mobilityhouse/acts_as_addressable — Make your models addressable
211
+ - `acts_as_addressable :postal, :billing`
212
+ - [`acts_as_addressable` association macro](https://github.com/mobilityhouse/acts_as_addressable/blob/master/lib/acts_as_addressable/addressable.rb)
213
+ - [`Address` model generator](https://github.com/mobilityhouse/acts_as_addressable/blob/master/lib/generators/acts_as_addressable/templates/address.rb)
214
+ - https://github.com/mariusz360/postally_addressable — Add postal addresses to your models
215
+ - [`has_postal_address` association macro](https://github.com/mariusz360/postally_addressable/blob/master/lib/postally_addressable/has_postal_address.rb)
216
+ - [`PostalAddress` model](https://github.com/mariusz360/postally_addressable/blob/master/app/models/postal_address.rb)
217
+ - `alias_attribute :state, :province`
218
+ - https://github.com/nybblr/somewhere — Serialized address class for use with Rails models. Like it should be.
219
+ - `address :billing, :postal_code => :zip, :include_prefix => false`
220
+ - `address.to_hash :exclude => [:country]`
221
+ - `address.to_s :country => false`
222
+ - [`Address` model](https://github.com/nybblr/somewhere/blob/master/lib/address.rb)
223
+ - [`address` association macro](https://github.com/nybblr/somewhere/blob/master/lib/somewhere.rb)
224
+ - https://github.com/rumblelabs/is_addressable
225
+
226
+ # License
227
+
228
+ Licensed under the MIT License.
229
+
230
+ See LICENSE.txt for further details.
231
+
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 1.0.1
@@ -0,0 +1,33 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "address_concern/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "address_concern"
7
+ s.version = AddressConcern.version
8
+ s.authors = ["Paul Campbell", "Tyler Rick"]
9
+ s.email = ["paul@rslw.com", "tyler@tylerrick.com"]
10
+ s.homepage = %q{http://github.com/TylerRick/address_concern}
11
+ s.summary = %q{A reusable Address model for your Rails apps}
12
+ s.description = s.summary
13
+ s.licenses = ["MIT"]
14
+
15
+ s.add_dependency "rake"
16
+ s.add_dependency "cucumber"
17
+ s.add_dependency "rails", ">= 4.0"
18
+ s.add_dependency "activerecord", ">= 4.0"
19
+ s.add_dependency "activesupport", ">= 4.0"
20
+ s.add_dependency "carmen", '>= 1.1.1'
21
+ s.add_dependency "attribute_normalizer"
22
+ s.add_dependency "active_record_ignored_attributes"
23
+ s.add_dependency "facets"
24
+
25
+ s.add_development_dependency 'rspec'
26
+ s.add_development_dependency 'sqlite3'
27
+ #s.add_development_dependency 'mysql2', '~>0.2.11'
28
+
29
+ s.files = `git ls-files`.split("\n")
30
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
31
+ #s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
32
+ s.require_paths = ["lib"]
33
+ end
data/bin/console ADDED
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'bundler/setup'
5
+ require 'address_concern'
6
+
7
+ # You can add fixtures and/or initialization code here to make experimenting
8
+ # with your gem easier. You can also use a different console, if you like.
9
+
10
+ require_relative "../spec/spec_helper"
11
+ require "pry"
12
+ Pry.start
@@ -0,0 +1,8 @@
1
+ ---
2
+ en:
3
+ world:
4
+ id:
5
+ jw:
6
+ jk:
7
+ #name: Jakarta Raya
8
+ name: DKI Jakarta
@@ -0,0 +1,306 @@
1
+ module AddressConcern::Address
2
+ extend ActiveSupport::Concern
3
+ included do
4
+
5
+ #validates_presence_of :name
6
+ #validates_presence_of :address
7
+ #validates_presence_of :state, :if => :state_required?
8
+ #validates_presence_of :country
9
+ #validates_format_of :phone, :with => /^[0-9\-\+ ]*$/
10
+ #validates_format_of :email, :with => /^[^@]*@.*\.[^\.]*$/, :message => 'is invalid. Please enter an address in the format of you@company.com'
11
+ #validates_presence_of :phone, :message => ' is required.'
12
+
13
+ #-------------------------------------------------------------------------------------------------
14
+ normalize_attributes :name, :city, :state, :postal_code, :country
15
+ normalize_attribute :address, :with => [:cleanlines, :strip]
16
+
17
+ #-------------------------------------------------------------------------------------------------
18
+ # Country code
19
+
20
+ def country_alpha2=(code)
21
+ if code.blank?
22
+ write_attribute(:country, nil)
23
+ write_attribute(:country_alpha2, nil)
24
+ write_attribute(:country_alpha3, nil)
25
+
26
+ elsif (country = Carmen::Country.alpha_2_coded(code))
27
+ # Only set it if it's a recognized country code
28
+ write_attribute(:country, country.name)
29
+ write_attribute(:country_alpha2, code)
30
+ end
31
+ end
32
+
33
+ # Aliases
34
+ def country_code
35
+ country_alpha2
36
+ end
37
+ def country_code=(code)
38
+ self.country_alpha2 = code
39
+ end
40
+ def state_code
41
+ state
42
+ end
43
+
44
+ def carmen_country
45
+ Carmen::Country.alpha_2_coded(country_alpha2)
46
+ end
47
+
48
+ def carmen_state
49
+ if (country = carmen_country)
50
+ Address.states_for_country(country).coded(state_code)
51
+ end
52
+ end
53
+
54
+ #-------------------------------------------------------------------------------------------------
55
+ # Country name
56
+
57
+ def country=(name)
58
+ if name.blank?
59
+ write_attribute(:country, nil)
60
+ write_attribute(:country_alpha2, nil)
61
+ write_attribute(:country_alpha3, nil)
62
+ else
63
+ name = recognize_country_name_alias(name)
64
+ if (country = Carmen::Country.named(name))
65
+ write_attribute(:country, country.name)
66
+ write_attribute(:country_alpha2, country.alpha_2_code)
67
+ write_attribute(:country_alpha3, country.alpha_3_code)
68
+ else
69
+ write_attribute(:country, nil)
70
+ write_attribute(:country_alpha2, nil)
71
+ write_attribute(:country_alpha3, nil)
72
+ end
73
+ end
74
+ end
75
+
76
+ def recognize_country_name_alias(name)
77
+ name = case name
78
+ when 'USA'
79
+ when 'The Democratic Republic of the Congo', 'Democratic Republic of the Congo'
80
+ 'Congo, the Democratic Republic of the'
81
+ when 'Republic of Macedonia', 'Macedonia, Republic of', 'Macedonia'
82
+ 'Macedonia, Republic of'
83
+ else
84
+ name
85
+ end
86
+ end
87
+
88
+ # This should not be different from the value stored in the country attribute, but allows you to
89
+ # look it up just to make sure they match (or to update country field to match this).
90
+ def country_name_from_code
91
+ if (country = Carmen::Country.alpha_2_coded(country_alpha2))
92
+ country.name
93
+ end
94
+ end
95
+
96
+ # Aliases
97
+ def country_name
98
+ country
99
+ end
100
+ def country_name=(name)
101
+ self.country = name
102
+ end
103
+
104
+ #════════════════════════════════════════════════════════════════════════════════════════════════════
105
+ # State/province options for country
106
+
107
+ # This is useful if want to list the state options allowed for a country in a select box and
108
+ # restrict entry to only officially listed state options.
109
+ # It is not required in the postal address for all countries, however. If you only want to show it
110
+ # if it's required in the postal address, you can make it conditional based on
111
+ # state_included_in_postal_address?.
112
+ def self.states_for_country(country)
113
+ return [] unless country
114
+ raise ArgumentError.new('expected a Carmen::Country') unless country.is_a? Carmen::Country
115
+ Carmen::RegionCollection.new(
116
+ if country.name == 'Kenya'
117
+ # https://github.com/jim/carmen/issues/227
118
+ # https://en.wikipedia.org/wiki/Provinces_of_Kenya
119
+ # Kenya's provinces were replaced by a system of counties in 2013.
120
+ # https://en.wikipedia.org/wiki/ISO_3166-2:KE confirms that they are "former" provinces.
121
+ # At the time of this writing, however, it doesn't look like Carmen has been updated to
122
+ # include the 47 counties listed under https://en.wikipedia.org/wiki/ISO_3166-2:KE.
123
+ country.subregions.typed('county')
124
+ elsif country.name == 'France'
125
+ # https://github.com/jim/carmen/issues/228
126
+ # https://en.wikipedia.org/wiki/Regions_of_France
127
+ # In 2016 what had been 27 regions was reduced to 18.
128
+ # France is divided into 18 administrative regions, including 13 metropolitan regions and 5 overseas regions.
129
+ # https://en.wikipedia.org/wiki/ISO_3166-2:FR
130
+ []
131
+ else # Needed for New Zealand, Philippines, Indonesia, and possibly others
132
+ country.subregions.map {|_| _.subregions.any? ? _.subregions : _ }.flatten
133
+ end
134
+ )
135
+ end
136
+ def states_for_country
137
+ self.class.states_for_country(carmen_country)
138
+ end
139
+ alias_method :state_options, :states_for_country
140
+
141
+ def country_with_states?
142
+ states_for_country.any?
143
+ end
144
+
145
+ # Is the state/province required in a postal address?
146
+ # If no, perhaps you want to collect it for other reasons (like seeing which people/things are in
147
+ # the same region). Or for countries where it *may* be included in a postal address but is not
148
+ # required to be included.
149
+ def state_required_in_postal_address?
150
+ [
151
+ 'Australia',
152
+ 'Brazil',
153
+ 'Canada',
154
+ 'Mexico',
155
+ 'United States',
156
+ 'Italy',
157
+ 'Venezuela',
158
+ ].include? country_name
159
+ end
160
+ def state_possibly_included_in_postal_address?
161
+ # https://ux.stackexchange.com/questions/64665/address-form-field-for-region
162
+ # http://www.bitboost.com/ref/international-address-formats/denmark/
163
+ # http://www.bitboost.com/ref/international-address-formats/poland/
164
+ return true if state_required_in_postal_address?
165
+ return false if [
166
+ 'Algeria',
167
+ 'Argentina',
168
+ 'Austria',
169
+ 'Denmark',
170
+ 'France',
171
+ 'Germany',
172
+ 'Indonesia',
173
+ 'Ireland',
174
+ 'Israel',
175
+ 'Netherlands',
176
+ 'New Zealand',
177
+ 'Poland',
178
+ 'Sweden',
179
+ 'United Kingdom',
180
+ ].include? country_name
181
+ # Default:
182
+ country_with_states?
183
+ end
184
+
185
+ # It's not called a "State" in all countries.
186
+ # In some countries, it could technically be multiple different types of regions:
187
+ # - In United States, it could be a state or an outlying region or a district or an APO
188
+ # - In Canada, it could be a province or a territory.
189
+ # This attempts to return the most common, expected name for this field.
190
+ # See also: https://ux.stackexchange.com/questions/64665/address-form-field-for-region
191
+ #
192
+ # To see what it should be called in all countries known to Carmen:
193
+ # Country.countries_with_states.map {|country| [country.name, Address.new(country_name: country.name).state_label] }.to_h
194
+ # => {"Afghanistan"=>"Province",
195
+ # "Armenia"=>"Province",
196
+ # "Angola"=>"Province",
197
+ # "Argentina"=>"Province",
198
+ # "Austria"=>"State",
199
+ # "Australia"=>"State",
200
+ # ...
201
+ def state_label
202
+ # In UK, it looks like they (optionally) include the *county* in their addresses. They don't actually have "states" per se.
203
+ # Reference: http://bitboost.com/ref/international-address-formats/united-kingdom/
204
+ # Could also limit to Countries (England, Scotland, Wales) and Provinces (Northern Ireland).
205
+ # Who knows. The UK's subregions are a mess.
206
+ # If allowing the full list of subregions from https://en.wikipedia.org/wiki/ISO_3166-2:GB,
207
+ # perhaps Region is a better, more inclusive term.
208
+ if country_name.in? ['United Kingdom']
209
+ 'Region'
210
+ elsif state_options.any?
211
+ state_options[0].type.capitalize
212
+ end
213
+ end
214
+
215
+ def state_name
216
+ carmen_state ? carmen_state.name : state
217
+ end
218
+
219
+ #════════════════════════════════════════════════════════════════════════════════════════════════════
220
+
221
+ def empty?
222
+ [:address, :city, :state, :postal_code, :country].all? {|_|
223
+ !self[_].present?
224
+ }
225
+ end
226
+
227
+ def started_filling_out?
228
+ [:address, :city, :state, :postal_code, :country].any? {|_|
229
+ self[_].present?
230
+ }
231
+ end
232
+
233
+ #════════════════════════════════════════════════════════════════════════════════════════════════════
234
+ # Formatting for humans
235
+
236
+ # Lines of a postal address
237
+ def lines
238
+ [
239
+ name,
240
+ address.to_s.lines.to_a,
241
+ city_line,
242
+ country_name,
243
+ ].flatten.reject(&:blank?)
244
+ end
245
+
246
+ # Used by #lines
247
+ #
248
+ # Instead of using `state` method (which is really state_code). That's fine for some countries
249
+ # like US, Canada, Australia but not other countries (presumably).
250
+ #
251
+ # TODO: Put postal code and city in a different order, as that countries conventions dictate.
252
+ # See http://bitboost.com/ref/international-address-formats/new-zealand/
253
+ #
254
+ def city_line
255
+ [
256
+ #[city, state].reject(&:blank?).join(', '),
257
+ [city, state_for_postal_address].reject(&:blank?).join(', '),
258
+ postal_code,
259
+ ].reject(&:blank?).join(' ')
260
+ end
261
+
262
+ def city_state_code
263
+ [city, state].reject(&:blank?).join(', ')
264
+ end
265
+
266
+ def city_state_name
267
+ [city, state_name].reject(&:blank?).join(', ')
268
+ end
269
+
270
+ def city_state_country
271
+ [city_state_name, country_name].join(', ')
272
+ end
273
+
274
+ def state_for_postal_address
275
+ # Possibly others use a code? But seems safer to default to a name until confirmed that they use
276
+ # a code.
277
+ if country_name.in? ['United States', 'Canada', 'Australia']
278
+ state_code
279
+ elsif state_possibly_included_in_postal_address?
280
+ state_name
281
+ else
282
+ ''
283
+ end
284
+ end
285
+
286
+ #════════════════════════════════════════════════════════════════════════════════════════════════════
287
+ # Misc. output
288
+
289
+ def parts
290
+ [
291
+ name,
292
+ address.to_s.lines.to_a,
293
+ city,
294
+ state_name,
295
+ postal_code,
296
+ country_name,
297
+ ].flatten.reject(&:blank?)
298
+ end
299
+
300
+ def inspect
301
+ inspect_with([:id, :name, :address, :city, :state, :postal_code, :country], ['{', '}'])
302
+ end
303
+
304
+ #-------------------------------------------------------------------------------------------------
305
+ end
306
+ end