barton 0.0.1 → 0.0.2
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 +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
|