fias 0.0.1
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/.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: []
|