address_concern 2.1.0 → 3.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 +4 -4
- data/.tool-versions +2 -0
- data/Changelog.md +27 -0
- data/address_concern.gemspec +2 -0
- data/config/locales/en.yml +6 -0
- data/config/{locale → locales}/overlay/en/id.yml +0 -0
- data/{app/models/concerns → lib/address_concern}/address.rb +96 -48
- data/{app/models/concerns → lib/address_concern}/address_associations.rb +0 -0
- data/{app/models/concerns → lib/address_concern}/attributes_slice.rb +0 -0
- data/lib/address_concern/engine.rb +1 -7
- data/{app/models/concerns → lib/address_concern}/inspect_base.rb +1 -0
- data/lib/address_concern/version.rb +1 -1
- data/lib/address_concern.rb +27 -5
- data/spec/models/acts_as_address_spec.rb +4 -4
- data/spec/models/address_spec.rb +93 -13
- data/spec/support/shoulda_matchers.rb +8 -0
- metadata +40 -9
- data/.ruby-version +0 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bcde48cb5114abd702acfe50d80c0f9d1a384faa94b750627a0b5fe17a6d1fc4
|
4
|
+
data.tar.gz: 5b049ab69ee5882d7747b5de0a6de40ef41aca78b3a5c565e2328c0bac87fac9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 35e52d1a95952bb73d9a6267ff4e1a59ca10b311f8e69a4906110eb09a4c21b4cd2e4c5d3c5e08899d843ab5f919a77960dcb2775f01ae729bcc8b473752f643
|
7
|
+
data.tar.gz: ac471eda04dc70ad516b9e6f79179a17b31f54ede686e504266d1c56e1da1014bb21877d27ea3c789675f6bb6ad7bef4102b5b52c3d71d0498de5bf9b0596622
|
data/.tool-versions
ADDED
data/Changelog.md
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
## 3.0.0
|
2
|
+
|
3
|
+
Breaking changes:
|
4
|
+
|
5
|
+
- Rename `.address_attributes`, `#address_lines`, … to something less ambiguous so it's clear whether we're talking about street address or all address attributes
|
6
|
+
- Rename .address_attr_names -> .street_address_attr_names
|
7
|
+
- Rename #address_lines -> #street_address_lines
|
8
|
+
|
9
|
+
It was confusing having .address_attributes and #address_attributes referring to completely
|
10
|
+
different sets of attributes.
|
11
|
+
|
12
|
+
- Change the default value for `street_address.attributes` config to a more strict Regex pattern to avoid
|
13
|
+
matching `'foo_address'`: `column_names.grep(/^address$|^address_\d$/)`
|
14
|
+
|
15
|
+
Fixes:
|
16
|
+
|
17
|
+
- Fix `.states_for_country` to always return a `Carmen::RegionCollection` rather than sometimes a
|
18
|
+
- plain Array `[]`, so that we won't get an error if we try to call `coded` on the returned collection.
|
19
|
+
|
20
|
+
- Fix error with rails 5.2
|
21
|
+
|
22
|
+
Added:
|
23
|
+
|
24
|
+
- Add experimental support for `:on_unknown` config and state validation (added
|
25
|
+
`validate_state_for_country`)
|
26
|
+
|
27
|
+
|
data/address_concern.gemspec
CHANGED
@@ -18,9 +18,11 @@ Gem::Specification.new do |s|
|
|
18
18
|
s.add_dependency "activesupport", ">= 4.0"
|
19
19
|
s.add_dependency "carmen", '>= 1.1.1'
|
20
20
|
#s.add_dependency "attribute_normalizer"
|
21
|
+
s.add_dependency "zeitwerk"
|
21
22
|
|
22
23
|
s.add_development_dependency 'active_record_ignored_attributes' # for be_same_as
|
23
24
|
s.add_development_dependency 'rspec'
|
25
|
+
s.add_development_dependency 'shoulda-matchers'
|
24
26
|
s.add_development_dependency 'sqlite3'
|
25
27
|
#s.add_development_dependency 'mysql2', '~>0.2.11'
|
26
28
|
|
File without changes
|
@@ -1,7 +1,7 @@
|
|
1
|
-
require_relative '
|
1
|
+
require_relative '../core_extensions/hash/reorder'
|
2
2
|
using Hash::Reorder
|
3
3
|
|
4
|
-
require_relative '
|
4
|
+
require_relative '../core_extensions/string/cleanlines'
|
5
5
|
using String::Cleanlines
|
6
6
|
|
7
7
|
require_relative 'inspect_base'
|
@@ -24,19 +24,6 @@ module Address
|
|
24
24
|
}
|
25
25
|
options = options.deep_symbolize_keys
|
26
26
|
default_config = {
|
27
|
-
state: {
|
28
|
-
#normalize: false,
|
29
|
-
#validate: false,
|
30
|
-
|
31
|
-
code_attribute: column_for_attribute(:state_code).yield_self(¬_null)&.name ||
|
32
|
-
(column_for_attribute(:state).yield_self(¬_null)&.name unless options.dig(:state, :name_attribute).to_s == 'state'),
|
33
|
-
|
34
|
-
name_attribute: column_for_attribute(:state_name).yield_self(¬_null)&.name ||
|
35
|
-
(column_for_attribute(:state).yield_self(¬_null)&.name unless options.dig(:state, :code_attribute).to_s == 'state'),
|
36
|
-
|
37
|
-
on_unknown: ->(value, name_or_code) { },
|
38
|
-
},
|
39
|
-
|
40
27
|
country: {
|
41
28
|
#normalize: false,
|
42
29
|
#validate: false,
|
@@ -50,15 +37,29 @@ module Address
|
|
50
37
|
name_attribute: column_for_attribute(:country_name).yield_self(¬_null)&.name ||
|
51
38
|
(column_for_attribute(:country).yield_self(¬_null)&.name unless options.dig(:country, :code_attribute).to_s == 'country'),
|
52
39
|
|
53
|
-
on_unknown: ->(
|
40
|
+
on_unknown: ->(record, name_or_code, value) { },
|
54
41
|
},
|
55
42
|
|
56
|
-
|
43
|
+
state: {
|
44
|
+
#normalize: false,
|
45
|
+
#validate: false,
|
46
|
+
|
47
|
+
code_attribute: column_for_attribute(:state_code).yield_self(¬_null)&.name ||
|
48
|
+
(column_for_attribute(:state).yield_self(¬_null)&.name unless options.dig(:state, :name_attribute).to_s == 'state'),
|
49
|
+
|
50
|
+
name_attribute: column_for_attribute(:state_name).yield_self(¬_null)&.name ||
|
51
|
+
(column_for_attribute(:state).yield_self(¬_null)&.name unless options.dig(:state, :code_attribute).to_s == 'state'),
|
52
|
+
|
53
|
+
on_unknown: ->(record, name_or_code, carmen_country, value) { },
|
54
|
+
debug_unknown: false
|
55
|
+
},
|
56
|
+
|
57
|
+
street_address: {
|
57
58
|
#normalize: false,
|
58
59
|
#validate: false,
|
59
60
|
|
60
61
|
# Try to auto-detect address columns
|
61
|
-
attributes: column_names.grep(
|
62
|
+
attributes: column_names.grep(/^address$|^address_\d$/),
|
62
63
|
}
|
63
64
|
}
|
64
65
|
@acts_as_address_config = config = {
|
@@ -141,24 +142,25 @@ module Address
|
|
141
142
|
|
142
143
|
#─────────────────────────────────────────────────────────────────────────────────────────────
|
143
144
|
|
144
|
-
def
|
145
|
-
@acts_as_address_config[:address]
|
145
|
+
def street_address_attr_config
|
146
|
+
if @acts_as_address_config[:address]
|
147
|
+
raise "The :address config key has been renamed to :street_address"
|
148
|
+
end
|
149
|
+
@acts_as_address_config[:street_address] || {}
|
146
150
|
end
|
147
151
|
|
148
|
-
|
149
|
-
|
150
|
-
def address_attributes
|
151
|
-
Array(address_attr_config[:attributes]).map(&:to_sym)
|
152
|
+
def street_address_attr_names
|
153
|
+
Array(street_address_attr_config[:attributes]).map(&:to_sym)
|
152
154
|
end
|
153
155
|
|
154
156
|
# Address line 1
|
155
|
-
def
|
156
|
-
|
157
|
+
def street_address_attribute
|
158
|
+
street_address_attr_names[0]
|
157
159
|
end
|
158
160
|
|
159
|
-
def
|
160
|
-
|
161
|
-
column = column_for_attribute(
|
161
|
+
def multi_line_street_address?
|
162
|
+
street_address_attr_names.size == 1 && (
|
163
|
+
column = column_for_attribute(street_address_attribute)
|
162
164
|
column.type == :text
|
163
165
|
)
|
164
166
|
end
|
@@ -168,7 +170,7 @@ module Address
|
|
168
170
|
# AKA configured_address_attributes
|
169
171
|
def address_attr_names
|
170
172
|
[
|
171
|
-
*
|
173
|
+
*street_address_attr_names,
|
172
174
|
:city,
|
173
175
|
state_name_attribute,
|
174
176
|
state_code_attribute,
|
@@ -180,18 +182,22 @@ module Address
|
|
180
182
|
end
|
181
183
|
|
182
184
|
#═════════════════════════════════════════════════════════════════════════════════════════════════
|
183
|
-
# Customizable validation (
|
185
|
+
# Customizable validation (part 1 of 2)
|
186
|
+
# TODO: Finish adding some optional reasonable default validations
|
184
187
|
|
185
188
|
#validates_presence_of :address
|
186
189
|
#validates_presence_of :state, if: :state_required?
|
187
190
|
#validates_presence_of :country
|
188
191
|
|
192
|
+
validate :validate_state_for_country, if: -> { state_config[:validate_code] }
|
193
|
+
|
189
194
|
#═════════════════════════════════════════════════════════════════════════════════════════════════
|
190
195
|
# Attributes
|
191
196
|
|
192
197
|
def _assign_attributes(attributes)
|
193
198
|
attributes = attributes.symbolize_keys
|
194
199
|
attributes = reorder_language_attributes(attributes)
|
200
|
+
attributes = attributes.stringify_keys
|
195
201
|
super(attributes)
|
196
202
|
end
|
197
203
|
|
@@ -215,7 +221,7 @@ module Address
|
|
215
221
|
|
216
222
|
# TODO: automatically normalize if attribute_normalizer/normalizy gem is loaded? add a config option to opt out?
|
217
223
|
#normalize_attributes :city, :state, :postal_code, :country
|
218
|
-
#normalize_attribute *
|
224
|
+
#normalize_attribute *street_address_attr_names, with: [:cleanlines, :strip]
|
219
225
|
|
220
226
|
#═════════════════════════════════════════════════════════════════════════════════════════════════
|
221
227
|
# Country & State (Carmen + custom)
|
@@ -386,7 +392,7 @@ module Address
|
|
386
392
|
if (country = self.class.find_carmen_country_by_code(value))
|
387
393
|
set_country_from_carmen_country(country)
|
388
394
|
else
|
389
|
-
country_config[:on_unknown]
|
395
|
+
on_unknown = country_config[:on_unknown]&.(self, :code, value)
|
390
396
|
write_attribute(self.class.country_code_attribute, value) if self.class.country_code_attribute
|
391
397
|
end
|
392
398
|
end
|
@@ -413,7 +419,7 @@ module Address
|
|
413
419
|
if (country = self.class.find_carmen_country_by_name(value))
|
414
420
|
set_country_from_carmen_country(country)
|
415
421
|
else
|
416
|
-
country_config[:on_unknown]
|
422
|
+
on_unknown = country_config[:on_unknown]&.(self, :name, value)
|
417
423
|
write_attribute(self.class.country_name_attribute, value) if self.class.country_name_attribute
|
418
424
|
end
|
419
425
|
end
|
@@ -458,9 +464,15 @@ module Address
|
|
458
464
|
if carmen_country && (state = self.class.find_carmen_state_by_code(carmen_country, value))
|
459
465
|
set_state_from_carmen_state(state)
|
460
466
|
else
|
461
|
-
|
462
|
-
|
463
|
-
|
467
|
+
if state_config[:debug_unknown]
|
468
|
+
puts carmen_country ? "unknown state code '#{value}'. Valid options: #{states_for_country_str}" : "can't find state without country"
|
469
|
+
end
|
470
|
+
on_unknown = state_config[:on_unknown]&.(self, :code, carmen_country, value)
|
471
|
+
if on_unknown == :find_by_name && carmen_country && (state = self.class.find_carmen_state_by_name(carmen_country, value))
|
472
|
+
set_state_from_carmen_state(state)
|
473
|
+
else
|
474
|
+
write_attribute(self.class.state_code_attribute, value) if self.class.state_code_attribute
|
475
|
+
end
|
464
476
|
end
|
465
477
|
end
|
466
478
|
end
|
@@ -491,7 +503,7 @@ module Address
|
|
491
503
|
set_state_from_carmen_state(state)
|
492
504
|
else
|
493
505
|
#puts carmen_country ? "unknown state name '#{name}'" : "can't find state without country"
|
494
|
-
state_config[:on_unknown]
|
506
|
+
on_unknown = state_config[:on_unknown]&.(self, :name, carmen_country, value)
|
495
507
|
write_attribute(self.class.state_name_attribute, value) if self.class.state_name_attribute
|
496
508
|
end
|
497
509
|
end
|
@@ -515,8 +527,11 @@ module Address
|
|
515
527
|
# It is not required in the postal address for all countries, however. If you only want to show it
|
516
528
|
# if it's required in the postal address, you can make it conditional based on
|
517
529
|
# state_included_in_postal_address?.
|
530
|
+
# @return [Carmen::RegionCollection]
|
518
531
|
def self.states_for_country(country)
|
519
|
-
|
532
|
+
empty_set = Carmen::RegionCollection.new([])
|
533
|
+
return empty_set unless country
|
534
|
+
|
520
535
|
country = find_carmen_country!(country)
|
521
536
|
|
522
537
|
has_states_at_level_1 = country.subregions.any? { |region|
|
@@ -540,7 +555,7 @@ module Address
|
|
540
555
|
# # In 2016 what had been 27 regions was reduced to 18.
|
541
556
|
# # France is divided into 18 administrative regions, including 13 metropolitan regions and 5 overseas regions.
|
542
557
|
# # https://en.wikipedia.org/wiki/ISO_3166-2:FR
|
543
|
-
#
|
558
|
+
# empty_set
|
544
559
|
elsif has_states_at_level_1
|
545
560
|
country.subregions
|
546
561
|
else
|
@@ -669,18 +684,24 @@ module Address
|
|
669
684
|
#════════════════════════════════════════════════════════════════════════════════════════════════════
|
670
685
|
# Street address / Address lines
|
671
686
|
|
687
|
+
def street_address_attributes
|
688
|
+
attributes_slice(
|
689
|
+
*self.class.street_address_attr_names
|
690
|
+
)
|
691
|
+
end
|
692
|
+
|
672
693
|
# Attribute alias for street address line 1
|
673
|
-
#if
|
674
|
-
# unless :
|
675
|
-
# alias_attribute :
|
694
|
+
#if street_address_attribute
|
695
|
+
# unless :street_address == street_address_attribute
|
696
|
+
# alias_attribute :street_address, :"#{street_address_attribute}"
|
676
697
|
# end
|
677
698
|
#end
|
678
699
|
|
679
|
-
def
|
680
|
-
if self.class.
|
700
|
+
def street_address_lines
|
701
|
+
if self.class.multi_line_street_address?
|
681
702
|
address.to_s.cleanlines.to_a
|
682
703
|
else
|
683
|
-
self.class.
|
704
|
+
self.class.street_address_attr_names.map do |attr_name|
|
684
705
|
send attr_name
|
685
706
|
end
|
686
707
|
end
|
@@ -693,7 +714,7 @@ module Address
|
|
693
714
|
def lines
|
694
715
|
[
|
695
716
|
#name,
|
696
|
-
*
|
717
|
+
*street_address_lines,
|
697
718
|
city_line,
|
698
719
|
country_name,
|
699
720
|
].reject(&:blank?)
|
@@ -746,7 +767,7 @@ module Address
|
|
746
767
|
def parts
|
747
768
|
[
|
748
769
|
#name,
|
749
|
-
*
|
770
|
+
*street_address_lines,
|
750
771
|
city,
|
751
772
|
state_name,
|
752
773
|
postal_code,
|
@@ -775,6 +796,33 @@ module Address
|
|
775
796
|
end
|
776
797
|
|
777
798
|
#─────────────────────────────────────────────────────────────────────────────────────────────────
|
799
|
+
end # included do
|
800
|
+
|
801
|
+
#═════════════════════════════════════════════════════════════════════════════════════════════════
|
802
|
+
# Customizable validation (part 2 of 2)
|
803
|
+
# Defining here rather than in included block, so that it is actually defined on the module, which
|
804
|
+
# gives the consumer more flexibility on how to reuse the validation code. You can, for example,
|
805
|
+
# do this:
|
806
|
+
#
|
807
|
+
# validate \
|
808
|
+
# def validate_state_for_country
|
809
|
+
# return unless addressable.is_a?(User)
|
810
|
+
#
|
811
|
+
# super
|
812
|
+
# end
|
813
|
+
|
814
|
+
def validate_state_for_country
|
815
|
+
return unless country_with_states?
|
816
|
+
return unless state_code
|
817
|
+
return if states_for_country.map(&:code).include? state_code
|
818
|
+
|
819
|
+
errors.add self.class.state_code_attribute, :state_not_in_list, country_name: country_name, states_for_country: states_for_country_str
|
820
|
+
# puts %(errors.messages=\n#{(errors.messages).pretty_inspect.indent(4)})
|
821
|
+
end
|
822
|
+
|
823
|
+
def states_for_country_str
|
824
|
+
return unless country_with_states?
|
825
|
+
states_for_country.map(&:code).join(', ')
|
778
826
|
end
|
779
827
|
end
|
780
828
|
end
|
File without changes
|
File without changes
|
@@ -4,15 +4,9 @@ module AddressConcern
|
|
4
4
|
class Engine < ::Rails::Engine
|
5
5
|
engine_name 'address_concern'
|
6
6
|
|
7
|
-
config.autoload_paths += Dir["#{config.root}/app/models/concerns"]
|
8
|
-
config.eager_load_paths += Dir["#{config.root}/app/models/concerns"]
|
9
|
-
|
10
7
|
initializer 'address_concern.active_record' do |app|
|
11
8
|
ActiveSupport.on_load :active_record do
|
12
|
-
#
|
13
|
-
AddressConcern::Address::Base
|
14
|
-
AddressConcern::AddressAssociations
|
15
|
-
# ActiveRecord::Base.extend(AddressConcern::Address::Base)
|
9
|
+
#
|
16
10
|
end
|
17
11
|
end
|
18
12
|
|
data/lib/address_concern.rb
CHANGED
@@ -2,11 +2,33 @@ require 'rails'
|
|
2
2
|
require 'carmen'
|
3
3
|
require 'active_record'
|
4
4
|
|
5
|
-
Carmen.i18n_backend.append_locale_path File.join(File.dirname(__FILE__), '../config/
|
5
|
+
Carmen.i18n_backend.append_locale_path File.join(File.dirname(__FILE__), '../config/locales/overlay/en')
|
6
|
+
|
7
|
+
require 'zeitwerk'
|
8
|
+
loader = Zeitwerk::Loader.for_gem
|
9
|
+
# Note: Because this gem has/is an engine, its "engine files" (under app) are autoload managed by
|
10
|
+
# the parent app. And you can't have more than one loader managing the same root. Therefore we can't
|
11
|
+
# do this:
|
12
|
+
# loader.push_dir("#{__dir__}/../app/models")
|
13
|
+
# That is one reason, the models/concerns have been moved to lib, where it won't conflict with Rails
|
14
|
+
# app's loader.
|
15
|
+
loader.ignore("#{__dir__}/address_concern/attribute_normalizer.rb")
|
16
|
+
loader.ignore("#{__dir__}/address_concern/version.rb")
|
17
|
+
loader.ignore("#{__dir__}/core_extensions")
|
18
|
+
loader.ignore("#{__dir__}/generators")
|
19
|
+
loader.setup
|
6
20
|
|
7
21
|
require 'address_concern/version'
|
8
|
-
|
9
|
-
|
22
|
+
#pp loader.autoloads
|
23
|
+
loader.eager_load
|
24
|
+
#require_relative '../app/models/address_concern/address'
|
10
25
|
|
11
|
-
|
12
|
-
|
26
|
+
# When used in a Rails app, this isn't needed because the engine will add its locale load paths, but
|
27
|
+
# when not using Rails, including from our tests, the engine isn't loaded.
|
28
|
+
I18n.load_path.unshift(
|
29
|
+
*Dir.glob(
|
30
|
+
x=File.expand_path(
|
31
|
+
File.join(%w[.. config locales *.yml]), File.dirname(__FILE__)
|
32
|
+
)
|
33
|
+
)
|
34
|
+
)
|
@@ -50,15 +50,15 @@ describe 'acts_as_address' do
|
|
50
50
|
describe 'address lines' do
|
51
51
|
describe Address do
|
52
52
|
it do
|
53
|
-
expect(klass.
|
54
|
-
expect(klass.
|
53
|
+
expect(klass.multi_line_street_address?).to eq true
|
54
|
+
expect(klass.street_address_attr_names).to eq [:address]
|
55
55
|
end
|
56
56
|
end
|
57
57
|
|
58
58
|
describe AddressWithSeparateAddressColumns do
|
59
59
|
it do
|
60
|
-
expect(klass.
|
61
|
-
expect(klass.
|
60
|
+
expect(klass.multi_line_street_address?).to eq false
|
61
|
+
expect(klass.street_address_attr_names).to eq [:address_1, :address_2, :address_3]
|
62
62
|
end
|
63
63
|
end
|
64
64
|
end
|
data/spec/models/address_spec.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
describe Address do
|
3
|
+
describe Address, type: :model do
|
4
4
|
def klass
|
5
5
|
described_class
|
6
6
|
end
|
@@ -213,16 +213,74 @@ describe Address do
|
|
213
213
|
|
214
214
|
#═════════════════════════════════════════════════════════════════════════════════════════════════
|
215
215
|
|
216
|
-
describe 'setting state
|
217
|
-
|
218
|
-
|
219
|
-
|
216
|
+
describe 'setting state' do
|
217
|
+
# Uses find_carmen_state, which finds by name, falling back to finding by code.
|
218
|
+
describe 'setting state_name_attribute' do
|
219
|
+
before {
|
220
|
+
expect(Address.state_code_attribute).to eq :state_code
|
221
|
+
expect(Address.state_name_attribute).to eq :state
|
222
|
+
}
|
223
|
+
|
224
|
+
context "setting state_name_attribute to code" do
|
225
|
+
subject { Address.new(state: 'FL', country_name: 'United States') }
|
226
|
+
it { expect(subject.state_code).to eq('FL') }
|
227
|
+
end
|
228
|
+
|
229
|
+
context "setting state_name_attribute to name" do
|
230
|
+
subject { Address.new(state: 'Florida', country_name: 'United States') }
|
231
|
+
it { expect(subject.state_code).to eq('FL') }
|
232
|
+
end
|
220
233
|
end
|
221
234
|
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
235
|
+
# Unlike {state_name_attribute}=, which falls back to finding by code, {state_code_attribute}=
|
236
|
+
# _only_ looks up by code by default.
|
237
|
+
describe 'setting state_code_attribute' do
|
238
|
+
subject { Address.new(state_code: input, country_name: 'United States') }
|
239
|
+
|
240
|
+
before {
|
241
|
+
expect(Address.state_code_attribute).to eq :state_code
|
242
|
+
expect(Address.state_name_attribute).to eq :state
|
243
|
+
|
244
|
+
}
|
245
|
+
around(:example) { |example|
|
246
|
+
validate_code = Address.state_config[:validate_code]
|
247
|
+
Address.state_config[:validate_code] = true
|
248
|
+
example.run
|
249
|
+
Address.state_config[:validate_code] = validate_code
|
250
|
+
}
|
251
|
+
|
252
|
+
context "setting state_code_attribute to code" do
|
253
|
+
let(:input) { 'FL' }
|
254
|
+
it { expect(subject.state_code).to eq(input) }
|
255
|
+
it { expect(subject.carmen_state&.code).to eq('FL') }
|
256
|
+
it { expect(subject).to allow_values(input).for(:state_code) }
|
257
|
+
end
|
258
|
+
|
259
|
+
context "setting state_code_attribute to name: doesn't find by default" do
|
260
|
+
let(:input) { 'Florida' }
|
261
|
+
subject { Address.new(state_code: input, country_name: 'United States') }
|
262
|
+
it { expect(subject.state_code).to eq(input) }
|
263
|
+
it { expect(subject.carmen_state&.code).to eq(nil) }
|
264
|
+
it { expect(subject).to_not allow_values(input).for(:state_code).with_message('is not a valid option for United States') }
|
265
|
+
|
266
|
+
context "when state_config[:on_unknown] returns :find_by_name" do
|
267
|
+
before {
|
268
|
+
@orig = Address.state_config[:on_unknown]
|
269
|
+
Address.state_config[:on_unknown] = Proc.new { :find_by_name }
|
270
|
+
}
|
271
|
+
after { Address.state_config[:on_unknown] = @orig }
|
272
|
+
it { expect(subject.carmen_state&.code).to eq('FL') }
|
273
|
+
it { expect(subject.state_code).to eq('FL') }
|
274
|
+
it { expect(subject).to allow_values(input).for(:state_code) }
|
275
|
+
end
|
276
|
+
end
|
277
|
+
end
|
278
|
+
end
|
279
|
+
|
280
|
+
#═════════════════════════════════════════════════════════════════════════════════════════════════
|
281
|
+
describe 'validations' do
|
282
|
+
it do
|
283
|
+
expect(AddressConcern::Address.instance_method(:validate_state_for_country)).to be_a UnboundMethod
|
226
284
|
end
|
227
285
|
end
|
228
286
|
|
@@ -254,14 +312,14 @@ describe Address do
|
|
254
312
|
describe 'address, address_lines' do
|
255
313
|
describe Address do
|
256
314
|
it do
|
257
|
-
expect(klass.
|
315
|
+
expect(klass.multi_line_street_address?).to eq true
|
258
316
|
|
259
317
|
address = klass.new(address: str = 'Line 1')
|
260
318
|
expect(address.address).to eq str
|
261
319
|
|
262
320
|
address = klass.new(address: str = "Line 1\nLine 2\nLine 3")
|
263
321
|
expect(address.address).to eq str
|
264
|
-
expect(address.
|
322
|
+
expect(address.street_address_lines).to eq [
|
265
323
|
'Line 1',
|
266
324
|
'Line 2',
|
267
325
|
'Line 3',
|
@@ -271,7 +329,7 @@ describe Address do
|
|
271
329
|
|
272
330
|
describe AddressWithSeparateAddressColumns do
|
273
331
|
it do
|
274
|
-
expect(klass.
|
332
|
+
expect(klass.multi_line_street_address?).to eq false
|
275
333
|
|
276
334
|
address = klass.new(
|
277
335
|
address_1: 'Line 1',
|
@@ -281,7 +339,7 @@ describe Address do
|
|
281
339
|
expect(address.address_1).to eq 'Line 1'
|
282
340
|
expect(address.address_2).to eq 'Line 2'
|
283
341
|
expect(address.address_3).to eq 'Line 3'
|
284
|
-
expect(address.
|
342
|
+
expect(address.street_address_lines).to eq [
|
285
343
|
'Line 1',
|
286
344
|
'Line 2',
|
287
345
|
'Line 3',
|
@@ -368,6 +426,7 @@ describe Address do
|
|
368
426
|
end
|
369
427
|
context "when address has a state name instead of code entered for state_name, and state is for different country" do
|
370
428
|
let(:user) { User.create }
|
429
|
+
# Internally, it sees: unknown state code 'FL'
|
371
430
|
subject { user.build_physical_address(address: '123', city: 'Ocala', state_code: 'FL', country_name: 'Denmark') }
|
372
431
|
it do
|
373
432
|
expect(subject.state_code). to eq('FL')
|
@@ -412,6 +471,7 @@ describe Address do
|
|
412
471
|
it { expect(Address.new(country: 'United States').states_for_country.map(&:name)).to include 'Puerto Rico' }
|
413
472
|
it { expect(Address.new(country: 'South Africa').states_for_country.map(&:name)).to include 'Mpumalanga' }
|
414
473
|
it { expect(Address.new(country: 'Kenya').states_for_country.typed('province')).to be_empty }
|
474
|
+
it { expect(Address.new(country: 'Kenya').states_for_country.typed('province')).to be_empty }
|
415
475
|
# At the time of this writing, it doesn't look like Carmen has been updated to
|
416
476
|
# include the 47 counties listed under https://en.wikipedia.org/wiki/ISO_3166-2:KE.
|
417
477
|
#it { Address.new(country: 'Kenya').states_for_country.map(&:name).should include 'Nyeri' }
|
@@ -448,6 +508,26 @@ describe Address do
|
|
448
508
|
it { expect(Address.new(country_name: 'France').state_options.map(&:name)).to include 'Auvergne-Rhône-Alpes' }
|
449
509
|
#it { Address.new(country: 'France').state_options.size.should eq 18 }
|
450
510
|
#it { Address.new(country: 'France').state_options.map(&:name).should include 'Auvergne-Rhône-Alpes' }
|
511
|
+
|
512
|
+
context 'for a country without states data (Aruba)' do
|
513
|
+
subject { Address.new(country_name: 'Aruba') }
|
514
|
+
it do
|
515
|
+
expect(subject.states_for_country).to be_empty
|
516
|
+
expect(subject.states_for_country).to be_a Carmen::RegionCollection
|
517
|
+
expect(subject.states_for_country.coded('Roo')).to eq nil
|
518
|
+
expect(subject.country_with_states?).to eq false
|
519
|
+
end
|
520
|
+
end
|
521
|
+
|
522
|
+
context 'with an invalid country code (ZZ)' do
|
523
|
+
subject { Address.new(country_code: 'ZZ') }
|
524
|
+
it do
|
525
|
+
expect(subject.states_for_country).to be_empty
|
526
|
+
expect(subject.states_for_country).to be_a Carmen::RegionCollection
|
527
|
+
expect(subject.states_for_country.coded('Roo')).to eq nil
|
528
|
+
expect(subject.country_with_states?).to eq false
|
529
|
+
end
|
530
|
+
end
|
451
531
|
end
|
452
532
|
|
453
533
|
#═════════════════════════════════════════════════════════════════════════════════════════════════
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: address_concern
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 3.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Paul Campbell
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2022-
|
12
|
+
date: 2022-11-28 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rake
|
@@ -81,6 +81,20 @@ dependencies:
|
|
81
81
|
- - ">="
|
82
82
|
- !ruby/object:Gem::Version
|
83
83
|
version: 1.1.1
|
84
|
+
- !ruby/object:Gem::Dependency
|
85
|
+
name: zeitwerk
|
86
|
+
requirement: !ruby/object:Gem::Requirement
|
87
|
+
requirements:
|
88
|
+
- - ">="
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
version: '0'
|
91
|
+
type: :runtime
|
92
|
+
prerelease: false
|
93
|
+
version_requirements: !ruby/object:Gem::Requirement
|
94
|
+
requirements:
|
95
|
+
- - ">="
|
96
|
+
- !ruby/object:Gem::Version
|
97
|
+
version: '0'
|
84
98
|
- !ruby/object:Gem::Dependency
|
85
99
|
name: active_record_ignored_attributes
|
86
100
|
requirement: !ruby/object:Gem::Requirement
|
@@ -109,6 +123,20 @@ dependencies:
|
|
109
123
|
- - ">="
|
110
124
|
- !ruby/object:Gem::Version
|
111
125
|
version: '0'
|
126
|
+
- !ruby/object:Gem::Dependency
|
127
|
+
name: shoulda-matchers
|
128
|
+
requirement: !ruby/object:Gem::Requirement
|
129
|
+
requirements:
|
130
|
+
- - ">="
|
131
|
+
- !ruby/object:Gem::Version
|
132
|
+
version: '0'
|
133
|
+
type: :development
|
134
|
+
prerelease: false
|
135
|
+
version_requirements: !ruby/object:Gem::Requirement
|
136
|
+
requirements:
|
137
|
+
- - ">="
|
138
|
+
- !ruby/object:Gem::Version
|
139
|
+
version: '0'
|
112
140
|
- !ruby/object:Gem::Dependency
|
113
141
|
name: sqlite3
|
114
142
|
requirement: !ruby/object:Gem::Requirement
|
@@ -134,24 +162,26 @@ files:
|
|
134
162
|
- ".document"
|
135
163
|
- ".gitignore"
|
136
164
|
- ".rspec"
|
137
|
-
- ".
|
165
|
+
- ".tool-versions"
|
138
166
|
- CHANGELOG
|
167
|
+
- Changelog.md
|
139
168
|
- Gemfile
|
140
169
|
- LICENSE.txt
|
141
170
|
- Rakefile
|
142
171
|
- Readme.md
|
143
172
|
- VERSION
|
144
173
|
- address_concern.gemspec
|
145
|
-
- app/models/concerns/address.rb
|
146
|
-
- app/models/concerns/address_associations.rb
|
147
|
-
- app/models/concerns/attributes_slice.rb
|
148
|
-
- app/models/concerns/inspect_base.rb
|
149
174
|
- bin/console
|
150
175
|
- config/address_concern.rb
|
151
|
-
- config/
|
176
|
+
- config/locales/en.yml
|
177
|
+
- config/locales/overlay/en/id.yml
|
152
178
|
- lib/address_concern.rb
|
179
|
+
- lib/address_concern/address.rb
|
180
|
+
- lib/address_concern/address_associations.rb
|
153
181
|
- lib/address_concern/attribute_normalizer.rb
|
182
|
+
- lib/address_concern/attributes_slice.rb
|
154
183
|
- lib/address_concern/engine.rb
|
184
|
+
- lib/address_concern/inspect_base.rb
|
155
185
|
- lib/address_concern/version.rb
|
156
186
|
- lib/core_extensions/hash/reorder.rb
|
157
187
|
- lib/core_extensions/string/cleanlines.rb
|
@@ -174,6 +204,7 @@ files:
|
|
174
204
|
- spec/support/models/employee.rb
|
175
205
|
- spec/support/models/user.rb
|
176
206
|
- spec/support/schema.rb
|
207
|
+
- spec/support/shoulda_matchers.rb
|
177
208
|
- tmp/.gitkeep
|
178
209
|
homepage: http://github.com/TylerRick/address_concern
|
179
210
|
licenses:
|
@@ -194,7 +225,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
194
225
|
- !ruby/object:Gem::Version
|
195
226
|
version: '0'
|
196
227
|
requirements: []
|
197
|
-
rubygems_version: 3.3.
|
228
|
+
rubygems_version: 3.3.7
|
198
229
|
signing_key:
|
199
230
|
specification_version: 4
|
200
231
|
summary: A reusable Address model for your Rails apps
|
data/.ruby-version
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
ruby-2.7.4
|