fias 0.0.2 → 1.0.0

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.
Files changed (69) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +15 -22
  3. data/.rubocop.yml +7 -0
  4. data/.travis.yml +10 -0
  5. data/Gemfile +1 -1
  6. data/LICENSE.txt +2 -2
  7. data/README.md +259 -155
  8. data/Rakefile +6 -1
  9. data/config/names.txt +0 -0
  10. data/config/synonyms.yml +50 -0
  11. data/examples/create.rb +106 -0
  12. data/examples/generate_index.rb +63 -0
  13. data/fias.gemspec +33 -21
  14. data/lib/fias.rb +197 -10
  15. data/lib/fias/config.rb +74 -0
  16. data/lib/fias/import/copy.rb +62 -0
  17. data/lib/fias/import/dbf.rb +81 -0
  18. data/lib/fias/import/download_service.rb +37 -0
  19. data/lib/fias/import/restore_parent_id.rb +51 -0
  20. data/lib/fias/import/tables.rb +74 -0
  21. data/lib/fias/name/append.rb +30 -0
  22. data/lib/fias/name/canonical.rb +42 -0
  23. data/lib/fias/name/extract.rb +85 -0
  24. data/lib/fias/name/house_number.rb +71 -0
  25. data/lib/fias/name/split.rb +60 -0
  26. data/lib/fias/name/synonyms.rb +93 -0
  27. data/lib/fias/query.rb +43 -0
  28. data/lib/fias/query/estimate.rb +67 -0
  29. data/lib/fias/query/finder.rb +75 -0
  30. data/lib/fias/query/params.rb +101 -0
  31. data/lib/fias/railtie.rb +3 -17
  32. data/lib/fias/version.rb +1 -1
  33. data/spec/fixtures/ACTSTAT.DBF +0 -0
  34. data/spec/fixtures/NORDOC99.DBF +0 -0
  35. data/spec/fixtures/STRSTAT.DBF +0 -0
  36. data/spec/fixtures/addressing.yml +93 -0
  37. data/spec/fixtures/query.yml +79 -0
  38. data/spec/fixtures/query_sanitization.yml +75 -0
  39. data/spec/fixtures/status_append.yml +60 -0
  40. data/spec/lib/import/copy_spec.rb +44 -0
  41. data/spec/lib/import/dbf_spec.rb +28 -0
  42. data/spec/lib/import/download_service_spec.rb +15 -0
  43. data/spec/lib/import/restore_parent_id_spec.rb +34 -0
  44. data/spec/lib/import/tables_spec.rb +26 -0
  45. data/spec/lib/name/append_spec.rb +14 -0
  46. data/spec/lib/name/canonical_spec.rb +20 -0
  47. data/spec/lib/name/extract_spec.rb +67 -0
  48. data/spec/lib/name/house_number_spec.rb +45 -0
  49. data/spec/lib/name/query_spec.rb +21 -0
  50. data/spec/lib/name/split_spec.rb +15 -0
  51. data/spec/lib/name/synonyms_spec.rb +51 -0
  52. data/spec/lib/query/params_spec.rb +15 -0
  53. data/spec/lib/query_spec.rb +27 -0
  54. data/spec/spec_helper.rb +30 -0
  55. data/spec/support/db.rb +30 -0
  56. data/spec/support/query.rb +13 -0
  57. data/tasks/db.rake +52 -0
  58. data/tasks/download.rake +15 -0
  59. metadata +246 -64
  60. data/lib/fias/active_record/address_object.rb +0 -231
  61. data/lib/fias/active_record/address_object_type.rb +0 -15
  62. data/lib/fias/dbf_wrapper.rb +0 -90
  63. data/lib/fias/importer.rb +0 -30
  64. data/lib/fias/importer/base.rb +0 -59
  65. data/lib/fias/importer/pg.rb +0 -81
  66. data/lib/fias/importer/sqlite.rb +0 -38
  67. data/lib/generators/fias/migration.rb +0 -34
  68. data/lib/generators/fias/templates/create_fias_tables.rb +0 -5
  69. data/tasks/fias.rake +0 -68
