addressable_record 1.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.
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ README.rdoc
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ LICENSE
data/.gitignore ADDED
@@ -0,0 +1,22 @@
1
+ ## MAC OS
2
+ .DS_Store
3
+
4
+ ## TEXTMATE
5
+ *.tmproj
6
+ tmtags
7
+
8
+ ## EMACS
9
+ *~
10
+ \#*
11
+ .\#*
12
+
13
+ ## VIM
14
+ *.swp
15
+
16
+ ## PROJECT::GENERAL
17
+ coverage
18
+ rdoc
19
+ pkg
20
+
21
+ ## PROJECT::SPECIFIC
22
+ .idea/*
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Jason Harrelson (midas)
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
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.
data/README.rdoc ADDED
@@ -0,0 +1,144 @@
1
+ = addressable_record
2
+
3
+ http://github.com/midas/addressable_record
4
+
5
+
6
+ == DESCRIPTION
7
+
8
+ Encapsulates the composed of pattern for addresses into any easy to use library.
9
+
10
+
11
+ == FEATURES
12
+
13
+ * Store an address in multiple database fields, but load it as a AddressableRecord::Address object.
14
+ * Parse virtually any formatting an address can be represented with.
15
+ * Use 1 or more street address parts with no limit.
16
+ * Overrides #to_s with format strings to control output.
17
+ * Pre-defined named format strings to control output.
18
+ * Migration generator to generate a migration file containing the correct fields to hold the address data.
19
+
20
+
21
+ == REQUIREMENTS
22
+
23
+ * geographer >= 1.1.1
24
+ * active_record >= 2.3
25
+
26
+
27
+ == INSTALL
28
+
29
+ gem sources -a http://gemcutter.org
30
+ sudo gem install addressable_record
31
+
32
+
33
+ == INSTALL FOR RAILS
34
+
35
+ Add to environment file:
36
+
37
+ config.gem "addressable_record", :version => '1.0.0', :source => 'http://gemcutter.org'
38
+
39
+ Run:
40
+
41
+ sudo rake:gems:install
42
+
43
+
44
+ == USAGE
45
+
46
+ Generate a migration to add the necessary field to the database:
47
+
48
+ script/generate addressable_record_migration {file_name} {table_name} {field_name}
49
+ script/generate addressable_record_migration users_have_home_address users home_address
50
+
51
+ Will yield:
52
+
53
+ class UsersHaveHomeAddress < ActiveRecord::Migration
54
+ def self.up
55
+ add_column :users, :home_address_raw_street, :string, :limit => 255
56
+ add_column :users, :home_address_city, :string, :limit => 50
57
+ add_column :users, :home_address_state_or_province, :string, :limit => 50
58
+ add_column :users, :home_address_raw_zip_code, :string, :limit => 9
59
+ add_column :users, :home_address_country, :string, :limit => 75
60
+ end
61
+
62
+ def self.down
63
+ remove_column :users, :home_address_raw_street
64
+ remove_column :users, :home_address_city
65
+ remove_column :users, :home_address_state_or_province
66
+ remove_column :users, :home_address_raw_zip_code
67
+ remove_column :users, :home_address_country
68
+ end
69
+ end
70
+
71
+ Call the macro in an ActiveRecord descendant:
72
+
73
+ class User < ActiveRecord::Base
74
+ address :home_address
75
+ end
76
+
77
+ Set the field equal to something:
78
+
79
+ @user.home_address = AddressableRecord::Address.new( :raw_street => '123 Jones Street###Suite 540', :city => 'Atlanta',
80
+ :state_or_province => 'GA', :raw_zip_code => '333331111', :country => 'United States' )
81
+
82
+ or (with identical results):
83
+
84
+ @user.home_address = ['123 Jones Street', 'Suite 540', 'Atlanta', 'GA', '33333-1111']
85
+
86
+ Reference the raw database fields:
87
+
88
+ @user.home_address_raw_street # => 123 Jones Street###Suite 540
89
+ @user.home_address_city # => Atlanta
90
+ @user.home_address_state_or_province # => GA
91
+ @user.home_address_raw_zip_code # => 333331111
92
+ @user.home_address_country # => United States
93
+
94
+ Reference the sub parts of the field:
95
+
96
+ @user.home_address.streets.first # => 123 Jones Street
97
+ @user.home_address.streets.join( ', ' ) # => 123 Jones Street, Suite 540
98
+ @user.home_address.streets[1] # => Suite 540
99
+ @user.home_address.street # => 123 Jones Street, Suite 540
100
+ @user.home_address.city # => Atlanta
101
+ @user.home_address.state_or_province # => GA
102
+ @user.home_address.state # => GA
103
+ @user.home_address.province # => GA
104
+ @user.home_address.zip_code # => 33333-1111
105
+ @user.home_address.country # => United States
106
+
107
+ Use formats to control the output:
108
+
109
+ @user.home_address.to_s( '%s' ) # => 123 Jones Street, Suite 540
110
+ @user.home_address.to_s( '%c' ) # => Atlanta
111
+ @user.home_address.to_s( '%S' ) # => GA
112
+ @user.home_address.to_s( '%z' ) # => 33333-1111
113
+ @user.home_address.to_s( '%C' ) # => United States
114
+ @user.home_address.to_s( '%c %S' ) # => Atlanta GA
115
+
116
+ Use pre-defined named formats to control the output:
117
+
118
+ @user.home_address.to_s( :us_long ) # => 123 Jones Street, Suite 540, Atlanta GA, 33333-1111, United States
119
+ @user.home_address.to_s( :us ) # => 123 Jones Street, Suite 540, Atlanta GA, 33333-1111
120
+
121
+
122
+ == Note on Patches/Pull Requests
123
+
124
+ * Fork the project.
125
+ * Make your feature addition or bug fix.
126
+ * Add tests for it. This is important so I don't break it in a
127
+ future version unintentionally.
128
+ * Commit, do not mess with rakefile, version, or history.
129
+ (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
130
+ * Send me a pull request. Bonus points for topic branches.
131
+
132
+
133
+ == Copyright
134
+
135
+ Copyright (c) 2009 C. Jason Harrelson (midas)
136
+
137
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
138
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
139
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
140
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
141
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
142
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
143
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
144
+
data/Rakefile ADDED
@@ -0,0 +1,47 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "addressable_record"
8
+ gem.summary = %Q{Encapsulates the composed of pattern for addresses into any easy to use library.}
9
+ gem.description = %Q{Encapsulates the composed of pattern for addresses into any easy to use library. Provides conveniencce methods for formatting, parsing, etc.}
10
+ gem.email = "jason@lookforwardenterprises.com"
11
+ gem.homepage = "http://github.com/midas/addressable_record"
12
+ gem.authors = ["C. Jason Harrelson (midas)"]
13
+ gem.add_dependency "geographer", ">= 1.1.1"
14
+ gem.add_dependency "activerecord", ">= 2.3"
15
+ gem.add_development_dependency "rspec", ">= 1.2.9"
16
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
17
+ end
18
+ Jeweler::GemcutterTasks.new
19
+ rescue LoadError
20
+ puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
21
+ end
22
+
23
+ require 'spec/rake/spectask'
24
+ Spec::Rake::SpecTask.new(:spec) do |spec|
25
+ spec.libs << 'lib' << 'spec'
26
+ spec.spec_files = FileList['spec/**/*_spec.rb']
27
+ end
28
+
29
+ Spec::Rake::SpecTask.new(:rcov) do |spec|
30
+ spec.libs << 'lib' << 'spec'
31
+ spec.pattern = 'spec/**/*_spec.rb'
32
+ spec.rcov = true
33
+ end
34
+
35
+ task :spec => :check_dependencies
36
+
37
+ task :default => :spec
38
+
39
+ require 'rake/rdoctask'
40
+ Rake::RDocTask.new do |rdoc|
41
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
42
+
43
+ rdoc.rdoc_dir = 'rdoc'
44
+ rdoc.title = "addressable_record #{version}"
45
+ rdoc.rdoc_files.include('README*')
46
+ rdoc.rdoc_files.include('lib/**/*.rb')
47
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 1.0.0
@@ -0,0 +1,74 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{addressable_record}
8
+ s.version = "1.0.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["C. Jason Harrelson (midas)"]
12
+ s.date = %q{2009-12-31}
13
+ s.description = %q{Encapsulates the composed of pattern for addresses into any easy to use library. Provides conveniencce methods for formatting, parsing, etc.}
14
+ s.email = %q{jason@lookforwardenterprises.com}
15
+ s.extra_rdoc_files = [
16
+ "LICENSE",
17
+ "README.rdoc"
18
+ ]
19
+ s.files = [
20
+ ".document",
21
+ ".gitignore",
22
+ "LICENSE",
23
+ "README.rdoc",
24
+ "Rakefile",
25
+ "VERSION",
26
+ "addressable_record.gemspec",
27
+ "lib/addressable_record.rb",
28
+ "lib/addressable_record/active_record_extesions.rb",
29
+ "lib/addressable_record/address.rb",
30
+ "lib/addressable_record/states.rb",
31
+ "rails_generators/addressable_record_migration_generator/addressable_record_migration_generator.rb",
32
+ "rails_generators/addressable_record_migration_generator/templates/migration.rb",
33
+ "script/console",
34
+ "script/environment.rb",
35
+ "script/seed.rb",
36
+ "spec/addressable_record/address_parsing_shared_spec.rb",
37
+ "spec/addressable_record/address_spec.rb",
38
+ "spec/addressable_record_spec.rb",
39
+ "spec/database.yml",
40
+ "spec/spec.opts",
41
+ "spec/spec_helper.rb"
42
+ ]
43
+ s.homepage = %q{http://github.com/midas/addressable_record}
44
+ s.rdoc_options = ["--charset=UTF-8"]
45
+ s.require_paths = ["lib"]
46
+ s.rubygems_version = %q{1.3.5}
47
+ s.summary = %q{Encapsulates the composed of pattern for addresses into any easy to use library.}
48
+ s.test_files = [
49
+ "spec/addressable_record/address_parsing_shared_spec.rb",
50
+ "spec/addressable_record/address_spec.rb",
51
+ "spec/addressable_record_spec.rb",
52
+ "spec/spec_helper.rb"
53
+ ]
54
+
55
+ if s.respond_to? :specification_version then
56
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
57
+ s.specification_version = 3
58
+
59
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
60
+ s.add_runtime_dependency(%q<geographer>, [">= 1.1.1"])
61
+ s.add_runtime_dependency(%q<activerecord>, [">= 2.3"])
62
+ s.add_development_dependency(%q<rspec>, [">= 1.2.9"])
63
+ else
64
+ s.add_dependency(%q<geographer>, [">= 1.1.1"])
65
+ s.add_dependency(%q<activerecord>, [">= 2.3"])
66
+ s.add_dependency(%q<rspec>, [">= 1.2.9"])
67
+ end
68
+ else
69
+ s.add_dependency(%q<geographer>, [">= 1.1.1"])
70
+ s.add_dependency(%q<activerecord>, [">= 2.3"])
71
+ s.add_dependency(%q<rspec>, [">= 1.2.9"])
72
+ end
73
+ end
74
+
@@ -0,0 +1,33 @@
1
+ module AddressableRecord
2
+ module ActiveRecordExtensions
3
+ def self.included( base )
4
+ base.extend ActsMethods
5
+ end
6
+
7
+ module ActsMethods
8
+ def address( *args )
9
+ unless included_modules.include? InstanceMethods
10
+ self.class_eval { extend ClassMethods }
11
+ include InstanceMethods
12
+ end
13
+ initialize_compositions( args )
14
+ end
15
+
16
+ alias_method :addresses, :address
17
+ end
18
+
19
+ module ClassMethods
20
+ def initialize_compositions( attrs )
21
+ attrs.each do |attr|
22
+ composed_of attr, :class_name => 'AddressableRecord::Address', :converter => :convert, :allow_nil => true,
23
+ :mapping => [["#{attr}_raw_street", 'raw_street'], ["#{attr}_city", 'city'], ["#{attr}_state_or_province", 'state_or_province'], ["#{attr}_raw_zip_code", 'raw_zip_code'], ["#{attr}_country", 'country']],
24
+ :constructor => Proc.new { |raw_street, city, state_or_province, raw_zip_code, country| AddressableRecord::Address.new( :raw_street => raw_street, :city => city, :state_or_province => state_or_province, :raw_zip_code => raw_zip_code, :country => country ) }
25
+ end
26
+ end
27
+ end
28
+
29
+ module InstanceMethods
30
+
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,127 @@
1
+ require File.dirname(__FILE__) + '/states'
2
+
3
+ module AddressableRecord
4
+ class Address
5
+ attr_reader :raw_street, :streets, :city, :state_or_province, :zip_code, :country
6
+
7
+ @@street_delimiter ||= '###'
8
+ @@zip_code_delimiter ||= '-'
9
+ @@patterns ||= {
10
+ :us_long => "%s, %c %S, %z, %C",
11
+ :us => "%s, %c %S, %z"
12
+ }
13
+
14
+ def initialize( attrs )
15
+ raise 'Initilaizer argument must be an attributes hash.' unless attrs.is_a?( Hash )
16
+ @city, @state_or_province, @country = attrs[:city], attrs[:state_or_province], attrs[:country]
17
+
18
+ @streets = AddressableRecord::Address.parse_street( attrs[:raw_street] || '' )
19
+ raw_zip = (attrs[:raw_zip_code] || '')
20
+ @zip_code = raw_zip.size == 5 ? @raw_zip_code : raw_zip.gsub( /(\d{5})(\d{4})/, "\\1#{@@zip_code_delimiter}\\2" )
21
+
22
+ @pattern_map = {
23
+ '%s' => @streets.join( ', ' ) || "",
24
+ '%1' => @streets[0] || "",
25
+ '%2' => @streets[1] || "",
26
+ '%3' => @streets[2] || "",
27
+ '%4' => @streets[3] || "",
28
+ '%5' => @streets[4] || "",
29
+ '%c' => @city || "",
30
+ '%S' => @state_or_province || "",
31
+ '%z' => @zip_code || "",
32
+ '%C' => @country || ""
33
+ }
34
+
35
+ self.freeze
36
+ end
37
+
38
+ def self.street_delimiter
39
+ @@street_delimiter
40
+ end
41
+
42
+ def state
43
+ @state_or_province
44
+ end
45
+
46
+ def province
47
+ @state_or_province
48
+ end
49
+
50
+ def street( delimiter=', ' )
51
+ return @streets.nil? ? '' : @streets.join( delimiter )
52
+ end
53
+
54
+ def self.parse( address )
55
+ raise "Cannot convert #{address.class.to_s.downcase} to an AddressableRecord::Address" unless [Array].include?( address.class )
56
+ self.send( :"parse_#{address.class.to_s.downcase}", address )
57
+ end
58
+
59
+ def self.convert( address ) #:nodoc:
60
+ parse( address )
61
+ end
62
+
63
+ def self.parse_street( street ) #:nodoc:
64
+ return street.split( @@street_delimiter )
65
+ end
66
+
67
+ # Outputs a address based on pattern provided.
68
+ #
69
+ # Symbols:
70
+ # %s - street
71
+ # %c - city
72
+ # %S - state
73
+ # %z - zip code
74
+ # %C - country
75
+ #
76
+ def to_s( pattern=nil )
77
+ to_return = pattern.is_a?( Symbol ) ? @@patterns[pattern] : pattern
78
+ to_return = @@patterns[:us] if to_return.nil? || to_return.empty?
79
+ @pattern_map.each { |pat, replacement| to_return = to_return.gsub( pat, replacement ) }
80
+ to_return.strip
81
+ end
82
+
83
+ protected
84
+
85
+ def raw_street #:nodoc:
86
+ return @streets.nil? ? '' : @streets.join( @@street_delimiter ) #@streets.join( @@street_delimiter )
87
+ end
88
+
89
+ def raw_zip_code #:nodoc:
90
+ return @zip_code.nil? ? '' : @zip_code.gsub( /#{@@zip_code_delimiter}/, '' )
91
+ end
92
+
93
+ class << self
94
+ private
95
+
96
+ def parse_array( address_elements ) #:nodoc:
97
+ state_pos = find_state_position( address_elements )
98
+ raise 'Cannot parse address array. Failed to find a state.' if state_pos.nil?
99
+ raise 'Cannot parse address array. No zip code found.' unless address_elements.size >= (state_pos + 1)
100
+ state = States.by_abbreviation.has_key?( address_elements[state_pos] ) ? address_elements[state_pos] : States.by_name[address_elements[state_pos]]
101
+ zip_code = address_elements[state_pos+1].gsub( /#{@@zip_code_delimiter}/, '' )
102
+ country = address_elements.size >= (state_pos + 3) ? address_elements[state_pos+2] : 'United States'
103
+ city = address_elements[state_pos-1]
104
+ streets = []
105
+ (0..state_pos-2).each { |i| streets << address_elements[i] }
106
+ street = streets.join( @@street_delimiter )
107
+ return AddressableRecord::Address.new( :raw_street => street, :city => city, :state_or_province => state, :raw_zip_code => zip_code, :country => country )
108
+ end
109
+
110
+ def find_state_position( address_elements )
111
+ # Look for state abbreviation
112
+ possible_abbreviation_positions = find_possible_state_abbrev_positions( address_elements )
113
+ state_index = possible_abbreviation_positions.detect { |i| States.by_abbreviation.has_key?( address_elements[i] ) }
114
+ return state_index unless state_index.nil?
115
+
116
+ # Look for state name
117
+ (0..address_elements.size-1).detect { |i| States.by_name.has_key?( address_elements[i] ) }
118
+ end
119
+
120
+ def find_possible_state_abbrev_positions( address_array )
121
+ positions = []
122
+ address_array.each_with_index { |str, i| positions << i if str.size == 2 }
123
+ positions
124
+ end
125
+ end
126
+ end
127
+ end
@@ -0,0 +1,8 @@
1
+ require 'rubygems'
2
+ require 'geographer'
3
+
4
+ module AddressableRecord
5
+ class States
6
+ include Geographer::Us::States
7
+ end
8
+ end
@@ -0,0 +1,10 @@
1
+ $:.unshift(File.dirname(__FILE__)) unless
2
+ $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
3
+ require 'addressable_record/address'
4
+ require 'addressable_record/active_record_extesions'
5
+
6
+ module AddressableRecord
7
+ VERSION = '1.0.0'
8
+ end
9
+
10
+ ActiveRecord::Base.send( :include, AddressableRecord::ActiveRecordExtensions ) if defined?( ActiveRecord::Base )
@@ -0,0 +1,21 @@
1
+ class AddressableRecordMigrationGenerator < Rails::Generator::NamedBase
2
+ def initialize( runtime_args, runtime_options={} )
3
+ super
4
+ @stamp = DateTime.now.utc.strftime( "%Y%m%d%H%M%S" )
5
+ parse_args( args )
6
+ end
7
+
8
+ def manifest
9
+ record do |m|
10
+ m.directory "db/migrate"
11
+ m.template "migration.rb", "db/migrate/#{@stamp}_#{name}.rb", :assigns => { :table => @table, :field => @field }
12
+ end
13
+ end
14
+
15
+ private
16
+
17
+ def parse_args( args )
18
+ @table = args[0]
19
+ @field = args[1]
20
+ end
21
+ end
@@ -0,0 +1,17 @@
1
+ class <%= class_name %> < ActiveRecord::Migration
2
+ def self.up
3
+ add_column :<%= table %>, :<%= field %>_raw_street, :string, :limit => 255
4
+ add_column :<%= table %>, :<%= field %>_city, :string, :limit => 50
5
+ add_column :<%= table %>, :<%= field %>_state_or_province, :string, :limit => 50
6
+ add_column :<%= table %>, :<%= field %>_raw_zip_code, :string, :limit => 9
7
+ add_column :<%= table %>, :<%= field %>_country, :string, :limit => 75
8
+ end
9
+
10
+ def self.down
11
+ remove_column :<%= table %>, :<%= field %>_raw_street
12
+ remove_column :<%= table %>, :<%= field %>_city
13
+ remove_column :<%= table %>, :<%= field %>_state_or_province
14
+ remove_column :<%= table %>, :<%= field %>_raw_zip_code
15
+ remove_column :<%= table %>, :<%= field %>_country
16
+ end
17
+ end
data/script/console ADDED
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env ruby
2
+ # File: script/console
3
+ irb = RUBY_PLATFORM =~ /(:?mswin|mingw)/ ? 'irb.bat' : 'irb'
4
+
5
+ libs = " -r irb/completion"
6
+ # Perhaps use a console_lib to store any extra methods I may want available in the cosole
7
+ # libs << " -r #{File.dirname(__FILE__) + '/../lib/console_lib/console_logger.rb'}"
8
+ libs << " -r 'rubygems' -r 'active_record' -r 'binary_search/pure' -r 'geographer' -r '#{File.dirname(__FILE__) + '/../lib/addressable_record.rb'}' -r '#{File.dirname(__FILE__) + '/environment'}' -r '#{File.dirname(__FILE__) + '/seed'}'"
9
+
10
+ puts "Loading addressable_record gem"
11
+ exec "#{irb} #{libs} --simple-prompt"
@@ -0,0 +1,43 @@
1
+ ActiveRecord::Base.configurations = YAML::load( IO.read( File.dirname(__FILE__) + '/../spec/database.yml' ) )
2
+ ActiveRecord::Base.establish_connection( 'test' )
3
+
4
+ ActiveRecord::Schema.define :version => 1 do
5
+ create_table "users", :force => true do |t|
6
+ t.string "name", :limit => 50
7
+ t.string "address_street", :limit => 255
8
+ t.string "address_city", :limit => 50
9
+ t.string "address_state_or_province", :limit => 50
10
+ t.string "address_zip_code", :limit => 9
11
+ t.string "address_country", :limit => 50
12
+ end
13
+
14
+ create_table "people", :force => true do |t|
15
+ t.string "name", :limit => 50
16
+ end
17
+
18
+ create_table "contact_addresses", :force => true do |t|
19
+ t.integer :person_id
20
+ t.string :location, :default => 'unknown', :null => false
21
+ t.string "address_raw_street", :limit => 255
22
+ t.string "address_city", :limit => 50
23
+ t.string "address_state_or_province", :limit => 50
24
+ t.string "address_raw_zip_code", :limit => 9
25
+ t.string "address_country", :limit => 50
26
+ end
27
+ end
28
+
29
+ class User < ActiveRecord::Base
30
+ address :address
31
+ end
32
+
33
+ class Person < ActiveRecord::Base
34
+ has_many :contact_addresses
35
+ end
36
+
37
+ class ContactAddress < ActiveRecord::Base
38
+ address :address
39
+ belongs_to :person
40
+ end
41
+
42
+ ADDRESS_ATTRIBUTES = {:raw_street => '123 Jones Street###Suite 540', :city => 'Atlanta', :state_or_province => 'GA',
43
+ :raw_zip_code => '312347890', :country => 'United States' }
data/script/seed.rb ADDED
@@ -0,0 +1,3 @@
1
+ @person = Person.create( :name => 'John Smith' )
2
+ @person.contact_addresses.build( :address => AddressableRecord::Address.new( ADDRESS_ATTRIBUTES ) )
3
+ @person.save!
@@ -0,0 +1,31 @@
1
+ require File.expand_path( File.dirname(__FILE__) + '/../spec_helper' )
2
+
3
+ shared_examples_for "The address 123 Jones Street, Suite 540, Atlanta, GA, 33333-1111, United States" do
4
+ it "should be an AddressableRecord::Address" do
5
+ @address.is_a?( AddressableRecord::Address ).should be_true
6
+ end
7
+
8
+ it "should agree that the size of streets is 2" do
9
+ @address.streets.size.should eql( 2 )
10
+ end
11
+
12
+ it "should agree that the street address is 123 Jones Street, Suite 540" do
13
+ @address.street.should eql( '123 Jones Street, Suite 540' )
14
+ end
15
+
16
+ it "should agree that the city is Atlanta" do
17
+ @address.city.should eql( 'Atlanta' )
18
+ end
19
+
20
+ it "should agree that the state is GA" do
21
+ @address.state.should eql( 'GA' )
22
+ end
23
+
24
+ it "should agree that the zip_code is 33333-1111" do
25
+ @address.zip_code.should eql( '33333-1111' )
26
+ end
27
+
28
+ it "should agree that the country is United States" do
29
+ @address.country.should eql( 'United States' )
30
+ end
31
+ end
@@ -0,0 +1,151 @@
1
+ require File.expand_path( File.dirname(__FILE__) + '/../spec_helper' )
2
+ require File.expand_path( File.dirname(__FILE__) + '/address_parsing_shared_spec' )
3
+
4
+ describe "AddressableRecord::Address" do
5
+ before :each do
6
+ @address_attributes = ADDRESS_ATTRIBUTES
7
+ @klass = AddressableRecord::Address
8
+ @instance = AddressableRecord::Address.new( @address_attributes )
9
+ end
10
+
11
+ it "should agree that the raw_street is correct" do
12
+ @instance.send( :raw_street ).should eql( @address_attributes[:raw_street] )
13
+ end
14
+
15
+ it "should agree that the city is correct" do
16
+ @instance.city.should eql( @address_attributes[:city] )
17
+ end
18
+
19
+ it "should agree that the state_or_province is correct" do
20
+ @instance.state_or_province.should eql( @address_attributes[:state_or_province] )
21
+ end
22
+
23
+ it "should agree that the raw_zip_code is correct" do
24
+ @instance.send( :raw_zip_code ).should eql( @address_attributes[:raw_zip_code] )
25
+ end
26
+
27
+ it "should agree that the country is correct" do
28
+ @instance.country.should eql( @address_attributes[:country] )
29
+ end
30
+
31
+ it "should agree that the streets array is the correct size" do
32
+ @instance.streets.size.should eql( 2 )
33
+ end
34
+
35
+ it "should agree that the default call to \#street is correct" do
36
+ @instance.street.should eql( @address_attributes[:raw_street].split( AddressableRecord::Address.street_delimiter ).join( ', ' ) )
37
+ end
38
+
39
+ it "should agree that the call to \#street with a pattern of '\\n' is correct" do
40
+ @instance.street( '\n' ).should eql( @address_attributes[:raw_street].split( AddressableRecord::Address.street_delimiter ).join( '\n' ) )
41
+ end
42
+
43
+ it "should agree that the zip code is correct" do
44
+ @instance.zip_code.should eql( "#{@address_attributes[:raw_zip_code][0..4]}-#{@address_attributes[:raw_zip_code][5..9]}")
45
+ end
46
+
47
+ it "should agree that the state is the state_or_province" do
48
+ @instance.state.should eql( @instance.state_or_province )
49
+ end
50
+
51
+ it "should agree that the province is the state_or_province" do
52
+ @instance.province.should eql( @instance.state_or_province )
53
+ end
54
+
55
+ it "should be able to find the position of a state abbreviation in an array" do
56
+ @klass.send( :find_state_position, ['123 Jones St.', 'Atlanta', 'GA', '33333', ] ).should eql( 2 )
57
+ end
58
+
59
+ it "should be able to find the position of a state name in an array" do
60
+ @klass.send( :find_state_position, ['123 Jones St.', 'Atlanta', 'Georgia', '33333', ] ).should eql( 2 )
61
+ end
62
+
63
+ it "should return nil if an address array does not have a state in it" do
64
+ @klass.send( :find_state_position, ['123 Jones St.', 'Atlanta', '33333' ] ).should be_nil
65
+ end
66
+
67
+ describe "when parsing an array of address elements" do
68
+ before :each do
69
+ @address_elements_without_country = ['123 Jones Street', 'Suite 540', 'Atlanta', 'GA', '33333-1111']
70
+ end
71
+
72
+ describe "with a country" do
73
+ before :each do
74
+ @address = @klass.parse( @address_elements_without_country + ['United States'] )
75
+ end
76
+
77
+ it_should_behave_like "The address 123 Jones Street, Suite 540, Atlanta, GA, 33333-1111, United States"
78
+ end
79
+
80
+ describe "without a country" do
81
+ before :each do
82
+ @address = @klass.parse( @address_elements_without_country )
83
+ end
84
+
85
+ it_should_behave_like "The address 123 Jones Street, Suite 540, Atlanta, GA, 33333-1111, United States"
86
+ end
87
+
88
+ describe "with a spelled out state name" do
89
+ before :each do
90
+ @address_elements_without_country[@address_elements_without_country.index( 'GA' )] = 'Georgia'
91
+ @address = @klass.parse( @address_elements_without_country )
92
+ end
93
+
94
+ it_should_behave_like "The address 123 Jones Street, Suite 540, Atlanta, GA, 33333-1111, United States"
95
+ end
96
+
97
+ describe "when printing out a formatted string" do
98
+ before :each do
99
+ @address = @klass.parse( @address_elements_without_country )
100
+ end
101
+
102
+ it "should obey the :us format correctly" do
103
+ @address.to_s( :us ).should eql( '123 Jones Street, Suite 540, Atlanta GA, 33333-1111' )
104
+ end
105
+
106
+ it "should obey the :us_long format correctly" do
107
+ @address.to_s( :us_long ).should eql( '123 Jones Street, Suite 540, Atlanta GA, 33333-1111, United States' )
108
+ end
109
+
110
+ it "should obey the %s format correctly" do
111
+ @address.to_s( '%s' ).should eql( '123 Jones Street, Suite 540' )
112
+ end
113
+
114
+ it "should obey the %1 format correctly" do
115
+ @address.to_s( '%1' ).should eql( '123 Jones Street' )
116
+ end
117
+
118
+ it "should obey the %2 format correctly" do
119
+ @address.to_s( '%2' ).should eql( 'Suite 540' )
120
+ end
121
+
122
+ it "should obey the %3 format correctly" do
123
+ @address.to_s( '%3' ).should eql( '' )
124
+ end
125
+
126
+ it "should obey the %4 format correctly" do
127
+ @address.to_s( '%4' ).should eql( '' )
128
+ end
129
+
130
+ it "should obey the %5 format correctly" do
131
+ @address.to_s( '%5' ).should eql( '' )
132
+ end
133
+
134
+ it "should obey the %c format correctly" do
135
+ @address.to_s( '%c' ).should eql( 'Atlanta' )
136
+ end
137
+
138
+ it "should obey the %S format correctly" do
139
+ @address.to_s( '%S' ).should eql( 'GA' )
140
+ end
141
+
142
+ it "should obey the %z format correctly" do
143
+ @address.to_s( '%z' ).should eql( '33333-1111' )
144
+ end
145
+
146
+ it "should obey the %C format correctly" do
147
+ @address.to_s( '%C' ).should eql( 'United States' )
148
+ end
149
+ end
150
+ end
151
+ end
@@ -0,0 +1,109 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe "AddressableRecord" do
4
+ describe "having ActiveRecord extensions" do
5
+ it "should respond to address" do
6
+ ActiveRecord::Base.respond_to?( :address ).should be_true
7
+ end
8
+
9
+ it "should respond to addresses" do
10
+ ActiveRecord::Base.respond_to?( :addresses ).should be_true
11
+ end
12
+ end
13
+
14
+ describe "having models descending from ActiveRecord" do
15
+ before :each do
16
+ @address_attributes = ADDRESS_ATTRIBUTES
17
+ @user = User.new( :name => 'John Smith', :address => AddressableRecord::Address.new( @address_attributes ) )
18
+ @user.save!
19
+ end
20
+
21
+ it "should respond to home_address" do
22
+ @user.respond_to?( :address ).should be_true
23
+ end
24
+
25
+ it "should be an AddressableRecord::Address" do
26
+ @user.address.is_a?( AddressableRecord::Address ).should be_true
27
+ end
28
+
29
+ it "should agree that the size of streets is 2" do
30
+ @user.address.streets.size.should eql( 2 )
31
+ end
32
+
33
+ it "should agree that the street address is 123 Jones Street, Suite 540" do
34
+ @user.address.street.should eql( '123 Jones Street, Suite 540' )
35
+ end
36
+
37
+ it "should agree that the city is Atlanta" do
38
+ @user.address.city.should eql( 'Atlanta' )
39
+ end
40
+
41
+ it "should agree that the state is GA" do
42
+ @user.address.state.should eql( 'GA' )
43
+ end
44
+
45
+ it "should agree that the zip_code is 31234-7890" do
46
+ @user.address.zip_code.should eql( '31234-7890' )
47
+ end
48
+
49
+ it "should agree that the country is United States" do
50
+ @user.address.country.should eql( 'United States' )
51
+ end
52
+ end
53
+
54
+ describe "when used through an association" do
55
+ before :each do
56
+ @address_attributes = ADDRESS_ATTRIBUTES
57
+ @person = Person.new( :name => 'John Smith' )
58
+ @person.save!
59
+ end
60
+
61
+ describe "creating through the association" do
62
+ before :each do
63
+ @address = AddressableRecord::Address.new( @address_attributes )
64
+ @person.contact_addresses.build( :address => @address )
65
+ @person.save!
66
+ end
67
+
68
+ it "should agree that the address street is 123 Jones Street, Suite 540" do
69
+ @address.street.should eql( '123 Jones Street, Suite 540' )
70
+ end
71
+
72
+ it "should agree that the associated street is 123 Jones Street, Suite 540" do
73
+ @person.contact_addresses.first.address.street.should eql( '123 Jones Street, Suite 540' )
74
+ end
75
+
76
+ it "should agree that the address city is Atlanta" do
77
+ @address.city.should eql( 'Atlanta' )
78
+ end
79
+
80
+ it "should agree that the associated street is Atlanta" do
81
+ @person.contact_addresses.first.address.city.should eql( 'Atlanta' )
82
+ end
83
+
84
+ it "should agree that the address state is GA" do
85
+ @address.state.should eql( 'GA' )
86
+ end
87
+
88
+ it "should agree that the associated state is GA" do
89
+ @person.contact_addresses.first.address.state.should eql( 'GA' )
90
+ end
91
+
92
+ it "should agree that the address zip code is 31234-7890" do
93
+ @address.zip_code.should eql( '31234-7890' )
94
+ end
95
+
96
+ it "should agree that the associated zip code is 31234-7890" do
97
+ @person.contact_addresses.first.address.zip_code.should eql( '31234-7890' )
98
+ end
99
+
100
+ it "should agree that the address country is United States" do
101
+ @address.country.should eql( 'United States' )
102
+ end
103
+
104
+ it "should agree that the associated country is United States" do
105
+ @person.contact_addresses.first.address.country.should eql( 'United States' )
106
+ end
107
+ end
108
+ end
109
+ end
data/spec/database.yml ADDED
@@ -0,0 +1,3 @@
1
+ test:
2
+ :adapter: sqlite3
3
+ :database: ":memory:"
data/spec/spec.opts ADDED
@@ -0,0 +1 @@
1
+ --color
@@ -0,0 +1,13 @@
1
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
2
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
3
+ require 'rubygems'
4
+ require 'active_record'
5
+ require 'addressable_record'
6
+ require 'spec'
7
+ require 'spec/autorun'
8
+
9
+ Spec::Runner.configure do |config|
10
+
11
+ end
12
+
13
+ require File.dirname(__FILE__) + '/../script/environment'
metadata ADDED
@@ -0,0 +1,109 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: addressable_record
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - C. Jason Harrelson (midas)
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-12-31 00:00:00 -06:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: geographer
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 1.1.1
24
+ version:
25
+ - !ruby/object:Gem::Dependency
26
+ name: activerecord
27
+ type: :runtime
28
+ version_requirement:
29
+ version_requirements: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: "2.3"
34
+ version:
35
+ - !ruby/object:Gem::Dependency
36
+ name: rspec
37
+ type: :development
38
+ version_requirement:
39
+ version_requirements: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ version: 1.2.9
44
+ version:
45
+ description: Encapsulates the composed of pattern for addresses into any easy to use library. Provides conveniencce methods for formatting, parsing, etc.
46
+ email: jason@lookforwardenterprises.com
47
+ executables: []
48
+
49
+ extensions: []
50
+
51
+ extra_rdoc_files:
52
+ - LICENSE
53
+ - README.rdoc
54
+ files:
55
+ - .document
56
+ - .gitignore
57
+ - LICENSE
58
+ - README.rdoc
59
+ - Rakefile
60
+ - VERSION
61
+ - addressable_record.gemspec
62
+ - lib/addressable_record.rb
63
+ - lib/addressable_record/active_record_extesions.rb
64
+ - lib/addressable_record/address.rb
65
+ - lib/addressable_record/states.rb
66
+ - rails_generators/addressable_record_migration_generator/addressable_record_migration_generator.rb
67
+ - rails_generators/addressable_record_migration_generator/templates/migration.rb
68
+ - script/console
69
+ - script/environment.rb
70
+ - script/seed.rb
71
+ - spec/addressable_record/address_parsing_shared_spec.rb
72
+ - spec/addressable_record/address_spec.rb
73
+ - spec/addressable_record_spec.rb
74
+ - spec/database.yml
75
+ - spec/spec.opts
76
+ - spec/spec_helper.rb
77
+ has_rdoc: true
78
+ homepage: http://github.com/midas/addressable_record
79
+ licenses: []
80
+
81
+ post_install_message:
82
+ rdoc_options:
83
+ - --charset=UTF-8
84
+ require_paths:
85
+ - lib
86
+ required_ruby_version: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - ">="
89
+ - !ruby/object:Gem::Version
90
+ version: "0"
91
+ version:
92
+ required_rubygems_version: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: "0"
97
+ version:
98
+ requirements: []
99
+
100
+ rubyforge_project:
101
+ rubygems_version: 1.3.5
102
+ signing_key:
103
+ specification_version: 3
104
+ summary: Encapsulates the composed of pattern for addresses into any easy to use library.
105
+ test_files:
106
+ - spec/addressable_record/address_parsing_shared_spec.rb
107
+ - spec/addressable_record/address_spec.rb
108
+ - spec/addressable_record_spec.rb
109
+ - spec/spec_helper.rb