Merge commit 'b4911b8'

This commit is contained in:
gregoirenovel 2018-10-16 11:56:41 +02:00
commit f5fc83b4cd
47 changed files with 179 additions and 197 deletions

View file

@ -2,7 +2,7 @@ class Ban::SearchController < ApplicationController
def get
request = params[:request]
json = ApiAdresse::AddressRetriever.new(request).list.map do |value|
json = ApiAdresse::AddressAdapter.new(request).get_suggestions.map do |value|
{ label: value }
end.to_json
@ -10,7 +10,9 @@ class Ban::SearchController < ApplicationController
end
def get_address_point
point = ApiAdresse::Geocodeur.convert_adresse_to_point(params[:request])
request = params[:request]
point = ApiAdresse::PointAdapter.new(request).geocode
if point.present?
lon = point.x.to_s

View file

@ -0,0 +1,33 @@
class ApiAdresse::Adapter
private
def initialize(address, limit, blank_return)
@address = address
@limit = limit
@blank_return = blank_return
end
def features
@features ||= get_features
end
def get_features
response = ApiAdresse::API.call(@address, @limit)
result = JSON.parse(response)
result['features']
rescue RestClient::Exception, JSON::ParserError, TypeError
@blank_return
end
def handle_result
if features.present?
process_features
else
@blank_return
end
end
def process_features
raise NoMethodError
end
end

View file

@ -0,0 +1,17 @@
class ApiAdresse::AddressAdapter < ApiAdresse::Adapter
def initialize(address)
super(address, 5, [])
end
def get_suggestions
handle_result
end
private
def process_features
features.map do |feature|
feature['properties']['label']
end
end
end

View file

@ -1,34 +0,0 @@
module ApiAdresse
# input : address
# output : Array List label address
class AddressRetriever
def initialize(address)
@address = address
end
def list
@list ||= convert_driver_result_to_full_address
end
private
def driver
@driver ||= ApiAdresse::Driver.new(@address, 5)
end
def convert_driver_result_to_full_address
result = JSON.parse(driver.call)
if result['features'].empty?
Rails.logger.error "unable to find location for address #{@address}"
return []
end
result['features'].map do |feature|
feature['properties']['label']
end
rescue TypeError, JSON::ParserError
[]
end
end
end

View file

@ -0,0 +1,9 @@
class ApiAdresse::API
def self.call(address, limit = 1)
search_url = [API_ADRESSE_URL, "search"].join("/")
RestClient.get(search_url, params: { q: address, limit: limit })
rescue RestClient::ServiceUnavailable
nil
end
end

View file

@ -1,18 +0,0 @@
module ApiAdresse
# input : string (address)
# output : json
class Driver
def initialize(address, limit = 1)
@address = address
@limit = limit
end
def call
search_url = [API_ADRESSE_URL, "search"].join("/")
RestClient.get(search_url, params: { q: @address, limit: @limit })
rescue RestClient::ServiceUnavailable
nil
end
end
end

View file

@ -1,11 +0,0 @@
module ApiAdresse
# this class take a string in input and return a point
class Geocodeur
def self.convert_adresse_to_point(address)
ApiAdresse::PointRetriever.new(address).point
rescue RestClient::Exception, JSON::ParserError => e
Rails.logger.error(e.message)
nil
end
end
end

View file

@ -0,0 +1,15 @@
class ApiAdresse::PointAdapter < ApiAdresse::Adapter
def initialize(address)
super(address, 1, nil)
end
def geocode
handle_result
end
private
def process_features
RGeo::GeoJSON.decode(features[0]['geometry'], json_parser: :json)
end
end

View file

@ -1,28 +0,0 @@
module ApiAdresse
# input : address
# output : point RGeo::Cartesian::PointImpl
class PointRetriever
def initialize(address)
@address = address
end
def point
@point ||= convert_driver_result_to_point
end
private
def driver
@driver ||= ApiAdresse::Driver.new(@address)
end
def convert_driver_result_to_point
result = JSON.parse(driver.call)
if result['features'].empty?
Rails.logger.error "unable to find location for address #{@address}"
return nil
end
RGeo::GeoJSON.decode(result['features'][0]['geometry'], json_parser: :json)
end
end
end

View file

