uk_postcode 1.0.0 → 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: fd5d3327b3f2fff64453bb32cbf18941c6e668ed
4
+ data.tar.gz: 9e8d9284064d002eb6b004ed1fbd0d5779b9a9aa
5
+ SHA512:
6
+ metadata.gz: efa1121b17ba18e5d1c33ddd6a8d0ee7a239e1c1baa35a1699400e5e2f3892542636d585fe597bd66be3fa7a4f0148ec824d5a335430a1dd06daf13b6887325e
7
+ data.tar.gz: 26f43a092dce9d1f706cf36eee76af39d076b988af4d08ff581ee7ac21c84465f8a2f8d34b570e7021b68038f9e1558bf6c28e21b3c42bd18c221a7526122b31
data/README.md CHANGED
@@ -1,66 +1,114 @@
1
- uk_postcode
2
- ===========
1
+ # uk_postcode
3
2
 
4
- UK postcode parsing and validation for Ruby. I've checked it against every postcode I can get my hands on: that's about 1.8 million of them.
3
+ UK postcode parsing and validation for Ruby for writing friendly software.
5
4
 
6
- Usage
7
- -----
5
+ Features:
8
6
 
9
- require "uk_postcode"
7
+ * Handles errors with `I`/`1` and `O`/`0`.
8
+ * Does not require postcodes to contain spaces.
9
+ * Normalises postcodes (e.g. `wiaiaa` to `W1A 1AA`).
10
+ * Parses full postcodes or outcodes (`W1A`)
11
+ * Allows extraction of fields within postcode.
12
+ * Validated against 2.5 million postcodes in England, Wales, Scotland, Northern
13
+ Ireland, the Channel Islands, and the Isle of Man.
14
+
15
+ ## Usage
16
+
17
+ ```ruby
18
+ require "uk_postcode"
19
+ ```
10
20
 
11
21
  Validate and extract sections of a full postcode:
12
22
 
13
- pc = UKPostcode.new("W1A 2AB")
14
- pc.valid? #=> true
15
- pc.full? #=> true
16
- pc.outcode #=> "W1A"
17
- pc.incode #=> "2AB"
18
- pc.area #=> "W"
19
- pc.district #=> "1A"
20
- pc.sector #=> "2"
21
- pc.unit #=> "AB"
23
+ ```ruby
24
+ pc = UKPostcode.new("W1A 2AB")
25
+ pc.valid? #=> true
26
+ pc.full? #=> true
27
+ pc.outcode #=> "W1A"
28
+ pc.incode #=> "2AB"
29
+ pc.area #=> "W"
30
+ pc.district #=> "1A"
31
+ pc.sector #=> "2"
32
+ pc.unit #=> "AB"
33
+ ```
22
34
 
23
35
  Or of a partial postcode:
24
36
 
25
- pc = UKPostcode.new("W1A")
26
- pc.valid? #=> true
27
- pc.full? #=> false
28
- pc.outcode #=> "W1A"
29
- pc.incode #=> nil
30
- pc.area #=> "W"
31
- pc.district #=> "1A"
32
- pc.sector #=> nil
33
- pc.unit #=> nil
37
+ ```ruby
38
+ pc = UKPostcode.new("W1A")
39
+ pc.valid? #=> true
40
+ pc.full? #=> false
41
+ pc.outcode #=> "W1A"
42
+ pc.incode #=> nil
43
+ pc.area #=> "W"
44
+ pc.district #=> "1A"
45
+ pc.sector #=> nil
46
+ pc.unit #=> nil
47
+ ```
34
48
 
35
- Normalise postcodes:
49
+ Normalise postcodes with `normalize` (or just `norm`):
36
50
 
37
- UKPostcode.new("w1a1aa").norm #=> "W1A 1AA"
51
+ ```ruby
52
+ UKPostcode.new("w1a1aa").normalize #=> "W1A 1AA"
53
+ ```
38
54
 
39
55
  Fix mistakes with IO/10:
40
56
 
41
- pc = UKPostcode.new("WIA OAA")
42
- pc.outcode #=> "W1A"
43
- pc.incode #=> "0AA"
57
+ ```ruby
58
+ pc = UKPostcode.new("WIA OAA")
59
+ pc.outcode #=> "W1A"
60
+ pc.incode #=> "0AA"
61
+ ```
62
+
63
+ ## Gem?
44
64
 
