ons_openapi 0.1.0

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: b1a1edf4c26311e209664f2c74d01601f169c77d
4
+ data.tar.gz: d25742c9874d3bd14602b0cd1a0bafc89ea83ed4
5
+ SHA512:
6
+ metadata.gz: 211e09eae5a302907f2a1f06256fbe88e592c48d85609bfc901b3802d3a960b0cd14bc12b1ea18f75aa89688c1dcbbeaaad61bd2b295277786cd0a72c04d1694
7
+ data.tar.gz: e172c11cf23355fcc0db0519b37bbde324beb677023cf7e4e05df9434f5ea666b823705e7d2724b2f2338a93c6b3f1280422bf03a585dac2c65ec880cc124966
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2014 Rob McKinnon
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+
data/README.md ADDED
@@ -0,0 +1,218 @@
1
+ ons-openapi
2
+ ===========
3
+
4
+ Ruby wrapper around the [ONS OpenAPI](https://www.ons.gov.uk/ons/apiservice/web/apiservice/home) - the UK Office of National Statistics's data API. The intention is to make it easy to quickly retrieve data. It may not expose the full functionality of the ONS OpenAPI.
5
+
6
+ This gem was partially written at [Accountability Hack 2014](https://twitter.com/search?q=%23AccHack14), an event organised by Parliament, ONS, and NAO.
7
+
8
+ Please provide feedback via [GitHub issues](https://github.com/robmckinnon/ons-openapi/issues).
9
+
10
+ # Installation
11
+
12
+ ```
13
+ gem install ons_openapi
14
+ ```
15
+
16
+ then in Ruby code
17
+
18
+ ```
19
+ require 'ons_openapi'
20
+ ```
21
+
22
+ or if using bundler (as with Rails), add to the Gemfile
23
+
24
+ ```
25
+ gem 'ons_openapi'
26
+ ```
27
+
28
+ You must have an ExecJS supported runtime when running this gem. If you are using Mac OS X or Windows, you already have a JavaScript runtime installed in your operating system. Check [ExecJS documentation](https://github.com/sstephenson/execjs#readme) to know all supported JavaScript runtimes.
29
+
30
+ The gem includes code from the [JSON-stat Javascript Toolkit](https://github.com/badosa/JSON-stat) to parse JSON-stat formatted results from the ONS OpenAPI. ExecJS is used to run JSON-stat JavaScript code from within Ruby.
31
+
32
+ # Register for API key
33
+
34
+ The ONS OpenAPI requires you [register for an API key](https://www.ons.gov.uk/ons/apiservice/web/apiservice/home#reg-main-content).
35
+
36
+ When using the gem, set an environment variable named `ONS_APIKEY` with your API key value.
37
+
38
+ ```
39
+ $ ONS_APIKEY=<your_ons_openapi_key>
40
+ ```
41
+
42
+ # Getting started
43
+
44
+ Running in irb:
45
+
46
+ $ ONS_APIKEY=<your_ons_openapi_key> irb
47
+
48
+ require 'ons_openapi'
49
+
50
+ census = OnsOpenApi.context('Census')
51
+
52
+ religion_detailed = census.collection('Religion (detailed)')
53
+
54
+ religion_detailed.data_for('Islington')
55
+ #=> [["2011 Administrative Hierarchy", "Religion (Flat) (T059A)", "Time Dimension", "Value"],
56
+ # ["Islington", "All categories: Religion", "2011", 206125],
57
+ # ["Islington", "Christian", "2011", 82879],
58
+ # ["Islington", "Buddhist", "2011", 2117],
59
+ # ...
60
+
61
+ religion_detailed.data_for('Islington S')
62
+ #=> [["2011 Westminster Parliamentary Constituency Hierarchy", "Religion (Flat) (T059A)", "Time", "Value"],
63
+ # ["Islington South and Finsbury", "All categories: Religion", "2011", 102656],
64
+ # ["Islington South and Finsbury", "Christian", "2011", 42222],
65
+ # ["Islington South and Finsbury", "Buddhist", "2011", 1126],
66
+ # ...
67
+
68
+ religion_detailed.data_for('England')
69
+ #=> [["2011 Administrative Hierarchy", "Religion (Flat) (T059A)", "Time Dimension", "Value"],
70
+ # ["England", "All categories: Religion", "2011", 53012456],
71
+ # ["England", "Christian", "2011", 31479876],
72
+ # ["England", "Buddhist", "2011", 238626],
73
+ # ...
74
+
75
+ religion_detailed.data_for('North West')
76
+ #=> [["2011 Administrative Hierarchy", "Religion (Flat) (T059A)", "Time Dimension", "Value"],
77
+ # ["North West", "All categories: Religion", "2011", 7052177],
78
+ # ["North West", "Christian", "2011", 4742860],
79
+ # ["North West", "Buddhist", "2011", 20695]
80
+
81
+ religion_detailed.data_for('Scotland')
82
+ # RuntimeError: ONS Exception: 404 INTERNAL ERROR: Invalid dimension item code S92000003
83
+
84
+ religion_detailed.data_for('Woodlands')
85
+ # RuntimeError: more than one match, try one of:
86
+ #
87
+ # data_for('E05006341 Woodlands') or data_for('E05006341') see http://statistics.data.gov.uk/doc/statistical-geography/E05006341
88
+ #
89
+ # data_for('E05008891 Woodlands') or data_for('E05008891') see http://statistics.data.gov.uk/doc/statistical-geography/E05008891
90
+ #
91
+ # data_for('E05001234 Woodlands') or data_for('E05001234') see http://statistics.data.gov.uk/doc/statistical-geography/E05001234
92
+ #
93
+ # data_for('E05004981 Woodlands') or data_for('E05004981') see http://statistics.data.gov.uk/doc/statistical-geography/E05004981
94
+
95
+
96
+ # Contexts
97
+
98
+ The datastore underneath the ONS OpenAPI is divided into four sections called contexts.
99
+
100
+ OnsOpenApi.context_names
101
+ #=> ["Census", "Socio-Economic", "Economic", "Social"]
102
+
103
+ OnsOpenApi.contexts.size
104
+ #=> 4
105
+
106
+ The Census context contains data from the 2011 Census in England and Wales.
107
+
108
+ # Collections
109
+
110
+ Each context consists of several dataset collections.
111
+
112
+ economic = OnsOpenApi.context('Economic')
113
+ economic.collections.size
114
+ #=> 26
115
+
116
+ census = OnsOpenApi.context('Census')
117
+ census.collections.size
118
+ #=> 340
119
+
120
+ Use `collection_names()` to view a list of collection names:
121
+
122
+ puts census.collection_names.select {|n| n[/religion/i]}
123
+ # DC1202EW Household composition by religion of Household Reference Person (HRP)
124
+ # DC2107EW Religion by sex by age
125
+ # DC2201EW Ethnic group by religion
126
+ # ...
127
+ # QS208EW Religion
128
+ # QS210EW Religion (detailed)
129
+ # ST210EWla Religion (non-UK born short-term residents)
130
+
131
+ Retrieve a collection using `collection()`. Pass in the collection code, collection name, or collection code and name:
132
+
133
+ census.collection('QS210EW')
134
+ census.collection('Religion (detailed)')
135
+ census.collection('QS210EW Religion (detailed)')
136
+
137
+ # Geographical hierarchies
138
+
139
+ Each collection can be filtered with different geographical hierarchies.
140
+
141
+ census = OnsOpenApi.context('Census')
142
+ religion = census.collection('Religion')
143
+
144
+ religion.geography_codes
145
+ # [
146
+ # ["2011STATH", "2011 Statistical Geography Hierarchy"],
147
+ # ["2011WARDH", "2011 Administrative Hierarchy"],
148
+ # ["2011PCONH", "2011 Westminster Parliamentary Constituency Hierarchy"]
149
+ # ]
150
+
151
+ # Listing areas from geography hierarchy
152
+
153
+ Use `geographies()` to get a hash of geography hierarchies. To get a list of geography items for a hierarchy, say '2011PCONH', do:
154
+
155
+ census = OnsOpenApi.context('Census')
156
+ religion = census.collection('Religion')
157
+ constituencies = religion.geographies['2011PCONH']
158
+
159
+ constituencies.map(&:label)
160
+ # ["Aberavon", "Aberconwy", "Aldershot", "Aldridge-Brownhills", ...
161
+
162
+ constituencies.map(&:item_code)
163
+ # ["E14000759", "E14000531", "E14000967", "E14000904", ...
164
+
165
+ To see `area_types` in the hierarchy:
166
+
167
+ constituencies.map(&:area_type).map {|a| [a.codename, a.level]}.uniq
168
+ # [["Westminster Parliamentary Constituency", 3],
169
+ # ["Region", 2],
170
+ # ["Country", 1],
171
+ # ["England and Wales", 0]]
172
+
173
+ Or for hierarchy '2011WARDH', do:
174
+
175
+ areas = religion.geographies['2011WARDH']
176
+
177
+ areas.map(&:label)
178
+ # ["Aldwick East", "West Mersea", "Stowmarket Central", ...
179
+
180
+ areas.map {|a| [a.item_code, a.label, a.area_type.codename, a.area_type.level]}
181
+ # [["E05007576", "Aldwick East", "Electoral Ward/Division ", 7],
182
+ # ["E05004144", "West Mersea", "Electoral Ward/Division ", 7],
183
+ # ["E05007153", "Stowmarket Central", "Electoral Ward/Division ", 7]], ...
184
+
185
+ To see `area_types` in the hierarchy:
186
+
187
+ areas.map(&:area_type).map {|a| [a.codename, a.level]}.uniq
188
+ # [["Electoral Ward/Division ", 7],
189
+ # ["Electoral Division", 7],
190
+ # ["Metropolitan District ", 6],
191
+ # ["Council Area", 4],
192
+ # ["County", 5],
193
+ # ["Non-metropolitan District", 6],
194
+ # ["London Borough ", 6],
195
+ # ["Unitary Authority", 5],
196
+ # ["Metropolitan County", 5],
197
+ # ["Country", 3],
198
+ # ["Great Britain", 1],
199
+ # ["United Kingdom", 0],
200
+ # ["Region", 4],
201
+ # ["England and Wales", 2],
202
+ # ["Inner and Outer London", 5]]
203
+
204
+ # Data for a geographic area
205
+
206
+ Use `data_for()` to retrieve data for a geography that matches given label_or_code.
207
+
208
+ census = OnsOpenApi.context('Census')
209
+ religion = census.collection('Religion')
210
+
211
+ religion.data_for('England')
212
+ religion.data_for('Islington S')
213
+ religion.data_for('E05002040')
214
+
215
+ # Feedback
216
+
217
+ Please provide feedback via [GitHub issues](https://github.com/robmckinnon/ons-openapi/issues).
218
+
@@ -0,0 +1,10 @@
1
+ class OnsOpenApi::Classification
2
+
3
+ include Morph
4
+ include OnsOpenApi::DataHelper
5
+
6
+ def classification_detail
7
+ OnsOpenApi::get(url.first, url.last).classification_detail
8
+ end
9
+
10
+ end
@@ -0,0 +1,151 @@
1
+ class OnsOpenApi::Collection
2
+
3
+ include Morph
4
+ include OnsOpenApi::DataHelper
5
+
6
+ # Returns title, i.e. "id name"
7
+ def title
8
+ [id, name].join(' ')
9
+ end
10
+
11
+ # Returns data as array of arrays, for a geography that matches label_or_code.
12
+ # e.g. data_for('England'), data_for('Islington S'), data_for('E05002040')
13
+ # Raises exception if no match or more than one match.
14
+ def data_for label_or_code
15
+ if geographies = geography(label_or_code)
16
+ if geographies.size > 1
17
+ cmds = geographies.map {|g| "data_for('#{g.title}') or data_for('#{g.item_code}') see http://statistics.data.gov.uk/doc/statistical-geography/#{g.item_code}"}
18
+ raise "more than one match, try one of:\n\n #{cmds.join(" \n\n ") }\n\n"
19
+ else
20
+ geo = geographies.first
21
+ data geo.item_code, geo.geography_code
22
+ end
23
+ end
24
+ end
25
+
26
+ # Returns data for given geog_code, geog, and optional JSON-stat command.
27
+ def data geog_code, geog, stat='.toTable()'
28
+ @json_stats ||={}
29
+ @json_stats[geog_code + geog] ||= OnsOpenApi::request("dataset/#{id}",
30
+ context: context_name,
31
+ geog: geog,
32
+ "dm/#{geog}" => geog_code,
33
+ totals: 'false',
34
+ jsontype: 'json-stat')
35
+
36
+ raw_json_stat = @json_stats[geog_code + geog].gsub("\n", ' ').gsub("'", "").squeeze(' ')
37
+
38
+ if raw_json_stat.include?('ns1faultstring')
39
+ raise "ONS Exception: #{raw_json_stat.gsub(/(<.?ns1XMLFault>)|(<.?ns1faultstring>)/,'')}"
40
+ elsif raw_json_stat.include?('errorMessage')
41
+ raise "ONS Error: #{raw_json_stat}"
42
+ end
43
+
44
+ begin
45
+ table = js_context.eval( %Q| JSONstat( JSON.parse(' #{raw_json_stat} ') ).Dataset(0)#{stat} | )
46
+ rescue Encoding::UndefinedConversionError => e
47
+ if e.to_s[/ASCII-8BIT to UTF-8/]
48
+ raw_json_stat = raw_json_stat.force_encoding('ASCII-8BIT').encode('UTF-8', :invalid => :replace, :undef => :replace, :replace => '?')
49
+ table = js_context.eval( %Q| JSONstat( JSON.parse(' #{raw_json_stat} ') ).Dataset(0)#{stat} | )
50
+ else
51
+ raise "#{e.to_s}: #{raw_json_stat}"
52
+ end
53
+ rescue ExecJS::RuntimeError, ExecJS::ProgramError => e
54
+ raise "#{e.to_s}: #{raw_json_stat}"
55
+ end
56
+
57
+ if table.is_a?(Array) && (index = table[1].index('Segment_1'))
58
+ table.each {|row| row.delete_at(index)}
59
+ end
60
+ table
61
+ end
62
+
63
+ #
64
+ # Returns array of [geography_code, description] that are supported by this
65
+ # collection.
66
+ #
67
+ # e.g.
68
+ # 2011WARDH - 2011 Administrative Hierarchy
69
+ # 2011STATH - 2011 Statistical Geography Hierarchy
70
+ # 2011PCONH - 2011 Westminster Parliamentary Constituency Hierarchy
71
+ # 2011HTWARDH - 2011 Census Merged Ward Hierarchy
72
+ # 2011CMLADH - 2011 Census merged local authority district hierarchy
73
+ # 2011PARISH - 2011 Parish Hierarchy
74
+ #
75
+ def geography_codes
76
+ gh ||= geographical_hierarchies
77
+ @geographies_data ||= if gh.respond_to?(:geographical_hierarchy) && gh.geographical_hierarchy
78
+ url, args = gh.geographical_hierarchy.url
79
+ OnsOpenApi::get(url, args)
80
+ elsif gh.respond_to?(:geographical_hierarchies) && gh.geographical_hierarchies
81
+ url, args = gh.geographical_hierarchies.first.url
82
+ OnsOpenApi::get(url, args)
83
+ end
84
+
85
+ if @geographies_data
86
+ list = @geographies_data.geographical_hierarchy_list
87
+ if list.respond_to?(:geographical_hierarchy) && list.geographical_hierarchy
88
+ [ [list.geographical_hierarchy.id, list.geographical_hierarchy.name] ]
89
+ elsif list.respond_to?(:geographical_hierarchies) && list.geographical_hierarchies
90
+ list.geographical_hierarchies.map{|x| [x.id, x.name]}
91
+ else
92
+ []
93
+ end
94
+ else
95
+ []
96
+ end
97
+ end
98
+
99
+ # Returns geography item that matches given label_or_code.
100
+ # Raises exception if there is no match.
101
+ def geography label_or_code
102
+ if matches = geography_exact_match(label_or_code) || geography_partial_match(label_or_code)
103
+ matches
104
+ else
105
+ raise "no geography match found for: #{label_or_code}"
106
+ end
107
+ end
108
+
109
+ # Returns collection_detail object.
110
+ def collection_detail
111
+ OnsOpenApi::get(url.first, url.last).collection_detail
112
+ end
113
+
114
+ # Returns hash of geography code to list of geography items.
115
+ def geographies
116
+ codes = geography_codes.map(&:first)
117
+ codes.each_with_object({}) do |code, hash|
118
+ hash[code] = OnsOpenApi.context(context_name).geographies(code)
119
+ end
120
+ end
121
+
122
+ private
123
+
124
+ def geography_exact_match label_or_code
125
+ matches = []
126
+ geographies.values.each do |list|
127
+ found = list.select{|c| (c.label == label_or_code) || (c.item_code == label_or_code) || (c.title == label_or_code) }
128
+ matches += found unless found.empty?
129
+ end
130
+ matches.empty? ? nil : matches.uniq {|m| m.item_code}
131
+ end
132
+
133
+ def geography_partial_match label_or_code
134
+ matches = []
135
+ geographies.values.each do |list|
136
+ found = list.select{|c| c.label[label_or_code] }
137
+ matches += found unless found.empty?
138
+ end
139
+ matches.empty? ? nil : matches.uniq {|m| m.item_code}
140
+ end
141
+
142
+ def js_context
143
+ unless @js_context
144
+ jsonstatjs = File.expand_path('../../../vendor/json-stat.max.js', __FILE__)
145
+ source = open(jsonstatjs).read
146
+ @js_context = ExecJS.compile(source)
147
+ end
148
+ @js_context
149
+ end
150
+
151
+ end
@@ -0,0 +1,6 @@
1
+ class OnsOpenApi::Concept
2
+
3
+ include Morph
4
+ include OnsOpenApi::DataHelper
5
+
6
+ end
@@ -0,0 +1,65 @@
1
+ require 'net/https'
2
+
3
+ module OnsOpenApi::Connection
4
+
5
+ BASE_URI = 'http://data.ons.gov.uk/ons/api/data/'
6
+ API_KEY = ENV['ONS_APIKEY']
7
+
8
+ def get(resource, args={})
9
+ to_object request(resource, "get", args)
10
+ end
11
+
12
+ def post(resource, args={})
13
+ to_object request(resource, "post", args)
14
+ end
15
+
16
+ def to_object json
17
+ json.gsub!('"@', '"')
18
+ json.gsub!('xml.lang','xml_lang')
19
+ json.gsub!('"$":','"text":')
20
+ json.gsub!('"2011WARDH" : {', '"X2011WARDH" : {')
21
+ json.gsub!('"2011HTWARDH" : {', '"X2011HTWARDH" : {')
22
+ hash = JSON.parse json
23
+ Morph.from_hash hash, OnsOpenApi
24
+ end
25
+
26
+ def request_uri(resource, args)
27
+ unless API_KEY
28
+ raise 'No ONS OpenAPI key found. Set this environment variable: ONS_APIKEY=<your_ons_openapi_key>'
29
+ end
30
+ uri = URI.join(BASE_URI, (resource+'.json').sub('.json.json','.json') )
31
+
32
+ args ||= {}
33
+ args.delete('apikey')
34
+ args.merge!( apikey: API_KEY )
35
+ uri.query = args.map { |k,v| "%s=%s" % [URI.encode(k.to_s), URI.encode(v.to_s)] }.join("&") if args
36
+
37
+ puts uri.to_s
38
+ uri
39
+ end
40
+
41
+ def request(resource, method="get", args)
42
+ uri = request_uri resource, args
43
+ case method
44
+ when "get"
45
+ req = Net::HTTP::Get.new(uri.request_uri)
46
+ when "post"
47
+ req = Net::HTTP::Post.new(uri.request_uri)
48
+ end
49
+
50
+ http = Net::HTTP.new(uri.host, uri.port)
51
+ http.use_ssl = (uri.port == 443)
52
+
53
+ res = http.start() { |conn| conn.request(req) }
54
+ res.body
55
+ end
56
+
57
+ end
58
+
59
+ module OnsOpenApi
60
+
61
+ class << self
62
+ include OnsOpenApi::Connection
63
+ end
64
+
65
+ end
@@ -0,0 +1,106 @@
1
+ class OnsOpenApi::Context
2
+
3
+ include Morph
4
+
5
+ class << self
6
+ def all
7
+ @contexts ||= OnsOpenApi::get('contexts').context_list.statistical_contexts.map {|x| new x}
8
+ end
9
+ end
10
+
11
+ def initialize x
12
+ self.id = x.context_id
13
+ self.name = x.context_name
14
+ end
15
+
16
+ def concepts
17
+ @concepts ||= OnsOpenApi::get('concepts', context: @name).concept_list.concepts
18
+ end
19
+
20
+ def collections
21
+ @collections ||= OnsOpenApi::get('collections', context: @name).collection_list.collections
22
+ unless @collections.first.respond_to?(:context_name) && @collections.first.context_name
23
+ @collections.each {|c| c.context_name = @name}
24
+ end
25
+ @collections
26
+ end
27
+
28
+ def classifications
29
+ @classifications ||= OnsOpenApi::get('classifications', context: @name).classification_list.classifications
30
+ end
31
+
32
+ def collection id_or_name
33
+ collection = collections.detect{|c| (c.id == id_or_name || c.title == id_or_name) }
34
+
35
+ unless collection
36
+ list = collections.select{|c| c.name == id_or_name}
37
+ if list.size > 1
38
+ cmds = list.map{|c| [c.id,c.title]}.flatten.map{|n| "collection('#{n}')"}
39
+ raise "more than one match, try one of:\n\n #{cmds.join(" \n\n ") }\n\n"
40
+ else
41
+ collection = list.first
42
+ end
43
+ end
44
+
45
+ collection
46
+ end
47
+
48
+ def concept_names
49
+ names_for concepts
50
+ end
51
+
52
+ def collection_names
53
+ names_for collections
54
+ end
55
+
56
+ def classification_names
57
+ names_for classifications
58
+ end
59
+
60
+ # Returns geography objects for given geography code.
61
+ #
62
+ # Parameter +code+ defaults to +'2011WARDH'+ for the 2011 Administrative
63
+ # Hierarchy, if no +code+ supplied.
64
+ #
65
+ # Codes include:
66
+ # +2011WARDH+ - 2011 Administrative Hierarchy
67
+ # +2011STATH+ - 2011 Statistical Geography Hierarchy
68
+ # +2011PCONH+ - 2011 Westminster Parliamentary Constituency Hierarchy
69
+ # +2011HTWARDH+ - 2011 Census Merged Ward Hierarchy
70
+ # +2011CMLADH+ - 2011 Census merged local authority district hierarchy
71
+ # +2011PARISH+ - 2011 Parish Hierarchy
72
+ def geographies code='2011WARDH'
73
+ @geographies ||= {}
74
+ unless @geographies[code]
75
+ params = { context: @name }
76
+
77
+ if code == '2011STATH'
78
+ params.merge!({ levels: '0,1,2,3,4,5' }) # restrict levels to reduce delay
79
+ end
80
+
81
+ result = OnsOpenApi::get "hierarchies/hierarchy/#{code}", params
82
+ @geographies[code] = result.geography_list.items.items
83
+ end
84
+ @geographies[code].each {|g| g.geography_code = code }
85
+ @geographies[code]
86
+ end
87
+
88
+ # Returns geography objects from the 2011 Administrative Hierarchy
89
+ # with area type 'Electoral Division'
90
+ def electoral_divisions
91
+ geographies('2011WARDH').select {|z| z.area_type.codename['Electoral Division']}
92
+ end
93
+
94
+ # Returns geography objects from the 2011 Administrative Hierarchy
95
+ # with area type 'Electoral Ward/Division'
96
+ def electoral_wards
97
+ geographies('2011WARDH').select {|z| z.area_type.codename['Electoral Ward/Division']}
98
+ end
99
+
100
+ private
101
+
102
+ def names_for list
103
+ list.map(&:title)
104
+ end
105
+
106
+ end
@@ -0,0 +1,5 @@
1
+ module OnsOpenApi::DataHelper
2
+
3
+ include OnsOpenApi::NameHelper
4
+ include OnsOpenApi::UrlHelper
5
+ end
@@ -0,0 +1,46 @@
1
+ class OnsOpenApi::Dimension
2
+
3
+ include Morph
4
+
5
+ def values
6
+ ids.each_with_object({}) do |x, h|
7
+ h[alt_label(x)] = send(method(x))
8
+ end
9
+ end
10
+
11
+ def labels
12
+ data = values
13
+ non_data_keys = role.morph_attributes.values.flatten.map{|x| alt_label x}
14
+ non_data_keys.each do |k|
15
+ data.delete(k)
16
+ end
17
+ data = data.values.first.category
18
+
19
+ key_to_index = data.index.morph_attributes
20
+ key_to_label = data.label.morph_attributes
21
+
22
+ labels = key_to_index.to_a.each_with_object([]) do |k_i, a|
23
+ if index = k_i[1]
24
+ key = k_i[0]
25
+ a[index] = key_to_label[key]
26
+ end
27
+ end
28
+
29
+ # label = data.label
30
+ # items = data.category.index
31
+ # labels = data.category.label
32
+ end
33
+
34
+ private
35
+
36
+ def alt_label x
37
+ x['2011WARDH'] ? 'X2011_WARDH' : x
38
+ x['2011HTWARDH'] ? 'X2011_HTWARDH' : x
39
+ end
40
+
41
+ def method x
42
+ x = alt_label x
43
+ method = Morph::InstanceMethods::Helper.convert_to_morph_method_name x
44
+ end
45
+
46
+ end
@@ -0,0 +1,6 @@
1
+ class OnsOpenApi::GeographicalHierarchy
2
+
3
+ include Morph
4
+ include OnsOpenApi::DataHelper
5
+
6
+ end
@@ -0,0 +1,13 @@
1
+ class OnsOpenApi::Item
2
+
3
+ include Morph
4
+
5
+ def label
6
+ labels.labels.first.text
7
+ end
8
+
9
+ def title
10
+ [item_code, label].join(' ')
11
+ end
12
+
13
+ end
@@ -0,0 +1,7 @@
1
+ module OnsOpenApi::NameHelper
2
+
3
+ def name
4
+ names.names.first.text
5
+ end
6
+
7
+ end
@@ -0,0 +1,12 @@
1
+ module OnsOpenApi::UrlHelper
2
+
3
+ def url
4
+ require 'cgi'
5
+ if respond_to?(:urls) && urls
6
+ uri = URI.parse urls.urls.detect{|x| x.representation['json'] }.href
7
+ params = Rack::Utils.parse_query(uri.query)
8
+ params.delete('apikey')
9
+ return [uri.path, params]
10
+ end
11
+ end
12
+ end