@@ -0,0 +1,44 @@
1
+ require 'spec_helper'
2
+
3
+ describe Fias::Import::Copy do
4
+ let(:name) { 'actual_statuses' }
5
+ let(:files) { Fias::Import::Dbf.new('spec/fixtures').only(name) }
6
+ let(:table_name) { "fias_#{name}".to_sym }
7
+ let(:db) { double('db') }
8
+ let(:raw_connection) { double('raw_connection') }
9
+
10
+ subject { Fias::Import::Tables.new(db, files).copy.first }
11
+
12
+ before do
13
+ stub_const('Fias::Import::Tables::UUID', name.to_sym => %w(name))
14
+ end
15
+
16
+ context '#encode' do
17
+ it do
18
+ expect(PgDataEncoder::EncodeForCopy).to receive(:new).with(
19
+ column_types: { 1 => :uuid }
20
+ ).and_call_original
21
+
22
+ subject.encode
23
+ end
24
+ end
25
+
26
+ context '#copy' do
27
+ let(:result) { double('result') }
28
+
29
+ before do
30
+ table_obj = double(table_name)
31
+ expect(db).to receive(:[]).with(table_name).and_return(table_obj)
32
+ expect(table_obj).to receive(:truncate)
33
+ expect(db).to receive(:run).with(/SET client/)
34
+ expect(db).to receive(:copy_into).with(
35
+ :fias_actual_statuses, columns: [:actstatid, :name], format: :binary
36
+ ).and_yield.and_yield
37
+ end
38
+
39
+ it do
40
+ subject.encode
41
+ subject.copy
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,28 @@
1
+ require 'spec_helper'
2
+
3
+ describe Fias::Import::Dbf do
4
+ subject { described_class.new('spec/fixtures') }
5
+
6
+ context '#initialize' do
7
+ it 'fails without files' do
8
+ expect { described_class.new('foo') }.to raise_error
9
+ end
10
+
11
+ it 'returns correct file list' do
12
+ expect(subject.files.keys).to eq(
13
+ [:actual_statuses, :structure_statuses, :nordoc99]
14
+ )
15
+ expect(subject.files.values).to all(be_present)
16
+ expect(subject.files.values).to all(be_kind_of(DBF::Table))
17
+ end
18
+ end
19
+
20
+ context '#only' do
21
+ it 'returns only houses' do
22
+ expect(subject.only(:nordocs).keys).to eq([:nordoc99])
23
+ expect(subject.only(:address_objects, :structure_statuses).keys).to eq(
24
+ [:structure_statuses]
25
+ )
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,15 @@
1
+ require 'spec_helper'
2
+
3
+ describe Fias::Import::DownloadService do
4
+ it 'parses url' do
5
+ stub_request(
6
+ :post,
7
+ 'http://fias.nalog.ru/WebServices/Public/DownloadService.asmx'
8
+ ).with(described_class::OPTIONS).to_return(
9
+ status: 200,
10
+ body: '<FiasCompleteDbfUrl>http://www.ya.ru</FiasCompleteDbfUrl>'
11
+ )
12
+
13
+ expect(described_class.url).to eq('http://www.ya.ru')
14
+ end
15
+ end
@@ -0,0 +1,34 @@
1
+ require 'spec_helper'
2
+
3
+ describe Fias::Import::RestoreParentId do
4
+ let(:db) { Sequel.sqlite }
5
+ let(:table) { db[:address_objects] }
6
+ let(:records) { table.select_map([:id, :parent_id]).index_by(&:first) }
7
+
8
+ subject { described_class.new(table) }
9
+
10
+ before do
11
+ db.create_table! :address_objects do
12
+ primary_key :id
13
+ column :aoguid, :string
14
+ column :parentguid, :string
15
+ column :parent_id, :integer
16
+ end
17
+
18
+ table.insert(id: 1, aoguid: 'g1')
19
+ table.insert(id: 2, aoguid: 'g2')
20
+ table.insert(id: 3, aoguid: 'g3', parentguid: 'g1')
21
+ table.insert(id: 4, aoguid: 'g4', parentguid: 'g1')
22
+ table.insert(id: 5, aoguid: 'g5', parentguid: 'g2')
23
+ end
24
+
25
+ it do
26
+ subject.restore
27
+
28
+ expect(records[1].last).to be_nil
29
+ expect(records[2].last).to be_nil
30
+ expect(records[3].last).to eq(1)
31
+ expect(records[4].last).to eq(1)
32
+ expect(records[5].last).to eq(2)
33
+ end
34
+ end
@@ -0,0 +1,26 @@
1
+ require 'spec_helper'
2
+
3
+ describe Fias::Import::Tables do
4
+ let(:files) { Fias::Import::Dbf.new('spec/fixtures').files }
5
+ let(:db) { double('db') }
6
+
7
+ subject { described_class.new(db, files, '_fias') }
8
+
9
+ it '#create' do
10
+ stub_const('Fias::Import::Tables::UUID', actual_statuses: %w(name))
11
+
12
+ expect(db).to receive(:create_table).with(:_fias_actual_statuses).and_yield
13
+ expect(db).to receive(:create_table).with(:_fias_nordoc99)
14
+ expect(db).to receive(:create_table).with(:_fias_structure_statuses)
15
+
16
+ expect(subject).to receive(:primary_key).with(:id)
17
+ expect(subject).to receive(:column).with(:name, :uuid)
18
+ expect(subject).to receive(:column).with(:actstatid, :float)
19
+
20
+ expect { subject.create }.to_not raise_error
21
+ end
22
+
23
+ it '#copy' do
24
+ expect(subject.copy.size).to eq(3)
25
+ end
26
+ end
@@ -0,0 +1,14 @@
1
+ require 'spec_helper'
2
+
3
+ describe Fias::Name::Append do
4
+ context '#append' do
5
+ YAML.load_file('spec/fixtures/status_append.yml').each do |item|
6
+ name, toponym = *item.first
7
+ short, long = *item.slice(1..-1)
8
+
9
+ it "#{toponym} #{name} must generate #{short} and #{long}" do
10
+ expect(described_class.append(name, toponym)).to eq([short, long])
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,20 @@
1
+ require 'spec_helper'
2
+
3
+ describe Fias::Name::Canonical do
4
+ context '#canonical' do
5
+ {
6
+ 'ул' => %w(улица ул ул.),
7
+ 'Улица' => %w(улица ул ул.),
8
+ 'микр' => %w(микрорайон мкр мкр. мкрн микр),
9
+ 'микрорайон' => %w(микрорайон мкр мкр. мкрн микр),
10
+ 'АО' => ['автономный округ', 'АО', 'АО'],
11
+ 'Аобл' => ['автономная область', 'Аобл', 'Аобл'],
12
+ 'республика' => %w(Республика Респ Респ.),
13
+ 'Чувашия' => ['Чувашская Республика - Чувашия', 'Чувашия']
14
+ }.each do |to, normalized|
15
+ it "#{to} must become #{normalized.inspect}" do
16
+ expect(described_class.canonical(to)).to eq(normalized)
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,67 @@
1
+ require 'spec_helper'
2
+
3
+ describe Fias::Name::Extract do
4
+ {
5
+ 'г Краснодар' => %w(Краснодар город г г.),
6
+ 'г. Краснодар' => %w(Краснодар город г г.),
7
+ 'Краснодар город' => %w(Краснодар город г г.),
8
+ 'Раменский район' => ['Раменский', 'район', 'р-н', 'р-н'],
9
+ 'Ямало-Ненецкий АО' => ['Ямало-Ненецкий', 'автономный округ', 'АО', 'АО'],
10
+ 'Еврейский автономный округ' => [
11
+ 'Еврейский', 'автономный округ', 'АО', 'АО'
12
+ ],
13
+ 'Корягинский район' => ['Корягинский', 'район', 'р-н', 'р-н'],
14
+ 'гопотека Южное Бутово' => ['гопотека Южное Бутово'],
15
+ 'ул. Длинная' => %w(Длинная улица ул ул.),
16
+ 'ул. им. Злых Марсиан-3' => ['им. Злых Марсиан-3', 'улица', 'ул', 'ул.'],
17
+ 'Тверь г' => ['Тверь', 'город', 'г', 'г.'],
18
+ 'Тверь г.' => ['Тверь', 'город', 'г', 'г.'],
19
+ 'Гаврилова' => ['Гаврилова'],
20
+ 'пр Космонавтов' => ['Космонавтов', 'проспект', 'пр-кт', 'пр-кт'],
21
+ 'Искровский проспект' => ['Искровский', 'проспект', 'пр-кт', 'пр-кт'],
22
+ 'коттеджный поселок Морозов' => [
23
+ 'Морозов', 'коттеджный поселок', 'кп', 'кп'
24
+ ],
25
+ 'поселок городского типа Свердловский' => [
26
+ 'Свердловский', 'поселок городского типа', 'пгт', 'пгт'
27
+ ],
28
+ 'поселок Павловская Слобода' => [
29
+ 'Павловская Слобода', 'поселок', 'п', 'п.'
30
+ ],
31
+ 'Павловская Слобода поселок' => [
32
+ 'Павловская Слобода', 'поселок', 'п', 'п.'
33
+ ],
34
+ 'Иваново рабочий поселок' => ['Иваново', 'рабочий поселок', 'рп', 'рп'],
35
+ 'ул Славянский бульвар' => ['Славянский бульвар', 'улица', 'ул', 'ул.'],
36
+ 'ул Набережная' => ['Набережная', 'улица', 'ул', 'ул.'],
37
+ 'Сокольнический Вал ул.' => ['Сокольнический Вал', 'улица', 'ул', 'ул.'],
38
+ 'Сокольнический Вал улица' => ['Сокольнический Вал', 'улица', 'ул', 'ул.'],
39
+ 'ул Сокольнический Вал' => ['Сокольнический Вал', 'улица', 'ул', 'ул.'],
40
+ 'улица Сокольнический Вал' => ['Сокольнический Вал', 'улица', 'ул', 'ул.'],
41
+ 'М.Бронная ул.' => ['М.Бронная', 'улица', 'ул', 'ул.'],
42
+ '1-я улица Машиностроения' => ['1-я Машиностроения', 'улица', 'ул', 'ул.'],
43
+ 'Аллея Ильича ул' => ['Аллея Ильича', 'улица', 'ул', 'ул.'],
44
+ 'ул.Сычева' => %w(Сычева улица ул ул.),
45
+ 'Мира улица.' => %w(Мира улица ул ул.),
46
+ 'Малаховка городского типа поселок' => [
47
+ 'Малаховка', 'поселок городского типа', 'пгт', 'пгт'
48
+ ],
49
+ 'Калининград город' => ['Калининград', 'город', 'г', 'г.'],
50
+ 'коттеджный поселок Морозов' => [
51
+ 'Морозов', 'коттеджный поселок', 'кп', 'кп'
52
+ ],
53
+ 'коттеджный Морозов' => ['Морозов', 'коттеджный поселок', 'кп', 'кп'],
54
+ 'Морозов коттеджный' => ['Морозов', 'коттеджный поселок', 'кп', 'кп'],
55
+ 'Морозов коттеджный поселок' => [
56
+ 'Морозов', 'коттеджный поселок', 'кп', 'кп'
57
+ ],
58
+ '' => nil,
59
+ nil => nil
60
+ }.each do |name, expected|
61
+ it "must extract status from #{name} correctly" do
62
+ given = described_class.extract(name)
63
+ given = given.first(4) if given.is_a?(Array)
64
+ expect(given).to eq(expected)
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,45 @@
1
+ require 'spec_helper'
2
+
3
+ describe Fias::Name::HouseNumber do
4
+ {
5
+ '14' => ['14', nil],
6
+ 'мкр. 14' => ['мкр. 14', nil],
7
+ 'лин. 5' => ['лин. 5', nil],
8
+ 'линия 14' => ['линия 14', nil],
9
+ '2 мкр' => ['2 мкр', nil],
10
+ '2-я советская' => ['2-я советская', nil],
11
+ '50 лет октября' => ['50 лет октября', nil],
12
+ 'советская 2-я' => ['советская 2-я', nil],
13
+ 'Советской Армии ул,238а' => ['Советской Армии ул', '238а'],
14
+ 'Советской Армии ул,181,корп.в' => ['Советской Армии ул', '181,корп.в'],
15
+ 'пр.Энергетиков, 72/2' => ['пр.Энергетиков', '72/2'],
16
+ 'Засечное с, 34' => ['Засечное с', '34'],
17
+ 'Ново-Садовая ул,303а' => ['Ново-Садовая ул', '303а'],
18
+ 'ЖК Бутово Парк-2, корп. 11' => ['ЖК Бутово Парк-2', 'корп. 11'],
19
+ 'советская 2-я' => ['советская 2-я', nil],
20
+ 'Вербицкого 25' => %w(Вербицкого 25),
21
+ 'Новоколомяжский 11к1' => %w(Новоколомяжский 11к1),
22
+ 'пр.Энергетиков 72/2' => ['пр.Энергетиков', '72/2'],
23
+ '2-я линия В.О. 12' => ['2-я линия В.О.', '12'],
24
+ 'Шуваловский пр.88к1' => ['Шуваловский пр.', '88к1'],
25
+ 'Мкр. Северное Чертан, вл.1А' => ['Мкр. Северное Чертан', 'вл.1А'],
26
+ 'Московское ш,43 а,корп.стр.' => ['Московское ш', '43 а,корп.стр.'],
27
+ 'Заводская ул 35-А' => ['Заводская ул 35-А', nil],
28
+ '50 лет октября' => ['50 лет октября', nil],
29
+ 'ул 1905 года 28' => ['ул 1905 года', '28'],
30
+ 'Новослободская 29 корп 3' => ['Новослободская', '29 корп 3'],
31
+ 'Александрова д 29' => %w(Александрова 29),
32
+ 'Николаева дом 29' => %w(Николаева 29),
33
+ 'Невский д. 29' => %w(Невский 29),
34
+ 'ул 1905 года' => ['ул 1905 года', nil],
35
+ 'ул 1905 года 28' => ['ул 1905 года', '28'],
36
+ 'Малая Морская ом. 29' => ['Малая Морская', '29'],
37
+ '26 линия В.О. д.15 к.A' => ['26 линия В.О.', '15 к.A'],
38
+ 'Дунайский пр.' => ['Дунайский пр.', nil],
39
+ 'Пионерстроя ул. 14 к 1' => ['Пионерстроя ул.', '14 к 1']
40
+ }.each do |street, extracted|
41
+ it "Must extract house_number from #{street}" do
42
+ expect(described_class.extract(street)).to eq(extracted)
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,21 @@
1
+ require 'spec_helper'
2
+
3
+ describe Fias::Query::Params do
4
+ YAML.load_file('spec/fixtures/query_sanitization.yml').each do |pair|
5
+ from, to = pair
6
+ from.symbolize_keys!
7
+ to.symbolize_keys!
8
+
9
+ it from.values.to_s do
10
+ expect(described_class.new(from).sanitized).to eq(to)
11
+ end
12
+ end
13
+
14
+ it 'must not resanitize already sanitized parts' do
15
+ sanitized = described_class.new(
16
+ city: 'г Краснодар', street: 'Ушинского'
17
+ ).sanitized
18
+
19
+ expect(described_class.new(sanitized).sanitized).to eq(sanitized)
20
+ end
21
+ end
@@ -0,0 +1,15 @@
1
+ require 'spec_helper'
2
+
3
+ describe Fias::Name::Split do
4
+ {
5
+ '"Новый" Оккервиль' => %w(новый оккервиль),
6
+ 'Старый Дом (ограниченное снт)' => %w(старый дом ограниченное снт),
7
+ 'ю.р.г.Эрвье' => %w(ю.р.г. эрвье),
8
+ 'А.Невского' => %w(а. невского),
9
+ 'им.Максима Горького' => %w(им. максима горького),
10
+ '50-летия Октября' => ['50-летия', 'октября'],
11
+ 'героя советского союза Жукова' => ['героя советского союза', 'жукова']
12
+ }.each do |name, tokens|
13
+ it(name) { expect(described_class.split(name)).to eq(tokens) }
14
+ end
15
+ end
@@ -0,0 +1,51 @@
1
+ require 'spec_helper'
2
+
3
+ describe Fias::Name::Synonyms do
4
+ context '#expand' do
5
+ {
6
+ '2-я Советская улица' => [
7
+ %w(
8
+ 2й 2-й 2я 2-я 2е 2-е 2ая 2-ая 2ий 2-ий 2ый 2-ый
9
+ 2ой 2-ой 2ые 2-ые 2ое 2-ое 2го 2-го 2
10
+ ),
11
+ %w(советская),
12
+ %w(улица)],
13
+ '2-ой проспект им. 50 лет Николая Лавочкина героя соцтруда улица' => [
14
+ %w(
15
+ 2й 2-й 2я 2-я 2е 2-е 2ая 2-ая 2ий 2-ий 2ый 2-ый
16
+ 2ой 2-ой 2ые 2-ые 2ое 2-ое 2го 2-го 2
17
+ ),
18
+ ['проспект'],
19
+ ['им', 'имени', 'им.', ''],
20
+ ['50-летия', '50-лет', '50 летия', '50 лет', '50-летие', '50 летие'],
21
+ ['николая', ''],
22
+ ['лавочкина'],
23
+ ['героя', ''],
24
+ ['соцтруда', 'соц.труда', ''],
25
+ ['улица']
26
+ ],
27
+ 'ул. И.А.Покрышкина' => [
28
+ ['ул.'], ['и.а.', ''], ['покрышкина']
29
+ ]
30
+ }.each do |name, synonyms|
31
+ it(name) do
32
+ expect(described_class.expand(name)).to eq(synonyms)
33
+ end
34
+ end
35
+ end
36
+
37
+ it '#forms' do
38
+ expect(described_class.forms('им. И.П.Павлова')).to eq(
39
+ [
40
+ 'и.п. им павлова',
41
+ 'им павлова',
42
+ 'и.п. имени павлова',
43
+ 'имени павлова',
44
+ 'и.п. им. павлова',
45
+ 'им. павлова',
46
+ 'и.п. павлова',
47
+ 'павлова'
48
+ ]
49
+ )
50
+ end
51
+ end
@@ -0,0 +1,15 @@
1
+ require 'spec_helper'
2
+
3
+ describe Fias::Query::Params do
4
+ context '#initialize' do
5
+ YAML.load_file('spec/fixtures/query_sanitization.yml').each do |pair|
6
+ from, to = pair
7
+ from.symbolize_keys!
8
+ to.symbolize_keys!
9
+
10
+ it from.values.to_s do
11
+ expect(described_class.new(from).sanitized).to eq(to)
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,27 @@
1
+ require 'spec_helper'
2
+
3
+ describe Fias::Query do
4
+ context '#perform' do
5
+ context 'by default' do
6
+ subject { UndefinedQuery.new(city: 'Санкт-Петербург') }
7
+
8
+ it 'raises error' do
9
+ expect { subject.perform }.to raise_error(NotImplementedError)
10
+ end
11
+ end
12
+
13
+ context 'with provided #find method' do
14
+ YAML.load_file('spec/fixtures/query.yml').each do |query, indexes|
15
+ query = query.symbolize_keys
16
+ it "looks up #{query.inspect}" do
17
+ result = TestQuery.new(query).perform
18
+ result = result.map(&:last).sort_by { |r| r[:id] }
19
+
20
+ expected = SHORTCUTS.values_at(*indexes).sort_by { |r| r[:id] }
21
+
22
+ expect(result.first(expected.size)).to eq(expected)
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,30 @@
1
+ $LOAD_PATH << '.' unless $LOAD_PATH.include?('.')
2
+
3
+ require 'rubygems'
4
+ require 'bundler/setup'
5
+ require 'simplecov'
6
+ require 'webmock/rspec'
7
+ require 'sequel'
8
+
9
+ SimpleCov.start do
10
+ add_filter 'spec'
11
+ end
12
+
13
+ if ENV['CODECLIMATE_REPO_TOKEN']
14
+ require 'codeclimate-test-reporter'
15
+ CodeClimate::TestReporter.start
16
+ end
17
+
18
+ require 'fias'
19
+ require 'spec/support/query'
20
+ require 'spec/support/db'
21
+
22
+ WebMock.disable_net_connect!(allow: %w(codeclimate.com))
23
+
24
+ RSpec.configure do |config|
25
+ config.order = :random
26
+ config.run_all_when_everything_filtered = true
27
+ config.filter_run :focus
28
+ end
29
+
30
+ $LOAD_PATH << File.join(File.dirname(__FILE__), '..', 'lib')