45
- Gem?
46
- ----
65
+ ```sh
66
+ $ gem install uk_postcode
67
+ ```
47
68
 
48
- gem install uk_postcode
69
+ ## Testing
49
70
 
50
- Testing
51
- -------
71
+ To run the test suite:
72
+
73
+ ```sh
74
+ $ rake
75
+ ```
52
76
 
53
77
  The full list of UK postcodes is not included in the repository due to its
54
78
  size.
79
+ Additional sample files under `test/samples` will automatically be used.
80
+
81
+ The format of each line in a sample file must be `OOOOIII` or `OOO III` (where
82
+ `O` = outcode, `I` = incode), e.g.:
83
+
84
+ ```
85
+ AB1 0AA
86
+ BT109AH
87
+ ```
88
+
89
+ You can obtain lists of postcodes by processing various datasets available
90
+ from [mySociety][mys].
91
+
92
+ ### Code-Point Open
93
+
94
+ This does not include postcodes for Northern Ireland, the Channel Islands,
95
+ or the Isle of Man.
96
+
97
+ ```sh
98
+ $ cut -c 2-8 Data/CSV/*.csv | \
99
+ sort -uV > test/samples/large/code_point_open.list
100
+ ```
55
101
 
56
- To test against the full UK postcode set, you need to obtain the
57
- [Code-Point® Open data set][cpo] from Ordnance Survey, and to extract and
58
- transform it:
102
+ ### ONS Postcode Directory
59
103
 
60
- unzip /path/to/codepo_gb.zip
61
- cat Code-Point\ Open/data/*.csv | cut -c 2-8 | sort -V | uniq > test/samples/code_point_open.list
104
+ This includes postcodes for the whole UK as well as the Channel Islands and the
105
+ Isle of Man.
106
+ It also includes some defunct postcodes, most notably the NPT outcode, which
107
+ must be filtered out.
62
108
 
63
- Alternatively, a [pre-generated list][dl] is available for download.
109
+ ```sh
110
+ $ cut -c 2-8 ONSPD_*.csv | grep '[A-Z]' | grep -v ^NPT | \
111
+ sort -uV > test/samples/large/onspd.list
112
+ ```
64
113
 
65
- [cpo]: https://www.ordnancesurvey.co.uk/opendatadownload/products.html
66
- [dl]: https://github.com/threedaymonk/uk_postcode/downloads
114
+ [mys]: http://parlvid.mysociety.org/os/
@@ -1,3 +1,3 @@
1
1
  class UKPostcode
2
- VERSION = "1.0.0"
2
+ VERSION = "1.0.1"
3
3
  end
data/test/samples_test.rb CHANGED
@@ -1,30 +1,17 @@
1
- $:.unshift File.join(File.dirname(__FILE__), "..", "lib")
2
- require "test/unit"
3
- require "shoulda"
1
+ require_relative "./test_helper"
4
2
  require "uk_postcode"
5
3
 
6
- class UKPostcodeTest < Test::Unit::TestCase
7
-
8
- Dir[File.join(File.dirname(__FILE__), "samples", "*.list")].each do |path|
9
- context "in sample file #{File.basename(path, ".list")}" do
10
- setup do
11
- @file = open(path)
12
- end
13
-
14
- teardown do
15
- @file.close
16
- end
17
-
18
- should "be valid for each line in sample file" do
19
- @file.each_line do |line|
20
- next if line =~ /^#|^$/
21
- outcode = line[0,4].strip
22
- incode = line[4,4].strip
23
- postcode = UKPostcode.new(outcode + incode)
24
- assert postcode.valid?, "'#{outcode} #{incode}' should be valid"
25
- assert_equal outcode, postcode.outcode, "incorrect outcode for '#{outcode} #{incode}'"
26
- assert_equal incode, postcode.incode, "incorrect incode for '#{outcode} #{incode}'"
27
- end
4
+ describe "Sample files" do
5
+ Dir[File.expand_path("../samples/**/*.list", __FILE__)].each do |path|
6
+ it "should be valid for each line in #{File.basename(path, ".list")}" do
7
+ open(path).each_line do |line|
8
+ next if line =~ /^#|^$/
9
+ outcode = line[0,4].strip
10
+ incode = line[4,3].strip
11
+ postcode = UKPostcode.new(outcode + incode)
12
+ postcode.must_be :valid?
13
+ postcode.outcode.must_equal outcode
14
+ postcode.incode.must_equal incode
28
15
  end
