require 'open-uri' require 'cgi' require 'rexml/document' # Defined by the ISO 3166 standard. The ISO 3166 standard includes a # "Country Subdivision Code", giving a code for the names of the principal # administrative subdivisions of the countries coded in ISO 3166. class Country < ActiveRecord::Base # The url of the open source version of the ISO 3166 standard ISO_3166_URL = 'http://svn.debian.org/wsvn/pkg-isocodes/trunk/iso-codes/iso_3166/iso_3166.xml?op=file' class << self # Creates a fixtures file containing all possible countries def create_fixtures(output_file_path = nil) output_file_path ||= 'db/bootstrap/countries.yml' output_file_path = File.join(RAILS_ROOT, output_file_path) FileUtils.mkdir_p(File.dirname(output_file_path)) output_file = File.new(output_file_path, File::CREAT|File::TRUNC|File::RDWR) output = '' countries = download_all puts "Saving countries to #{output_file_path}..." if PluginAWeek::Has::Addresses.verbose countries.each do |country| record_name = country.name.gsub(' ', '_').gsub(/[^A-Za-z_]/, '').downcase output << "#{record_name}:\n" country.attributes.each do |attr, value| output << " #{attr}: #{value}\n" if value end end output_file << output.slice(0..output.length-2) output_file.close puts 'Done!' if PluginAWeek::Has::Addresses.verbose true end # Bootstraps the table by downloading the latest ISO 3166 standard and # saving each country to the database def bootstrap countries = download_all puts 'Loading countries into database...' if PluginAWeek::Has::Addresses.verbose delete_all countries.each {|country| country.save!} puts 'Done!' if PluginAWeek::Has::Addresses.verbose true end # Downloads the latest ISO 3166 standard and returns the data as a list of # countries def download_all # Download the standard puts 'Downloading ISO 3166 data...' if PluginAWeek::Has::Addresses.verbose iso_3166 = open(ISO_3166_URL).readlines * "\n" iso_3166 = CGI::unescapeHTML(/
(.+)<\/pre>/im.match(iso_3166)[1].gsub(' ', '')) # Parse and load the countries puts 'Parsing countries...' if PluginAWeek::Has::Addresses.verbose countries = [] REXML::Document.new(iso_3166).elements.each('*/iso_3166_entry') do |country| name = country.attributes['name'].to_s.gsub("'","\\'") official_name = country.attributes['official_name'] official_name = official_name.to_s.gsub!("'", "\\'") if official_name alpha_2_code = country.attributes['alpha_2_code'].to_s.upcase alpha_3_code = country.attributes['alpha_3_code'].to_s.upcase country_id = country.attributes['numeric_code'].to_s.to_i record_name = name.gsub(' ', '_').gsub(/[^A-Za-z_]/, '').downcase country = new( :name => name, :official_name => official_name, :alpha_2_code => alpha_2_code, :alpha_3_code => alpha_3_code ) country.id = country_id countries << country end countries end end has_many :regions validates_presence_of :name, :alpha_2_code, :alpha_3_code validates_uniqueness_of :name, :alpha_2_code, :alpha_3_code validates_length_of :name, :within => 2..80 validates_length_of :alpha_2_code, :is => 2 validates_length_of :alpha_3_code, :is => 3 alias_attribute :abbreviation_2, :alpha_2_code alias_attribute :abbreviation_3, :alpha_3_code # The official name of the country def official_name read_attribute(:official_name) || name end # Returns the name of the country def to_s #:nodoc name end end