geonames_dump 0.0.2

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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 0d54cf96d1f31ae2a2fd2a94b6d8badeb317e0df
4
+ data.tar.gz: b2a120c181cc803aae3172523013206e2efa3f46
5
+ SHA512:
6
+ metadata.gz: 2bb9c4fddd4bc7838967891358be49dd1ef1a999275223e524a939515a58d85882a90f05fbea423a1b1abb7db9f9aa2ad79292c6e39ac217962cefde3f0bd4b2
7
+ data.tar.gz: de04975b021b84aea162b710124fefa8fbe06b55ca4c4c6b8429426088efa9a016651307656245633cacb26a571b28b31c4590c4691727dff96199ea60722d36
data/.gitignore ADDED
@@ -0,0 +1,19 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ .DS_Store
18
+ .*.swp
19
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in geonames.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,23 @@
1
+ Copyright (c) 2012 Thomas Kienlen, La Fourmi Immo
2
+ Including original code Copyright (c) 2009 Alex Pooley, Brown Beagle Software
3
+
4
+ MIT License
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining
7
+ a copy of this software and associated documentation files (the
8
+ "Software"), to deal in the Software without restriction, including
9
+ without limitation the rights to use, copy, modify, merge, publish,
10
+ distribute, sublicense, and/or sell copies of the Software, and to
11
+ permit persons to whom the Software is furnished to do so, subject to
12
+ the following conditions:
13
+
14
+ The above copyright notice and this permission notice shall be
15
+ included in all copies or substantial portions of the Software.
16
+
17
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,85 @@
1
+ # GeonamesDump
2
+
3
+ GeonamesDump import geographic data from geonames project into your application, avoiding to use external service like google maps.
4
+ It's a "gem" version of the application [brownbeagle/geonames](https://github.com/brownbeagle/geonames).
5
+ Now you only need to include the dependency into your Gemfile and your project will include geonames.
6
+
7
+ You're free to use [geocoder](https://github.com/alexreisner/geocoder) or [geokit](https://github.com/imajes/geokit) or any other geocoding solution.
8
+
9
+ ## Installation
10
+
11
+ Add this line to your application's Gemfile:
12
+
13
+ gem 'geonames_dump'
14
+
15
+ And then execute:
16
+
17
+ $ bundle install
18
+
19
+ Or install it yourself as:
20
+
21
+ $ gem install geonames_dump
22
+
23
+ ## Usage
24
+
25
+ Create models and migration files
26
+
27
+ $ rails generate geonames_dump:install
28
+
29
+ Import data (takes a loonnnng time!), it will download data, import countries and many features (Countries, Cities, Admin1 (first administrative subdivision), Admin2 (second level administrative subdivision))
30
+
31
+ $ rake geonames_dump:install
32
+
33
+ If you need more fine grained control over the installation process you can run individual geoname rake tasks instead of the all-in-one install :
34
+
35
+ $ rake -T | grep geonames_dump
36
+
37
+ rake geonames_dump:import:all # Import ALL geonames data.
38
+ rake geonames_dump:import:many # Import most of geonames data.
39
+
40
+ rake geonames_dump:import:admin1 # Import admin1 codes
41
+ rake geonames_dump:import:admin2 # Import admin2 codes
42
+ rake geonames_dump:import:cities # Import all cities, regardless of population.
43
+ rake geonames_dump:import:cities1000 # Import cities with population greater than 1000
44
+ rake geonames_dump:import:cities15000 # Import cities with population greater than 15000
45
+ rake geonames_dump:import:cities5000 # Import cities with population greater than 5000
46
+ rake geonames_dump:import:countries # Import countries informations
47
+ rake geonames_dump:import:features # Import feature data.
48
+
49
+ rake geonames_dump:truncate:all # Truncate all geonames data.
50
+ rake geonames_dump:truncate:countries # Truncate countries informations
51
+ rake geonames_dump:truncate:admin1 # Truncate admin1 codes
52
+ rake geonames_dump:truncate:admin2 # Truncate admin2 codes
53
+ rake geonames_dump:truncate:cities # Truncate cities informations
54
+ rake geonames_dump:truncate:features # Truncate features informations
55
+
56
+ ## Geonames data usage
57
+
58
+ The above commands will import geonames data in your Rails application, in other words, this will create models and fill database with place/city/country informations.
59
+ Now to find a city for example :
60
+
61
+ GeonamesFeature.search('paris')
62
+
63
+ If your request is ambiguous, like not searching Dublin in Ireland but Dublin in the USA, you may specify country :
64
+
65
+ GeonamesFeature.search('dublin, us')
66
+
67
+ Models available allows to specify the type of place you want to search for :
68
+
69
+ - GeonamesAdmin1, for first level of adminstrative subdivision
70
+ - GeonamesAdmin2, for second level of adminstrative subdivision
71
+ - GeonamesCity, for city names
72
+ - GeonamesFeature, for generic names including all the above
73
+ - GeonamesCountry, for country names
74
+
75
+ Searching for a city like dublin may be done using :
76
+
77
+ GeonamesCity.search('dublin')
78
+
79
+ ## Contributing
80
+
81
+ 1. Fork it
82
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
83
+ 3. Commit your changes (`git commit -am 'Added some feature'`)
84
+ 4. Push to the branch (`git push origin my-new-feature`)
85
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
@@ -0,0 +1,20 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/geonames_dump/version', __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.authors = ["Alex Pooley", "Thomas Kienlen"]
6
+ gem.email = ["thomas.kienlen@lafourmi-immo.com"]
7
+ gem.description = %q{GeonamesDump import geographic data from geonames project into your application, avoiding to use external service like Google Maps.}
8
+ gem.summary = %q{Import data from Geonames}
9
+ gem.homepage = "https://github.com/kmmndr/geonames_dump"
10
+
11
+ gem.files = `git ls-files`.split($\)
12
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
13
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
14
+ gem.name = "geonames_dump"
15
+ gem.require_paths = ["lib"]
16
+ gem.version = GeonamesDump::VERSION
17
+ gem.add_runtime_dependency 'ruby-progressbar'
18
+ gem.add_runtime_dependency 'activerecord-reset-pk-sequence'
19
+ gem.add_runtime_dependency 'rubyzip'
20
+ end
@@ -0,0 +1,32 @@
1
+ module GeonamesDump
2
+ module Generators
3
+ class InstallGenerator < Rails::Generators::Base
4
+ include Rails::Generators::Migration
5
+ source_root File.expand_path(File.join(File.dirname(__FILE__), 'templates'))
6
+
7
+ desc <<DESC
8
+ Description:
9
+ Create Geonames initial migrations files and Geonames model files in your application
10
+ DESC
11
+ def copy_migrations_files
12
+ #template File.join('app', 'models', 'geonames_country.rb', 'config/initializers/piktur_config.rb'
13
+ %w(create_geonames_countries create_geonames_features).each do |file|
14
+ migration_template File.join('db', 'migrate', "#{file}.rb")
15
+ end
16
+ end
17
+
18
+ def copy_models_files
19
+ #template File.join('app', 'models', 'geonames_country.rb', 'config/initializers/piktur_config.rb'
20
+ %w(geonames_admin1 geonames_admin2 geonames_city geonames_country geonames_feature).each do |file|
21
+ copy_file File.join('app', 'models', "#{file}.rb")
22
+ end
23
+ end
24
+
25
+ def self.next_migration_number(path)
26
+ sleep 1 # OPTIMIZE: there might be a better way to do this ...
27
+ @migration_number = Time.now.utc.strftime("%Y%m%d%H%M%S").to_i.to_s
28
+ end
29
+
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,2 @@
1
+ class GeonamesAdmin1 < GeonamesFeature
2
+ end
@@ -0,0 +1,2 @@
1
+ class GeonamesAdmin2 < GeonamesFeature
2
+ end
@@ -0,0 +1,2 @@
1
+ class GeonamesCity < GeonamesFeature
2
+ end
@@ -0,0 +1,25 @@
1
+ class GeonamesCountry < ActiveRecord::Base
2
+ validates_uniqueness_of :geonameid
3
+
4
+ ##
5
+ # search by iso first, then by name if not found
6
+ #
7
+ scope :search, lambda { |q|
8
+ by_iso(q).count > 0 ? by_iso(q) : by_name(q)
9
+ }
10
+
11
+ ##
12
+ # search by iso code
13
+ #
14
+ scope :by_iso, lambda { |q|
15
+ where("iso = ? or iso3 = ?", q.upcase, q.upcase)
16
+ }
17
+
18
+ ##
19
+ # search by name
20
+ #
21
+ scope :by_name, lambda { |q|
22
+ where("country LIKE ?", "#{q}%")
23
+ }
24
+
25
+ end
@@ -0,0 +1,49 @@
1
+ class GeonamesFeature < ActiveRecord::Base
2
+ validates_uniqueness_of :geonameid
3
+ before_save :set_asciiname_first_letters
4
+
5
+ ##
6
+ # Search for feature, searches might include country (separated by ',')
7
+ #
8
+ scope :search, lambda { |query|
9
+ virgule = query.include? ','
10
+
11
+ splited = virgule ? query.split(',') : [query]
12
+
13
+ country = virgule ? splited.last.strip : nil
14
+
15
+ queries = virgule ? splited[0...-1] : splited
16
+ queries = queries.join(' ').split(' ')
17
+
18
+ ret = by_name(*queries)
19
+
20
+ unless country.nil?
21
+ geonames_country = GeonamesCountry.search(country).first
22
+ ret = ret.where(:country => geonames_country.iso) unless geonames_country.nil?
23
+ end
24
+
25
+ ret
26
+ }
27
+
28
+ ##
29
+ # Find by names
30
+ #
31
+ scope :by_name, lambda { |*queries|
32
+ ret = self.scoped
33
+ count = queries.count
34
+ queries.collect.with_index do |q, idx|
35
+ query = idx == 0 ? "#{q}" : "%#{q}%"
36
+ ret = ret.where("asciiname_first_letters = ?", q[0...3].downcase)
37
+ ret = ret.where("name LIKE ? or asciiname LIKE ?", query, query)
38
+ end
39
+ ret
40
+ }
41
+
42
+ ##
43
+ # Set first letters of name into index column
44
+ #
45
+ def set_asciiname_first_letters
46
+ self.asciiname_first_letters = self.asciiname[0...3].downcase unless self.asciiname.nil?
47
+ end
48
+
49
+ end
@@ -0,0 +1,38 @@
1
+
2
+ # http://download.geonames.org/export/dump/countryInfo.txt
3
+
4
+ class CreateGeonamesCountries < ActiveRecord::Migration
5
+
6
+ def self.up
7
+ create_table :geonames_countries do |t|
8
+ t.string :iso
9
+ t.string :iso3
10
+ t.string :iso_numeric
11
+ t.string :fips
12
+ t.string :country
13
+ t.string :capital
14
+ t.integer :area # in sq. km
15
+ t.integer :population
16
+ t.string :continent
17
+ t.string :tld
18
+ t.string :currency_code
19
+ t.string :currency_name
20
+ t.string :phone
21
+ t.string :postal_code_format
22
+ t.string :postal_code_regex
23
+ t.string :languages
24
+ t.integer :geonameid
25
+ t.string :neighbours
26
+ t.string :equivalent_fips_code
27
+
28
+ t.timestamps
29
+ end
30
+
31
+ add_index :geonames_countries, :geonameid
32
+ add_index :geonames_countries, :country
33
+ end
34
+
35
+ def self.down
36
+ drop_table :geonames_countries
37
+ end
38
+ end
@@ -0,0 +1,64 @@
1
+ class CreateGeonamesFeatures < ActiveRecord::Migration
2
+
3
+ # geonameid : integer id of record in geonames database
4
+ # name : name of geographical point (utf8) varchar(200)
5
+ # asciiname : name of geographical point in plain ascii characters, varchar(200)
6
+ # alternatenames : alternatenames, comma separated varchar(4000) (varchar(5000) for SQL Server)
7
+ # latitude : latitude in decimal degrees (wgs84)
8
+ # longitude : longitude in decimal degrees (wgs84)
9
+ # feature class : see http://www.geonames.org/export/codes.html, char(1)
10
+ # feature code : see http://www.geonames.org/export/codes.html, varchar(10)
11
+ # country code : ISO-3166 2-letter country code, 2 characters
12
+ # cc2 : alternate country codes, comma separated, ISO-3166 2-letter country code, 60 characters
13
+ # admin1 code : fipscode (subject to change to iso code), isocode for the us and ch, see file admin1Codes.txt for display names of this code; varchar(20)
14
+ # admin2 code : code for the second administrative division, a county in the US, see file admin2Codes.txt; varchar(80)
15
+ # admin3 code : code for third level administrative division, varchar(20)
16
+ # admin4 code : code for fourth level administrative division, varchar(20)
17
+ # population : bigint (4 byte int)
18
+ # elevation : in meters, integer
19
+ # gtopo30 : average elevation of 30'x30' (ca 900mx900m) area in meters, integer
20
+ # timezone : the timezone id (see file timeZone.txt)
21
+ # modification date : date of last modification in yyyy-MM-dd format
22
+ def self.up
23
+ create_table :geonames_features do |t|
24
+ t.integer :geonameid
25
+ t.string :name
26
+ t.string :asciiname
27
+ t.string :alternatenames
28
+ t.float :latitude
29
+ t.float :longitude
30
+ t.string :feature_class
31
+ t.string :feature
32
+ t.string :country
33
+ t.string :cc2
34
+ t.string :admin1
35
+ t.string :admin2
36
+ t.string :admin3
37
+ t.string :admin4
38
+ t.integer :population
39
+ t.integer :elevation
40
+ t.integer :gtopo30
41
+ t.string :timezone
42
+ t.timestamp :modification
43
+ t.string :type
44
+ # OPTIMIZE: create another table for all names (alternate names)
45
+ t.string :asciiname_first_letters
46
+
47
+
48
+ t.timestamps
49
+ end
50
+
51
+ add_index :geonames_features, :geonameid
52
+ add_index :geonames_features, :name
53
+ add_index :geonames_features, :asciiname
54
+ add_index :geonames_features, :country
55
+ add_index :geonames_features, :population
56
+ add_index :geonames_features, :admin1
57
+ add_index :geonames_features, :type
58
+ add_index :geonames_features, :asciiname_first_letters
59
+ end
60
+
61
+ def self.down
62
+ drop_table :geonames_features
63
+ end
64
+ end
@@ -0,0 +1,19 @@
1
+ Piktur.configure do |config|
2
+ ##config.public_abs_path = Rails.root.join(Rails.public_path).to_s
3
+ #config.public_abs_path = "nullll"
4
+ #config.gallery_base_path = "piktur/"
5
+ #config.thumbs_dir = "thumbs/"
6
+
7
+ #config.thumb_extension = ".jpg"
8
+ #config.image_extensions = ['jpg', 'jpeg']
9
+ ##config.image_extensions = ['*']
10
+ #config.associated_extension = ".yml"
11
+
12
+ ##config.thumb_file = "%{basename}-%{width}-%{height}%{extension}"
13
+ #config.thumb_file = "%{basename}-size%{size}%{extension}"
14
+ #config.associated_file = "%{basename}%{extension}"
15
+ #config.watermark_file = nil
16
+
17
+ #config.thumbs_sizes = [[140, 110], [640, 480]]
18
+ #config.param_path = :path
19
+ end
@@ -0,0 +1,31 @@
1
+ module GeonamesDump
2
+ class Blocks
3
+ attr_accessor :blocks
4
+ def initialize
5
+ reset
6
+ end
7
+
8
+ def reset
9
+ self.blocks = []
10
+ end
11
+
12
+ def add_block(&block)
13
+ self.blocks << block
14
+ end
15
+
16
+ def empty?
17
+ blocks.empty?
18
+ end
19
+
20
+ def call_and_reset
21
+ call
22
+ reset
23
+ end
24
+
25
+ def call
26
+ blocks.each do |block|
27
+ block.call
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,11 @@
1
+ #require 'rails'
2
+
3
+ module GeonamesDump
4
+ class Railtie < ::Rails::Railtie #:nodoc:
5
+ # import rake tast into rails application
6
+ rake_tasks do
7
+ Dir[File.join(File.dirname(__FILE__),'../tasks/*.rake')].each { |f| load f }
8
+ end
9
+ end
10
+ end
11
+
@@ -0,0 +1,3 @@
1
+ module GeonamesDump
2
+ VERSION = '0.0.2'
3
+ end
@@ -0,0 +1,8 @@
1
+ require "geonames_dump/version"
2
+ require "geonames_dump/blocks"
3
+ require "geonames_dump/railtie" #if defined?(Rails)
4
+
5
+ module GeonamesDump
6
+ # TODO: remove this logger
7
+ #ActiveRecord::Base.logger = Logger.new(STDOUT) if Rails.env.development? && !ENV['SILENT']
8
+ end
@@ -0,0 +1,257 @@
1
+ require 'net/http'
2
+ require 'ruby-progressbar'
3
+ require 'zip/zip'
4
+ require 'geonames_dump'
5
+
6
+ namespace :geonames_dump do
7
+ namespace :import do
8
+ CACHE_DIR = "#{Rails.root}/db/geonames_cache"
9
+
10
+ GEONAMES_FEATURES_COL_NAME = [
11
+ :geonameid, :name, :asciiname, :alternatenames, :latitude, :longitude, :feature_class,
12
+ :feature, :country, :cc2, :admin1, :admin2, :admin3, :admin4, :population, :elevation,
13
+ :gtopo30, :timezone, :modification
14
+ ]
15
+ GEONAMES_COUNTRIES_COL_NAME = [
16
+ :iso, :iso3, :iso_numeric, :fips, :country, :capital, :area, :population, :continent,
17
+ :tld, :currency_code, :currency_name, :phone, :postal_code_format, :postal_code_regex,
18
+ :languages, :geonameid, :neighbours, :equivalent_fips_code
19
+ ]
20
+ GEONAMES_ADMINS_COL_NAME = [ :code, :name, :asciiname, :geonameid ]
21
+
22
+ desc 'Prepare everything to import data'
23
+ task :prepare do
24
+ Dir::mkdir(CACHE_DIR) rescue nil
25
+ disable_logger
26
+ disable_validations if ENV['QUICK']
27
+ end
28
+
29
+ desc 'Import ALL geonames data.'
30
+ task :all => [:many, :features]
31
+
32
+ desc 'Import most of geonames data. Recommended after a clean install.'
33
+ task :many => [:prepare, :countries, :cities, :admin1, :admin2]
34
+
35
+ desc 'Import all cities, regardless of population.'
36
+ task :cities => [:prepare, :cities15000, :cities5000, :cities1000]
37
+
38
+ desc 'Import feature data. Specify Country ISO code (example : COUNTRY=FR) for just a single country. NOTE: This task can take a long time!'
39
+ task :features => [:prepare, :environment] do
40
+ download_file = ENV['COUNTRY'].present? ? ENV['COUNTRY'].upcase : 'allCountries'
41
+ zip_filename = download_file+'.zip'
42
+
43
+ txt_file = get_or_download("http://download.geonames.org/export/dump/#{zip_filename}")
44
+
45
+ # Import into the database.
46
+ File.open(txt_file) do |f|
47
+ #VALID_FEATURES = %w[ADMIN1]
48
+ #feature_attrs = VALID_FEATURES & ENV.keys
49
+ # TODO: add feature selection
50
+ insert_data(f, GEONAMES_FEATURES_COL_NAME, GeonamesCity, :title => "Features")
51
+ end
52
+ end
53
+
54
+ # geonames:import:citiesNNN where NNN is population size.
55
+ %w[15000 5000 1000].each do |population|
56
+ desc "Import cities with population greater than #{population}"
57
+ task "cities#{population}".to_sym => [:prepare, :environment] do
58
+
59
+ txt_file = get_or_download("http://download.geonames.org/export/dump/cities#{population}.zip")
60
+
61
+ # Import into the database.
62
+ File.open(txt_file) do |f|
63
+ insert_data(f, GEONAMES_FEATURES_COL_NAME, GeonamesCity, :title => "cities of #{population}")
64
+ end
65
+ end
66
+ end
67
+
68
+ desc 'Import countries informations'
69
+ task :countries => :environment do
70
+ txt_file = get_or_download('http://download.geonames.org/export/dump/countryInfo.txt')
71
+
72
+ # Import into the database.
73
+ File.open(txt_file) do |f|
74
+ insert_data(f, GEONAMES_COUNTRIES_COL_NAME, GeonamesCountry, :title => "Countries")
75
+ end
76
+ end
77
+
78
+ desc 'Import admin1 codes'
79
+ task :admin1 => [:prepare, :environment] do
80
+ txt_file = get_or_download('http://download.geonames.org/export/dump/admin1CodesASCII.txt')
81
+
82
+ # Import into the database.
83
+ File.open(txt_file) do |f|
84
+ insert_data(f, GEONAMES_ADMINS_COL_NAME, GeonamesAdmin1, :title => "Admin1 subdivisions") do |klass, attributes, col_value, idx|
85
+ col_value.gsub!('(general)', '')
86
+ col_value.strip!
87
+ if idx == 0
88
+ country, admin1 = col_value.split('.')
89
+ attributes[:country] = country.strip
90
+ attributes[:admin1] = admin1.strip rescue nil
91
+ else
92
+ attributes[GEONAMES_ADMINS_COL_NAME[idx]] = col_value
93
+ end
94
+ end
95
+ end
96
+ end
97
+
98
+ desc 'Import admin2 codes'
99
+ task :admin2 => [:prepare, :environment] do
100
+ txt_file = get_or_download('http://download.geonames.org/export/dump/admin2Codes.txt')
101
+
102
+ # Import into the database.
103
+ File.open(txt_file) do |f|
104
+ insert_data(f, GEONAMES_ADMINS_COL_NAME, GeonamesAdmin2, :title => "Admin2 subdivisions") do |klass, attributes, col_value, idx|
105
+ col_value.gsub!('(general)', '')
106
+ if idx == 0
107
+ country, admin1, admin2 = col_value.split('.')
108
+ attributes[:country] = country.strip
109
+ attributes[:admin1] = admin1.strip #rescue nil
110
+ attributes[:admin2] = admin2.strip #rescue nil
111
+ else
112
+ attributes[GEONAMES_ADMINS_COL_NAME[idx]] = col_value
113
+ end
114
+ end
115
+ end
116
+ end
117
+
118
+ private
119
+
120
+ def disable_logger
121
+ ActiveRecord::Base.logger = Logger.new('/dev/null')
122
+ end
123
+
124
+ def disable_validations
125
+ ActiveRecord::Base.reset_callbacks(:validate)
126
+ end
127
+
128
+
129
+ def get_or_download(url, options = {})
130
+ filename = File.basename(url)
131
+ unzip = File.extname(filename) == '.zip'
132
+ txt_filename = unzip ? "#{File.basename(filename, '.zip')}.txt" : filename
133
+ txt_file_in_cache = File.join(CACHE_DIR, options[:txt_file] || txt_filename)
134
+ zip_file_in_cache = File.join(CACHE_DIR, filename)
135
+
136
+ unless File::exist?(txt_file_in_cache)
137
+ puts 'file doesn\'t exists'
138
+ if unzip
139
+ download(url, zip_file_in_cache)
140
+ unzip_file(zip_file_in_cache, CACHE_DIR)
141
+ else
142
+ download(url, txt_file_in_cache)
143
+ end
144
+ else
145
+ puts "file already exists : #{txt_file_in_cache}"
146
+ end
147
+
148
+ ret = (File::exist?(txt_file_in_cache) ? txt_file_in_cache : nil)
149
+ end
150
+
151
+ def unzip_file(file, destination)
152
+ puts "unzipping #{file}"
153
+ Zip::ZipFile.open(file) do |zip_file|
154
+ zip_file.each do |f|
155
+ f_path = File.join(destination, f.name)
156
+ FileUtils.mkdir_p(File.dirname(f_path))
157
+ zip_file.extract(f, f_path) unless File.exist?(f_path)
158
+ end
159
+ end
160
+ end
161
+
162
+ def download(url, output)
163
+ File.open(output, "wb") do |file|
164
+ body = fetch(url)
165
+ puts "Writing #{url} to #{output}"
166
+ file.write(body)
167
+ end
168
+ end
169
+
170
+ def fetch(url)
171
+ puts "Fetching #{url}"
172
+ url = URI.parse(url)
173
+ req = Net::HTTP::Get.new(url.path)
174
+ res = Net::HTTP.start(url.host, url.port) {|http| http.request(req)}
175
+ return res.body
176
+ end
177
+
178
+ def insert_data(file_fd, col_names, main_klass = GeonamesFeature, options = {}, &block)
179
+ # Setup nice progress output.
180
+ file_size = file_fd.stat.size
181
+ title = options[:title] || 'Feature Import'
182
+ progress_bar = ProgressBar.create(:title => title, :total => file_size, :format => '%a |%b>%i| %p%% %t')
183
+
184
+ # create block array
185
+ blocks = GeonamesDump::Blocks.new
186
+ line_counter = 0
187
+
188
+ file_fd.each_line do |line|
189
+ # prepare data
190
+ attributes = {}
191
+ klass = main_klass
192
+
193
+ # skip comments
194
+ next if line.start_with?('#')
195
+
196
+ line_counter += 1
197
+
198
+ # read values
199
+ line.strip.split("\t").each_with_index do |col_value, idx|
200
+ col = col_names[idx]
201
+
202
+ # skip leading and trailing whitespace
203
+ col_value.strip!
204
+
205
+ # block may change the type of object to create
206
+ if block_given?
207
+ yield klass, attributes, col_value, idx
208
+ else
209
+ attributes[col] = col_value
210
+ end
211
+ end
212
+
213
+ # create or update object
214
+ #if filter?(attributes) && (block && block.call(attributes))
215
+ blocks.add_block do
216
+ if attributes.include?(:geonameid)
217
+ object = klass.where(geonameid: attributes[:geonameid]).first_or_initialize
218
+ object.update_attributes(attributes)
219
+ object.save if object.new_record? || object.changed?
220
+ else
221
+ klass.create(attributes)
222
+ end
223
+ end
224
+
225
+ # increase import speed by performing insert using transaction
226
+ if line_counter % 1000 == 0
227
+ ActiveRecord::Base.transaction do
228
+ blocks.call_and_reset
229
+ end
230
+ line_counter = 0
231
+ end
232
+
233
+ # move progress bar
234
+ progress_bar.progress = file_fd.pos
235
+ end
236
+
237
+ unless blocks.empty?
238
+ ActiveRecord::Base.transaction do
239
+ blocks.call_and_reset
240
+ end
241
+ end
242
+ end
243
+
244
+ # Return true when either:
245
+ # no filter keys apply.
246
+ # all applicable filter keys include the filter value.
247
+ def filter?(attributes)
248
+ return attributes.keys.all?{|key| filter_keyvalue?(key, attributes[key])}
249
+ end
250
+
251
+ def filter_keyvalue?(col, col_value)
252
+ return true unless ENV[col.to_s]
253
+ return ENV[col.to_s].split('|').include?(col_value.to_s)
254
+ end
255
+
256
+ end
257
+ end
@@ -0,0 +1,4 @@
1
+ namespace :geonames_dump do
2
+ desc 'Truncate and install most of geonames data (country, admin1, admin2, cities)'
3
+ task :install => ['truncate:all', 'import:many']
4
+ end
@@ -0,0 +1,34 @@
1
+
2
+ namespace :geonames_dump do
3
+ desc 'Run db:migrate to be up-to-date'
4
+ #task :migrate => [:environment, :copy_migrations, 'db:migrate']
5
+ task :migrate => [:environment, 'db:migrate']
6
+
7
+ # # Inspired by http://interblah.net/plugin-migrations
8
+ # desc 'Copy over the migration files and migrate'
9
+ # task :copy_migrations => :environment do
10
+ # require 'fileutils'
11
+ # APP_MIGRATION_DIR = "#{Rails.root}/db/migrate"
12
+ # PLUGIN_MIGRATION_DIR = "#{File.dirname(__FILE__)}/../../db/migrate"
13
+ #
14
+ # # Find all application migrations
15
+ # existing_migrations = Dir[APP_MIGRATION_DIR+'/*']
16
+ # existing_migrations.map!{|file| File.basename(file) =~ /^[0-9]+_(.+)$/ && $1}
17
+ #
18
+ # # Find all of this plugin's migrations
19
+ # plugin_migrations = Dir[PLUGIN_MIGRATION_DIR+'/*']
20
+ # plugin_migrations.map!{|file| File.basename(file)}
21
+ # # ... handle case when copying to plugins migrate directory.
22
+ # plugin_migrations.map!{|file| File.basename(file) =~ /^[0-9]+_(.+)$/ ? $1 : File.basename(file)}
23
+ #
24
+ # # Compare application migrations with this plugins set of migrations, and copy new migrations.
25
+ # puts 'There are no new migrations to copy.' if (plugin_migrations - existing_migrations).empty?
26
+ # base_time = Time.now
27
+ # (plugin_migrations - existing_migrations).each do |new_migration|
28
+ # migration_timestamp = base_time.strftime('%Y%m%d%H%M%S')
29
+ # puts "Copying from #{PLUGIN_MIGRATION_DIR}/#{new_migration} to #{APP_MIGRATION_DIR}/#{migration_timestamp}_#{new_migration}"
30
+ # FileUtils::cp "#{PLUGIN_MIGRATION_DIR}/#{new_migration}", "#{APP_MIGRATION_DIR}/#{migration_timestamp}_#{new_migration}"
31
+ # base_time+=1
32
+ # end
33
+ # end
34
+ end
@@ -0,0 +1,40 @@
1
+ require 'net/http'
2
+ require 'ruby-progressbar'
3
+ require 'activerecord-reset-pk-sequence'
4
+
5
+ namespace :geonames_dump do
6
+ namespace :truncate do
7
+
8
+ desc 'Truncate all geonames data.'
9
+ #task :all => [:countries, :cities, :admin1, :admin2]
10
+ task :all => [:countries, :features]
11
+
12
+ desc 'Truncate admin1 codes'
13
+ task :admin1 => :environment do
14
+ GeonamesAdmin1.delete_all #&& GeonamesAdmin1.reset_pk_sequence
15
+ end
16
+
17
+ desc 'Truncate admin2 codes'
18
+ task :admin2 => :environment do
19
+ GeonamesAdmin2.delete_all #&& GeonamesAdmin2.reset_pk_sequence
20
+ end
21
+
22
+ desc 'Truncate cities informations'
23
+ task :cities => :environment do
24
+ GeonamesCity.delete_all #&& GeonamesCity.reset_pk_sequence
25
+ end
26
+
27
+ desc 'Truncate countries informations'
28
+ task :countries => :environment do
29
+ GeonamesCountry.delete_all && GeonamesCountry.reset_pk_sequence
30
+ end
31
+
32
+ desc 'Truncate features informations'
33
+ task :features => :environment do
34
+ GeonamesFeature.delete_all && GeonamesFeature.reset_pk_sequence
35
+ end
36
+
37
+ # private
38
+
39
+ end
40
+ end
metadata ADDED
@@ -0,0 +1,110 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: geonames_dump
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ platform: ruby
6
+ authors:
7
+ - Alex Pooley
8
+ - Thomas Kienlen
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-11-22 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: ruby-progressbar
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - '>='
19
+ - !ruby/object:Gem::Version
20
+ version: '0'
21
+ type: :runtime
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - '>='
26
+ - !ruby/object:Gem::Version
27
+ version: '0'
28
+ - !ruby/object:Gem::Dependency
29
+ name: activerecord-reset-pk-sequence
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - '>='
33
+ - !ruby/object:Gem::Version
34
+ version: '0'
35
+ type: :runtime
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - '>='
40
+ - !ruby/object:Gem::Version
41
+ version: '0'
42
+ - !ruby/object:Gem::Dependency
43
+ name: rubyzip
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - '>='
47
+ - !ruby/object:Gem::Version
48
+ version: '0'
49
+ type: :runtime
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - '>='
54
+ - !ruby/object:Gem::Version
55
+ version: '0'
56
+ description: GeonamesDump import geographic data from geonames project into your application,
57
+ avoiding to use external service like Google Maps.
58
+ email:
59
+ - thomas.kienlen@lafourmi-immo.com
60
+ executables: []
61
+ extensions: []
62
+ extra_rdoc_files: []
63
+ files:
64
+ - .gitignore
65
+ - Gemfile
66
+ - LICENSE
67
+ - README.md
68
+ - Rakefile
69
+ - geonames_dump.gemspec
70
+ - lib/generators/geonames_dump/install_generator.rb
71
+ - lib/generators/geonames_dump/templates/app/models/geonames_admin1.rb
72
+ - lib/generators/geonames_dump/templates/app/models/geonames_admin2.rb
73
+ - lib/generators/geonames_dump/templates/app/models/geonames_city.rb
74
+ - lib/generators/geonames_dump/templates/app/models/geonames_country.rb
75
+ - lib/generators/geonames_dump/templates/app/models/geonames_feature.rb
76
+ - lib/generators/geonames_dump/templates/db/migrate/create_geonames_countries.rb
77
+ - lib/generators/geonames_dump/templates/db/migrate/create_geonames_features.rb
78
+ - lib/generators/geonames_dump/templates/piktur_config.rb
79
+ - lib/geonames_dump.rb
80
+ - lib/geonames_dump/blocks.rb
81
+ - lib/geonames_dump/railtie.rb
82
+ - lib/geonames_dump/version.rb
83
+ - lib/tasks/import.rake
84
+ - lib/tasks/install.rake
85
+ - lib/tasks/migrate.rake
86
+ - lib/tasks/truncate.rake
87
+ homepage: https://github.com/kmmndr/geonames_dump
88
+ licenses: []
89
+ metadata: {}
90
+ post_install_message:
91
+ rdoc_options: []
92
+ require_paths:
93
+ - lib
94
+ required_ruby_version: !ruby/object:Gem::Requirement
95
+ requirements:
96
+ - - '>='
97
+ - !ruby/object:Gem::Version
98
+ version: '0'
99
+ required_rubygems_version: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - '>='
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ requirements: []
105
+ rubyforge_project:
106
+ rubygems_version: 2.0.3
107
+ signing_key:
108
+ specification_version: 4
109
+ summary: Import data from Geonames
110
+ test_files: []