29
16
  end
30
17
  end
@@ -0,0 +1,4 @@
1
+ lib = File.expand_path("../../lib", __FILE__)
2
+ $LOAD_PATH.unshift lib unless $LOAD_PATH.include?(lib)
3
+ require "minitest/spec"
4
+ require "minitest/autorun"
@@ -1,10 +1,7 @@
1
- # -*- coding: undecided -*-
2
- $:.unshift File.join(File.dirname(__FILE__), "..", "lib")
3
- require "test/unit"
4
- require "shoulda"
1
+ require_relative "./test_helper"
5
2
  require "uk_postcode"
6
3
 
7
- class UKPostcodeTest < Test::Unit::TestCase
4
+ describe UKPostcode do
8
5
 
9
6
  VALID_SAMPLES = [
10
7
  %w[A 9 9 AA], %w[A 99 9 AA], %w[AA 9 9 AA], %w[AA 99 9 AA], %w[A 9A 9 AA],
@@ -13,122 +10,122 @@ class UKPostcodeTest < Test::Unit::TestCase
13
10
  %w[EX 1 1 AE], %w[TQ 1 1 AG]
14
11
  ]
15
12
 
16
- { "full samples with spaces" => lambda{ |a,b,c,d| [[a, b, " ", c, d].join, [a, b, c, d]] },
17
- "full samples without spaces" => lambda{ |a,b,c,d| [[a, b, c, d].join, [a, b, c, d]] },
13
+ { "full samples with spaces" => lambda{ |(a,b,c,d)| [[a, b, " ", c, d].join, [a, b, c, d]] },
14
+ "full samples without spaces" => lambda{ |(a,b,c,d)| [[a, b, c, d].join, [a, b, c, d]] },
18
15
  }.each do |desc, mapping|
19
- context desc do
20
- setup do
21
- @samples = VALID_SAMPLES.map(&mapping)
22
- end
23
-
24
- should "all be valid" do
25
- @samples.each do |sample, _|
26
- assert UKPostcode.new(sample).valid?, "'#{sample}' should be valid"
16
+ describe desc do
17
+ let(:samples) {
18
+ VALID_SAMPLES.map(&mapping)
19
+ }
20
+
21
+ it "should all be valid" do
22
+ samples.each do |sample, _|
23
+ UKPostcode.new(sample).must_be :valid?
27
24
  end
28
25
  end
29
26
 
30
- should "all be full" do
31
- @samples.each do |sample, _|
32
- assert UKPostcode.new(sample).full?, "'#{sample}' should be full"
27
+ it "should all be full" do
28
+ samples.each do |sample, _|
29
+ UKPostcode.new(sample).must_be :full?
33
30
  end
34
31
  end
35
32
 
36
- should "extract outcodes" do
37
- @samples.each do |sample, parts|
38
- assert_equal parts[0]+parts[1], UKPostcode.new(sample).outcode
33
+ it "should extract outcodes" do
34
+ samples.each do |sample, parts|
35
+ UKPostcode.new(sample).outcode.must_equal parts[0] + parts[1]
39
36
  end
40
37
  end
41
38
 
42
- should "extract incodes" do
43
- @samples.each do |sample, parts|
44
- assert_equal parts[2]+parts[3], UKPostcode.new(sample).incode
39
+ it "should extract incodes" do
40
+ samples.each do |sample, parts|
41
+ UKPostcode.new(sample).incode.must_equal parts[2] + parts[3]
45
42
  end
46
43
  end
47
44
 
48
- should "extract area" do
49
- @samples.each do |sample, parts|
50
- assert_equal parts[0], UKPostcode.new(sample).area
45
+ it "should extract area" do
46
+ samples.each do |sample, parts|
47
+ UKPostcode.new(sample).area.must_equal parts[0]
51
48
  end
52
49
  end
53
50
 
54
- should "extract district" do
55
- @samples.each do |sample, parts|
56
- assert_equal parts[1], UKPostcode.new(sample).district
51
+ it "should extract district" do
52
+ samples.each do |sample, parts|
53
+ UKPostcode.new(sample).district.must_equal parts[1]
57
54
  end
58
55
  end
59
56
 
60
- should "extract sector" do
61
- @samples.each do |sample, parts|
62
- assert_equal parts[2], UKPostcode.new(sample).sector
57
+ it "should extract sector" do
58
+ samples.each do |sample, parts|
59
+ UKPostcode.new(sample).sector.must_equal parts[2]
63
60
  end
64
61
  end
65
62
 
66
- should "extract unit" do
67
- @samples.each do |sample, parts|
68
- assert_equal parts[3], UKPostcode.new(sample).unit
63
+ it "should extract unit" do
64
+ samples.each do |sample, parts|
65
+ UKPostcode.new(sample).unit.must_equal parts[3]
69
66
  end
70
67
  end
71
68
 
72
- should "be the same when normalised" do
73
- @samples.each do |sample, parts|
69
+ it "should be the same when normalised" do
70
+ samples.each do |sample, parts|
74
71
  expected = [parts[0], parts[1], " ", parts[2], parts[3]].join
75
- assert_equal expected, UKPostcode.new(sample).norm
72
+ UKPostcode.new(sample).norm.must_equal expected
76
73
  end
77
74
  end
78
75
  end
79
76
  end
80
77
 
81
- context "outcode samples" do
82
- setup do
83
- @samples = VALID_SAMPLES.map{ |a,b,c,d| [a, b].join }
84
- end
78
+ describe "outcode samples" do
79
+ let(:samples) {
80
+ VALID_SAMPLES.map{ |a,b,c,d| [a, b].join }
81
+ }
85
82
 
86
- should "all be valid" do
87
- @samples.each do |sample|
88
- assert UKPostcode.new(sample).valid?, "'#{sample}' should be valid"
83
+ it "should all be valid" do
84
+ samples.each do |sample|
85
+ UKPostcode.new(sample).must_be :valid?
89
86
  end
90
87
  end
91
88
 
92
- should "not be full" do
93
- @samples.each do |sample|
94
- assert !UKPostcode.new(sample).full?, "'#{sample}' should not be full"
89
+ it "should not be full" do
90
+ samples.each do |sample|
91
+ UKPostcode.new(sample).wont_be :full?
95
92
  end
96
93
  end
97
94
 
98
- should "keep outcode unchanged" do
99
- @samples.each do |sample|
100
- assert_equal sample, UKPostcode.new(sample).outcode
95
+ it "should keep outcode unchanged" do
96
+ samples.each do |sample|
97
+ UKPostcode.new(sample).outcode.must_equal sample
101
98
  end
102
99
  end
103
100
 
104
- should "have nil incode" do
105
- @samples.each do |sample|
106
- assert_nil UKPostcode.new(sample).incode
101
+ it "should have nil incode" do
102
+ samples.each do |sample|
103
+ UKPostcode.new(sample).incode.must_be_nil
107
104
  end
108
105
  end
109
106
 
110
- should "be the same when normalised" do
111
- @samples.each do |sample|
112
- assert_equal sample, UKPostcode.new(sample).norm
107
+ it "should be the same when normalised" do
108
+ samples.each do |sample|
109
+ UKPostcode.new(sample).norm.must_equal sample
113
110
  end
114
111
  end
115
112
  end
116
113
 
117
- context "when the postcode is supplied in lower case" do
118
- setup do
119
- @postcode = UKPostcode.new("w1a 1aa")
120
- end
114
+ describe "when the postcode is supplied in lower case" do
115
+ let(:postcode) {
116
+ UKPostcode.new("w1a 1aa")
117
+ }
121
118
 
122
- should "extract outcode in upper case" do
123
- assert_equal "W1A", @postcode.outcode
119
+ it "should extract outcode in upper case" do
120
+ postcode.outcode.must_equal "W1A"
124
121
  end
125
122
 
126
- should "extract incode in upper case" do
127
- assert_equal "1AA", @postcode.incode
123
+ it "should extract incode in upper case" do
124
+ postcode.incode.must_equal "1AA"
128
125
  end
129
126
 
130
- should "be valid" do
131
- assert @postcode.valid?
127
+ it "should be valid" do
128
+ postcode.must_be :valid?
132
129
  end
133
130
  end
134
131
 
@@ -137,147 +134,145 @@ class UKPostcodeTest < Test::Unit::TestCase
137
134
  "when the outcode is truncated" => "W",
138
135
  "when the postcode is invalid" => "ABC DEFG"
139
136
  }.each do |desc, sample|
