uk_postcode 1.0.0 → 1.0.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.
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