posty 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (8) hide show
  1. data/.gitignore +3 -0
  2. data/LICENCE +5 -0
  3. data/README.rdoc +52 -0
  4. data/Rakefile +19 -0
  5. data/VERSION +1 -0
  6. data/bin/posty-init +86 -0
  7. data/lib/posty.rb +49 -0
  8. metadata +103 -0
@@ -0,0 +1,3 @@
1
+ lib/posty/codepointopen.sqlite3
2
+ pkg/
3
+ posty.gemspec
data/LICENCE ADDED
@@ -0,0 +1,5 @@
1
+ Copyright © 2010, The Dextrous Web
2
+
3
+ Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies.
4
+
5
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
@@ -0,0 +1,52 @@
1
+ = Posty
2
+
3
+ Simple geolocation gem that stores the database locally.
4
+
5
+ = Getting started
6
+
7
+ gem install posty
8
+
9
+ To download mySociety's mirror of the Code-Point Open in WGS84 format, and create a database from it, and store that inside the gem (you may not need the sudo):
10
+
11
+ sudo posty-init -g
12
+
13
+ This takes about 8 minutes for me, and leaves me with a database of approximately 157M.
14
+
15
+ If you don't want the database being stored in your gem, run something like this instead:
16
+
17
+ posty-init -d database.sqlite3
18
+
19
+ Then, in Ruby:
20
+
21
+ require 'posty'
22
+ posty = Posty.new
23
+ postcode = posty.postcode('SE1 1EN') # space is optional, as is capitalisation
24
+
25
+ p postcode.postcode
26
+ p [postcode.latitude, postcode.longitude]
27
+ p postcode.county
28
+
29
+ If the database isn't in the gem, you'll need to tell it where to find it:
30
+
31
+ posty = Posty.new('database.sqlite3')
32
+
33
+ To make things even easier, there's a class method too (which accepts the database as the second parameter):
34
+
35
+ Posty.postcode('SE1 1EN')
36
+
37
+ = Notes
38
+
39
+ The table contains the following columns, extracted from the WGS84 edition of Code-Point Open:
40
+
41
+ * postcode
42
+ * quality
43
+ * latitude
44
+ * longitude
45
+ * country
46
+ * nhs_region
47
+ * nhs_health_authority
48
+ * county
49
+ * district
50
+ * ward
51
+
52
+ It does not contain eastings and northings.
@@ -0,0 +1,19 @@
1
+ require 'rake'
2
+
3
+ begin
4
+ require 'jeweler'
5
+ Jeweler::Tasks.new do |gem|
6
+ gem.name = 'posty'
7
+ gem.summary = %Q{Simple geolocation gem that stores the database locally}
8
+ gem.description = %Q{}
9
+ gem.email = 'tom@thedextrousweb.com'
10
+ gem.homepage = 'http://github.com/dxw/posty'
11
+ gem.authors = ['Tom Adams']
12
+ gem.add_dependency 'sqlite3-ruby'
13
+ gem.add_dependency 'choice'
14
+ gem.add_dependency 'fastercsv'
15
+ end
16
+ Jeweler::GemcutterTasks.new
17
+ rescue LoadError
18
+ puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
19
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 1.0.0
@@ -0,0 +1,86 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'posty'
4
+ require 'sqlite3'
5
+ require 'tmpdir'
6
+ require 'choice'
7
+ require 'fastercsv'
8
+ require 'fileutils'
9
+
10
+ codepoint_wgs = 'http://parlvid.mysociety.org:81/os/codepo_gb_wgs84.zip'
11
+
12
+ Choice.options do
13
+ option :database do
14
+ short '-d'
15
+ long '--database=SQLITE'
16
+ desc 'The database to create and put data into.'
17
+ end
18
+ option :gem do
19
+ short '-g'
20
+ long '--gem'
21
+ desc 'Install the database into the gem (may require sudo).'
22
+ end
23
+ option :codepoint do
24
+ short '-c'
25
+ long '--codepoint=ZIPFILE'
26
+ desc 'Existing (WGS84-formatted) codepoint zip file.'
27
+ default nil
28
+ end
29
+ end
30
+
31
+ database = Choice.choices[:database]
32
+ if Choice.choices[:gem]
33
+ FileUtils.mkdir_p File.dirname(Posty.gem_database)
34
+ database = Posty.gem_database
35
+ elsif database.nil?
36
+ STDERR.puts 'Requires either -d or -g option.'
37
+ exit 2
38
+ end
39
+ codepoint = Choice.choices[:codepoint]
40
+
41
+ # Die if db already exists
42
+ if File.exist? database
43
+ STDERR.puts 'Database already exists. Not overwriting.'
44
+ exit 1
45
+ end
46
+
47
+ Dir.mktmpdir do |dir|
48
+ # Download wgs84 dump from mySociety
49
+ unless codepoint and File.exist? codepoint
50
+ `wget '#{codepoint_wgs}' -O '#{dir}/codepo_gb_wgs84.zip'`
51
+ codepoint = "#{dir}/codepo_gb_wgs84.zip"
52
+ end
53
+
54
+ # Unzip
55
+ `unzip -d '#{dir}' '#{codepoint}'`
56
+
57
+ # Create database
58
+ STDERR.puts "Writing database to #{database}"
59
+ db = SQLite3::Database.new(database)
60
+ db.execute <<END
61
+ CREATE TABLE codepoint (postcode PRIMARY KEY, quality, latitude, longitude, country, nhs_region, nhs_health_authority, county, district, ward)
62
+ END
63
+
64
+ # Slurp CSV into SQLite
65
+ Dir.glob("#{dir}/data/CSV/*.csv").sort.each do |csv|
66
+ csv.match(/(\w+)\.csv$/)
67
+ STDERR.puts "Reading #{$1.upcase}"
68
+
69
+ db.transaction do |db|
70
+
71
+ FasterCSV.foreach(csv) do |row|
72
+ # Normalise postcode (strip the space)
73
+ norm_postcode = row[0].gsub(/[^\w\d]/,'').upcase
74
+ data = [norm_postcode]+row[1..-1]
75
+
76
+ db.execute <<END, *data
77
+ INSERT INTO codepoint VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
78
+ END
79
+ end
80
+ end
81
+ end
82
+
83
+ db.close
84
+ end
85
+
86
+ STDERR.puts 'Finished.'
@@ -0,0 +1,49 @@
1
+ require 'sqlite3'
2
+
3
+ class PostCode
4
+ attr_reader :data
5
+ def initialize data
6
+ @data = {}
7
+ data.each_pair do |a,b|
8
+ @data[a] = b if a.is_a? String
9
+ end
10
+
11
+ @data['latitude'] = @data['latitude'].to_f
12
+ @data['longitude'] = @data['longitude'].to_f
13
+ end
14
+
15
+ %w[postcode quality latitude longitude country nhs_region nhs_health_authority county district ward].each do |m|
16
+ define_method(m) {@data[m]}
17
+ end
18
+ end
19
+
20
+ class Posty
21
+ def initialize database = nil
22
+ if database.nil?
23
+ database = Posty.gem_database
24
+ unless File.exist? database
25
+ raise IOError, "No database found in gem. Have you run posty-init -g (possibly with sudo)?"
26
+ end
27
+ end
28
+
29
+ unless File.exist? database
30
+ raise IOError, "No database found at #{database}. Have you run posty-init -d '#{database}'?"
31
+ end
32
+
33
+ @db = SQLite3::Database.new(database)
34
+ @db.results_as_hash = true
35
+ end
36
+
37
+ def postcode code
38
+ code = code.gsub(/[^\w\d]/,'').upcase
39
+ PostCode.new(@db.get_first_row('SELECT * FROM codepoint WHERE postcode = ?', code))
40
+ end
41
+
42
+ def self.gem_database
43
+ "#{File.dirname(__FILE__)}/posty/codepointopen.sqlite3"
44
+ end
45
+
46
+ def self.postcode code, database = nil
47
+ Posty.new(database).postcode(code)
48
+ end
49
+ end
metadata ADDED
@@ -0,0 +1,103 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: posty
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 1
7
+ - 0
8
+ - 0
9
+ version: 1.0.0
10
+ platform: ruby
11
+ authors:
12
+ - Tom Adams
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-04-13 00:00:00 +01:00
18
+ default_executable: posty-init
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: sqlite3-ruby
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ segments:
28
+ - 0
29
+ version: "0"
30
+ type: :runtime
31
+ version_requirements: *id001
32
+ - !ruby/object:Gem::Dependency
33
+ name: choice
34
+ prerelease: false
35
+ requirement: &id002 !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ segments:
40
+ - 0
41
+ version: "0"
42
+ type: :runtime
43
+ version_requirements: *id002
44
+ - !ruby/object:Gem::Dependency
45
+ name: fastercsv
46
+ prerelease: false
47
+ requirement: &id003 !ruby/object:Gem::Requirement
48
+ requirements:
49
+ - - ">="
50
+ - !ruby/object:Gem::Version
51
+ segments:
52
+ - 0
53
+ version: "0"
54
+ type: :runtime
55
+ version_requirements: *id003
56
+ description: ""
57
+ email: tom@thedextrousweb.com
58
+ executables:
59
+ - posty-init
60
+ extensions: []
61
+
62
+ extra_rdoc_files:
63
+ - README.rdoc
64
+ files:
65
+ - .gitignore
66
+ - LICENCE
67
+ - README.rdoc
68
+ - Rakefile
69
+ - VERSION
70
+ - bin/posty-init
71
+ - lib/posty.rb
72
+ has_rdoc: true
73
+ homepage: http://github.com/dxw/posty
74
+ licenses: []
75
+
76
+ post_install_message:
77
+ rdoc_options:
78
+ - --charset=UTF-8
79
+ require_paths:
80
+ - lib
81
+ required_ruby_version: !ruby/object:Gem::Requirement
82
+ requirements:
83
+ - - ">="
84
+ - !ruby/object:Gem::Version
85
+ segments:
86
+ - 0
87
+ version: "0"
88
+ required_rubygems_version: !ruby/object:Gem::Requirement
89
+ requirements:
90
+ - - ">="
91
+ - !ruby/object:Gem::Version
92
+ segments:
93
+ - 0
94
+ version: "0"
95
+ requirements: []
96
+
97
+ rubyforge_project:
98
+ rubygems_version: 1.3.6
99
+ signing_key:
100
+ specification_version: 3
101
+ summary: Simple geolocation gem that stores the database locally
102
+ test_files: []
103
+