140
- context desc do
141
- setup do
142
- @postcode = UKPostcode.new(sample)
143
- end
137
+ describe desc do
138
+ let(:postcode) {
139
+ UKPostcode.new(sample)
140
+ }
144
141
 
145
- should "not be valid" do
146
- assert !@postcode.valid?
142
+ it "should not be valid" do
143
+ refute postcode.valid?
147
144
  end
148
145
 
149
- should "not be full" do
150
- assert !@postcode.full?
146
+ it "should not be full" do
147
+ refute postcode.full?
151
148
  end
152
149
 
153
- should "return an empty string when normalised" do
154
- assert_equal "", @postcode.norm
150
+ it "should return an empty string when normalised" do
151
+ postcode.norm.must_equal ""
155
152
  end
156
153
 
157
- should "return nil for outcode" do
158
- assert_nil @postcode.outcode
154
+ it "should return nil for outcode" do
155
+ postcode.outcode.must_be_nil
159
156
  end
160
157
 
161
- should "return nil for incode" do
162
- assert_nil @postcode.incode
158
+ it "should return nil for incode" do
159
+ postcode.incode.must_be_nil
163
160
  end
164
161
  end
165
162
  end
166
163
 
167
- context "when used as a string" do
168
- should "normalise spacing when no spacing has been used in the input" do
169
- assert_equal "W1A 1AA", UKPostcode.new("W1A1AA").norm
164
+ describe "when used as a string" do
165
+ it "should normalise spacing when no spacing has been used in the input" do
166
+ UKPostcode.new("W1A1AA").norm.must_equal "W1A 1AA"
170
167
  end
