pippa 0.1.0 → 0.2.1

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/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=