address_concern 2.1.0 → 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|