171
168
 
172
- should "normalise spacing when too much spacing has been used in the input" do
173
- assert_equal "W1A 1AA", UKPostcode.new("W1A 1AA").norm
169
+ it "should normalise spacing when too much spacing has been used in the input" do
170
+ UKPostcode.new("W1A 1AA").norm.must_equal "W1A 1AA"
174
171
  end
175
172
 
176
- should "convert case" do
177
- assert_equal "W1A 1AA", UKPostcode.new("w1a 1aa").norm
173
+ it "should convert case" do
174
+ UKPostcode.new("w1a 1aa").norm.must_equal "W1A 1AA"
178
175
  end
179
176
 
180
- should "ignore a missing incode" do
181
- assert_equal "W1A", UKPostcode.new("W1A").norm
177
+ it "should ignore a missing incode" do
178
+ UKPostcode.new("W1A").norm.must_equal "W1A"
182
179
  end
183
180
 
184
- should "trim whitespace from start and end of the string" do
185
- assert_equal "W1A 1AA", UKPostcode.new(" W1A 1AA ").norm
181
+ it "should trim whitespace from start and end of the string" do
182
+ UKPostcode.new(" W1A 1AA ").norm.must_equal "W1A 1AA"
186
183
  end
187
184
  end
188
185
 
189
- should "return original input for to_s" do
186
+ it "should return original input for to_s" do
190
187
  ["W1A1AA", "w1a 1aa", "W1A"].each do |s|
191
- postcode = UKPostcode.new(s)
192
- assert_equal s, postcode.to_s
188
+ UKPostcode.new(s).to_s.must_equal s
193
189
  end
194
190
  end
195
191
 
196
- should "return original input for to_str" do
192
+ it "should return original input for to_str" do
197
193
  ["W1A1AA", "w1a 1aa", "W1A"].each do |s|
198
- postcode = UKPostcode.new(s)
199
- assert_equal s, postcode.to_str
194
+ UKPostcode.new(s).to_str.must_equal s
200
195
  end
201
196
  end
202
197
 
