has_addresses 0.0.2 → 0.5.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.
- data/CHANGELOG.rdoc +50 -0
- data/{MIT-LICENSE → LICENSE} +2 -2
- data/README.rdoc +63 -0
- data/Rakefile +48 -41
- data/app/models/address.rb +92 -50
- data/app/models/country.rb +287 -101
- data/app/models/region.rb +5378 -106
- data/db/migrate/001_create_countries.rb +7 -7
- data/db/migrate/002_create_regions.rb +7 -5
- data/db/migrate/003_create_addresses.rb +10 -12
- data/lib/has_addresses.rb +9 -68
- data/test/app_root/app/models/company.rb +1 -5
- data/test/app_root/config/environment.rb +6 -19
- data/test/app_root/db/migrate/001_create_companies.rb +1 -1
- data/test/app_root/db/migrate/002_migrate_has_addresses_to_version_3.rb +13 -0
- data/test/factory.rb +68 -0
- data/test/functional/has_addresses_test.rb +22 -0
- data/test/test_helper.rb +11 -5
- data/test/unit/address_test.rb +210 -79
- data/test/unit/country_test.rb +101 -72
- data/test/unit/region_test.rb +104 -61
- metadata +70 -61
- data/CHANGELOG +0 -23
- data/README +0 -122
- data/tasks/has_addresses_tasks.rake +0 -23
- data/test/app_root/db/migrate/002_add_address_kinds.rb +0 -9
- data/test/files/iso_3166.xml +0 -1719
- data/test/files/iso_3166_2.xml +0 -8617
- data/test/fixtures/addresses.yml +0 -47
- data/test/fixtures/companies.yml +0 -7
- data/test/fixtures/countries.yml +0 -12
- data/test/fixtures/regions.yml +0 -5
- data/test/unit/has_addresses_test.rb +0 -15
data/CHANGELOG.rdoc
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
== master
|
2
|
+
|
3
|
+
== 0.5.0 / 2009-04-30
|
4
|
+
|
5
|
+
* Replace acts_as_enumeration with enumerate_by
|
6
|
+
* Add dependency on Rails 2.3
|
7
|
+
|
8
|
+
== 0.4.0 / 2008-12-14
|
9
|
+
|
10
|
+
* Remove the PluginAWeek namespace
|
11
|
+
|
12
|
+
== 0.3.0 / 2008-10-26
|
13
|
+
|
14
|
+
* Add mass-assignment protection in the Address model
|
15
|
+
* Change how the base module is included to prevent namespacing conflicts
|
16
|
+
|
17
|
+
== 0.2.1 / 2008-06-22
|
18
|
+
|
19
|
+
* Remove log files from gems
|
20
|
+
|
21
|
+
== 0.2.0 / 2008-06-22
|
22
|
+
|
23
|
+
* Fix incorrect regions being listed for most countries
|
24
|
+
* Use an id scheme for regions based on the id of the country to prevent id clashing in future updates
|
25
|
+
* Improve performance by not requiring that the country be looked up for every new region created
|
26
|
+
* Index region enumerations by their ISO code
|
27
|
+
* Use common display names for countries, rather than the default specified in the standard; use the official name if needed
|
28
|
+
* Organize country enumerations by id
|
29
|
+
* Index country enumerations by their alpha 2 code
|
30
|
+
|
31
|
+
== 0.1.0 / 2008-05-05
|
32
|
+
|
33
|
+
* Convert Country/Region to enumerations
|
34
|
+
* Add dependency on acts_as_enumeration
|
35
|
+
* Update documentation to reflect plugins_plus changes
|
36
|
+
|
37
|
+
== 0.0.2 / 2007-09-26
|
38
|
+
|
39
|
+
* Move test fixtures out of the test application root directory
|
40
|
+
|
41
|
+
== 0.0.1 / 2007-08-21
|
42
|
+
|
43
|
+
* Add documentation
|
44
|
+
* Add descriptive output for rake tasks
|
45
|
+
* Remove dependency on has_association_helper
|
46
|
+
* Remove default bootstrap files in favor of creating new ones through the bootstrap tasks
|
47
|
+
* Add tests for rake tests
|
48
|
+
* Fix not allowing single character abbreviations for regions
|
49
|
+
* Add countries:create_fixtures, countries:bootstrap, regions:create_fixtures, and regions:bootstrap files
|
50
|
+
* Refactor Rake code into Country/Region classes
|
data/{MIT-LICENSE → LICENSE}
RENAMED
@@ -1,4 +1,4 @@
|
|
1
|
-
Copyright (c) 2006-
|
1
|
+
Copyright (c) 2006-2009 Aaron Pfeifer
|
2
2
|
|
3
3
|
Permission is hereby granted, free of charge, to any person obtaining
|
4
4
|
a copy of this software and associated documentation files (the
|
@@ -17,4 +17,4 @@ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
17
17
|
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
18
|
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
19
|
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
-
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
= has_addresses
|
2
|
+
|
3
|
+
+has_addresses+ demonstrates a reference implementation for handling countries,
|
4
|
+
regions, and addresses.
|
5
|
+
|
6
|
+
== Resources
|
7
|
+
|
8
|
+
API
|
9
|
+
|
10
|
+
* http://api.pluginaweek.org/has_addresses
|
11
|
+
|
12
|
+
Bugs
|
13
|
+
|
14
|
+
* http://pluginaweek.lighthouseapp.com/projects/13271-has_addresses
|
15
|
+
|
16
|
+
Development
|
17
|
+
|
18
|
+
* http://github.com/pluginaweek/has_addresses
|
19
|
+
|
20
|
+
Source
|
21
|
+
|
22
|
+
* git://github.com/pluginaweek/has_addresses.git
|
23
|
+
|
24
|
+
== Description
|
25
|
+
|
26
|
+
Countries, regions, and addresses are all simple models whose data and
|
27
|
+
functionality should be able to be standardized across multiple applications.
|
28
|
+
has_addresses adds support for countries and regions based on the ISO 3166 and
|
29
|
+
ISO 3166-2 standard. The data for these standards is obtained through the
|
30
|
+
open-source Debian package, iso-codes.
|
31
|
+
|
32
|
+
Along with the simple Country and Region models, addresses can be defined and
|
33
|
+
integrated based on the data in these models. Addresses are minimalistic in
|
34
|
+
terms of the type of data required.
|
35
|
+
|
36
|
+
== Usage
|
37
|
+
|
38
|
+
Note that this is a reference implementation and, most likely, should be
|
39
|
+
modified for your own usage.
|
40
|
+
|
41
|
+
=== Example
|
42
|
+
|
43
|
+
address = Address.new(
|
44
|
+
:street_1 => '1600 Amphitheatre Parkway',
|
45
|
+
:city => 'Mountain View',
|
46
|
+
:region => 'US-CA',
|
47
|
+
:postal_code => '94043'
|
48
|
+
)
|
49
|
+
address.single_line # => "1600 Amphitheatre Parkway, Mountain View, California 94043, United States"
|
50
|
+
|
51
|
+
== Testing
|
52
|
+
|
53
|
+
Before you can run any tests, the following gem must be installed:
|
54
|
+
* plugin_test_helper[http://github.com/pluginaweek/plugin_test_helper]
|
55
|
+
|
56
|
+
To run against a specific version of Rails:
|
57
|
+
|
58
|
+
rake test RAILS_FRAMEWORK_ROOT=/path/to/rails
|
59
|
+
|
60
|
+
== Dependencies
|
61
|
+
|
62
|
+
* Rails 2.3 or later
|
63
|
+
* enumerate_by[http://github.com/pluginaweek/enumerate_by]
|
data/Rakefile
CHANGED
@@ -3,48 +3,55 @@ require 'rake/rdoctask'
|
|
3
3
|
require 'rake/gempackagetask'
|
4
4
|
require 'rake/contrib/sshpublisher'
|
5
5
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
6
|
+
spec = Gem::Specification.new do |s|
|
7
|
+
s.name = 'has_addresses'
|
8
|
+
s.version = '0.5.0'
|
9
|
+
s.platform = Gem::Platform::RUBY
|
10
|
+
s.summary = 'Demonstrates a reference implementation for handling countries, regions, and addresses.'
|
11
|
+
|
12
|
+
s.files = FileList['{app,db,lib,test}/**/*'] + %w(CHANGELOG.rdoc init.rb LICENSE Rakefile README.rdoc) - FileList['test/app_root/{log,log/*,script,script/*}']
|
13
|
+
s.require_path = 'lib'
|
14
|
+
s.has_rdoc = true
|
15
|
+
s.test_files = Dir['test/**/*_test.rb']
|
16
|
+
s.add_dependency 'enumerate_by', '>= 0.4.0'
|
17
|
+
|
18
|
+
s.author = 'Aaron Pfeifer'
|
19
|
+
s.email = 'aaron@pluginaweek.org'
|
20
|
+
s.homepage = 'http://www.pluginaweek.org'
|
21
|
+
s.rubyforge_project = 'pluginaweek'
|
22
|
+
end
|
23
|
+
|
24
|
+
desc 'Default: run all tests.'
|
15
25
|
task :default => :test
|
16
26
|
|
17
|
-
desc
|
27
|
+
desc "Test the #{spec.name} plugin."
|
18
28
|
Rake::TestTask.new(:test) do |t|
|
19
29
|
t.libs << 'lib'
|
20
|
-
t.
|
30
|
+
t.test_files = spec.test_files
|
21
31
|
t.verbose = true
|
22
32
|
end
|
23
33
|
|
24
|
-
|
34
|
+
begin
|
35
|
+
require 'rcov/rcovtask'
|
36
|
+
namespace :test do
|
37
|
+
desc "Test the #{spec.name} plugin with Rcov."
|
38
|
+
Rcov::RcovTask.new(:rcov) do |t|
|
39
|
+
t.libs << 'lib'
|
40
|
+
t.test_files = spec.test_files
|
41
|
+
t.rcov_opts << '--exclude="^(?!lib/|app/)"'
|
42
|
+
t.verbose = true
|
43
|
+
end
|
44
|
+
end
|
45
|
+
rescue LoadError
|
46
|
+
end
|
47
|
+
|
48
|
+
desc "Generate documentation for the #{spec.name} plugin."
|
25
49
|
Rake::RDocTask.new(:rdoc) do |rdoc|
|
26
50
|
rdoc.rdoc_dir = 'rdoc'
|
27
|
-
rdoc.title =
|
51
|
+
rdoc.title = spec.name
|
52
|
+
rdoc.template = '../rdoc_template.rb'
|
28
53
|
rdoc.options << '--line-numbers' << '--inline-source'
|
29
|
-
rdoc.rdoc_files.include('README')
|
30
|
-
rdoc.rdoc_files.include('lib/**/*.rb')
|
31
|
-
end
|
32
|
-
|
33
|
-
spec = Gem::Specification.new do |s|
|
34
|
-
s.name = PKG_NAME
|
35
|
-
s.version = PKG_VERSION
|
36
|
-
s.platform = Gem::Platform::RUBY
|
37
|
-
s.summary = 'Adds a base skeleton for handling countries, regions, and addresses.'
|
38
|
-
|
39
|
-
s.files = FileList['{app,db,lib,tasks,test}/**/*'].to_a + %w(CHANGELOG init.rb MIT-LICENSE Rakefile README)
|
40
|
-
s.require_path = 'lib'
|
41
|
-
s.autorequire = 'has_addresses'
|
42
|
-
s.has_rdoc = true
|
43
|
-
s.test_files = Dir['test/unit/**/*_test.rb']
|
44
|
-
|
45
|
-
s.author = 'Aaron Pfeifer, Neil Abraham'
|
46
|
-
s.email = 'info@pluginaweek.org'
|
47
|
-
s.homepage = 'http://www.pluginaweek.org'
|
54
|
+
rdoc.rdoc_files.include('README.rdoc', 'CHANGELOG.rdoc', 'LICENSE', 'lib/**/*.rb', 'app/**/*.rb')
|
48
55
|
end
|
49
56
|
|
50
57
|
Rake::GemPackageTask.new(spec) do |p|
|
@@ -53,30 +60,30 @@ Rake::GemPackageTask.new(spec) do |p|
|
|
53
60
|
p.need_zip = true
|
54
61
|
end
|
55
62
|
|
56
|
-
desc 'Publish the beta gem'
|
63
|
+
desc 'Publish the beta gem.'
|
57
64
|
task :pgem => [:package] do
|
58
|
-
Rake::SshFilePublisher.new('
|
65
|
+
Rake::SshFilePublisher.new('aaron@pluginaweek.org', '/home/aaron/gems.pluginaweek.org/public/gems', 'pkg', "#{spec.name}-#{spec.version}.gem").upload
|
59
66
|
end
|
60
67
|
|
61
|
-
desc 'Publish the API documentation'
|
68
|
+
desc 'Publish the API documentation.'
|
62
69
|
task :pdoc => [:rdoc] do
|
63
|
-
Rake::SshDirPublisher.new('
|
70
|
+
Rake::SshDirPublisher.new('aaron@pluginaweek.org', "/home/aaron/api.pluginaweek.org/public/#{spec.name}", 'rdoc').upload
|
64
71
|
end
|
65
72
|
|
66
73
|
desc 'Publish the API docs and gem'
|
67
|
-
task :publish => [:pdoc, :release]
|
74
|
+
task :publish => [:pgem, :pdoc, :release]
|
68
75
|
|
69
76
|
desc 'Publish the release files to RubyForge.'
|
70
77
|
task :release => [:gem, :package] do
|
71
78
|
require 'rubyforge'
|
72
79
|
|
73
|
-
ruby_forge = RubyForge.new
|
80
|
+
ruby_forge = RubyForge.new.configure
|
74
81
|
ruby_forge.login
|
75
82
|
|
76
|
-
%w(
|
77
|
-
file = "pkg/#{
|
83
|
+
%w(gem tgz zip).each do |ext|
|
84
|
+
file = "pkg/#{spec.name}-#{spec.version}.#{ext}"
|
78
85
|
puts "Releasing #{File.basename(file)}..."
|
79
86
|
|
80
|
-
ruby_forge.add_release(
|
87
|
+
ruby_forge.add_release(spec.rubyforge_project, spec.name, spec.version, file)
|
81
88
|
end
|
82
89
|
end
|
data/app/models/address.rb
CHANGED
@@ -1,43 +1,84 @@
|
|
1
|
-
# Represents a mailing address
|
1
|
+
# Represents a generic mailing address. Addresses are expected to consist of
|
2
|
+
# the following fields:
|
3
|
+
# * +addressable+ - The record that owns the address
|
4
|
+
# * +street_1+ - The first line of the street address
|
5
|
+
# * +city+ - The name of the city
|
6
|
+
# * +postal_code+ - A value uniquely identifying the area in the city
|
7
|
+
# * +region+ - Either a known region or a custom value for countries that have no list of regions available
|
8
|
+
# * +country+ - The country, which may be implied by the region
|
9
|
+
#
|
10
|
+
# The following fields are optional:
|
11
|
+
# * +street_2+ - The second line of the street address
|
12
|
+
#
|
13
|
+
# There is no attempt to validate open-ended fields since the context in which
|
14
|
+
# the addresses will be used is unknown
|
2
15
|
class Address < ActiveRecord::Base
|
3
|
-
belongs_to
|
4
|
-
|
5
|
-
belongs_to
|
6
|
-
belongs_to :country
|
16
|
+
belongs_to :addressable, :polymorphic => true
|
17
|
+
belongs_to :region
|
18
|
+
belongs_to :country
|
7
19
|
|
8
|
-
validates_presence_of :addressable_id,
|
9
|
-
:
|
10
|
-
|
11
|
-
|
12
|
-
:postal_code
|
13
|
-
validates_presence_of :region_id,
|
14
|
-
:if => :known_region_required?
|
15
|
-
validates_presence_of :custom_region,
|
16
|
-
:if => :custom_region_required?
|
17
|
-
validates_format_of :postal_code,
|
18
|
-
:with => /^[0-9]{5}$/,
|
19
|
-
:allow_nil => true
|
20
|
+
validates_presence_of :addressable_id, :addressable_type, :street_1, :city,
|
21
|
+
:postal_code, :country_id
|
22
|
+
validates_presence_of :region_id, :if => :known_region_required?
|
23
|
+
validates_presence_of :custom_region, :if => :custom_region_required?
|
20
24
|
|
21
|
-
|
25
|
+
attr_accessible :street_1, :street_2, :city, :postal_code, :region,
|
26
|
+
:custom_region, :country
|
22
27
|
|
23
|
-
|
24
|
-
def country_with_region_check
|
25
|
-
region ? region.country : country_without_region_check
|
26
|
-
end
|
27
|
-
alias_method_chain :country, :region_check
|
28
|
+
before_validation :ensure_exclusive_references, :set_region_attributes
|
28
29
|
|
29
|
-
# Gets the name of the region that this address is for (whether it is a
|
30
|
-
#
|
30
|
+
# Gets the name of the region that this address is for (whether it is a
|
31
|
+
# custom or known region in the database)
|
31
32
|
def region_name
|
32
|
-
custom_region ||
|
33
|
+
custom_region || region && region.name
|
33
34
|
end
|
34
35
|
|
35
|
-
# Gets
|
36
|
+
# Gets a representation of the address on a single line.
|
37
|
+
#
|
38
|
+
# For example,
|
39
|
+
#
|
40
|
+
# address = Address.new
|
41
|
+
# address.single_line # => ""
|
42
|
+
#
|
43
|
+
# address.street_1 = "1600 Amphitheatre Parkey"
|
44
|
+
# address.single_line # => "1600 Amphitheatre Parkway"
|
45
|
+
#
|
46
|
+
# address.street_2 = "Suite 100"
|
47
|
+
# address.single_line # => "1600 Amphitheatre Parkway, Suite 100"
|
48
|
+
#
|
49
|
+
# address.city = "Mountain View"
|
50
|
+
# address.single_line # => "1600 Amphitheatre Parkway, Suite 100, Mountain View"
|
51
|
+
#
|
52
|
+
# address.region = Region['US-CA']
|
53
|
+
# address.single_line # => "1600 Amphitheatre Parkway, Suite 100, Mountain View, California, United States"
|
54
|
+
#
|
55
|
+
# address.postal_code = '94043'
|
56
|
+
# address.single_line # => "1600 Amphitheatre Parkway, Suite 100, Mountain View, California 94043, United States"
|
36
57
|
def single_line
|
37
58
|
multi_line.join(', ')
|
38
59
|
end
|
39
60
|
|
40
|
-
# Gets
|
61
|
+
# Gets a representation of the address on multiple lines.
|
62
|
+
#
|
63
|
+
# For example,
|
64
|
+
#
|
65
|
+
# address = Address.new
|
66
|
+
# address.multi_line # => []
|
67
|
+
#
|
68
|
+
# address.street_1 = "1600 Amphitheatre Parkey"
|
69
|
+
# address.multi_line # => ["1600 Amphitheatre Parkey"]
|
70
|
+
#
|
71
|
+
# address.street_2 = "Suite 100"
|
72
|
+
# address.multi_line # => ["1600 Amphitheatre Parkey", "Suite 100"]
|
73
|
+
#
|
74
|
+
# address.city = "Mountain View"
|
75
|
+
# address.multi_line # => ["1600 Amphitheatre Parkey", "Suit 100", "Mountain View"]
|
76
|
+
#
|
77
|
+
# address.region = Region['US-CA']
|
78
|
+
# address.multi_line # => ["1600 Amphitheatre Parkey", "Suit 100", "Mountain View, California", "United States"]
|
79
|
+
#
|
80
|
+
# address.postal_code = '94043'
|
81
|
+
# address.multi_line # => ["1600 Amphitheatre Parkey", "Suit 100", "Mountain View, California 94043", "United States"]
|
41
82
|
def multi_line
|
42
83
|
lines = []
|
43
84
|
lines << street_1 if street_1?
|
@@ -46,39 +87,40 @@ class Address < ActiveRecord::Base
|
|
46
87
|
line = ''
|
47
88
|
line << city if city?
|
48
89
|
if region_name
|
49
|
-
line << ', '
|
90
|
+
line << ', ' unless line.blank?
|
50
91
|
line << region_name
|
51
92
|
end
|
52
93
|
if postal_code?
|
53
|
-
line << ' '
|
94
|
+
line << ' ' unless line.blank?
|
54
95
|
line << postal_code
|
55
96
|
end
|
56
|
-
lines << line
|
97
|
+
lines << line unless line.blank?
|
57
98
|
|
58
99
|
lines << country.name if country
|
59
100
|
lines
|
60
101
|
end
|
61
102
|
|
62
103
|
private
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
# A custom region name is required if a known region was not specified and
|
68
|
-
# the country in which this address resides has no known regions in the
|
69
|
-
# database
|
70
|
-
def custom_region_required?
|
71
|
-
region_id.nil? && country && country.regions.count == 0
|
72
|
-
end
|
73
|
-
|
74
|
-
# Ensures that the country id/user region combo is not set at the same time as
|
75
|
-
# the region id
|
76
|
-
def ensure_exclusive_references
|
77
|
-
if known_region_required?
|
78
|
-
self.country_id = nil
|
79
|
-
self.custom_region = nil
|
104
|
+
# Does the current country have a list of regions to choose from?
|
105
|
+
def known_region_required?
|
106
|
+
!country || country.regions.any?
|
80
107
|
end
|
81
108
|
|
82
|
-
|
83
|
-
|
109
|
+
# A custom region name is required if a known region was not specified and
|
110
|
+
# the country in which this address resides has no known regions in the
|
111
|
+
# database
|
112
|
+
def custom_region_required?
|
113
|
+
!region_id && country && country.regions.empty?
|
114
|
+
end
|
115
|
+
|
116
|
+
# Ensures that the custom region is not set at the same time as the known
|
117
|
+
# region
|
118
|
+
def ensure_exclusive_references
|
119
|
+
self.custom_region = nil if known_region_required?
|
120
|
+
end
|
121
|
+
|
122
|
+
# Sets the attributes on the address based on the region (if available)
|
123
|
+
def set_region_attributes
|
124
|
+
self.country = region.country if region
|
125
|
+
end
|
84
126
|
end
|