govkit-ca 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 CHANGED
@@ -1,4 +1,6 @@
1
1
  *.gem
2
2
  .bundle
3
+ .yardoc
3
4
  Gemfile.lock
5
+ doc/*
4
6
  pkg/*
data/README.md CHANGED
@@ -7,12 +7,15 @@ GovKit-CA is a Ruby gem that provides easy access to Canadian civic data around
7
7
  * [ndp.ca](http://www.ndp.ca/)
8
8
  * [digital-copyright.ca](http://www.digital-copyright.ca/)
9
9
  * [liberal.ca](http://www.liberal.ca/)
10
+ * [greenparty.ca](http://www.greenparty.ca/)
11
+ * [parl.gc.ca](http://www.parl.gc.ca/)
12
+ * [conservative.ca](http://www.conservative.ca/)
10
13
 
11
14
  GovKit-CA follows from [Participatory Politics Foundation](http://www.participatorypolitics.org/)'s [GovKit](https://github.com/opengovernment/govkit) gem. GovKit-CA is not affiliated with the Participatory Politics Foundation or GovKit.
12
15
 
13
16
  # Installation
14
17
 
15
- gem install govkit
18
+ gem install govkit-ca
16
19
 
17
20
  # Examples
18
21
 
@@ -21,24 +24,25 @@ GovKit-CA follows from [Participatory Politics Foundation](http://www.participat
21
24
  >> GovKit::CA::PostalCode.find_electoral_districts_by_postal_code('A1A1A1')
22
25
  => [10007]
23
26
  >> GovKit::CA::PostalCode.find_electoral_districts_by_postal_code('K0A1K0')
24
- => [35087, 35025, 35052, 35012, 35040, 35063, 35064]
27
+ => [35012, 35025, 35040, 35052, 35063, 35064, 35087]
28
+ >> GovKit::CA::PostalCode.find_electoral_districts_by_postal_code('H0H0H0')
29
+ => GovKit::CA::ResourceNotFound
25
30
 
26
31
  >> GovKit::CA::PostalCode.find_province_by_postal_code('A1A1A1')
27
32
  => "Newfoundland and Labrador"
28
33
  >> GovKit::CA::PostalCode.find_province_by_postal_code('K0A1K0')
29
34
  => "Ontario"
35
+ >> GovKit::CA::PostalCode.find_province_by_postal_code('H0H0H0')
36
+ => "Quebec"
30
37
 
31
38
  Postal codes may contain lowercase letters. Spaces and non-alphanumeric characters are removed before processing.
32
39
 
33
- GovKit-CA will raise GovKit::CA::ResourceNotFound if the electoral districts within a postal code cannot be determined.
40
+ GovKit-CA will raise GovKit::CA::ResourceNotFound if the electoral districts within a postal code cannot be determined, and GovKit::CA::InvalidRequest if a postal code is not properly formatted.
34
41
 
35
42
  # Bugs? Questions?
36
43
 
37
- Govkit-CA's main repository is on GitHub: [http://github.com/jpmckinney/govkit-ca](http://github.com/jpmckinney/govkit-ca), where your contributions, forks, bug reports, feature requests, and feedback are greatly welcomed.
38
-
39
- # TODOs
44
+ GovKit-CA interoperates with [Participatory Politics Foundation](http://www.participatorypolitics.org/)'s [GovKit](https://github.com/opengovernment/govkit). Please join the [GovKit Google Group](http://groups.google.com/group/govkit), especially if you'd like to talk about a new feature and get announcements.
40
45
 
41
- * Write tests
42
- * Add a `ElectoralDistrict` class to convert IDs to English and french names.
46
+ Govkit-CA's main repository is on GitHub: [http://github.com/jpmckinney/govkit-ca](http://github.com/jpmckinney/govkit-ca), where your contributions, forks, bug reports, feature requests, and feedback are greatly welcomed.
43
47
 
44
48
  Copyright (c) 2011 James McKinney, released under the MIT license
data/Rakefile CHANGED
@@ -6,4 +6,13 @@ RSpec::Core::RakeTask.new(:spec)
6
6
 
7
7
  task :default => :spec
8
8
 
9
+ begin
10
+ require 'yard'
11
+ YARD::Rake::YardocTask.new
12
+ rescue LoadError
13
+ task :yard do
14
+ abort 'YARD is not available. In order to run yard, you must: gem install yard'
15
+ end
16
+ end
17
+
9
18
  require File.expand_path('../tasks/rid_to_edid', __FILE__)
@@ -22,7 +22,7 @@ module GovKit
22
22
  # Returns the electoral districts within a postal code.
23
23
  # @return [Array<Fixnum>] the electoral districts within the postal code
24
24
  def electoral_districts
25
- valid? && electoral_districts!.map(&:to_i)
25
+ valid? && electoral_districts!.map(&:to_i).sort
26
26
  end
27
27
 
28
28
  private
@@ -2,6 +2,7 @@ module GovKit
2
2
  module CA
3
3
  module PostalCode
4
4
  module Strategy
5
+ # Occasionally suffers from timeout errors.
5
6
  class DigitalCopyrightCa < Base
6
7
  base_uri 'www.digital-copyright.ca'
7
8
 
@@ -0,0 +1,29 @@
1
+ module GovKit
2
+ module CA
3
+ module PostalCode
4
+ module Strategy
5
+ # greenparty.ca does not return electoral districts for postal codes
6
+ # that contain multiple electoral districts.
7
+ class GreenPartyCa < Base
8
+ base_uri 'greenparty.ca'
9
+
10
+ private
11
+
12
+ def electoral_districts!
13
+ [ response.headers['location'][/\d+\Z/] ]
14
+ end
15
+
16
+ def valid?
17
+ response.headers['location'] != 'http://greenparty.ca/find_your_riding'
18
+ end
19
+
20
+ def response
21
+ @response ||= self.class.head "/search/civicrm_lookup/#{@postal_code}"
22
+ end
23
+ end
24
+
25
+ StrategySet.register GreenPartyCa
26
+ end
27
+ end
28
+ end
29
+ end
@@ -2,6 +2,7 @@ module GovKit
2
2
  module CA
3
3
  module PostalCode
4
4
  module Strategy
5
+ # liberal.ca is unreliable during elections.
5
6
  class LiberalCa < Base
6
7
  base_uri 'www.liberal.ca'
7
8
 
@@ -18,7 +18,7 @@ module GovKit
18
18
  end
19
19
 
20
20
  def response
21
- @response ||= self.class.head "http://www.ndp.ca/riding/#{@postal_code}"
21
+ @response ||= self.class.head "/riding/#{@postal_code}"
22
22
  end
23
23
  end
24
24
 
@@ -24,8 +24,14 @@ module GovKit
24
24
  # @raise [ResourceNotFound] if no strategy succeeds
25
25
  def self.run(postal_code)
26
26
  strategies.each do |strategy|
27
- electoral_districts = strategy.new(postal_code).electoral_districts
28
- return electoral_districts if electoral_districts
27
+ begin
28
+ electoral_districts = strategy.new(postal_code).electoral_districts
29
+ return electoral_districts if electoral_districts
30
+ rescue Timeout::Error, Errno::EINVAL, Errno::ECONNRESET,
31
+ Errno::ETIMEDOUT, EOFError, Net::HTTPBadResponse,
32
+ Net::HTTPHeaderSyntaxError, Net::ProtocolError
33
+ # Do nothing. Continue.
34
+ end
29
35
  end
30
36
 
31
37
  raise ResourceNotFound
@@ -39,7 +45,4 @@ require 'gov_kit-ca/postal_code/strategy/base'
39
45
  require 'gov_kit-ca/postal_code/strategy/elections-ca'
40
46
  require 'gov_kit-ca/postal_code/strategy/cbc-ca'
41
47
  require 'gov_kit-ca/postal_code/strategy/ndp-ca'
42
- require 'gov_kit-ca/postal_code/strategy/digital_copyright-ca'
43
- require 'gov_kit-ca/postal_code/strategy/liberal-ca'
44
- #require 'gov_kit-ca/postal_code/strategy/parl-gc-ca'
45
- #require 'gov_kit-ca/postal_code/strategy/conservative-ca'
48
+ require 'gov_kit-ca/postal_code/strategy/greenparty-ca'
@@ -5,6 +5,13 @@ module GovKit
5
5
  # A collection of postal code helpers.
6
6
  # @see http://en.wikipedia.org/wiki/Postal_codes_in_Canada Postal codes in Canada
7
7
  module PostalCode
8
+ # @param [String] postal_code a postal code
9
+ # @return [Boolean] whether the postal code is properly formatted
10
+ # @see http://en.wikipedia.org/wiki/Postal_codes_in_Canada#Number_of_possible_postal_codes Possible postal codes
11
+ def self.valid?(postal_code)
12
+ !!postal_code.match(/\A[ABCEGHJKLMNPRSTVXY][0-9][ABCEGHJKLMNPRSTVWXYZ][0-9][ABCEGHJKLMNPRSTVWXYZ][0-9]\Z/)
13
+ end
14
+
8
15
  # Returns the electoral districts within a postal code.
9
16
  #
10
17
  # Statistics Canada charges for its Postal Codes by Federal Ridings File
@@ -12,10 +19,15 @@ module GovKit
12
19
  #
13
20
  # @param [String] postal_code a postal code
14
21
  # @return [Array<Fixnum>] the electoral districts within the postal code
22
+ # @raise [InvalidRequest] if the postal code is not properly formatted
15
23
  # @raise [ResourceNotFound] if the electoral districts cannot be determined
16
24
  # @see http://www.statcan.gc.ca/bsolc/olc-cel/olc-cel?lang=eng&catno=92F0193X Statistics Canada's product page for the Postal Codes by Federal Ridings File (PCFRF)
17
25
  def self.find_electoral_districts_by_postal_code(postal_code)
18
- StrategySet.run format_postal_code(postal_code)
26
+ if valid?(format_postal_code(postal_code))
27
+ StrategySet.run format_postal_code(postal_code)
28
+ else
29
+ raise InvalidRequest, "The postal code is not properly formatted"
30
+ end
19
31
  end
20
32
 
21
33
  # Returns the province that a postal code belongs to.
@@ -1,5 +1,5 @@
1
1
  module GovKit
2
2
  module CA
3
- VERSION = "0.0.1"
3
+ VERSION = "0.0.2"
4
4
  end
5
5
  end
data/lib/gov_kit-ca.rb CHANGED
@@ -14,5 +14,6 @@ module GovKit
14
14
 
15
15
  class GovKitError < StandardError; end
16
16
  class ResourceNotFound < GovKitError; end
17
+ class InvalidRequest < GovKitError; end
17
18
  end
18
19
  end
@@ -0,0 +1,24 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ class GovKit::CA::PostalCode::Strategy::CbcCa
4
+ describe GovKit::CA::PostalCode::Strategy::CbcCa do
5
+ describe '#electoral_districts' do
6
+ it 'should return the electoral districts within a postal code' do
7
+ { 'G0C2Y0' => [24019],
8
+ 'T5S2B9' => [48015, 48017], # differs from elections.ca, ndp.ca
9
+ 'K0A1K0' => [35012, 35025, 35040, 35052, 35063, 35064, 35087],
10
+ }.each do |postal_code,electoral_districts|
11
+ GovKit::CA::PostalCode::Strategy::CbcCa.new(postal_code).electoral_districts.should == electoral_districts
12
+ end
13
+ end
14
+
15
+ it 'should return false if a postal code contains no electoral districts' do
16
+ GovKit::CA::PostalCode::Strategy::CbcCa.new('H0H0H0').electoral_districts.should be_false
17
+ end
18
+
19
+ it 'should return false if a postal code does not exist' do
20
+ GovKit::CA::PostalCode::Strategy::CbcCa.new('X1B1B1').electoral_districts.should be_false
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,27 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ class GovKit::CA::PostalCode::Strategy::ElectionsCa
4
+ describe GovKit::CA::PostalCode::Strategy::ElectionsCa do
5
+ describe '#electoral_districts' do
6
+ it 'should return the electoral districts within a postal code' do
7
+ { 'G0C2Y0' => [24019],
8
+ 'T5S2B9' => [48015], # differs from cbc.ca
9
+ }.each do |postal_code,electoral_districts|
10
+ GovKit::CA::PostalCode::Strategy::ElectionsCa.new(postal_code).electoral_districts.should == electoral_districts
11
+ end
12
+ end
13
+
14
+ it 'should (unfortunately) return false if a postal code contains multiple electoral districts' do
15
+ GovKit::CA::PostalCode::Strategy::ElectionsCa.new('K0A1K0').electoral_districts.should be_false
16
+ end
17
+
18
+ it 'should return false if a postal code contains no electoral districts' do
19
+ GovKit::CA::PostalCode::Strategy::ElectionsCa.new('H0H0H0').electoral_districts.should be_false
20
+ end
21
+
22
+ it 'should return false if a postal code does not exist' do
23
+ GovKit::CA::PostalCode::Strategy::ElectionsCa.new('X1B1B1').electoral_districts.should be_false
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,27 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ class GovKit::CA::PostalCode::Strategy::GreenPartyCa
4
+ describe GovKit::CA::PostalCode::Strategy::GreenPartyCa do
5
+ describe '#electoral_districts' do
6
+ it 'should return the electoral districts within a postal code' do
7
+ { 'G0C2Y0' => [24019],
8
+ 'T5S2B9' => [48015], # differs from cbc.ca
9
+ }.each do |postal_code,electoral_districts|
10
+ GovKit::CA::PostalCode::Strategy::GreenPartyCa.new(postal_code).electoral_districts.should == electoral_districts
11
+ end
12
+ end
13
+
14
+ it 'should (unfortunately) return false if a postal code contains multiple electoral districts' do
15
+ GovKit::CA::PostalCode::Strategy::GreenPartyCa.new('K0A1K0').electoral_districts.should be_false
16
+ end
17
+
18
+ it 'should return false if a postal code contains no electoral districts' do
19
+ GovKit::CA::PostalCode::Strategy::GreenPartyCa.new('H0H0H0').electoral_districts.should be_false
20
+ end
21
+
22
+ it 'should return false if a postal code does not exist' do
23
+ GovKit::CA::PostalCode::Strategy::GreenPartyCa.new('X1B1B1').electoral_districts.should be_false
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,24 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ class GovKit::CA::PostalCode::Strategy::LiberalCa
4
+ describe GovKit::CA::PostalCode::Strategy::LiberalCa do
5
+ describe '#electoral_districts' do
6
+ it 'should return the electoral districts within a postal code' do
7
+ { 'G0C2Y0' => [24019],
8
+ 'T5S2B9' => [48015, 48017], # differs from elections.ca, ndp.ca
9
+ 'K0A1K0' => [35012, 35025, 35040, 35052, 35063, 35064, 35087],
10
+ }.each do |postal_code,electoral_districts|
11
+ GovKit::CA::PostalCode::Strategy::LiberalCa.new(postal_code).electoral_districts.should == electoral_districts
12
+ end
13
+ end
14
+
15
+ it 'should return false if a postal code contains no electoral districts' do
16
+ GovKit::CA::PostalCode::Strategy::LiberalCa.new('H0H0H0').electoral_districts.should be_false
17
+ end
18
+
19
+ it 'should return false if a postal code does not exist' do
20
+ GovKit::CA::PostalCode::Strategy::LiberalCa.new('X1B1B1').electoral_districts.should be_false
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,27 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ class GovKit::CA::PostalCode::Strategy::NDPCa
4
+ describe GovKit::CA::PostalCode::Strategy::NDPCa do
5
+ describe '#electoral_districts' do
6
+ it 'should return the electoral districts within a postal code' do
7
+ { 'G0C2Y0' => [24019],
8
+ 'T5S2B9' => [48015], # differs from cbc.ca
9
+ }.each do |postal_code,electoral_districts|
10
+ GovKit::CA::PostalCode::Strategy::NDPCa.new(postal_code).electoral_districts.should == electoral_districts
11
+ end
12
+ end
13
+
14
+ it 'should (unfortunately) return false if a postal code contains multiple electoral districts' do
15
+ GovKit::CA::PostalCode::Strategy::NDPCa.new('K0A1K0').electoral_districts.should be_false
16
+ end
17
+
18
+ it 'should return false if a postal code contains no electoral districts' do
19
+ GovKit::CA::PostalCode::Strategy::NDPCa.new('H0H0H0').electoral_districts.should be_false
20
+ end
21
+
22
+ it 'should return false if a postal code does not exist' do
23
+ GovKit::CA::PostalCode::Strategy::NDPCa.new('X1B1B1').electoral_districts.should be_false
24
+ end
25
+ end
26
+ end
27
+ end
@@ -1,3 +1,90 @@
1
1
  require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
2
 
3
- # TODO
3
+ module GovKit::CA::PostalCode
4
+ describe GovKit::CA::PostalCode do
5
+ describe '#valid?' do
6
+ it 'should return false if the postal code is not properly formatted' do
7
+ [ 'A1A1A', # too short
8
+ 'A1A1A1A', # too long
9
+ "A1A1A1\nA1A1A1", # multiline
10
+ 'AAAAAA', # no digits
11
+ '111111', # no letters
12
+ '1A1A1A', # wrong order
13
+ 'Z1Z1Z1', # Z as first letter
14
+ 'Q1Q1Q1', # Q as letter
15
+ 'a1a1a1', # lowercase
16
+ ].each do |postal_code|
17
+ subject.valid?(postal_code).should be_false
18
+ end
19
+ end
20
+
21
+ it 'should return true if the postal code is properly formatted' do
22
+ [ 'A1Z1Z1', # Z not as first letter
23
+ 'H0H0H0', # doesn't exist
24
+ 'A1A1A1', # does exist
25
+ ].each do |postal_code|
26
+ subject.valid?(postal_code).should be_true
27
+ end
28
+ end
29
+ end
30
+
31
+ describe '#find_electoral_districts_by_postal_code' do
32
+ it 'should return the electoral districts within a postal code' do
33
+ { 'A1A1A1' => [10007],
34
+ 'K0A1K0' => [35012, 35025, 35040, 35052, 35063, 35064, 35087],
35
+ }.each do |postal_code,electoral_districts|
36
+ subject.find_electoral_districts_by_postal_code(postal_code).should == electoral_districts
37
+ end
38
+ end
39
+
40
+ it 'should raise an error if the postal code cannot be determined' do
41
+ lambda{subject.find_electoral_districts_by_postal_code('H0H0H0')}.should raise_error(GovKit::CA::ResourceNotFound)
42
+ end
43
+
44
+ it 'should raise an error if the postal code is invalid' do
45
+ lambda{subject.find_electoral_districts_by_postal_code('AAAAAA')}.should raise_error(GovKit::CA::InvalidRequest)
46
+ end
47
+ end
48
+
49
+ describe '#find_province_by_postal_code' do
50
+ it 'should return the province that a postal code belongs to' do
51
+ { 'A' => 'Newfoundland and Labrador',
52
+ 'B' => 'Nova Scotia',
53
+ 'C' => 'Prince Edward Island',
54
+ 'E' => 'New Brunswick',
55
+ 'G' => 'Quebec',
56
+ 'H' => 'Quebec',
57
+ 'J' => 'Quebec',
58
+ 'K' => 'Ontario',
59
+ 'L' => 'Ontario',
60
+ 'M' => 'Ontario',
61
+ 'N' => 'Ontario',
62
+ 'P' => 'Ontario',
63
+ 'R' => 'Manitoba',
64
+ 'S' => 'Saskatchewan',
65
+ 'T' => 'Alberta',
66
+ 'V' => 'British Columbia',
67
+ 'X0A' => 'Nunavut',
68
+ 'X0B' => 'Nunavut',
69
+ 'X0C' => 'Nunavut',
70
+ 'X0E' => 'Northwest Territories',
71
+ 'X0G' => 'Northwest Territories',
72
+ 'X1A' => 'Northwest Territories',
73
+ 'Y' => 'Yukon',
74
+ }.each do |postal_code, province|
75
+ subject.find_province_by_postal_code(postal_code).should == province
76
+ end
77
+ end
78
+
79
+ it 'should raise an error if the province cannot be determined' do
80
+ lambda{subject.find_province_by_postal_code('X1B1B1')}.should raise_error(GovKit::CA::ResourceNotFound)
81
+ end
82
+ end
83
+
84
+ describe '#format_postal_code' do
85
+ it 'should format a postal code' do
86
+ subject.format_postal_code("+a1a 1a1\n").should == 'A1A1A1'
87
+ end
88
+ end
89
+ end
90
+ end
data/tasks/rid_to_edid.rb CHANGED
@@ -5,7 +5,7 @@ require File.expand_path('../../lib/gov_kit-ca', __FILE__)
5
5
  # http://www.digital-copyright.ca/pcfrf/pcfrf.tgz contains
6
6
  # `postal-code-for-districts.csv`, "which is 308 postal codes that should
7
7
  # map to each of the 308 different electoral districts." However, six of the
8
- # postal codes are invalid (G0A2C0, J8M1R8, J0W1B0, J0B1H0, L0J1B0, N2A1A3),
8
+ # postal codes do not exist (G0A2C0, J8M1R8, J0W1B0, J0B1H0, L0J1B0, N2A1A3),
9
9
  # 14 are duplicate, and the remaining 294 map to 246 electoral districts.
10
10
  desc "Picks the set cover for postal codes to cbc.ca riding IDs"
11
11
  task :trim_postal_codes do |t,args|
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 0
7
7
  - 0
8
- - 1
9
- version: 0.0.1
8
+ - 2
9
+ version: 0.0.2
10
10
  platform: ruby
11
11
  authors:
12
12
  - James McKinney
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2011-03-01 00:00:00 -05:00
17
+ date: 2011-04-16 00:00:00 -04:00
18
18
  default_executable:
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
@@ -101,11 +101,17 @@ files:
101
101
  - lib/gov_kit-ca/postal_code/strategy/conservative-ca.rb
102
102
  - lib/gov_kit-ca/postal_code/strategy/digital_copyright-ca.rb
103
103
  - lib/gov_kit-ca/postal_code/strategy/elections-ca.rb
104
+ - lib/gov_kit-ca/postal_code/strategy/greenparty-ca.rb
104
105
  - lib/gov_kit-ca/postal_code/strategy/liberal-ca.rb
105
106
  - lib/gov_kit-ca/postal_code/strategy/ndp-ca.rb
106
107
  - lib/gov_kit-ca/postal_code/strategy/parl-gc-ca.rb
107
108
  - lib/gov_kit-ca/version.rb
108
109
  - lib/govkit-ca.rb
110
+ - spec/cbc_ca_spec.rb
111
+ - spec/elections_ca_spec.rb
112
+ - spec/greenparty_ca_spec.rb
113
+ - spec/liberal_ca_spec.rb
114
+ - spec/ndp_ca_spec.rb
109
115
  - spec/postal_code_spec.rb
110
116
  - spec/spec.opts
111
117
  - spec/spec_helper.rb
@@ -143,6 +149,11 @@ signing_key:
143
149
  specification_version: 3
144
150
  summary: Easy access to Canadian civic data around the web
145
151
  test_files:
152
+ - spec/cbc_ca_spec.rb
153
+ - spec/elections_ca_spec.rb
154
+ - spec/greenparty_ca_spec.rb
155
+ - spec/liberal_ca_spec.rb
156
+ - spec/ndp_ca_spec.rb
146
157
  - spec/postal_code_spec.rb
147
158
  - spec/spec.opts
148
159
  - spec/spec_helper.rb