kladr 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.
Binary file
data/BASE/DOMA.DBF ADDED
Binary file
data/BASE/DOMA.DBF.gz ADDED
Binary file
data/BASE/FLAT.DBF.gz ADDED
Binary file
data/BASE/KLADR.DBF.gz ADDED
Binary file
Binary file
data/BASE/STREET.DBF ADDED
Binary file
Binary file
data/README ADDED
File without changes
data/README.ru ADDED
@@ -0,0 +1,9 @@
1
+ Классификатор адресов России (КЛАДР) живет по адресу http://www.gnivc.ru/downloads/kladr.aspx
2
+
3
+ Поскольку сами базы там находятся в редком формате ARJ и весят совсем немного, то они
4
+ прилагаются к этому проекту в сжатом виде в каталоге BASE.
5
+
6
+ Библиотека DBF, которая лежит на http://rubyforge.org/projects/dbf в сыром виде к импорту больших DBF
7
+ по причине того, что она при открытии файла вычитывает всю таблицу. Это неприемлемо, поэтому исправленная библиотека
8
+ прилагается.
9
+
data/Rakefile ADDED
@@ -0,0 +1,32 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+ require 'rake/testtask'
4
+ require 'rake/gempackagetask'
5
+
6
+ spec = Gem::Specification.new do |s|
7
+ s.name = 'kladr'
8
+ s.version = '0.1'
9
+ s.summary = 'Importer of russian classificator of addresses'
10
+ # s.autorequire = 'attacheable'
11
+ s.author = "Max Lapshin"
12
+ s.email = "max@maxidoors.ru"
13
+ s.description = ""
14
+ s.rubyforge_project = "kladr"
15
+ s.has_rdoc = false
16
+ s.files = FileList["**/**"].exclude(".git").to_a
17
+
18
+ end
19
+
20
+ Rake::GemPackageTask.new(spec) do |package|
21
+ package.gem_spec = spec
22
+ end
23
+
24
+
25
+ task :default => [ :test ]
26
+
27
+ desc "Run all tests"
28
+ Rake::TestTask.new("test") { |t|
29
+ t.libs << "test"
30
+ t.pattern = 'test/*_test.rb'
31
+ t.verbose = true
32
+ }
data/init.rb ADDED
@@ -0,0 +1,2 @@
1
+ $:.unshift(File.dirname(__FILE__)+'/lib')
2
+ require 'kladr'
data/kladr.sqlite3 ADDED
Binary file
data/lib/dbf/dbf.rb ADDED
@@ -0,0 +1,6 @@
1
+ require 'date'
2
+
3
+ require File.dirname(__FILE__)+'/dbf/globals'
4
+ require File.dirname(__FILE__)+'/dbf/record'
5
+ require File.dirname(__FILE__)+'/dbf/column'
6
+ require File.dirname(__FILE__)+'/dbf/table'
@@ -0,0 +1,54 @@
1
+ class Kladr
2
+ module DBF
3
+ class ColumnLengthError < DBFError; end
4
+
5
+ class Column
6
+ attr_reader :name, :type, :length, :decimal
7
+
8
+ def initialize(name, type, length, decimal)
9
+ raise ColumnLengthError, "field length must be greater than 0" unless length > 0
10
+ @name, @type, @length, @decimal = strip_non_ascii_chars(name), type, length, decimal
11
+ end
12
+
13
+ def schema_definition
14
+ "\"#{underscore(name)}\", " +
15
+ case type
16
+ when "N" # number
17
+ if decimal > 0
18
+ ":float"
19
+ else
20
+ ":integer"
21
+ end
22
+ when "D" # date
23
+ ":datetime"
24
+ when "L" # boolean
25
+ ":boolean"
26
+ when "M" # memo
27
+ ":text"
28
+ else
29
+ ":string, :limit => #{length}"
30
+ end +
31
+ "\n"
32
+ end
33
+
34
+ private
35
+
36
+ def underscore(camel_cased_word)
37
+ camel_cased_word.to_s.gsub(/::/, '/').
38
+ gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
39
+ gsub(/([a-z\d])([A-Z])/,'\1_\2').
40
+ tr("-", "_").
41
+ downcase
42
+ end
43
+
44
+ def strip_non_ascii_chars(s)
45
+ clean = ''
46
+ s.each_byte do |char|
47
+ clean << char if char > 31 && char < 128
48
+ end
49
+ clean
50
+ end
51
+ end
52
+
53
+ end
54
+ end
@@ -0,0 +1,30 @@
1
+ class Kladr
2
+ module DBF
3
+ DBF_HEADER_SIZE = 32
4
+ FPT_HEADER_SIZE = 512
5
+ FPT_BLOCK_HEADER_SIZE = 8
6
+ DATE_REGEXP = /([\d]{4})([\d]{2})([\d]{2})/
7
+ VERSION_DESCRIPTIONS = {
8
+ "02" => "FoxBase",
9
+ "03" => "dBase III without memo file",
10
+ "04" => "dBase IV without memo file",
11
+ "05" => "dBase V without memo file",
12
+ "30" => "Visual FoxPro",
13
+ "31" => "Visual FoxPro with AutoIncrement field",
14
+ "7b" => "dBase IV with memo file",
15
+ "83" => "dBase III with memo file",
16
+ "8b" => "dBase IV with memo file",
17
+ "8e" => "dBase IV with SQL table",
18
+ "f5" => "FoxPro with memo file",
19
+ "fb" => "FoxPro without memo file"
20
+ }
21
+
22
+ MS_PER_SECOND = 1000
23
+ MS_PER_MINUTE = MS_PER_SECOND * 60
24
+ MS_PER_HOUR = MS_PER_MINUTE * 60
25
+
26
+ class DBFError < StandardError; end
27
+ class InvalidColumnName < DBFError; end
28
+ class InvalidColumnLength < DBFError; end
29
+ end
30
+ end
@@ -0,0 +1,121 @@
1
+ class Kladr
2
+ module DBF
3
+ class Record
4
+ attr_reader :attributes
5
+
6
+ @@accessors_defined = false
7
+
8
+ def initialize(table)
9
+ @table, @data, @memo = table, table.data, table.memo
10
+ @attributes = {}
11
+ initialize_values(table.columns)
12
+ define_accessors
13
+ self
14
+ end
15
+
16
+ private
17
+
18
+ def define_accessors
19
+ return if @@accessors_defined
20
+ @table.columns.each do |column|
21
+ underscored_column_name = underscore(column.name)
22
+ if @table.options[:accessors] && !respond_to?(underscored_column_name)
23
+ self.class.send :define_method, underscored_column_name do
24
+ @attributes[column.name]
25
+ end
26
+ @@accessors_defined = true
27
+ end
28
+ end
29
+ end
30
+
31
+ def initialize_values(columns)
32
+ columns.each do |column|
33
+ @attributes[column.name] = case column.type
34
+ when 'N' # number
35
+ column.decimal.zero? ? unpack_string(column).to_i : unpack_string(column).to_f
36
+ when 'D' # date
37
+ raw = unpack_string(column).strip
38
+ unless raw.empty?
39
+ parts = raw.match(DATE_REGEXP).captures.map {|n| n.to_i}
40
+ begin
41
+ Time.gm(*parts)
42
+ rescue
43
+ Date.new(*parts)
44
+ end
45
+ end
46
+ when 'M' # memo
47
+ starting_block = unpack_string(column).to_i
48
+ read_memo(starting_block)
49
+ when 'L' # logical
50
+ unpack_string(column) =~ /^(y|t)$/i ? true : false
51
+ when 'I' # integer
52
+ unpack_integer(column)
53
+ when 'T' # datetime
54
+ unpack_datetime(column)
55
+ else
56
+ unpack_string(column).strip
57
+ end
58
+ end
59
+ end
60
+
61
+ def unpack_column(column)
62
+ @data.read(column.length).unpack("a#{column.length}")
63
+ end
64
+
65
+ def unpack_string(column)
66
+ unpack_column(column).to_s
67
+ end
68
+
69
+ def unpack_integer(column)
70
+ @data.read(column.length).unpack("v").first
71
+ end
72
+
73
+ def unpack_datetime(column)
74
+ days, milliseconds = @data.read(column.length).unpack('l2')
75
+ hours = (milliseconds / MS_PER_HOUR).to_i
76
+ minutes = ((milliseconds - (hours * MS_PER_HOUR)) / MS_PER_MINUTE).to_i
77
+ seconds = ((milliseconds - (hours * MS_PER_HOUR) - (minutes * MS_PER_MINUTE)) / MS_PER_SECOND).to_i
78
+ DateTime.jd(days, hours, minutes, seconds)
79
+ end
80
+
81
+ def read_memo(start_block)
82
+ return nil if start_block <= 0 || @table.memo_block_size.nil?
83
+ @memo.seek(start_block * @table.memo_block_size)
84
+ if @table.memo_file_format == :fpt
85
+ memo_type, memo_size, memo_string = @memo.read(@table.memo_block_size).unpack("NNa56")
86
+
87
+ # skip the memo if it isn't text
88
+ return nil unless memo_type == 1
89
+
90
+ memo_block_content_size = @table.memo_block_size - FPT_BLOCK_HEADER_SIZE
91
+ if memo_size > memo_block_content_size
92
+ memo_string << @memo.read(memo_size - @table.memo_block_size + FPT_BLOCK_HEADER_SIZE)
93
+ elsif memo_size > 0 and memo_size < memo_block_content_size
94
+ memo_string = memo_string[0, memo_size]
95
+ end
96
+ else
97
+ case @table.version
98
+ when "83" # dbase iii
99
+ memo_string = ""
100
+ loop do
101
+ memo_string << block = @memo.read(512)
102
+ break if block.strip.size < 512
103
+ end
104
+ when "8b" # dbase iv
105
+ memo_type, memo_size = @memo.read(8).unpack("LL")
106
+ memo_string = @memo.read(memo_size)
107
+ end
108
+ end
109
+ memo_string
110
+ end
111
+
112
+ def underscore(camel_cased_word)
113
+ camel_cased_word.to_s.gsub(/::/, '/').
114
+ gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
115
+ gsub(/([a-z\d])([A-Z])/,'\1_\2').
116
+ tr("-", "_").
117
+ downcase
118
+ end
119
+ end
120
+ end
121
+ end
@@ -0,0 +1,253 @@
1
+ class Kladr
2
+ module DBF
3
+
4
+ class Table
5
+ # The total number of columns (columns)
6
+ attr_reader :column_count
7
+
8
+ # An array of DBF::Column records
9
+ attr_reader :columns
10
+
11
+ # Internal dBase version number
12
+ attr_reader :version
13
+
14
+ # Last updated datetime
15
+ attr_reader :last_updated
16
+
17
+ # Either :fpt or :dpt
18
+ attr_reader :memo_file_format
19
+
20
+ # The block size for memo records
21
+ attr_reader :memo_block_size
22
+
23
+ # The options that were used when initializing DBF::Table. This is a Hash.
24
+ attr_reader :options
25
+
26
+ attr_reader :data
27
+ attr_reader :memo
28
+
29
+ # Initialize a new DBF::Reader.
30
+ # Example:
31
+ # reader = DBF::Reader.new 'data.dbf'
32
+ def initialize(filename, options = {})
33
+ @options = {:in_memory => true, :accessors => true}.merge(options)
34
+
35
+ @in_memory = @options[:in_memory]
36
+ @accessors = @options[:accessors]
37
+ @data = File.open(filename, 'rb')
38
+ @memo = open_memo(filename)
39
+ reload!
40
+ end
41
+
42
+ # Reloads the database and memo files
43
+ def reload!
44
+ @records = nil
45
+ get_header_info
46
+ get_memo_header_info if @memo
47
+ get_column_descriptors
48
+ build_db_index
49
+ end
50
+
51
+ # Returns true if there is a corresponding memo file
52
+ def has_memo_file?
53
+ @memo ? true : false
54
+ end
55
+
56
+ # The total number of active records.
57
+ def record_count
58
+ @db_index.size
59
+ end
60
+
61
+ # Returns an instance of DBF::Column for <b>column_name</b>. <b>column_name</b>
62
+ # can be a symbol or a string.
63
+ def column(column_name)
64
+ @columns.detect {|f| f.name == column_name.to_s}
65
+ end
66
+
67
+ # An array of all the records contained in the database file. Each record is an instance
68
+ # of DBF::Record (or nil if the record is marked for deletion).
69
+ def records
70
+ if options[:in_memory]
71
+ @records ||= get_all_records_from_file
72
+ else
73
+ get_all_records_from_file
74
+ end
75
+ end
76
+
77
+ alias_method :rows, :records
78
+
79
+ # Returns a DBF::Record (or nil if the record has been marked for deletion) for the record at <tt>index</tt>.
80
+ def record(index)
81
+ if options[:in_memory]
82
+ records[index]
83
+ else
84
+ get_record_from_file(index)
85
+ end
86
+ end
87
+
88
+ # Find records using a simple ActiveRecord-like syntax.
89
+ #
90
+ # Examples:
91
+ # reader = DBF::Reader.new 'mydata.dbf'
92
+ #
93
+ # # Find record number 5
94
+ # reader.find(5)
95
+ #
96
+ # # Find all records for Keith Morrison
97
+ # reader.find :all, :first_name => "Keith", :last_name => "Morrison"
98
+ #
99
+ # # Find first record
100
+ # reader.find :first, :first_name => "Keith"
101
+ #
102
+ # The <b>command</b> can be an id, :all, or :first.
103
+ # <b>options</b> is optional and, if specified, should be a hash where the keys correspond
104
+ # to column names in the database. The values will be matched exactly with the value
105
+ # in the database. If you specify more than one key, all values must match in order
106
+ # for the record to be returned. The equivalent SQL would be "WHERE key1 = 'value1'
107
+ # AND key2 = 'value2'".
108
+ def find(command, options = {})
109
+ results = options.empty? ? records : records.select {|record| all_values_match?(record, options)}
110
+
111
+ case command
112
+ when Fixnum
113
+ record(command)
114
+ when :all
115
+ results
116
+ when :first
117
+ results.first
118
+ end
119
+ end
120
+
121
+ alias_method :row, :record
122
+
123
+ # Returns a description of the current database file.
124
+ def version_description
125
+ VERSION_DESCRIPTIONS[version]
126
+ end
127
+
128
+ # Returns a database schema in the portable ActiveRecord::Schema format.
129
+ #
130
+ # xBase data types are converted to generic types as follows:
131
+ # - Number columns are converted to :integer if there are no decimals, otherwise
132
+ # they are converted to :float
133
+ # - Date columns are converted to :datetime
134
+ # - Logical columns are converted to :boolean
135
+ # - Memo columns are converted to :text
136
+ # - Character columns are converted to :string and the :limit option is set
137
+ # to the length of the character column
138
+ #
139
+ # Example:
140
+ # create_table "mydata" do |t|
141
+ # t.column :name, :string, :limit => 30
142
+ # t.column :last_update, :datetime
143
+ # t.column :is_active, :boolean
144
+ # t.column :age, :integer
145
+ # t.column :notes, :text
146
+ # end
147
+ def schema(path = nil)
148
+ s = "ActiveRecord::Schema.define do\n"
149
+ s << " create_table \"#{File.basename(@data.path, ".*")}\" do |t|\n"
150
+ columns.each do |column|
151
+ s << " t.column #{column.schema_definition}"
152
+ end
153
+ s << " end\nend"
154
+
155
+ if path
156
+ File.open(path, 'w') {|f| f.puts(s)}
157
+ else
158
+ s
159
+ end
160
+ end
161
+
162
+ private
163
+
164
+ def open_memo(file)
165
+ %w(fpt FPT dbt DBT).each do |extension|
166
+ filename = file.sub(/#{File.extname(file)[1..-1]}$/, extension)
167
+ if File.exists?(filename)
168
+ @memo_file_format = extension.downcase.to_sym
169
+ return File.open(filename, 'rb')
170
+ end
171
+ end
172
+ nil
173
+ end
174
+
175
+ def deleted_record?
176
+ @data.read(1).unpack('a') == ['*']
177
+ end
178
+
179
+ def get_header_info
180
+ @data.rewind
181
+ @version, @record_count, @header_length, @record_length = @data.read(DBF_HEADER_SIZE).unpack('H2 x3 V v2')
182
+ @column_count = (@header_length - DBF_HEADER_SIZE + 1) / DBF_HEADER_SIZE
183
+ end
184
+
185
+ def get_column_descriptors
186
+ @columns = []
187
+ @column_count.times do
188
+ name, type, length, decimal = @data.read(32).unpack('a10 x a x4 C2')
189
+ if length > 0
190
+ @columns << Column.new(name.strip, type, length, decimal)
191
+ end
192
+ end
193
+ # Reset the column count
194
+ @column_count = @columns.size
195
+
196
+ @columns
197
+ end
198
+
199
+ def get_memo_header_info
200
+ @memo.rewind
201
+ if @memo_file_format == :fpt
202
+ @memo_next_available_block, @memo_block_size = @memo.read(FPT_HEADER_SIZE).unpack('N x2 n')
203
+ else
204
+ @memo_block_size = 512
205
+ @memo_next_available_block = File.size(@memo.path) / @memo_block_size
206
+ end
207
+ end
208
+
209
+ def seek(offset)
210
+ @data.seek(@header_length + offset)
211
+ end
212
+
213
+ def seek_to_record(index)
214
+ seek(index * @record_length)
215
+ end
216
+
217
+ # Returns the record at <tt>index</tt> by seeking to the record in the
218
+ # physical database file. See the documentation for the records method for
219
+ # information on how these two methods differ.
220
+ def get_record_from_file(index)
221
+ seek_to_record(index)
222
+ deleted_record? ? nil : Record.new(self)
223
+ end
224
+
225
+ def get_all_records_from_file
226
+ all_records = []
227
+ 0.upto(@record_count - 1) do |n|
228
+ seek_to_record(n)
229
+ all_records << DBF::Record.new(self) unless deleted_record?
230
+ end
231
+ all_records
232
+ end
233
+
234
+ def build_db_index
235
+ @db_index = []
236
+ @deleted_records = []
237
+ 0.upto(@record_count - 1) do |n|
238
+ #seek_to_record(n)
239
+ if false && deleted_record?
240
+ @deleted_records << n
241
+ else
242
+ @db_index << n
243
+ end
244
+ end
245
+ end
246
+
247
+ def all_values_match?(record, options)
248
+ options.map {|key, value| record.attributes[key.to_s] == value}.all?
249
+ end
250
+ end
251
+
252
+ end
253
+ end
data/lib/kladr.rb ADDED
@@ -0,0 +1,150 @@
1
+ require 'dbf/dbf'
2
+ require 'iconv'
3
+ require 'active_support'
4
+ require 'active_record'
5
+ $KCODE = 'u'
6
+
7
+ class Kladr
8
+
9
+ def self.exec_streets_schema
10
+ ActiveRecord::Migration.create_table "streets" do |t|
11
+ t.column "name", :string, :limit => 40
12
+ t.column "street_code", :integer
13
+ t.column "abbrev", :string, :limit => 10
14
+ end
15
+ ActiveRecord::Migration.add_index :streets, :street_code
16
+ ActiveRecord::Migration.add_index :streets, :name
17
+ end
18
+
19
+
20
+ class Street < ActiveRecord::Base
21
+ has_many :houses
22
+ end
23
+
24
+ class House < ActiveRecord::Base
25
+ belongs_to :street
26
+ end
27
+
28
+ def self.file_unpack(file)
29
+ return if File.exists?(file)
30
+ return unless File.exists?(file+".gz")
31
+ `gzip -cd #{file}.gz > #{file}`
32
+ end
33
+
34
+ def self.recode(string)
35
+ Iconv.iconv("UTF-8", "CP866", string).first
36
+ end
37
+
38
+ def self.street_import(file = File.dirname(__FILE__)+"/../BASE/STREET.DBF")
39
+ start_time = Time.now
40
+ file_unpack(file)
41
+ table = Kladr::DBF::Table.new(file, :in_memory => false)
42
+ table.columns.each {|c| c.name.replace(c.name.downcase) }
43
+
44
+ exec_streets_schema rescue false
45
+
46
+ table_columns = Street.columns.map(&:name)
47
+
48
+ puts "Table created, importing #{table.record_count} records"
49
+ count = 0
50
+ 0.upto(table.record_count-1) do |i|
51
+ record = table.record(i)
52
+ next unless record
53
+ city_code = record.attributes["code"][0,2].to_i
54
+ street_code = record.attributes["code"][11, 4].to_i
55
+ actuality_code = record.attributes["code"][15,2].to_i
56
+
57
+ next unless city_code == 77 && actuality_code == 0
58
+ attributes = {:street_code => street_code, :name => recode(record.attributes["name"]), :abbrev => recode(record.attributes["socr"])}.
59
+ reject {|field, value| !table_columns.include?(field.to_s)}
60
+ street = Street.create(attributes)
61
+ puts ("%4d %s %s" % [street.street_code, street.abbrev, street.name])
62
+ count += 1
63
+ if count == 1
64
+ puts "Starting Moscow on #{i} record"
65
+ end
66
+ end
67
+ import_time = Time.now
68
+
69
+ puts "It took #{import_time - start_time} seconds to import #{count} records. #{Time.now - import_time} to build index."
70
+ end
71
+
72
+ def self.exec_houses_schema
73
+ ActiveRecord::Migration.create_table "houses" do |t|
74
+ t.column "number", :string, :limit => 10
75
+ t.column "street_code", :integer
76
+ t.column "abbrev", :string, :limit => 10
77
+ t.column "building", :integer
78
+ t.column "index", :integer
79
+ t.column "house_code", :integer
80
+ t.column "street_id", :integer
81
+ end
82
+ ActiveRecord::Migration.add_index :houses, [:street_code, :house_code]
83
+ end
84
+
85
+ def self.houses_import(file = File.dirname(__FILE__)+"/../BASE/DOMA.DBF")
86
+ start_time = Time.now
87
+ file_unpack(file)
88
+ table = Kladr::DBF::Table.new(file, :in_memory => false)
89
+ table.columns.each {|c| c.name.replace(c.name.downcase) }
90
+
91
+ exec_houses_schema rescue false
92
+
93
+ puts "Table created, importing #{table.record_count} records"
94
+ count = 0
95
+ table_columns = House.columns.map(&:name)
96
+
97
+ 0.upto(table.record_count-1) do |i|
98
+ record = table.record(i)
99
+ next unless record
100
+
101
+ city_code = record.attributes["code"][0,2].to_i
102
+ street_code = record.attributes["code"][11, 4].to_i
103
+ house_code = record.attributes["code"][15, 4].to_i
104
+ next unless city_code == 77
105
+ next if street_code == 0
106
+ attributes = {
107
+ :street_code => street_code, :house_code => house_code, :abbrev => recode(record.attributes["socr"]).chars.downcase.to_s,
108
+ :building => recode(record.attributes["korp"]), :index => record.attributes["index"].to_i
109
+ }.reject {|field, value| !table_columns.include?(field.to_s)}
110
+ attributes[:numbers] = recode(record.attributes["name"])
111
+ street = Street.find_by_street_code(street_code)
112
+ attributes[:street_id] = street.id if street
113
+ houses = create_houses(attributes)
114
+ count += houses.length
115
+ if count == 1
116
+ puts "Starting Moscow on #{i} record"
117
+ end
118
+ end
119
+ puts "It took #{Time.now - start_time} seconds to import #{count} records."
120
+ end
121
+
122
+ def self.extract_numbers(numbers)
123
+ return [] unless numbers
124
+ numbers.split(",").map do |part|
125
+ if part.index("-")
126
+ start_number, end_number = /(\d+)-(\d+)/.match(part).captures.map(&:to_i)
127
+ step = part.index("(") ? 2 : 1
128
+ res = []
129
+ (start_number..end_number).step(step) {|i| res << i.to_s}
130
+ res
131
+ else
132
+ part
133
+ end
134
+ end.flatten
135
+ end
136
+
137
+ def self.create_houses(attributes)
138
+ numbers = extract_numbers(attributes.delete(:numbers))
139
+ numbers.each do |number|
140
+ house = House.create(attributes.merge(:number => number))
141
+ puts ("%30s %4s" % [house.street && house.street.name || "-", house.number])
142
+ end
143
+ end
144
+
145
+ def self.import
146
+ street_import
147
+ houses_import
148
+ end
149
+
150
+ end
data/test.rb ADDED
@@ -0,0 +1,7 @@
1
+ $:.unshift("lib")
2
+ require 'rubygems'
3
+ require 'active_record'
4
+ require 'kladr'
5
+
6
+ ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :dbfile => "kladr.sqlite3")
7
+
@@ -0,0 +1,6 @@
1
+ require File.dirname(__FILE__)+'/test_helper'
2
+
3
+ class HousesTest < Test::Unit::TestCase
4
+ def test_number_extraction
5
+ end
6
+ end
@@ -0,0 +1,9 @@
1
+ require 'test/unit'
2
+ require 'rubygems'
3
+ require 'active_record'
4
+ $KCODE = 'u'
5
+
6
+ $:.unshift File.join(File.dirname(__FILE__), '../lib')
7
+ require 'kladr'
8
+
9
+
metadata ADDED
@@ -0,0 +1,80 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: kladr
3
+ version: !ruby/object:Gem::Version
4
+ version: "0.1"
5
+ platform: ruby
6
+ authors:
7
+ - Max Lapshin
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2008-04-10 00:00:00 +04:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description: ""
17
+ email: max@maxidoors.ru
18
+ executables: []
19
+
20
+ extensions: []
21
+
22
+ extra_rdoc_files: []
23
+
24
+ files:
25
+ - BASE
26
+ - BASE/ALTNAMES.DBF.gz
27
+ - BASE/DOMA.DBF
28
+ - BASE/DOMA.DBF.gz
29
+ - BASE/FLAT.DBF.gz
30
+ - BASE/KLADR.DBF.gz
31
+ - BASE/SOCRBASE.DBF.gz
32
+ - BASE/STREET.DBF
33
+ - BASE/STREET.DBF.gz
34
+ - init.rb
35
+ - kladr.sqlite3
36
+ - lib
37
+ - lib/dbf
38
+ - lib/dbf/dbf
39
+ - lib/dbf/dbf/column.rb
40
+ - lib/dbf/dbf/globals.rb
41
+ - lib/dbf/dbf/record.rb
42
+ - lib/dbf/dbf/table.rb
43
+ - lib/dbf/dbf.rb
44
+ - lib/kladr.rb
45
+ - pkg
46
+ - Rakefile
47
+ - README
48
+ - README.ru
49
+ - test
50
+ - test/houses_test.rb
51
+ - test/test_helper.rb
52
+ - test.rb
53
+ has_rdoc: false
54
+ homepage:
55
+ post_install_message:
56
+ rdoc_options: []
57
+
58
+ require_paths:
59
+ - lib
60
+ required_ruby_version: !ruby/object:Gem::Requirement
61
+ requirements:
62
+ - - ">="
63
+ - !ruby/object:Gem::Version
64
+ version: "0"
65
+ version:
66
+ required_rubygems_version: !ruby/object:Gem::Requirement
67
+ requirements:
68
+ - - ">="
69
+ - !ruby/object:Gem::Version
70
+ version: "0"
71
+ version:
72
+ requirements: []
73
+
74
+ rubyforge_project: kladr
75
+ rubygems_version: 1.1.0
76
+ signing_key:
77
+ specification_version: 2
78
+ summary: Importer of russian classificator of addresses
79
+ test_files: []
80
+