fias 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +22 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +81 -0
- data/Rakefile +2 -0
- data/fias.gemspec +24 -0
- data/lib/fias.rb +12 -0
- data/lib/fias/active_record/address_object.rb +76 -0
- data/lib/fias/active_record/address_object_type.rb +8 -0
- data/lib/fias/import/dbf_wrapper.rb +83 -0
- data/lib/fias/import/pg.rb +144 -0
- data/lib/fias/railtie.rb +22 -0
- data/lib/fias/version.rb +3 -0
- data/lib/generators/fias/migration.rb +30 -0
- data/lib/generators/fias/templates/create_fias_tables.rb +5 -0
- data/tasks/fias.rake +71 -0
- metadata +131 -0
data/.gitignore
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
*.gem
|
2
|
+
*.rbc
|
3
|
+
.bundle
|
4
|
+
.config
|
5
|
+
.yardoc
|
6
|
+
Gemfile.lock
|
7
|
+
InstalledFiles
|
8
|
+
_yardoc
|
9
|
+
coverage
|
10
|
+
doc/
|
11
|
+
coverage
|
12
|
+
InstalledFiles
|
13
|
+
tmp
|
14
|
+
pkg
|
15
|
+
rdoc
|
16
|
+
spec/reports
|
17
|
+
test/tmp
|
18
|
+
test/version_tmp
|
19
|
+
tmp
|
20
|
+
.yardoc
|
21
|
+
_yardoc
|
22
|
+
doc/
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Victor Sokolov
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,81 @@
|
|
1
|
+
# Федеральная Информационная Адресная Система (ФИАС)
|
2
|
+
|
3
|
+
Для работы с базой потребуются файлы полной БД ФИАС в формате DBF. Скачать их можно по адресу:
|
4
|
+
|
5
|
+
http://fias.nalog.ru/Public/DownloadPage.aspx
|
6
|
+
|
7
|
+
Там же можно скачать описание структуры базы.
|
8
|
+
|
9
|
+
# Установка и подготовка базы
|
10
|
+
|
11
|
+
1. Подключить гем
|
12
|
+
|
13
|
+
```
|
14
|
+
gem 'fias', git: 'https://github.com/evilmartians/kladr.git'
|
15
|
+
```
|
16
|
+
|
17
|
+
2. Скачать и распаковать базу ФИАС в tmp/fias (по умолчанию)
|
18
|
+
|
19
|
+
# Создание таблиц в базе данных
|
20
|
+
|
21
|
+
Возможны два варианта:
|
22
|
+
|
23
|
+
```
|
24
|
+
rake fias:create_tables [DATABASE_URL=... PREFIX=... PATH=...]
|
25
|
+
```
|
26
|
+
|
27
|
+
Либо:
|
28
|
+
|
29
|
+
```
|
30
|
+
rails g fias:migration [--path=... --prefix=...]
|
31
|
+
```
|
32
|
+
|
33
|
+
Первый вариант - для использования гема вне рельсов, либо для случая, когда
|
34
|
+
актуальная база ФИАС будет использоваться только для локального мапинга, и
|
35
|
+
на продакшн попасть не должна.
|
36
|
+
|
37
|
+
# Импорт данных
|
38
|
+
|
39
|
+
```
|
40
|
+
rake fias:import:placements fias:import:houses PREFIX=fias PATH=tmp/fias
|
41
|
+
```
|
42
|
+
|
43
|
+
Импорт данных разделен на два шага, по скольку, не всегда нужны данные
|
44
|
+
о строениях, а их почти в 20 раз больше, чем остальных. В большинстве случаев
|
45
|
+
достаточно городов и улиц.
|
46
|
+
|
47
|
+
# Некоторые замечания про ФИАС
|
48
|
+
|
49
|
+
1. ФИАС хранит историю изменений информации адресных объектов. Например,
|
50
|
+
в ней есть и Ленинград и Санкт-Петербург. Исторические версии это
|
51
|
+
двунаправленный список.
|
52
|
+
2. Записи базы данных ФИАС имеют признак актуальности.
|
53
|
+
3. Ленинград и Санкт-Петербург, хотя, и хранятся в разных записях базы данных,
|
54
|
+
являются одним и тем же территориальным образованием. Код территориального
|
55
|
+
образования хранится в поле AOGUID. Из внешних таблиц логично ссылаться
|
56
|
+
на AOGUID, а не на AOID.
|
57
|
+
|
58
|
+
# Работа с данными
|
59
|
+
|
60
|
+
Существующие регионы:
|
61
|
+
|
62
|
+
```
|
63
|
+
Fias::AddressObject.actual.leveled(:region).all
|
64
|
+
```
|
65
|
+
|
66
|
+
Подчиненные объекты в регионе (области, районы, столица региона):
|
67
|
+
|
68
|
+
```
|
69
|
+
region = Fias::AddressObject.actual.leveled(:region).first
|
70
|
+
region.children.actual
|
71
|
+
```
|
72
|
+
|
73
|
+
# TODO
|
74
|
+
|
75
|
+
1. Индексы.
|
76
|
+
|
77
|
+
# Полезные ссылки
|
78
|
+
|
79
|
+
* http://fias.nalog.ru/Public/DownloadPage.aspx
|
80
|
+
* http://wiki.gis-lab.info/w/%D0%A4%D0%98%D0%90%D0%A1#.D0.A2.D0.B5.D0.BA.D1.81.D1.82.D0.BE.D0.B2.D1.8B.D0.B5_.D1.8D.D0.BB.D0.B5.D0.BC.D0.B5.D0.BD.D1.82.D1.8B_.D0.B0.D0.B4.D1.80.D0.B5.D1.81.D0.B0
|
81
|
+
* http://basicdata.ru
|
data/Rakefile
ADDED
data/fias.gemspec
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'fias/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |gem|
|
7
|
+
gem.name = "fias"
|
8
|
+
gem.version = Fias::VERSION
|
9
|
+
gem.authors = ["Victor Sokolov"]
|
10
|
+
gem.email = ["gzigzigzeo@evilmartians.com"]
|
11
|
+
gem.description = %q{Ruby wrapper to FIAS database}
|
12
|
+
gem.summary = %q{Ruby wrapper to FIAS database}
|
13
|
+
gem.homepage = "http://github.com/evilmartians/fias"
|
14
|
+
|
15
|
+
gem.files = `git ls-files`.split($/)
|
16
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
17
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
18
|
+
gem.require_paths = ["lib"]
|
19
|
+
|
20
|
+
gem.add_dependency 'dbf'
|
21
|
+
gem.add_dependency 'rake'
|
22
|
+
gem.add_dependency 'activerecord', '> 3'
|
23
|
+
gem.add_dependency 'progress_bar'
|
24
|
+
end
|
data/lib/fias.rb
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
module Fias
|
2
|
+
class AddressObject < ActiveRecord::Base
|
3
|
+
self.table_name = "#{Rails.application.config.fias.prefix}_address_objects"
|
4
|
+
self.primary_key = 'aoid'
|
5
|
+
|
6
|
+
alias_attribute :name, :formalname
|
7
|
+
|
8
|
+
# Родительские объекты (Ленобласть для Лодейнопольского района)
|
9
|
+
# Для "проезд 1-й Конной Лахты 2-й" - Санкт-Петербург и Ленинград.
|
10
|
+
# Блядь, 1-й проезд 2-й Конной Лахты, ебануться!
|
11
|
+
# http://maps.yandex.ru/?text=%D0%A0%D0%BE%D1%81%D1%81%D0%B8%D1%8F%2C%20%D0%A1%D0%B0%D0%BD%D0%BA%D1%82-%D0%9F%D0%B5%D1%82%D0%B5%D1%80%D0%B1%D1%83%D1%80%D0%B3%2C%202-%D0%B9%20%D0%BF%D1%80%D0%BE%D0%B5%D0%B7%D0%B4%201-%D0%B9%20%D0%9A%D0%BE%D0%BD%D0%BD%D0%BE%D0%B9%20%D0%9B%D0%B0%D1%85%D1%82%D1%8B&sll=30.123296%2C60.007056&ll=30.123848%2C60.007475&spn=0.010085%2C0.006017&z=17&l=map
|
12
|
+
has_many :parents,
|
13
|
+
class_name: 'AddressObject',
|
14
|
+
foreign_key: 'aoguid',
|
15
|
+
primary_key: 'parentguid'
|
16
|
+
|
17
|
+
# Дочерние объекты (например, улицы для города)
|
18
|
+
has_many :children,
|
19
|
+
class_name: 'AddressObject',
|
20
|
+
primary_key: 'aoguid',
|
21
|
+
foreign_key: 'parentguid'
|
22
|
+
|
23
|
+
# Предыдущая историческая версия названия (Ленинград для Питера)
|
24
|
+
belongs_to :next_version,
|
25
|
+
class_name: 'AddressObject',
|
26
|
+
primary_key: 'aoid',
|
27
|
+
foreign_key: 'nextid'
|
28
|
+
|
29
|
+
# Следующая историческая версия названия (Питер для Ленинграда)
|
30
|
+
belongs_to :previous_version,
|
31
|
+
class_name: 'AddressObject',
|
32
|
+
primary_key: 'aoid',
|
33
|
+
foreign_key: 'previd'
|
34
|
+
|
35
|
+
# Актуальные записи (активные в настоящий момент)
|
36
|
+
# Проверено, что livestatus уже достаточен для идентификации
|
37
|
+
# актуальных объектов, вопреки показаниям вики.
|
38
|
+
scope :actual, where(livestatus: 1)
|
39
|
+
|
40
|
+
# Выбирает объекты определенного уровня, аргументы - символы из хеша
|
41
|
+
# AOLEVELS
|
42
|
+
scope :leveled, ->(*levels) {
|
43
|
+
levels = Array.wrap(levels).map { |level| AOLEVELS[level] }
|
44
|
+
where(aolevel: levels)
|
45
|
+
}
|
46
|
+
|
47
|
+
scope :sorted, order('formalname ASC')
|
48
|
+
|
49
|
+
# Полное наименование типа объекта (город, улица)
|
50
|
+
belongs_to :address_object_type,
|
51
|
+
class_name: 'Fias::AddressObjectType',
|
52
|
+
primary_key: 'shortname',
|
53
|
+
foreign_key: 'scname'
|
54
|
+
|
55
|
+
# Есть ли исторические варианты записи?
|
56
|
+
def has_history?
|
57
|
+
previd.present?
|
58
|
+
end
|
59
|
+
|
60
|
+
# Актуальный родитель. Для 1-го проезда 2-й Конной Лахты - только Питер.
|
61
|
+
def parent
|
62
|
+
parents.actual.first
|
63
|
+
end
|
64
|
+
|
65
|
+
def aolevel_sym
|
66
|
+
AOLEVELS.key(aolevel)
|
67
|
+
end
|
68
|
+
|
69
|
+
# Коды уровня адресного объекта
|
70
|
+
AOLEVELS = {
|
71
|
+
region: 1, autonomy: 2, district: 3, city: 4,
|
72
|
+
territory: 5, settlement: 6, street: 7,
|
73
|
+
additional_territory: 90, additional_territory_slave: 91
|
74
|
+
}
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
module Fias
|
2
|
+
module Import
|
3
|
+
# Класс для доступа к DBF-файлам ФИАС
|
4
|
+
# Пример:
|
5
|
+
# wrapper = DbfWrapper.new('tmp/fias')
|
6
|
+
# wrapper.address_objects.record_count
|
7
|
+
# wrapper.address_objects.each { |record| record.attributes }
|
8
|
+
class DbfWrapper
|
9
|
+
def initialize(pathspec)
|
10
|
+
unless Dir.exists?(pathspec)
|
11
|
+
raise ArgumentError, 'FIAS database path does not exists'
|
12
|
+
end
|
13
|
+
self.pathspec = pathspec
|
14
|
+
|
15
|
+
TABLES_ACCESSORS.each do |key, dbf_name|
|
16
|
+
filename = File.join(pathspec, dbf_name)
|
17
|
+
dbf = DBF::Table.new(filename, nil, DEFAULT_ENCODING)
|
18
|
+
|
19
|
+
send("#{key}=", dbf)
|
20
|
+
end
|
21
|
+
|
22
|
+
self.houses = {}
|
23
|
+
Dir[File.join(pathspec, HOUSE_DBF_MASK)].each do |filename|
|
24
|
+
File.basename(filename) =~ /(\d+)/
|
25
|
+
region_code = $1.to_i
|
26
|
+
|
27
|
+
dbf = DBF::Table.new(filename, nil, DEFAULT_ENCODING)
|
28
|
+
self.houses[region_code] = dbf
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def tables
|
33
|
+
hash = TABLES_ACCESSORS.keys.map do |accessor|
|
34
|
+
[accessor, send(accessor)]
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def build_importer(options)
|
39
|
+
config = ActiveRecord::Base.connection_config
|
40
|
+
if config[:adapter] == 'postgresql'
|
41
|
+
import = Fias::Import::PgImporter.new(
|
42
|
+
ActiveRecord::Base.connection.raw_connection,
|
43
|
+
self,
|
44
|
+
options
|
45
|
+
)
|
46
|
+
else
|
47
|
+
raise 'Only postgres supported now, fork'
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
# Таблица соответствий аттрибутов класса DBF-файлам
|
52
|
+
TABLES_ACCESSORS = {
|
53
|
+
address_object_types: 'SOCRBASE.DBF',
|
54
|
+
current_statuses: 'CURENTST.DBF',
|
55
|
+
actual_statuses: 'ACTSTAT.DBF',
|
56
|
+
operation_statuses: 'OPERSTAT.DBF',
|
57
|
+
center_statuses: 'CENTERST.DBF',
|
58
|
+
interval_statuses: 'INTVSTAT.DBF',
|
59
|
+
estate_statues: 'ESTSTAT.DBF',
|
60
|
+
structure_statuses: 'STRSTAT.DBF',
|
61
|
+
address_objects: 'ADDROBJ.DBF',
|
62
|
+
house_intervals: 'HOUSEINT.DBF',
|
63
|
+
landmarks: 'LANDMARK.DBF'
|
64
|
+
}
|
65
|
+
HOUSE_DBF_MASK = 'HOUSE??.DBF'
|
66
|
+
|
67
|
+
# Эти поля нужно отконвертировать в тип UUID после создания
|
68
|
+
CONVERT_TO_UUID = {
|
69
|
+
address_objects: %w(aoguid aoid previd nextid parentguid)
|
70
|
+
}
|
71
|
+
|
72
|
+
DEFAULT_ENCODING = Encoding::CP866
|
73
|
+
|
74
|
+
attr_reader *TABLES_ACCESSORS.keys
|
75
|
+
attr_reader :houses
|
76
|
+
|
77
|
+
private
|
78
|
+
attr_accessor :pathspec
|
79
|
+
attr_writer *TABLES_ACCESSORS.keys
|
80
|
+
attr_writer :houses
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,144 @@
|
|
1
|
+
module Fias
|
2
|
+
module Import
|
3
|
+
class PgImporter
|
4
|
+
# Класс для импорта данных из ФИАС в PostgreSQL.
|
5
|
+
# Используется COPY FROM STDIN.
|
6
|
+
def initialize(raw_connection, wrapper, options = {})
|
7
|
+
self.prefix = options.delete(:prefix) || 'fias'
|
8
|
+
self.raw_connection = raw_connection
|
9
|
+
self.wrapper = wrapper
|
10
|
+
end
|
11
|
+
|
12
|
+
# Генерирует схему базы для ActiveRecord в виде строки
|
13
|
+
def schema
|
14
|
+
"".tap do |s|
|
15
|
+
wrapper.tables.each do |accessor, table|
|
16
|
+
s << %{create_table "#{table_name(accessor)}", id: false do |t|\n}
|
17
|
+
s << dump_schema_for(accessor, table)
|
18
|
+
s << "end\n"
|
19
|
+
|
20
|
+
s << alter_table_to_pg_uuids(accessor)
|
21
|
+
end
|
22
|
+
|
23
|
+
s << %{create_table "#{table_name('houses')}", id: false do |t|\n}
|
24
|
+
s << dump_schema_for(:houses, wrapper.houses.values.first)
|
25
|
+
s << " t.column :regioncode, :integer\n"
|
26
|
+
s << "end\n"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def import(&block)
|
31
|
+
wrapper.tables.each do |accessor, table|
|
32
|
+
import_table(accessor, table, &block)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def import_houses(&block)
|
37
|
+
wrapper.houses.each do |region, table|
|
38
|
+
import_houses_for_region(region, table, &block)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
def dump_schema_for(accessor, table)
|
44
|
+
"".tap do |s|
|
45
|
+
table.columns.each do |column|
|
46
|
+
column_name = column.name.downcase
|
47
|
+
column_def = column.schema_definition
|
48
|
+
s << " t.column #{column_def}"
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def alter_table_to_pg_uuids(accessor)
|
54
|
+
"".tap do |s|
|
55
|
+
columns = wrapper.class::CONVERT_TO_UUID[accessor]
|
56
|
+
if columns.present?
|
57
|
+
columns.each do |column|
|
58
|
+
s << %{ActiveRecord::Base.connection.execute("ALTER TABLE #{table_name(accessor)} ALTER COLUMN #{column} TYPE UUID USING CAST (#{column} AS UUID);")\n}
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def import_table(accessor, table, &block)
|
65
|
+
fields = table_fields(table)
|
66
|
+
columns = table_columns(fields)
|
67
|
+
|
68
|
+
tn = table_name(accessor)
|
69
|
+
|
70
|
+
truncate_table(tn)
|
71
|
+
copy_from_stdin(tn, columns)
|
72
|
+
|
73
|
+
table.each_with_index do |record|
|
74
|
+
data = record.to_a
|
75
|
+
put_data(data)
|
76
|
+
yield(accessor, data) if block_given?
|
77
|
+
end
|
78
|
+
|
79
|
+
put_copy_end
|
80
|
+
end
|
81
|
+
|
82
|
+
def import_houses_for_region(region, table, &block)
|
83
|
+
fields = table_fields(table)
|
84
|
+
fields << :regioncode
|
85
|
+
columns = table_columns(fields)
|
86
|
+
|
87
|
+
tn = table_name('houses')
|
88
|
+
|
89
|
+
truncate_table(tn)
|
90
|
+
copy_from_stdin(tn, columns)
|
91
|
+
|
92
|
+
table.each_with_index do |record|
|
93
|
+
data = record.to_a
|
94
|
+
data << region
|
95
|
+
put_data(data)
|
96
|
+
yield('houses', data) if block_given?
|
97
|
+
end
|
98
|
+
|
99
|
+
put_copy_end
|
100
|
+
end
|
101
|
+
|
102
|
+
def table_name(table)
|
103
|
+
"#{prefix}_#{table}"
|
104
|
+
end
|
105
|
+
|
106
|
+
def table_fields(table)
|
107
|
+
table.columns.map(&:name).map(&:downcase)
|
108
|
+
end
|
109
|
+
|
110
|
+
def table_columns(fields)
|
111
|
+
fields.join(',')
|
112
|
+
end
|
113
|
+
|
114
|
+
def truncate_table(table_name)
|
115
|
+
raw_connection.exec "TRUNCATE TABLE #{table_name};"
|
116
|
+
end
|
117
|
+
|
118
|
+
def copy_from_stdin(table_name, columns)
|
119
|
+
sql = "COPY #{table_name} (#{columns}) FROM STDIN NULL AS '-nil-'\n"
|
120
|
+
raw_connection.exec(sql)
|
121
|
+
end
|
122
|
+
|
123
|
+
def put_data(data)
|
124
|
+
data.map! { |item| item == "" ? '-nil-' : item }
|
125
|
+
line = data.join("\t") + "\n"
|
126
|
+
raw_connection.put_copy_data(line)
|
127
|
+
end
|
128
|
+
|
129
|
+
def put_copy_end
|
130
|
+
raw_connection.put_copy_end
|
131
|
+
|
132
|
+
while res = raw_connection.get_result
|
133
|
+
result_status = res.res_status(res.result_status)
|
134
|
+
unless result_status == 'PGRES_COMMAND_OK'
|
135
|
+
raise "Import failure: #{result_status}"
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
attr_accessor :raw_connection, :wrapper
|
141
|
+
attr_accessor :prefix, :table_mappings
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
data/lib/fias/railtie.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
module Fias
|
2
|
+
class Railtie < Rails::Railtie
|
3
|
+
config.fias = ActiveSupport::OrderedOptions.new
|
4
|
+
config.fias.prefix = 'fias'
|
5
|
+
config.app_generators.orm :active_record
|
6
|
+
|
7
|
+
generators do
|
8
|
+
require 'generators/fias/migration'
|
9
|
+
end
|
10
|
+
|
11
|
+
rake_tasks do
|
12
|
+
load File.join(File.dirname(__FILE__), '../../tasks/fias.rake')
|
13
|
+
end
|
14
|
+
|
15
|
+
initializer 'fias.load_models' do
|
16
|
+
ActiveSupport.on_load(:active_record) do
|
17
|
+
require 'fias/active_record/address_object'
|
18
|
+
require 'fias/active_record/address_object_type'
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
data/lib/fias/version.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
module Fias
|
2
|
+
class MigrationGenerator < Rails::Generators::Base
|
3
|
+
include Rails::Generators::Migration
|
4
|
+
|
5
|
+
class_option :prefix, type: :string, default: :fias, desc: 'Table names prefix'
|
6
|
+
class_option :path, type: :string, default: 'tmp/fias', desc: 'Path to FIAS dbfs'
|
7
|
+
|
8
|
+
source_root File.expand_path("../templates", __FILE__)
|
9
|
+
|
10
|
+
def generate_migration
|
11
|
+
wrapper = Fias::Import::DbfWrapper.new(options.path)
|
12
|
+
importer = wrapper.build_importer(prefix: options.prefix)
|
13
|
+
@schema = importer.schema
|
14
|
+
@schema.gsub!("\n", "\n\t\t")
|
15
|
+
|
16
|
+
migration_template 'create_fias_tables.rb', 'db/migrate/create_fias_tables'
|
17
|
+
end
|
18
|
+
|
19
|
+
def usage
|
20
|
+
"Generates FIAS migrations for application"
|
21
|
+
end
|
22
|
+
|
23
|
+
# https://rails.lighthouseapp.com/projects/8994/tickets/3820-make-railsgeneratorsmigrationnext_migration_number-method-a-class-method-so-it-possible-to-use-it-in-custom-generators
|
24
|
+
def self.next_migration_number(dirname)
|
25
|
+
orm = Rails.configuration.generators.options[:rails][:orm]
|
26
|
+
require "rails/generators/#{orm}"
|
27
|
+
"#{orm.to_s.camelize}::Generators::Base".constantize.next_migration_number(dirname)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
data/tasks/fias.rake
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
require 'fias'
|
2
|
+
|
3
|
+
namespace :fias do
|
4
|
+
class << self
|
5
|
+
private
|
6
|
+
# Если гем используется внутри рельсов - стоит загрузить энвайронмент
|
7
|
+
# и подключиться к БД.
|
8
|
+
def may_be_rails(name)
|
9
|
+
defined?(Rails) ? {name => :environment} : name
|
10
|
+
end
|
11
|
+
|
12
|
+
# Открывает DBFы ФИАС, соединяется с базой и передает все это блоку
|
13
|
+
def within_connection(&block)
|
14
|
+
require 'active_record'
|
15
|
+
require 'progress_bar'
|
16
|
+
|
17
|
+
begin
|
18
|
+
ActiveRecord::Base.connection
|
19
|
+
rescue ActiveRecord::ConnectionNotEstablished
|
20
|
+
if ENV['DATABASE_URL'].nil?
|
21
|
+
raise ArgumentError, 'Specify database in DATABASE_URL env variable'
|
22
|
+
end
|
23
|
+
|
24
|
+
ActiveRecord::Base.establish_connection
|
25
|
+
end
|
26
|
+
|
27
|
+
fias_path = ENV['FIAS'] || 'tmp/fias'
|
28
|
+
wrapper = Fias::Import::DbfWrapper.new(fias_path)
|
29
|
+
importer = wrapper.build_importer(prefix: ENV['PREFIX'])
|
30
|
+
|
31
|
+
yield(wrapper, importer)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
desc 'Create FIAS tables (could specify tables PREFIX, PATH to dbfs and DATABASE_URL)'
|
36
|
+
task may_be_rails(:create_tables) do
|
37
|
+
within_connection do |wrapper, importer|
|
38
|
+
ActiveRecord::Schema.define { eval(importer.schema) }
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
namespace :import do
|
43
|
+
desc 'Import FIAS data (without houses)'
|
44
|
+
task may_be_rails(:placements) do
|
45
|
+
within_connection do |wrapper, importer|
|
46
|
+
total_record_count = wrapper.tables.sum { |accessor, dbf| dbf.record_count }
|
47
|
+
|
48
|
+
puts 'Importing FIAS data...'
|
49
|
+
|
50
|
+
bar = ProgressBar.new(total_record_count)
|
51
|
+
importer.import do
|
52
|
+
bar.increment!
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
desc 'Import FIAS data (houses)'
|
58
|
+
task may_be_rails(:houses) do
|
59
|
+
within_connection do |wrapper, importer|
|
60
|
+
total_record_count = wrapper.houses.sum { |region, dbf| dbf.record_count }
|
61
|
+
|
62
|
+
puts 'Importing FIAS data (houses)...'
|
63
|
+
|
64
|
+
bar = ProgressBar.new(total_record_count)
|
65
|
+
importer.import_houses do
|
66
|
+
bar.increment!
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
metadata
ADDED
@@ -0,0 +1,131 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: fias
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Victor Sokolov
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-01-21 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: dbf
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: rake
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :runtime
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: activerecord
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>'
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '3'
|
54
|
+
type: :runtime
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>'
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '3'
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: progress_bar
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ! '>='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
type: :runtime
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
78
|
+
description: Ruby wrapper to FIAS database
|
79
|
+
email:
|
80
|
+
- gzigzigzeo@evilmartians.com
|
81
|
+
executables: []
|
82
|
+
extensions: []
|
83
|
+
extra_rdoc_files: []
|
84
|
+
files:
|
85
|
+
- .gitignore
|
86
|
+
- Gemfile
|
87
|
+
- LICENSE.txt
|
88
|
+
- README.md
|
89
|
+
- Rakefile
|
90
|
+
- fias.gemspec
|
91
|
+
- lib/fias.rb
|
92
|
+
- lib/fias/active_record/address_object.rb
|
93
|
+
- lib/fias/active_record/address_object_type.rb
|
94
|
+
- lib/fias/import/dbf_wrapper.rb
|
95
|
+
- lib/fias/import/pg.rb
|
96
|
+
- lib/fias/railtie.rb
|
97
|
+
- lib/fias/version.rb
|
98
|
+
- lib/generators/fias/migration.rb
|
99
|
+
- lib/generators/fias/templates/create_fias_tables.rb
|
100
|
+
- tasks/fias.rake
|
101
|
+
homepage: http://github.com/evilmartians/fias
|
102
|
+
licenses: []
|
103
|
+
post_install_message:
|
104
|
+
rdoc_options: []
|
105
|
+
require_paths:
|
106
|
+
- lib
|
107
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
108
|
+
none: false
|
109
|
+
requirements:
|
110
|
+
- - ! '>='
|
111
|
+
- !ruby/object:Gem::Version
|
112
|
+
version: '0'
|
113
|
+
segments:
|
114
|
+
- 0
|
115
|
+
hash: -2160443642439180378
|
116
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
117
|
+
none: false
|
118
|
+
requirements:
|
119
|
+
- - ! '>='
|
120
|
+
- !ruby/object:Gem::Version
|
121
|
+
version: '0'
|
122
|
+
segments:
|
123
|
+
- 0
|
124
|
+
hash: -2160443642439180378
|
125
|
+
requirements: []
|
126
|
+
rubyforge_project:
|
127
|
+
rubygems_version: 1.8.24
|
128
|
+
signing_key:
|
129
|
+
specification_version: 3
|
130
|
+
summary: Ruby wrapper to FIAS database
|
131
|
+
test_files: []
|