203
- context "when letters are used instead of digits" do
204
- context "in a full postcode" do
205
- setup do
206
- @postcode = UKPostcode.new("SWIA OPW")
207
- end
198
+ describe "when letters are used instead of digits" do
199
+ describe "in a full postcode" do
200
+ let(:postcode) {
201
+ UKPostcode.new("SWIA OPW")
202
+ }
208
203
 
209
- should "be valid" do
210
- assert @postcode.valid?
204
+ it "should be valid" do
205
+ postcode.must_be :valid?
211
206
  end
212
207
 
213
- should "be full" do
214
- assert @postcode.full?
208
+ it "should be full" do
209
+ postcode.must_be :full?
215
210
  end
216
211
 
217
- should "normalise to digits" do
218
- assert_equal "SW1A 0PW", @postcode.norm
212
+ it "should normalise to digits" do
213
+ postcode.norm.must_equal "SW1A 0PW"
219
214
  end
220
215
  end
221
216
  end
222
217
 
223
- context "when digits are used instead of letters" do
224
- context "in a full postcode" do
225
- setup do
226
- @postcode = UKPostcode.new("0X1 0AB")
227
- end
218
+ describe "when digits are used instead of letters" do
219
+ describe "in a full postcode" do
220
+ let(:postcode) {
221
+ UKPostcode.new("0X1 0AB")
222
+ }
228
223
 
229
- should "be valid" do
230
- assert @postcode.valid?
224
+ it "should be valid" do
225
+ postcode.must_be :valid?
231
226
  end
232
227
 
233
- should "be full" do
234
- assert @postcode.full?
228
+ it "should be full" do
229
+ postcode.must_be :full?
235
230
  end
236
231
 
237
- should "normalise to letters" do
238
- assert_equal "OX1 0AB", @postcode.norm
232
+ it "should normalise to letters" do
233
+ postcode.norm.must_equal "OX1 0AB"
239
234
  end
240
235
  end
241
236
  end
242
237
 
243
- context "single-letter area code" do
238
+ describe "single-letter area code" do
244
239
  %w[B E G L M N S W].each do |area|
245
- context area do
246
- should "not convert 1 to I in two-digit outcode" do
240
+ describe area do
241
+ it "should not convert 1 to I in two-digit outcode" do
247
242
  outcode = area + "11"
248
243
  postcode = UKPostcode.new(outcode)
249
- assert_equal area, postcode.area
250
- assert_equal outcode, postcode.outcode
244
+ postcode.area.must_equal area
245
+ postcode.outcode.must_equal outcode
251
246
  end
252
247
 
253
- should "not convert 1 to I in full postcode with space" do
248
+ it "should not convert 1 to I in full postcode with space" do
254
249
  outcode = area + "13"
255
250
  postcode = UKPostcode.new(outcode + " 1AA")
256
- assert_equal area, postcode.area
257
- assert_equal outcode, postcode.outcode
251
+ postcode.area.must_equal area
252
+ postcode.outcode.must_equal outcode
258
253
  end
259
254
 
260
- should "not convert 1 to I in full postcode without space" do
255
+ it "should not convert 1 to I in full postcode without space" do
261
256
  outcode = area + "13"
262
257
  postcode = UKPostcode.new(outcode + "2AA")
263
- assert_equal area, postcode.area
264
- assert_equal outcode, postcode.outcode
258
+ postcode.area.must_equal area
259
+ postcode.outcode.must_equal outcode
265
260
  end
266
261
  end
267
262
  end
268
263
  end
269
264
 
270
- context "GIR 0AA" do
271
- setup do
272
- @norm = "GIR 0AA"
273
- end
265
+ describe "GIR 0AA" do
266
+ let(:norm) {
267
+ "GIR 0AA"
268
+ }
274
269
 
275
- should "stay as is" do
276
- assert_equal @norm, UKPostcode.new(@norm).norm
270
+ it "should stay as is if already normalised" do
271
+ UKPostcode.new(norm).norm.must_equal norm
277
272
  end
278
273
 
279
- should "be normalised" do
280
- assert_equal @norm, UKPostcode.new("G1ROAA").norm
274
+ it "should be normalised" do
275
+ UKPostcode.new("G1ROAA").norm.must_equal norm
281
276
  end
282
277
  end
283
278
  end