pippa 0.1.0 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -1,5 +1,7 @@
1
1
  # Pippa
2
2
 
3
+ [![Gem Version](https://badge.fury.io/rb/pippa.png)](http://badge.fury.io/rb/pippa)
4
+
3
5
  Pippa - a Ruby gem for producing simple map graphics overlain with
4
6
  geocoded dots of given area. Dot coordinates are in screen pixels,
5
7
  latitude/longitude, or US zipcode.
@@ -9,6 +9,7 @@ require 'pippa/version'
9
9
  require 'RMagick'
10
10
  require 'csv'
11
11
 
12
+ # The Pippa API.
12
13
  module Pippa
13
14
 
14
15
  # Return a list of the valid map names.
@@ -16,6 +17,53 @@ module Pippa
16
17
  Map.info[:map].keys
17
18
  end
18
19
 
20
+ # Compress the zipcode CSV file to something that loads quicker.
21
+ #
22
+ # This gem is packaged with compressed zipcode table that only works
23
+ # if your ruby has compatible a +Marshal+ version. If loading fails,
24
+ # it will attempt to rewrite the table in a compatible format, but if
25
+ # you don't have write permission in the gem store, that will
26
+ # consistently fail. You can use this call with +sudo∂ irb+ to
27
+ # write a compatible table.
28
+ def self.compress_zipcodes
29
+ dump_zips.size
30
+ end
31
+
32
+ # Return a hash mapping zip codes to CSV records of zip code data.
33
+ # NB: The file is big, so this takes a while to return the first time called.
34
+ #
35
+ # +CSV::Row+ struct format (see also http://ruby-doc.org/stdlib-1.9.2/libdoc/csv/rdoc/CSV/Row.html):
36
+ #
37
+ # #<CSV::Row
38
+ # zipcode:"97475"
39
+ # zip_code_type:"PO BOX"
40
+ # city:"SPRINGFIELD"
41
+ # state:"OR"
42
+ # location_type:"PRIMARY"
43
+ # lat:44.05
44
+ # long:-123.02
45
+ # location:"NA-US-OR-SPRINGFIELD"
46
+ # decommisioned:"false"
47
+ # tax_returns_filed:nil
48
+ # estimated_population:nil
49
+ # total_wages:nil>
50
+ #
51
+ # See http://federalgovernmentzipcodes.us for more information on the zipcode data.
52
+ def self.zips
53
+ @@zips ||= zips_from_file
54
+ end
55
+
56
+ # Run the profiler and record results. (For development.)
57
+ def self.profile
58
+ require 'ruby-prof'
59
+ RubyProf.start
60
+ Map.write_zipcode_maps
61
+ result = RubyProf.stop
62
+ File.open('profile.htm', 'w') do |f|
63
+ RubyProf::GraphHtmlPrinter.new(result).print(f)
64
+ end
65
+ end
66
+
19
67
  # An image-based map class that can be overlain with dots
20
68
  # of given area and location given by pixel coordinates, lat/lon,
21
69
  # or zipcode (courtesy of http://federalgovernmentzipcodes.us).
@@ -160,6 +208,7 @@ module Pippa
160
208
  def add_at_lat_lon(lat, lon, area = 0)
161
209
  add_dot(*lat_lon_to_xy(lat, lon), area)
162
210
  end
211
+ alias_method :add_dot_at_lat_lon, :add_at_lat_lon
163
212
 
164
213
  # Add a dot on the map at given 5-digit zip code.
165
214
  #
@@ -176,33 +225,10 @@ module Pippa
176
225
  # map.add_at_zip('10996', 100)
177
226
  # map.write_png('map.png')
178
227
  def add_at_zip(zip, area = 0)
179
- data = Map.zips[zip]
180
- add_at_lat_lon(data[:lat], data[:long], area) if data
181
- end
182
-
183
- # Return a hash mapping zip codes to CSV records of zip code data.
184
- # NB: The file is big, so this takes a while to return the first time called.
185
- #
186
- # +CSV::Row+ struct format (see also http://ruby-doc.org/stdlib-1.9.2/libdoc/csv/rdoc/CSV/Row.html):
187
- #
188
- # #<CSV::Row
189
- # zipcode:"97475"
190
- # zip_code_type:"PO BOX"
191
- # city:"SPRINGFIELD"
192
- # state:"OR"
193
- # location_type:"PRIMARY"
194
- # lat:44.05
195
- # long:-123.02
196
- # location:"NA-US-OR-SPRINGFIELD"
197
- # decommisioned:"false"
198
- # tax_returns_filed:nil
199
- # estimated_population:nil
200
- # total_wages:nil>
201
- #
202
- # See http://federalgovernmentzipcodes.us for more information on the zipcode data.
203
- def self.zips
204
- @@zips ||= zips_from_file
228
+ data = Pippa.zips[zip]
229
+ add_at_lat_lon(data[:lat], data[:lon], area) if data
205
230
  end
231
+ alias_method :add_dot_at_zip, :add_at_zip
206
232
 
207
233
  # Force rendering of all dots added so far onto the map.
208
234
  # Then forget them so they're never rendered again.
@@ -299,7 +325,7 @@ module Pippa
299
325
  def self.zipcode_map
300
326
  generator = Random.new(42) # Force same on every run for testing.
301
327
  m = Map.new('USA')
302
- zips.each_key.each do |zip|
328
+ Pippa.zips.each_key.each do |zip|
303
329
  m.add_at_zip(zip, generator.rand(4) ** 2)
304
330
  end
305
331
  m.fill = 'red'
@@ -316,17 +342,6 @@ module Pippa
316
342
  m.write_jpg('spec/data/zipcodes.jpg')
317
343
  end
318
344
 
319
- # Run the profiler and record results.
320
- def self.profile
321
- require 'ruby-prof'
322
- RubyProf.start
323
- write_zipcode_maps
324
- result = RubyProf.stop
325
- File.open('profile.htm', 'w') do |f|
326
- RubyProf::GraphHtmlPrinter.new(result).print(f)
327
- end
328
- end
329
-
330
345
  private
331
346
 
332
347
  #:nodoc:
@@ -411,36 +426,65 @@ module Pippa
411
426
  data
412
427
  end
413
428
  end
429
+ end
414
430
 
415
- # Read CSV file of zipcode data. Much more than we need.
416
- # TODO: Develop quicker-loading version of the data file.
417
- # Format:
418
- # "Zipcode","ZipCodeType","City","State","LocationType","Lat","Long",
419
- # "Location","Decommisioned","TaxReturnsFiled","EstimatedPopulation","TotalWages"
420
- def self.zips_from_file
421
- CSV::HeaderConverters[:underscore_symbol] = lambda do |s|
422
- t = s.gsub(/::/, '/')
423
- t.gsub!(/([A-Z]+)([A-Z][a-z])/,'\1_\2')
424
- t.gsub!(/([a-z\d])([A-Z])/,'\1_\2')
425
- t.tr!("-", "_")
426
- t.downcase!
427
- t.to_sym
428
- end
429
- CSV::Converters[:custom] = lambda do |s, info|
430
- begin
431
- [:lat, :long].include?(info.header) ? Float(s) : s
432
- rescue
433
- s
434
- end
435
- end
436
- zips = {}
437
- CSV.foreach("#{File.dirname(__FILE__)}/pippa/maps/_zipcodes.csv",
438
- :headers => :first_row,
439
- :header_converters => :underscore_symbol,
440
- :converters => :custom) do |row|
441
- zips[row[:zipcode]] = row if row[:lat] && row[:long]
431
+ private
432
+
433
+ ZIPCODE_CSV_FILE_PATH = "#{File.dirname(__FILE__)}/pippa/maps/_zipcodes.csv" # :nodoc:
434
+
435
+ # Read zipcode data from unaltered CSV file.
436
+ def self.zips_from_csv
437
+ CSV::HeaderConverters[:underscore_symbol] = lambda do |s|
438
+ t = s.gsub(/::/, '/')
439
+ t.gsub!(/([A-Z]+)([A-Z][a-z])/,'\1_\2')
440
+ t.gsub!(/([a-z\d])([A-Z])/,'\1_\2')
441
+ t.tr!("-", "_")
442
+ t.downcase!
443
+ t.to_sym
444
+ end
445
+ CSV::Converters[:custom] = lambda do |s, info|
446
+ begin
447
+ [:lat, :long].include?(info.header) ? Float(s) : s
448
+ rescue
449
+ s
442
450
  end
443
- zips
444
451
  end
452
+ zips = {}
453
+ CSV.foreach(ZIPCODE_CSV_FILE_PATH,
454
+ :headers => :first_row,
455
+ :header_converters => :underscore_symbol,
456
+ :converters => :custom) do |row|
457
+ zips[row[:zipcode]] = row if row[:lat] && row[:long]
458
+ end
459
+ zips
460
+ end
461
+
462
+ ZIPCODE_DUMP_FILE_PATH = "#{File.dirname(__FILE__)}/pippa/maps/_zipcodes.dmp" # :nodoc:
463
+
464
+ # Use native Ruby facility to create a quick-loading, compatible version of CSV zipcode data.
465
+ def self.dump_zips
466
+ hash = {}
467
+ zips_from_csv.each do |zip, row|
468
+ hash[zip] = { :lat => row[:lat], :lon => row[:long] }
469
+ end
470
+ File.open(ZIPCODE_DUMP_FILE_PATH, 'wb') {|f| Marshal.dump(hash, f) }
471
+ hash
472
+ rescue
473
+ hash
474
+ end
475
+
476
+ # Read a previously created dump of the zipcode database.
477
+ def self.zips_from_dump
478
+ File.open(ZIPCODE_DUMP_FILE_PATH, 'rb') {|f| Marshal.load(f) }
479
+ end
480
+
481
+ # Read zipcode data. Tries compressed form first and then CSV.
482
+ # Format:
483
+ # "Zipcode","ZipCodeType","City","State","LocationType","Lat","Long",
484
+ # "Location","Decommisioned","TaxReturnsFiled","EstimatedPopulation","TotalWages"
485
+ def self.zips_from_file
486
+ zips_from_dump
487
+ rescue
488
+ dump_zips
445
489
  end
446
490
  end
@@ -1,4 +1,5 @@
1
+ # Bundler auto-generated mixin for gem version.
1
2
  module Pippa
2
3
  # Current version of Pippa
3
- VERSION = "0.1.0"
4
+ VERSION = "0.2.1"
4
5
  end
@@ -8,14 +8,21 @@ Gem::Specification.new do |spec|
8
8
  spec.version = Pippa::VERSION
9
9
  spec.authors = ["Gene Ressler"]
10
10
  spec.email = ["gene.ressler@gmail.com"]
11
- spec.description = %q{Draw dots on maps by lat/lon or zip code.}
12
- spec.summary = %q{Port of the plot-latlon utility from CAIDA (http://www.caida.org).}
11
+
12
+ spec.summary = %q{Reimplements some parts of the plot-latlon utility from CAIDA (http://www.caida.org).}
13
+ spec.description =
14
+ %q{Draw dots on maps by lat/lon or zip code. Includes a library of 30 map backgrounds,
15
+ and associated geocoding configuration data, and a table of US zip codes with their
16
+ approximate centroids as latitude and longitude. Exposes the ImageMagick image and
17
+ coordinate conversions so that overlaying labels, lines, and other features on dots
18
+ is possible. Renders as a blob suitable for e.g. Rails send_data as an img tag src
19
+ and writes files in any supported ImageMagick graphic format.}
20
+
13
21
  spec.homepage = "https://github.com/gene-ressler/pippa/wiki"
14
- spec.license = "GPLv3"
22
+ spec.licenses = ["GPL-3.0", "RUC"]
15
23
 
16
- spec.files = `git ls-files`.split($/) +
17
- spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
- spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
24
+ spec.files = `git ls-files`.split($/)
25
+ spec.test_files = spec.files.grep(%r{^spec/})
19
26
  spec.require_paths = ["lib"]
20
27
 
21
28
  # Make work on earlier versions, but this is where testing has been performed.
Binary file
@@ -1,5 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
+ # Test functions of the Pippa::Map API lightly. Much more possible here.
3
4
  describe Pippa::Map do
4
5
 
5
6
  let(:map) { Pippa::Map.zipcode_map }
@@ -19,10 +20,6 @@ describe Pippa::Map do
19
20
  i[:projection].size.should == 4
20
21
  end
21
22
 
22
- it 'should have right number of zipcodes' do
23
- Pippa::Map.zips.size.should == 41874
24
- end
25
-
26
23
  # Here I'm assuming timestamp metadata chunk always has same size.
27
24
  # PNG docs are encouraging on this:
28
25
  # http://www.libpng.org/pub/png/book/chapter11.html#png.ch11.div.2
@@ -1,5 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
+ # Test the Pippa API. Much more work possible here.
3
4
  describe Pippa do
4
5
 
5
6
  it 'should report version' do
@@ -10,4 +11,8 @@ describe Pippa do
10
11
  Pippa.map_names.size.should be == 30
11
12
  end
12
13
 
14
+ it 'should have right number of zipcodes' do
15
+ Pippa.zips.size.should == 41874
16
+ end
17
+
13
18
  end
metadata CHANGED
@@ -1,18 +1,20 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pippa
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.1
5
+ prerelease:
5
6
  platform: ruby
6
7
  authors:
7
8
  - Gene Ressler
8
9
  autorequire:
9
10
  bindir: bin
10
11
  cert_chain: []
11
- date: 2013-12-29 00:00:00.000000000 Z
12
+ date: 2013-12-30 00:00:00.000000000 Z
12
13
  dependencies:
13
14
  - !ruby/object:Gem::Dependency
14
15
  name: bundler
15
16
  requirement: !ruby/object:Gem::Requirement
17
+ none: false
16
18
  requirements:
17
19
  - - ~>
18
20
  - !ruby/object:Gem::Version
@@ -20,6 +22,7 @@ dependencies:
20
22
  type: :development
21
23
  prerelease: false
22
24
  version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
23
26
  requirements:
24
27
  - - ~>
25
28
  - !ruby/object:Gem::Version
@@ -27,6 +30,7 @@ dependencies:
27
30
  - !ruby/object:Gem::Dependency
28
31
  name: rake
29
32
  requirement: !ruby/object:Gem::Requirement
33
+ none: false
30
34
  requirements:
31
35
  - - ~>
32
36
  - !ruby/object:Gem::Version
@@ -34,6 +38,7 @@ dependencies:
34
38
  type: :development
35
39
  prerelease: false
36
40
  version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
37
42
  requirements:
38
43
  - - ~>
39
44
  - !ruby/object:Gem::Version
@@ -41,6 +46,7 @@ dependencies:
41
46
  - !ruby/object:Gem::Dependency
42
47
  name: rspec
43
48
  requirement: !ruby/object:Gem::Requirement
49
+ none: false
44
50
  requirements:
45
51
  - - ~>
46
52
  - !ruby/object:Gem::Version
@@ -48,6 +54,7 @@ dependencies:
48
54
  type: :development
49
55
  prerelease: false
50
56
  version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
51
58
  requirements:
52
59
  - - ~>
53
60
  - !ruby/object:Gem::Version
@@ -55,6 +62,7 @@ dependencies:
55
62
  - !ruby/object:Gem::Dependency
56
63
  name: ruby-prof
57
64
  requirement: !ruby/object:Gem::Requirement
65
+ none: false
58
66
  requirements:
59
67
  - - ~>
60
68
  - !ruby/object:Gem::Version
@@ -62,6 +70,7 @@ dependencies:
62
70
  type: :development
63
71
  prerelease: false
64
72
  version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
65
74
  requirements:
66
75
  - - ~>
67
76
  - !ruby/object:Gem::Version
@@ -69,6 +78,7 @@ dependencies:
69
78
  - !ruby/object:Gem::Dependency
70
79
  name: rmagick
71
80
  requirement: !ruby/object:Gem::Requirement
81
+ none: false
72
82
  requirements:
73
83
  - - ~>
74
84
  - !ruby/object:Gem::Version
@@ -76,11 +86,23 @@ dependencies:
76
86
  type: :runtime
77
87
  prerelease: false
78
88
  version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
79
90
  requirements:
80
91
  - - ~>
81
92
  - !ruby/object:Gem::Version
82
93
  version: '2.13'
83
- description: Draw dots on maps by lat/lon or zip code.
94
+ description: ! 'Draw dots on maps by lat/lon or zip code. Includes a library of 30
95
+ map backgrounds,
96
+
97
+ and associated geocoding configuration data, and a table of US zip codes with their
98
+
99
+ approximate centroids as latitude and longitude. Exposes the ImageMagick image and
100
+
101
+ coordinate conversions so that overlaying labels, lines, and other features on dots
102
+
103
+ is possible. Renders as a blob suitable for e.g. Rails send_data as an img tag src
104
+
105
+ and writes files in any supported ImageMagick graphic format.'
84
106
  email:
85
107
  - gene.ressler@gmail.com
86
108
  executables: []
@@ -123,6 +145,7 @@ files:
123
145
  - lib/pippa/maps/World50-new.png
124
146
  - lib/pippa/maps/_info
125
147
  - lib/pippa/maps/_zipcodes.csv
148
+ - lib/pippa/maps/_zipcodes.dmp
126
149
  - lib/pippa/version.rb
127
150
  - pippa.gemspec
128
151
  - spec/data/zipcodes.jpg
@@ -132,28 +155,30 @@ files:
132
155
  - spec/spec_helper.rb
133
156
  homepage: https://github.com/gene-ressler/pippa/wiki
134
157
  licenses:
135
- - GPLv3
136
- metadata: {}
158
+ - GPL-3.0
159
+ - RUC
137
160
  post_install_message:
138
161
  rdoc_options: []
139
162
  require_paths:
140
163
  - lib
141
164
  required_ruby_version: !ruby/object:Gem::Requirement
165
+ none: false
142
166
  requirements:
143
167
  - - ! '>='
144
168
  - !ruby/object:Gem::Version
145
169
  version: '0'
146
170
  required_rubygems_version: !ruby/object:Gem::Requirement
171
+ none: false
147
172
  requirements:
148
173
  - - ! '>='
149
174
  - !ruby/object:Gem::Version
150
175
  version: '0'
151
176
  requirements: []
152
177
  rubyforge_project:
153
- rubygems_version: 2.0.3
178
+ rubygems_version: 1.8.23
154
179
  signing_key:
155
- specification_version: 4
156
- summary: Port of the plot-latlon utility from CAIDA (http://www.caida.org).
180
+ specification_version: 3
181
+ summary: Reimplements some parts of the plot-latlon utility from CAIDA (http://www.caida.org).
157
182
  test_files:
158
183
  - spec/data/zipcodes.jpg
159
184
  - spec/data/zipcodes.png
checksums.yaml DELETED
@@ -1,15 +0,0 @@
1
- ---
2
- !binary "U0hBMQ==":
3
- metadata.gz: !binary |-
4
- ZDg5YjUzMzdjYjMwZTBhZjFhZTlmZDM5OWM5MzgxMzYxNmU0YTdkZA==
5
- data.tar.gz: !binary |-
6
- NDc1MzEzMTc3MmZkMjRjN2IzMmNlZjM1MzYwZmU4OTlmZDA4NzllYw==
7
- !binary "U0hBNTEy":
8
- metadata.gz: !binary |-
9
- MmY3YTFjMDRmNzMyZjUxNjIwMzU5NTIyY2I5ZjhjYWUyZWE5ZTJkZDg3Yjg5
10
- ZDY5YThmZmYyNDAwY2JiZjMyZmJkZGE5MjQ1YzRkOGZiZjMxZTk0ZWI3NTBk
11
- ZmY3ZTRhOGI4NTI5NTBjZWNlNDEzNDg4Y2E4MGU2NGMyNGJmZmQ=
12
- data.tar.gz: !binary |-
13
- Y2ZhM2E3YjhmNTUxYmJlNDE2YWQxNTA5YWE3YjgzNzk3MzliYTUzMmI3ZGMw
14
- ZTE0M2ZiOGQwOWJiZDJlNjBhN2VjZjRhYzBjZDk1Yzk1YWU1ODFkMTllZDJh
15
- NDQxZTgwYWE0MDlmNzBkNDFhZDAyZWM2MDI3Y2U2ZWJjOTQ1NTE=