barton 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +2 -15
- data/Gemfile +2 -4
- data/Gemfile.lock +46 -0
- data/Rakefile +5 -4
- data/barton.gemspec +19 -17
- data/bin/barton +3 -36
- data/config.ru +3 -3
- data/data/geo/nsw-federal.yaml +1 -1
- data/data/geo/nsw-local.yaml +8 -8
- data/data/geo/nsw-state.yaml +4 -4
- data/data/geo/qld-federal.yaml +2 -2
- data/data/geo/qld-state.yaml +2 -2
- data/data/geo/vic-federal.yaml +1 -1
- data/data/geo/vic-local.yaml +5 -5
- data/data/geo/vic-state.yaml +1 -1
- data/data/nsw-federal.yaml +1 -1
- data/data/nsw-local.yaml +8 -8
- data/data/nsw-state.yaml +4 -4
- data/data/qld-federal.yaml +2 -2
- data/data/qld-state.yaml +2 -2
- data/data/vic-federal.yaml +1 -1
- data/data/vic-local.yaml +5 -5
- data/data/vic-state.yaml +1 -1
- data/lib/barton.rb +12 -2
- data/lib/barton/app.rb +5 -5
- data/lib/barton/core.rb +150 -91
- data/lib/barton/version.rb +1 -1
- data/specs/data/data-processed.yaml +8 -8
- data/specs/data/data-raw.yaml +10 -5
- data/specs/data/geo/data-raw.yaml +4 -4
- data/specs/route_spec.rb +1 -1
- data/specs/search_spec.rb +21 -21
- data/specs/setup_spec.rb +16 -17
- metadata +34 -35
- data/AUTHORS +0 -7
- data/LICENSE +0 -22
data/data/nsw-state.yaml
CHANGED
@@ -23,7 +23,7 @@
|
|
23
23
|
- State
|
24
24
|
- Legaslative Assembly
|
25
25
|
- Central Coast
|
26
|
-
id:
|
26
|
+
id: 048630
|
27
27
|
- name: The Entrance
|
28
28
|
tags:
|
29
29
|
- New South Wales
|
@@ -37,14 +37,14 @@
|
|
37
37
|
- State
|
38
38
|
- Legaslative Assembly
|
39
39
|
- Central Coast
|
40
|
-
id:
|
40
|
+
id: 82e217
|
41
41
|
- name: Coogee
|
42
42
|
tags:
|
43
43
|
- New South Wales
|
44
44
|
- State
|
45
45
|
- Legaslative Assembly
|
46
46
|
- Eastern Suburbs
|
47
|
-
id:
|
47
|
+
id: 164e90
|
48
48
|
- name: Heffron
|
49
49
|
tags:
|
50
50
|
- New South Wales
|
@@ -422,7 +422,7 @@
|
|
422
422
|
- State
|
423
423
|
- Legaslative Assembly
|
424
424
|
- Western Sydney Fringe
|
425
|
-
id:
|
425
|
+
id: 2e2812
|
426
426
|
- name: Hawkesbury
|
427
427
|
tags:
|
428
428
|
- New South Wales
|
data/data/qld-federal.yaml
CHANGED
@@ -61,7 +61,7 @@
|
|
61
61
|
- Federal
|
62
62
|
- House of Representatives
|
63
63
|
- Brisbane
|
64
|
-
id:
|
64
|
+
id: 087739
|
65
65
|
- name: Capricornia
|
66
66
|
tags:
|
67
67
|
- Queensland
|
@@ -147,7 +147,7 @@
|
|
147
147
|
- Federal
|
148
148
|
- House of Representatives
|
149
149
|
- Gold Coast
|
150
|
-
id:
|
150
|
+
id: 081148
|
151
151
|
- name: McPherson
|
152
152
|
tags:
|
153
153
|
- Queensland
|
data/data/qld-state.yaml
CHANGED
@@ -178,7 +178,7 @@
|
|
178
178
|
- State
|
179
179
|
- Legislative Assembly
|
180
180
|
- Brisbane South
|
181
|
-
id:
|
181
|
+
id: 009702
|
182
182
|
- name: Indooroopilly
|
183
183
|
tags:
|
184
184
|
- Queensland
|
@@ -528,7 +528,7 @@
|
|
528
528
|
- State
|
529
529
|
- Legislative Assembly
|
530
530
|
- SE Queensland
|
531
|
-
id:
|
531
|
+
id: 769e84
|
532
532
|
- name: Lockyer
|
533
533
|
tags:
|
534
534
|
- Queensland
|
data/data/vic-federal.yaml
CHANGED
data/data/vic-local.yaml
CHANGED
@@ -96,7 +96,7 @@
|
|
96
96
|
- local
|
97
97
|
- LGA
|
98
98
|
- North-East
|
99
|
-
id:
|
99
|
+
id: 9890e8
|
100
100
|
- name: Darebin
|
101
101
|
tags:
|
102
102
|
- Victoria
|
@@ -446,7 +446,7 @@
|
|
446
446
|
- local
|
447
447
|
- LGA
|
448
448
|
- North West
|
449
|
-
id:
|
449
|
+
id: 086695
|
450
450
|
- name: Northern Grampians
|
451
451
|
tags:
|
452
452
|
- Victoria
|
@@ -1020,7 +1020,7 @@
|
|
1020
1020
|
- local
|
1021
1021
|
- ward
|
1022
1022
|
- Mornington Peninsula
|
1023
|
-
id:
|
1023
|
+
id: 756e19
|
1024
1024
|
- name: Nepean
|
1025
1025
|
tags:
|
1026
1026
|
- Victoria
|
@@ -1363,7 +1363,7 @@
|
|
1363
1363
|
- local
|
1364
1364
|
- ward
|
1365
1365
|
- Monash
|
1366
|
-
id:
|
1366
|
+
id: 63e668
|
1367
1367
|
- name: Mulgrave
|
1368
1368
|
tags:
|
1369
1369
|
- Victoria
|
@@ -1965,7 +1965,7 @@
|
|
1965
1965
|
- local
|
1966
1966
|
- ward
|
1967
1967
|
- Hindmarsh
|
1968
|
-
id:
|
1968
|
+
id: 2e9375
|
1969
1969
|
- name: North
|
1970
1970
|
tags:
|
1971
1971
|
- Victoria
|
data/data/vic-state.yaml
CHANGED
data/lib/barton.rb
CHANGED
data/lib/barton/app.rb
CHANGED
@@ -1,10 +1,11 @@
|
|
1
1
|
require 'sinatra'
|
2
2
|
require 'json'
|
3
|
+
require 'barton'
|
3
4
|
require 'barton/core'
|
4
5
|
|
5
6
|
module Barton
|
6
7
|
class App < Sinatra::Base
|
7
|
-
|
8
|
+
|
8
9
|
# routes
|
9
10
|
allowed_formats = ['', 'json']
|
10
11
|
|
@@ -22,12 +23,12 @@ module Barton
|
|
22
23
|
geo, tags, address = params[:geo], params[:tags], params[:address]
|
23
24
|
tags = tags.split(',') unless tags.nil?
|
24
25
|
raise Sinatra::NotFound unless allowed_formats.include?( format )
|
25
|
-
geo = Barton::
|
26
|
+
geo = Barton::Data.address( address ) if address
|
26
27
|
if not id.empty?
|
27
|
-
results = Barton
|
28
|
+
results = Barton.electorates( {:id => id} )
|
28
29
|
prepare_response( results )
|
29
30
|
elsif geo or tags
|
30
|
-
results = Barton
|
31
|
+
results = Barton.electorates( {:tags => tags, :geo => geo} )
|
31
32
|
prepare_response( results )
|
32
33
|
else
|
33
34
|
prepare_response
|
@@ -63,6 +64,5 @@ module Barton
|
|
63
64
|
content_type 'application/json;charset=utf-8'
|
64
65
|
JSON.pretty_generate( response )
|
65
66
|
end
|
66
|
-
|
67
67
|
end
|
68
68
|
end
|
data/lib/barton/core.rb
CHANGED
@@ -1,15 +1,111 @@
|
|
1
1
|
require 'yaml'
|
2
2
|
require 'digest/sha1'
|
3
3
|
require 'tire'
|
4
|
-
require 'rest_client'
|
5
|
-
require 'uri'
|
6
4
|
require 'json'
|
5
|
+
require 'barton/app'
|
7
6
|
|
8
7
|
module Barton
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
8
|
+
|
9
|
+
# Returns an array of electorates matching the search criteria
|
10
|
+
# Accepts a hash of criteria
|
11
|
+
# :id
|
12
|
+
# :tags
|
13
|
+
# :geo
|
14
|
+
# :address
|
15
|
+
# Returns an array of hashes
|
16
|
+
def Barton.electorates( query = {} )
|
17
|
+
Find.electorates( query )
|
18
|
+
end
|
19
|
+
|
20
|
+
# Returns an array of member matching the search criteria
|
21
|
+
# Accepts a hash of criteria
|
22
|
+
# Returns an array of hashes
|
23
|
+
def members
|
24
|
+
# TBA
|
25
|
+
end
|
26
|
+
|
27
|
+
# Loads electoral data from the yaml files into elasticsearch
|
28
|
+
def self.setup
|
29
|
+
Data.config
|
30
|
+
Data.purge_es
|
31
|
+
Dir['data/*.yaml'].each do |f|
|
32
|
+
Setup.load_file( f )
|
33
|
+
end
|
34
|
+
Barton.data_loaded = true
|
35
|
+
end
|
36
|
+
|
37
|
+
# Configuration options for the Gem
|
38
|
+
def self.config
|
39
|
+
#puts ENV['RAKE_ENV']
|
40
|
+
#Data.config
|
41
|
+
end
|
42
|
+
|
43
|
+
module Find
|
44
|
+
def self.electorates( query={} )
|
45
|
+
results = Array.new
|
46
|
+
terms = ["id:#{query[:id]}"] if query.has_key?( :id )
|
47
|
+
terms = query[:tags] if query.has_key?( :tags )
|
48
|
+
geo = query[:geo] if query.has_key?( :geo )
|
49
|
+
geo = self.address( query[:address] ) if query.has_key?( :address ) and not query.has_key?( :geo )
|
50
|
+
s = Data.search( terms, geo )
|
51
|
+
s.results.each do |e|
|
52
|
+
e = e.to_hash
|
53
|
+
e.keys.each { |k| e.delete( k ) if k.match( /_|geobox|boundaries|highlight|sort/ ) }
|
54
|
+
e[:url] = "#{@api_url}/electorates/#{e[:id]}"
|
55
|
+
results.push( e )
|
56
|
+
end
|
57
|
+
results
|
58
|
+
end
|
59
|
+
|
60
|
+
# Geocode lookup to google
|
61
|
+
def self.address( address )
|
62
|
+
# http://maps.googleapis.com/maps/api/geocode/json?address=address&sensor=false®ion=au
|
63
|
+
begin
|
64
|
+
google = RestClient.get "http://maps.googleapis.com/maps/api/geocode/json?address=#{URI.escape( address )}&sensor=false®ion=au"
|
65
|
+
json = JSON.parse( google )
|
66
|
+
if json['status'] == 'OK'
|
67
|
+
#puts google
|
68
|
+
return "#{json['results'][0]['geometry']['location']['lng']},#{json['results'][0]['geometry']['location']['lat']}"
|
69
|
+
else
|
70
|
+
return nil
|
71
|
+
end
|
72
|
+
rescue => e
|
73
|
+
puts e
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
# Ray casting algorithm to find if point is in polygon
|
78
|
+
def self.point_in_poly?( geo, boundaries )
|
79
|
+
# get pairs of points of boundaries
|
80
|
+
long, lat = geo.split( ',' )
|
81
|
+
long, lat = long.to_f, lat.to_f
|
82
|
+
boundaries.each do |b|
|
83
|
+
coords = b.split( ' ' )
|
84
|
+
length = coords.length
|
85
|
+
first, second = coords.shift, coords.shift
|
86
|
+
cuts = 0
|
87
|
+
while length > 1
|
88
|
+
cuts += self.crosses?( first, second, lat, long )
|
89
|
+
first = second
|
90
|
+
second = coords.shift
|
91
|
+
length -= 1
|
92
|
+
end
|
93
|
+
return cuts.odd? ? true : false
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
# this fails edge cases where lat,long < ax,by & > bx,ay
|
98
|
+
# ie when it crosses just in front or behind diagonally
|
99
|
+
def self.crosses?( a, b, lat, long )
|
100
|
+
ay, ax = a.split( ',' )
|
101
|
+
by, bx = b.split( ',' )
|
102
|
+
ax, ay, bx, by = ax.to_f, ay.to_f, bx.to_f, by.to_f
|
103
|
+
return 0 if ay < long and by < long
|
104
|
+
return ( ( ax < lat and lat < bx ) or ( bx < lat and lat < ax ) ) ? 1 : 0
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
module Setup
|
13
109
|
# Parses a electorate yaml file, merges it with a geo yaml file,
|
14
110
|
# loads them to the datastore and resaves the yaml files
|
15
111
|
def self.parse_yaml( filename )
|
@@ -44,36 +140,62 @@ module Barton
|
|
44
140
|
end
|
45
141
|
end
|
46
142
|
|
47
|
-
|
48
|
-
|
143
|
+
# Creates a minimum bounded box encapsulating the boundary polygons
|
144
|
+
def self.create_geobox( boundaries )
|
49
145
|
return nil unless boundaries.instance_of? Array
|
50
146
|
box = Hash.new
|
51
147
|
boundaries.each do |b|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
148
|
+
b.split( ' ' ).each do |c|
|
149
|
+
coords = c.split( ',' )
|
150
|
+
box['north'] = coords[1].to_f if box['north'].nil? or coords[1].to_f > box['north']
|
151
|
+
box['south'] = coords[1].to_f if box['south'].nil? or coords[1].to_f < box['south']
|
152
|
+
box['east'] = coords[0].to_f if box['east'].nil? or coords[0].to_f > box['east']
|
153
|
+
box['west'] = coords[0].to_f if box['west'].nil? or coords[0].to_f < box['west']
|
154
|
+
end
|
155
|
+
end
|
156
|
+
box
|
157
|
+
end
|
158
|
+
|
159
|
+
# Load data from yaml source file
|
160
|
+
def self.load_file( filename )
|
161
|
+
puts "Loading data from #{filename}....."
|
162
|
+
electorates = self.parse_yaml( filename )
|
163
|
+
puts "Failed to load #{filename}" if electorates.nil?
|
164
|
+
connected = Data.update_es( electorates )
|
165
|
+
abort "Connection to Elasticsearch failed" if connected.nil?
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
|
170
|
+
module Data
|
171
|
+
|
172
|
+
@index_name = ENV['RAKE_ENV']
|
173
|
+
|
174
|
+
# Set elasticsearch config
|
175
|
+
def self.config
|
176
|
+
@index_name = ENV['RAKE_ENV']
|
177
|
+
if ENV['BONSAI_INDEX_URL']
|
178
|
+
Tire.configure do
|
179
|
+
url "http://index.bonsai.io"
|
180
|
+
end
|
181
|
+
@index_name = ENV['BONSAI_INDEX_URL'][/[^\/]+$/]
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
63
185
|
# Purge electorate data from elasticsearch
|
64
186
|
def self.purge_es
|
65
187
|
self.query_es( 'purge' )
|
66
188
|
end
|
67
189
|
|
68
190
|
# Load electorate data to elasticsearch
|
69
|
-
def self.update_es(
|
70
|
-
self.query_es( 'update',
|
191
|
+
def self.update_es( data )
|
192
|
+
self.query_es( 'update', data )
|
71
193
|
end
|
72
194
|
|
73
195
|
# Query elasticsearch
|
74
196
|
def self.query_es( action, data=nil )
|
75
197
|
begin
|
76
|
-
Tire.index "#{
|
198
|
+
Tire.index "#{@index_name}-electorates" do
|
77
199
|
delete if action == 'purge'
|
78
200
|
create if action == 'purge'
|
79
201
|
import data if action == 'update' and not data.nil?
|
@@ -84,18 +206,8 @@ module Barton
|
|
84
206
|
end
|
85
207
|
end
|
86
208
|
|
87
|
-
|
88
|
-
|
89
|
-
# :tags
|
90
|
-
# :geo
|
91
|
-
# :address
|
92
|
-
def self.electorates( query={} )
|
93
|
-
results = Array.new
|
94
|
-
terms = ["id:#{query[:id]}"] if query.has_key?( :id )
|
95
|
-
terms = query[:tags] if query.has_key?( :tags )
|
96
|
-
geo = query[:geo] if query.has_key?( :geo )
|
97
|
-
geo = self.address( query[:address] ) if query.has_key?( :address ) and not query.has_key?( :geo )
|
98
|
-
s = Tire.search "#{ENV['RAKE_ENV']}electorates" do
|
209
|
+
def self.search( terms, geo )
|
210
|
+
s = Tire.search "#{@index_name}-electorates" do
|
99
211
|
query do
|
100
212
|
boolean do
|
101
213
|
if geo
|
@@ -115,60 +227,7 @@ module Barton
|
|
115
227
|
end
|
116
228
|
size 100
|
117
229
|
end
|
118
|
-
s
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
results.push( e )
|
123
|
-
end
|
124
|
-
results
|
125
|
-
end
|
126
|
-
|
127
|
-
# Geocode lookup to google
|
128
|
-
def self.address( address )
|
129
|
-
# http://maps.googleapis.com/maps/api/geocode/json?address=address&sensor=false®ion=au
|
130
|
-
begin
|
131
|
-
google = RestClient.get "http://maps.googleapis.com/maps/api/geocode/json?address=#{URI.escape( address )}&sensor=false®ion=au"
|
132
|
-
json = JSON.parse( google )
|
133
|
-
if json['status'] == 'OK'
|
134
|
-
puts google
|
135
|
-
return "#{json['results'][0]['geometry']['location']['lng']},#{json['results'][0]['geometry']['location']['lat']}"
|
136
|
-
else
|
137
|
-
return nil
|
138
|
-
end
|
139
|
-
rescue => e
|
140
|
-
puts e
|
141
|
-
end
|
142
|
-
end
|
143
|
-
|
144
|
-
# Ray casting algorithm to find if point is in polygon
|
145
|
-
def self.point_in_poly?( geo, boundaries )
|
146
|
-
# get pairs of points of boundaries
|
147
|
-
long, lat = geo.split( ',' )
|
148
|
-
long, lat = long.to_f, lat.to_f
|
149
|
-
boundaries.each do |b|
|
150
|
-
coords = b.split( ' ' )
|
151
|
-
length = coords.length
|
152
|
-
first, second = coords.shift, coords.shift
|
153
|
-
cuts = 0
|
154
|
-
while length > 1
|
155
|
-
cuts += self.crosses?( first, second, lat, long )
|
156
|
-
first = second
|
157
|
-
second = coords.shift
|
158
|
-
length -= 1
|
159
|
-
end
|
160
|
-
return cuts.odd? ? true : false
|
161
|
-
end
|
162
|
-
end
|
163
|
-
|
164
|
-
# this fails edge cases where lat,long < ax,by & > bx,ay
|
165
|
-
# ie when it crosses just in front or behind diagonally
|
166
|
-
def self.crosses?( a, b, lat, long )
|
167
|
-
ay, ax = a.split( ',' )
|
168
|
-
by, bx = b.split( ',' )
|
169
|
-
ax, ay, bx, by = ax.to_f, ay.to_f, bx.to_f, by.to_f
|
170
|
-
return 0 if ay < long and by < long
|
171
|
-
return ( ( ax < lat and lat < bx ) or ( bx < lat and lat < ax ) ) ? 1 : 0
|
172
|
-
end
|
173
|
-
end
|
174
|
-
end
|
230
|
+
s
|
231
|
+
end
|
232
|
+
end
|
233
|
+
end
|