has_addresses 0.0.2 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -1,4 +1,4 @@
1
- Copyright (c) 2006-2007 Aaron Pfeifer & Neil Abraham
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
- # Load custom rakefile extensions
7
- Dir["#{File.dirname(__FILE__)}/tasks/**/*.rake"].sort.each {|ext| load ext}
8
-
9
- PKG_NAME = 'has_addresses'
10
- PKG_VERSION = '0.0.2'
11
- PKG_FILE_NAME = "#{PKG_NAME}-#{PKG_VERSION}"
12
- RUBY_FORGE_PROJECT = 'pluginaweek'
13
-
14
- desc 'Default: run unit tests.'
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 'Test the has_addresses plugin.'
27
+ desc "Test the #{spec.name} plugin."
18
28
  Rake::TestTask.new(:test) do |t|
19
29
  t.libs << 'lib'
20
- t.pattern = 'test/unit/**/*_test.rb'
30
+ t.test_files = spec.test_files
21
31
  t.verbose = true
22
32
  end
23
33
 
24
- desc 'Generate documentation for the has_addresses plugin.'
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 = 'HasAddresses'
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('pluginaweek@pluginaweek.org', '/home/pluginaweek/gems.pluginaweek.org/gems', 'pkg', "#{PKG_FILE_NAME}.gem").upload
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('pluginaweek@pluginaweek.org', "/home/pluginaweek/api.pluginaweek.org/#{PKG_NAME}", 'rdoc').upload
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( gem tgz zip ).each do |ext|
77
- file = "pkg/#{PKG_FILE_NAME}.#{ext}"
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(RUBY_FORGE_PROJECT, PKG_NAME, PKG_VERSION, file)
87
+ ruby_forge.add_release(spec.rubyforge_project, spec.name, spec.version, file)
81
88
  end
82
89
  end
@@ -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 :addressable,
4
- :polymorphic => true
5
- belongs_to :region
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
- :addressable_type,
10
- :street_1,
11
- :city,
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
- before_save :ensure_exclusive_references
25
+ attr_accessible :street_1, :street_2, :city, :postal_code, :region,
26
+ :custom_region, :country
22
27
 
23
- # Returns the region's country if the region is specified
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 custom or
30
- # stored region in the database)
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 || (region ? region.name : nil)
33
+ custom_region || region && region.name
33
34
  end
34
35
 
35
- # Gets the value of the address on a single line
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 the value of the address on multiple lines
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 << ', ' if !line.blank?
90
+ line << ', ' unless line.blank?
50
91
  line << region_name
51
92
  end
52
93
  if postal_code?
53
- line << ' ' if !line.blank?
94
+ line << ' ' unless line.blank?
54
95
  line << postal_code
55
96
  end
56
- lines << line if !line.blank?
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
- def known_region_required?
64
- country.nil? || country.regions.count != 0
65
- end
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
- true
83
- end
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