@ -1,7 +1,4 @@
class ApiCarto::API
def initialize
end
def self.search_qp(geojson)
url = [API_CARTO_URL, "quartiers-prioritaires", "search"].join("/")
call(url, geojson)

View file

@ -1,4 +1,4 @@
class ApiCarto::Cadastre::Adapter
class ApiCarto::CadastreAdapter
def initialize(coordinates)
@coordinates = GeojsonService.to_json_polygon_for_cadastre(coordinates)
end

View file

@ -1,4 +1,4 @@
class ApiCarto::QuartiersPrioritaires::Adapter
class ApiCarto::QuartiersPrioritairesAdapter
def initialize(coordinates)
@coordinates = GeojsonService.to_json_polygon_for_qp(coordinates)
end

View file

@ -6,9 +6,6 @@ class ApiEntreprise::API
TIMEOUT = 15
def initialize
end
def self.entreprise(siren, procedure_id)
call(ENTREPRISE_RESOURCE_NAME, siren, procedure_id)
end

23
app/lib/api_geo/api.rb Normal file
View file

@ -0,0 +1,23 @@
class ApiGeo::API
def self.regions
url = [API_GEO_URL, "regions"].join("/")
call(url)
end
def self.departements
url = [API_GEO_URL, "departements"].join("/")
call(url)
end
def self.pays
File.open('app/lib/api_geo/pays.json').read
end
private
def self.call(url)
RestClient.get(url, params: { fields: :nom })
rescue RestClient::ServiceUnavailable
nil
end
end

View file

@ -1,25 +0,0 @@
module ApiGeo
class Driver
def self.regions
url = [API_GEO_URL, "regions"].join("/")
call(url)
end
def self.departements
url = [API_GEO_URL, "departements"].join("/")
call(url)
end
def self.pays
File.open('app/lib/api_geo/pays.json').read
end
private
def self.call(url)
RestClient.get(url, params: { fields: :nom })
rescue RestClient::ServiceUnavailable
nil
end
end
end

View file

@ -1,5 +1,5 @@
class Champs::DepartementChamp < Champs::TextChamp
def self.departements
JSON.parse(ApiGeo::Driver.departements).map { |liste| "#{liste['code']} - #{liste['nom']}" }.push('99 - Étranger')
JSON.parse(ApiGeo::API.departements).map { |liste| "#{liste['code']} - #{liste['nom']}" }.push('99 - Étranger')
end
end

View file

@ -1,5 +1,5 @@
class Champs::PaysChamp < Champs::TextChamp
def self.pays
JSON.parse(ApiGeo::Driver.pays).pluck("nom")
JSON.parse(ApiGeo::API.pays).pluck("nom")
end
end

View file

@ -1,5 +1,5 @@
class Champs::RegionChamp < Champs::TextChamp
def self.regions
JSON.parse(ApiGeo::Driver.regions).sort_by { |e| e['nom'] }.pluck("nom")
JSON.parse(ApiGeo::API.regions).sort_by { |e| e['nom'] }.pluck("nom")
end
end

View file

@ -243,7 +243,7 @@ class Dossier < ApplicationRecord
def geo_position
if etablissement.present?
point = ApiAdresse::Geocodeur.convert_adresse_to_point(etablissement.geo_adresse)
point = ApiAdresse::PointAdapter.new(etablissement.geo_adresse).geocode
end
lon = "2.428462"

View file

@ -25,7 +25,7 @@ class ModuleApiCartoService
def self.generate_qp(coordinates)
coordinates.flat_map do |coordinate|
ApiCarto::QuartiersPrioritaires::Adapter.new(
ApiCarto::QuartiersPrioritairesAdapter.new(
coordinate.map { |element| [element['lng'], element['lat']] }
).results
end
@ -33,7 +33,7 @@ class ModuleApiCartoService
def self.generate_cadastre(coordinates)
coordinates.flat_map do |coordinate|
ApiCarto::Cadastre::Adapter.new(
ApiCarto::CadastreAdapter.new(
coordinate.map { |element| [element['lng'], element['lat']] }
).results
end

View file

@ -113,7 +113,7 @@ shared_examples 'carte_controller_spec' do
let(:module_api_carto) { create(:module_api_carto, :with_quartiers_prioritaires) }
before do
allow_any_instance_of(ApiCarto::QuartiersPrioritaires::Adapter)
allow_any_instance_of(ApiCarto::QuartiersPrioritairesAdapter)
.to receive(:results)
.and_return([{ :code => "QPCODE1234", :nom => "QP de test", :commune => "Paris", :geometry => { :type => "MultiPolygon", :coordinates => [[[[2.38715792094576, 48.8723062632126], [2.38724851642619, 48.8721392348061]]]] } }])
@ -160,7 +160,7 @@ shared_examples 'carte_controller_spec' do
let(:module_api_carto) { create(:module_api_carto, :with_cadastre) }
before do
allow_any_instance_of(ApiCarto::Cadastre::Adapter)
allow_any_instance_of(ApiCarto::CadastreAdapter)
.to receive(:results)
.and_return([{ :surface_intersection => "0.0006", :surface_parcelle => 11252.692583090324, :numero => "0013", :feuille => 1, :section => "CD", :code_dep => "30", :nom_com => "Le Grau-du-Roi", :code_com => "133", :code_arr => "000", :geometry => { :type => "MultiPolygon", :coordinates => [[[[4.134084, 43.5209193], [4.1346615, 43.5212035], [4.1346984, 43.521189], [4.135096, 43.5213848], [4.1350839, 43.5214122], [4.1352697, 43.521505], [4.1356278, 43.5211065], [4.1357402, 43.5207188], [4.1350935, 43.5203936], [4.135002, 43.5204366], [4.1346051, 43.5202412], [4.134584, 43.5202472], [4.1345572, 43.5202551], [4.134356, 43.5203137], [4.1342488, 43.5203448], [4.134084, 43.5209193]]]] } }])
@ -215,7 +215,7 @@ shared_examples 'carte_controller_spec' do
render_views
before do
allow_any_instance_of(ApiCarto::QuartiersPrioritaires::Adapter)
allow_any_instance_of(ApiCarto::QuartiersPrioritairesAdapter)
.to receive(:results)
.and_return([{ :code => "QPCODE1234", :geometry => { :type => "MultiPolygon", :coordinates => [[[[2.38715792094576, 48.8723062632126], [2.38724851642619, 48.8721392348061]]]] } }])

View file

@ -15,7 +15,7 @@ describe Users::DossiersController, type: :controller do
let(:user) { create :user }
let(:exercices_status) { 200 }
let(:exercices_body) { File.read('spec/support/files/exercices.json') }
let(:exercices_body) { File.read('spec/support/files/api_entreprise/exercices.json') }
let(:siren) { '440117620' }
let(:siret) { '44011762001530' }
@ -199,10 +199,10 @@ describe Users::DossiersController, type: :controller do
.to_return(status: 404, body: 'fake body')
stub_request(:get, /https:\/\/entreprise.api.gouv.fr\/v2\/etablissements\/#{siret}?.*token=/)
.to_return(status: status_entreprise_call, body: File.read('spec/support/files/etablissement.json'))
.to_return(status: status_entreprise_call, body: File.read('spec/support/files/api_entreprise/etablissements.json'))
stub_request(:get, /https:\/\/entreprise.api.gouv.fr\/v2\/entreprises\/#{siren}?.*token=/)
.to_return(status: status_entreprise_call, body: File.read('spec/support/files/entreprise.json'))
.to_return(status: status_entreprise_call, body: File.read('spec/support/files/api_entreprise/entreprises.json'))
stub_request(:get, /https:\/\/entreprise.api.gouv.fr\/v2\/exercices\/#{siret}?.*token=/)
.to_return(status: exercices_status, body: exercices_body)
@ -280,7 +280,7 @@ describe Users::DossiersController, type: :controller do
context 'when siren have rna informations' do
let(:rna_status) { 200 }
let(:rna_body) { File.read('spec/support/files/rna.json') }
let(:rna_body) { File.read('spec/support/files/api_entreprise/associations.json') }
it 'creates rna information for entreprise' do
subject

View file

@ -31,12 +31,12 @@ feature 'user path for dossier creation' do
context 'sets siret' do
before do
stub_request(:get, /https:\/\/entreprise.api.gouv.fr\/v2\/etablissements\/#{siret}?.*token=/)
.to_return(body: File.read('spec/support/files/etablissement.json', status: 200))
.to_return(body: File.read('spec/support/files/api_entreprise/etablissements.json', status: 200))
stub_request(:get, /https:\/\/entreprise.api.gouv.fr\/v2\/entreprises\/#{siren}?.*token=/)
.to_return(status: 200, body: File.read('spec/support/files/entreprise.json'))
.to_return(status: 200, body: File.read('spec/support/files/api_entreprise/entreprises.json'))
stub_request(:get, /https:\/\/entreprise.api.gouv.fr\/v2\/exercices\/#{siret}?.*token=/)
.to_return(status: 200, body: File.read('spec/support/files/exercices.json'))
.to_return(status: 200, body: File.read('spec/support/files/api_entreprise/exercices.json'))
stub_request(:get, /https:\/\/entreprise.api.gouv.fr\/v2\/associations\/#{siret}?.*token=/)
.to_return(status: 404, body: '')

View file

@ -67,11 +67,11 @@ feature 'As a User I wanna create a dossier' do
expect(page).to have_current_path(users_dossier_path(procedure_with_siret.dossiers.last.id.to_s))
stub_request(:get, /https:\/\/entreprise.api.gouv.fr\/v2\/etablissements\/#{siret}?.*token=/)
.to_return(status: 200, body: File.read('spec/support/files/etablissement.json'))
.to_return(status: 200, body: File.read('spec/support/files/api_entreprise/etablissements.json'))
stub_request(:get, /https:\/\/entreprise.api.gouv.fr\/v2\/entreprises\/#{siren}?.*token=/)
.to_return(status: 200, body: File.read('spec/support/files/entreprise.json'))
.to_return(status: 200, body: File.read('spec/support/files/api_entreprise/entreprises.json'))
stub_request(:get, /https:\/\/entreprise.api.gouv.fr\/v2\/exercices\/#{siret}?.*token=/)
.to_return(status: 200, body: File.read('spec/support/files/exercices.json'))
.to_return(status: 200, body: File.read('spec/support/files/api_entreprise/exercices.json'))
stub_request(:get, /https:\/\/entreprise.api.gouv.fr\/v2\/associations\/#{siret}?.*token=/)
.to_return(status: 404, body: '')

View file

@ -27,11 +27,11 @@ feature 'user arrive on siret page' do
context 'when enter a siret', js: true do
before do
stub_request(:get, /https:\/\/entreprise.api.gouv.fr\/v2\/etablissements\/#{siret}?.*token=/)
.to_return(status: 200, body: File.read('spec/support/files/etablissement.json'))
.to_return(status: 200, body: File.read('spec/support/files/api_entreprise/etablissements.json'))
stub_request(:get, /https:\/\/entreprise.api.gouv.fr\/v2\/entreprises\/#{siren}?.*token=/)
.to_return(status: 200, body: File.read('spec/support/files/entreprise.json'))
.to_return(status: 200, body: File.read('spec/support/files/api_entreprise/entreprises.json'))
stub_request(:get, /https:\/\/entreprise.api.gouv.fr\/v2\/exercices\/#{siret}?.*token=/)
.to_return(status: 200, body: File.read('spec/support/files/exercices.json'))
.to_return(status: 200, body: File.read('spec/support/files/api_entreprise/exercices.json'))
stub_request(:get, /https:\/\/entreprise.api.gouv.fr\/v2\/associations\/#{siret}?.*token=/)
.to_return(status: 404, body: '')

View file

@ -1,12 +1,12 @@
require 'spec_helper'
describe ApiAdresse::AddressRetriever do
describe '#list' do
describe ApiAdresse::AddressAdapter do
describe '#get_suggestions' do
let(:request) { 'Paris' }
let(:response) { File.open('spec/support/files/ban_address_search.json') }
let(:response) { File.open('spec/support/files/api_adresse/search_results.json') }
let(:status) { 200 }
subject { described_class.new(request).list }
subject { described_class.new(request).get_suggestions }
before do
stub_request(:get, "https://api-adresse.data.gouv.fr/search?&q=#{request}&limit=5")
@ -19,7 +19,7 @@ describe ApiAdresse::AddressRetriever do
end
context 'when address return an empty list' do
let(:response) { File.open('spec/support/files/ban_address_search_no_result.json') }
let(:response) { File.open('spec/support/files/api_adresse/search_no_results.json') }
it { expect(subject.size).to eq 0 }
it { is_expected.to be_an_instance_of Array }

View file

@ -1,26 +0,0 @@
require 'spec_helper'
describe ApiAdresse::Geocodeur do
let(:address) { '50 av des champs elysees' }
describe '.convert_adresse_to_point', vcr: { cassette_name: 'api_adresse_octo' } do
it 'return a point' do
expect(described_class.convert_adresse_to_point(address).class).to eq(RGeo::Cartesian::PointImpl)
end
context 'when RestClient::Exception' do
before do
allow_any_instance_of(ApiAdresse::Driver).to receive(:call).and_raise(RestClient::Exception)
end
it 'return nil' do
expect(described_class.convert_adresse_to_point(address)).to be_nil
end
end
context 'when JSON::ParserError' do
before do
allow_any_instance_of(ApiAdresse::PointRetriever).to receive(:point).and_raise(JSON::ParserError)
end
it 'return nil' do
expect(described_class.convert_adresse_to_point(address)).to be_nil
end
end
end
end

View file

@ -0,0 +1,31 @@
require 'spec_helper'
describe ApiAdresse::PointAdapter do
let(:address) { '50 av des champs elysees' }
describe '.geocode', vcr: { cassette_name: 'api_adresse_octo' } do
it 'return a point' do
expect(described_class.new(address).geocode.class).to eq(RGeo::Cartesian::PointImpl)
end
context 'when RestClient::Exception' do
before do
allow(ApiAdresse::API).to receive(:call).and_raise(RestClient::Exception)
end
it 'return nil' do
expect(described_class.new(address).geocode).to be_nil
end
end
context 'when JSON::ParserError' do
before do
allow(JSON).to receive(:parse).and_raise(JSON::ParserError)
end
it 'return nil' do
expect(described_class.new(address).geocode).to be_nil
end
end
end
end

View file

@ -21,7 +21,7 @@ describe ApiCarto::API do
end
context 'when request return 500' do
let(:geojson) { File.read('spec/support/files/geojson/request_qp.json') }
let(:geojson) { File.read('spec/support/files/api_carto/request_qp.json') }
let(:status) { 500 }
let(:body) { 'toto' }
@ -31,7 +31,7 @@ describe ApiCarto::API do
end
context 'when geojson exist' do
let(:geojson) { File.read('spec/support/files/geojson/request_qp.json') }
let(:geojson) { File.read('spec/support/files/api_carto/request_qp.json') }
let(:status) { 200 }
let(:body) { 'toto' }
@ -40,7 +40,7 @@ describe ApiCarto::API do
end
context 'when geojson is at format JSON' do
let(:geojson) { JSON.parse(File.read('spec/support/files/geojson/request_qp.json')) }
let(:geojson) { JSON.parse(File.read('spec/support/files/api_carto/request_qp.json')) }
it 'returns response body' do
expect(subject).to eq(body)
@ -69,7 +69,7 @@ describe ApiCarto::API do
end
context 'when geojson exist' do
let(:geojson) { File.read('spec/support/files/geojson/request_cadastre.json') }
let(:geojson) { File.read('spec/support/files/api_carto/request_cadastre.json') }
let(:status) { 200 }
let(:body) { 'toto' }
@ -78,7 +78,7 @@ describe ApiCarto::API do
end
context 'when geojson is at format JSON' do
let(:geojson) { JSON.parse(File.read('spec/support/files/geojson/request_cadastre.json')) }
let(:geojson) { JSON.parse(File.read('spec/support/files/api_carto/request_cadastre.json')) }
it 'returns response body' do
expect(subject).to eq(body)

View file

@ -1,6 +1,6 @@
require 'spec_helper'
describe ApiCarto::Cadastre::Adapter do
describe ApiCarto::CadastreAdapter do
subject { described_class.new(coordinates).results }
before do
@ -13,7 +13,7 @@ describe ApiCarto::Cadastre::Adapter do
context 'coordinates are filled' do
let(:coordinates) { '[[2.252728, 43.27151][2.323223, 32.835332]]' }
let(:status) { 200 }
let(:body) { File.read('spec/support/files/geojson/response_cadastre.json') }
let(:body) { File.read('spec/support/files/api_carto/response_cadastre.json') }
it { expect(subject).to be_a_instance_of(Array) }
it { expect(subject.size).to eq(16) }

View file

@ -1,6 +1,6 @@
require 'spec_helper'
describe ApiCarto::QuartiersPrioritaires::Adapter do
describe ApiCarto::QuartiersPrioritairesAdapter do
subject { described_class.new(coordinates).results }
before do
@ -13,7 +13,7 @@ describe ApiCarto::QuartiersPrioritaires::Adapter do
context 'coordinates are filled' do
let(:coordinates) { '[[2.252728, 43.27151][2.323223, 32.835332]]' }
let(:status) { 200 }
let(:body) { File.read('spec/support/files/geojson/response_qp.json') }
let(:body) { File.read('spec/support/files/api_carto/response_qp.json') }
it { expect(subject).to be_a_instance_of(Array) }

View file

@ -20,7 +20,7 @@ describe ApiEntreprise::API do
context 'when siret exist' do
let(:siren) { '418166096' }
let(:status) { 200 }
let(:body) { File.read('spec/support/files/entreprise.json') }
let(:body) { File.read('spec/support/files/api_entreprise/entreprises.json') }
it 'returns response body' do
expect(subject).to eq(JSON.parse(body, symbolize_names: true))
@ -48,7 +48,7 @@ describe ApiEntreprise::API do
context 'when siret exists' do
let(:siret) { '41816609600051' }
let(:status) { 200 }
let(:body) { File.read('spec/support/files/etablissement.json') }
let(:body) { File.read('spec/support/files/api_entreprise/etablissements.json') }
it 'returns body' do
expect(subject).to eq(JSON.parse(body, symbolize_names: true))
@ -79,7 +79,7 @@ describe ApiEntreprise::API do
let(:siret) { '41816609600051' }
let(:status) { 200 }
let(:body) { File.read('spec/support/files/exercices.json') }
let(:body) { File.read('spec/support/files/api_entreprise/exercices.json') }
it 'raises RestClient::Unauthorized' do
expect(subject).to eq(JSON.parse(body, symbolize_names: true))
@ -108,7 +108,7 @@ describe ApiEntreprise::API do
context 'when siren exists' do
let(:siren) { '418166096' }
let(:status) { 200 }
let(:body) { File.read('spec/support/files/rna.json') }
let(:body) { File.read('spec/support/files/api_entreprise/associations.json') }
it { expect(subject).to eq(JSON.parse(body, symbolize_names: true)) }
end

View file

@ -8,7 +8,7 @@ describe ApiEntreprise::EntrepriseAdapter do
before do
stub_request(:get, /https:\/\/entreprise.api.gouv.fr\/v2\/entreprises\/#{siren}?.*token=/)
.to_return(body: File.read('spec/support/files/entreprise.json', status: 200))
.to_return(body: File.read('spec/support/files/api_entreprise/entreprises.json', status: 200))
end
it '#to_params class est une Hash ?' do

View file

@ -9,7 +9,7 @@ describe ApiEntreprise::EtablissementAdapter do
before do
stub_request(:get, /https:\/\/entreprise.api.gouv.fr\/v2\/etablissements\/#{siret}?.*token=/)
.to_return(body: File.read('spec/support/files/etablissement.json', status: 200))
.to_return(body: File.read('spec/support/files/api_entreprise/etablissements.json', status: 200))
end
it '#to_params class est une Hash ?' do

View file

@ -7,7 +7,7 @@ describe ApiEntreprise::ExercicesAdapter do
before do
stub_request(:get, /https:\/\/entreprise.api.gouv.fr\/v2\/exercices\/.*token=/)
.to_return(body: File.read('spec/support/files/exercices.json', status: 200))
.to_return(body: File.read('spec/support/files/api_entreprise/exercices.json', status: 200))
end
it '#to_params class est un Hash ?' do

View file

@ -3,7 +3,7 @@ require 'spec_helper'
describe ApiEntreprise::RNAAdapter do
let(:siret) { '50480511000013' }
let(:procedure_id) { 22 }
let(:body) { File.read('spec/support/files/rna.json') }
let(:body) { File.read('spec/support/files/api_entreprise/associations.json') }
let(:status) { 200 }
let(:adapter) { described_class.new(siret, procedure_id) }

View file

@ -1,6 +1,6 @@
require 'spec_helper'
describe ApiGeo::Driver do
describe ApiGeo::API do
describe '.regions', vcr: { cassette_name: 'api_geo_regions' } do
subject { described_class.regions }