postcodeinfo-client-ruby 0.1.0

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: ca6ca25946353c44ba94a7512c8077202c414b62
4
+ data.tar.gz: c15c8b55cf06276466ab4445573efa8ff540074d
5
+ SHA512:
6
+ metadata.gz: 38057890127e5a2202d7643d036a9f32f89e17751f9b58fb6405069af37545b06f2f8ce96169dafd33bc73b4ad81af7117e6c6b281d1b324d2fbb766eeb96e0f
7
+ data.tar.gz: 6bbb6256d82091e3c5e377785f73c67280ee70b6fd4fa59bb1c3582e73845eef337412859ddf923a216efdadcb41a9d6be5147f43d2835e73e664ce34b03724e
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ lib/**/*.rb
2
+ bin/*
3
+ -
4
+ features/**/*.feature
5
+ LICENSE.txt
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/.ruby-gemset ADDED
@@ -0,0 +1,2 @@
1
+ postcodeinfo-client-ruby
2
+
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 2.1.5
data/.simplecov ADDED
@@ -0,0 +1,6 @@
1
+ SimpleCov.start do
2
+ # any custom configs like groups and filters can be here at a central place
3
+ add_filter '/test/'
4
+ add_filter '/spec/'
5
+ add_filter '/.rvm/'
6
+ end
data/Gemfile ADDED
@@ -0,0 +1,18 @@
1
+ source "http://rubygems.org"
2
+ # Add dependencies required to use your gem here.
3
+ # Example:
4
+ # gem "activesupport", ">= 2.3.5"
5
+
6
+ gem 'json'
7
+ gem 'rest-client'
8
+
9
+ # Add dependencies to develop your gem here.
10
+ # Include everything needed to run rake, tests, features, etc.
11
+ group :development do
12
+ gem "byebug"
13
+ gem "rspec", ">= 3.2.0"
14
+ gem "rdoc", "~> 3.12"
15
+ gem "bundler", "~> 1.0"
16
+ gem "jeweler", "~> 2.0.1"
17
+ gem "simplecov", ">= 0"
18
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,97 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ addressable (2.3.8)
5
+ builder (3.2.2)
6
+ byebug (5.0.0)
7
+ columnize (= 0.9.0)
8
+ columnize (0.9.0)
9
+ descendants_tracker (0.0.4)
10
+ thread_safe (~> 0.3, >= 0.3.1)
11
+ diff-lcs (1.2.5)
12
+ docile (1.1.5)
13
+ domain_name (0.5.24)
14
+ unf (>= 0.0.5, < 1.0.0)
15
+ faraday (0.9.1)
16
+ multipart-post (>= 1.2, < 3)
17
+ git (1.2.9.1)
18
+ github_api (0.12.3)
19
+ addressable (~> 2.3)
20
+ descendants_tracker (~> 0.0.4)
21
+ faraday (~> 0.8, < 0.10)
22
+ hashie (>= 3.3)
23
+ multi_json (>= 1.7.5, < 2.0)
24
+ nokogiri (~> 1.6.3)
25
+ oauth2
26
+ hashie (3.4.1)
27
+ highline (1.7.2)
28
+ http-cookie (1.0.2)
29
+ domain_name (~> 0.5)
30
+ jeweler (2.0.1)
31
+ builder
32
+ bundler (>= 1.0)
33
+ git (>= 1.2.5)
34
+ github_api
35
+ highline (>= 1.6.15)
36
+ nokogiri (>= 1.5.10)
37
+ rake
38
+ rdoc
39
+ json (1.8.2)
40
+ jwt (1.5.0)
41
+ mime-types (2.5)
42
+ mini_portile (0.6.2)
43
+ multi_json (1.11.0)
44
+ multi_xml (0.5.5)
45
+ multipart-post (2.0.0)
46
+ netrc (0.10.3)
47
+ nokogiri (1.6.6.2)
48
+ mini_portile (~> 0.6.0)
49
+ oauth2 (1.0.0)
50
+ faraday (>= 0.8, < 0.10)
51
+ jwt (~> 1.0)
52
+ multi_json (~> 1.3)
53
+ multi_xml (~> 0.5)
54
+ rack (~> 1.2)
55
+ rack (1.6.1)
56
+ rake (10.4.2)
57
+ rdoc (3.12.2)
58
+ json (~> 1.4)
59
+ rest-client (1.8.0)
60
+ http-cookie (>= 1.0.2, < 2.0)
61
+ mime-types (>= 1.16, < 3.0)
62
+ netrc (~> 0.7)
63
+ rspec (3.2.0)
64
+ rspec-core (~> 3.2.0)
65
+ rspec-expectations (~> 3.2.0)
66
+ rspec-mocks (~> 3.2.0)
67
+ rspec-core (3.2.3)
68
+ rspec-support (~> 3.2.0)
69
+ rspec-expectations (3.2.1)
70
+ diff-lcs (>= 1.2.0, < 2.0)
71
+ rspec-support (~> 3.2.0)
72
+ rspec-mocks (3.2.1)
73
+ diff-lcs (>= 1.2.0, < 2.0)
74
+ rspec-support (~> 3.2.0)
75
+ rspec-support (3.2.2)
76
+ simplecov (0.10.0)
77
+ docile (~> 1.1.0)
78
+ json (~> 1.8)
79
+ simplecov-html (~> 0.10.0)
80
+ simplecov-html (0.10.0)
81
+ thread_safe (0.3.5)
82
+ unf (0.1.4)
83
+ unf_ext
84
+ unf_ext (0.0.7.1)
85
+
86
+ PLATFORMS
87
+ ruby
88
+
89
+ DEPENDENCIES
90
+ bundler (~> 1.0)
91
+ byebug
92
+ jeweler (~> 2.0.1)
93
+ json
94
+ rdoc (~> 3.12)
95
+ rest-client
96
+ rspec (>= 3.2.0)
97
+ simplecov
data/LICENSE.MD ADDED
@@ -0,0 +1,19 @@
1
+ Copyright (C) 2015 HM Government (Ministry of Justice Digital Services)
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
4
+ this software and associated documentation files (the "Software"), to deal in
5
+ the Software without restriction, including without limitation the rights to
6
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
7
+ of the Software, and to permit persons to whom the Software is furnished to do
8
+ so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in all
11
+ copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,150 @@
1
+ # postcodeinfo-client-ruby
2
+
3
+ API Client wrapper for https://github.com/ministryofjustice/postcodeinfo
4
+
5
+ # Installation
6
+
7
+ Assuming you use Bundler, add
8
+ ```ruby
9
+ gem 'postcodeinfo-client-ruby'
10
+ ```
11
+ to your Gemfile, and ```bundle install```
12
+
13
+ # Usage
14
+
15
+ ## Authentication
16
+
17
+ You will need an _authentication token_ ('auth token'). If you're using MoJ DS's Postcode Info server,
18
+ you can get one by emailing platforms@digital.justice.gov.uk with a brief summary of:
19
+
20
+ * who you are
21
+ * what project you're going to be using it on
22
+ * roughly how many lookups you expect to do per day
23
+
24
+ If you're running your own server, see https://github.com/ministryofjustice/postcodeinfo#auth_tokens for instructions on how to set a token up.
25
+
26
+ ## Quick Start
27
+
28
+ In your code:
29
+
30
+ ```ruby
31
+ require 'postcodeinfo-client-ruby'
32
+
33
+ # create a client
34
+ client = PostcodeInfo::Client.new(auth_token: "(your auth token here, without parentheses)")
35
+
36
+ # lookup a postcode
37
+ postcode = client.lookup_postcode('SN15NB')
38
+
39
+ # postcode details
40
+ postcode.valid?
41
+ => true
42
+
43
+ postcode.latitude
44
+ => 51.55669583757671
45
+
46
+ postcode.longitude
47
+ => -1.788422750342563
48
+
49
+ postcode.local_authority
50
+ => {
51
+ gss_code: "E09000003"
52
+ name: "Barnet"
53
+ }
54
+
55
+ postcode.addresses
56
+ =>
57
+ [{"uprn"=>"100121127903",
58
+ "organisation_name"=>"",
59
+ "department_name"=>"",
60
+ "po_box_number"=>"",
61
+ "building_name"=>"",
62
+ "sub_building_name"=>"",
63
+ "building_number"=>45,
64
+ "thoroughfare_name"=>"DEACON STREET",
65
+ "dependent_thoroughfare_name"=>"",
66
+ "dependent_locality"=>"",
67
+ "double_dependent_locality"=>"",
68
+ "post_town"=>"SWINDON",
69
+ "postcode"=>"SN1 5NB",
70
+ "postcode_type"=>"S",
71
+ "formatted_address"=>"45 Deacon Street\nSwindon\nSN1 5NB",
72
+ "point"=>
73
+ {"type"=>"Point", "coordinates"=>[-1.788451994079729, 51.55661047202816]}},
74
+ {"uprn"=>"100121127907",
75
+ "organisation_name"=>"",
76
+ "department_name"=>"",
77
+ "po_box_number"=>"",
78
+ "building_name"=>"48B",
79
+ "sub_building_name"=>"",
80
+ "building_number"=>nil,
81
+ "thoroughfare_name"=>"DEACON STREET",
82
+ "dependent_thoroughfare_name"=>"",
83
+ "dependent_locality"=>"",
84
+ "double_dependent_locality"=>"",
85
+ "post_town"=>"SWINDON",
86
+ "postcode"=>"SN1 5NB",
87
+ "postcode_type"=>"S",
88
+ "formatted_address"=>"48B Deacon Street\nSwindon\nSN1 5NB",
89
+ "point"=>
90
+ {"type"=>"Point", "coordinates"=>[-1.788393506605397, 51.55678120312527]}}]
91
+ ```
92
+
93
+ ## Configuration
94
+
95
+ Apart from the auth_token, there is only one other parameter that the API client needs - api_url.
96
+
97
+ ### Explicit api_url
98
+
99
+ You can set the api_url explicitly by passing it to the client constructor, like this:
100
+ ```ruby
101
+ # create a client
102
+ client = PostcodeInfo::Client.new(api_url: 'https://some.dom.ain/', auth_token: "(your auth token here, without parentheses)")
103
+ ```
104
+ or by setting it on an existing client, like this:
105
+ ```ruby
106
+ # create a client
107
+ client = PostcodeInfo::Client.new(auth_token: "(your auth token here, without parentheses)")
108
+ # then set the api_url separately:
109
+ client.api_url = 'https://some.dom.ain/'
110
+ ```
111
+
112
+ ### Implicit api_url
113
+
114
+ If you don't pass an api_url to the constructor, it will attempt to infer one from the environment. The client
115
+ has a built-in mapping of environment names to URLs:
116
+ ```ruby
117
+ PostcodeInfo::Client.api_urls
118
+ => {
119
+ development: 'http://localhost:8000/',
120
+ test: 'http://localhost:8000/',
121
+ staging: 'https://postcodeinfo.dsd.io/',
122
+ production: 'https://postcodeinfo.service.gov.uk/'
123
+ }
124
+ ```
125
+
126
+ It will use the following rules to infer the URL:
127
+
128
+ 1. If you pass an :env to the constructor (e.g. `client = PostcodeInfo::Client.new(env: 'staging', auth_token:'...')`, it will use that as a reference into the api_urls mapping
129
+ 2. If you don't pass an :env, but ENV['RAILS_ENV'] is set, it will use that value (so if you're using this gem in a Rails app, it should 'just work')
130
+ 3. If neither of the above produce a known environment name, it will default to development
131
+
132
+ ## Support
133
+
134
+ This code is provided as-is, with no incident response or support levels. Please log all questions, issues, and feature requests in the Github issue tracker for this repo, and we'll take a look as soon as we can. If you're reporting a bug, then it really helps if you can provide the smallest possible bit of code that reproduces the issue. A failing rspec example is even better!
135
+
136
+ ## Contributing to postcodeinfo-client-ruby
137
+
138
+ * Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet.
139
+ * Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it.
140
+ * Fork the project.
141
+ * Start a feature/bugfix branch.
142
+ * Commit and push until you are happy with your contribution.
143
+ * Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
144
+ * Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
145
+
146
+ ## Copyright
147
+
148
+ Copyright (C) 2015 HM Government (Ministry of Justice Digital Services). See LICENSE.md for
149
+ further details.
150
+
data/Rakefile ADDED
@@ -0,0 +1,54 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rubygems'
4
+ require 'bundler'
5
+ begin
6
+ Bundler.setup(:default, :development)
7
+ rescue Bundler::BundlerError => e
8
+ $stderr.puts e.message
9
+ $stderr.puts "Run `bundle install` to install missing gems"
10
+ exit e.status_code
11
+ end
12
+ require 'rake'
13
+
14
+ require 'jeweler'
15
+ Jeweler::Tasks.new do |gem|
16
+ # gem is a Gem::Specification... see http://guides.rubygems.org/specification-reference/ for more options
17
+ gem.name = "postcodeinfo-client-ruby"
18
+ gem.homepage = "https://github.com/ministryofjustice/postcodeinfo-client-ruby"
19
+ gem.license = "Open Government License"
20
+ gem.summary = %Q{Client for postcodeinfo API (https://://github.com/ministryofjustice/postcodeinfo)}
21
+ gem.description = %Q{Provides a convenient interface for looking up postcodes in an instance of the MoJ postcodeinfo API (https://://github.com/ministryofjustice/postcodeinfo).
22
+ Lets you check if a postcode is valid, and ookup:
23
+ * all addresses with that postcode
24
+ * the latitude/longitude of its centre point
25
+ * the name & GSS code of the local authority under which it resides.}
26
+ gem.email = "alistair.davidson@digital.justice.gov.uk"
27
+ gem.authors = ["Al Davidson"]
28
+ # dependencies defined in Gemfile
29
+ end
30
+ Jeweler::RubygemsDotOrgTasks.new
31
+
32
+ require 'rspec/core'
33
+ require 'rspec/core/rake_task'
34
+ RSpec::Core::RakeTask.new(:spec) do |spec|
35
+ spec.pattern = FileList['spec/**/*_spec.rb']
36
+ end
37
+
38
+ desc "Code coverage detail"
39
+ task :simplecov do
40
+ ENV['COVERAGE'] = "true"
41
+ Rake::Task['spec'].execute
42
+ end
43
+
44
+ task :default => :spec
45
+
46
+ require 'rdoc/task'
47
+ Rake::RDocTask.new do |rdoc|
48
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
49
+
50
+ rdoc.rdoc_dir = 'rdoc'
51
+ rdoc.title = "postcodeinfo-client-ruby #{version}"
52
+ rdoc.rdoc_files.include('README*')
53
+ rdoc.rdoc_files.include('lib/**/*.rb')
54
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
@@ -0,0 +1,3 @@
1
+ require 'postcodeinfo/client'
2
+ require 'postcodeinfo/postcode'
3
+ require 'postcodeinfo/exceptions'
@@ -0,0 +1,129 @@
1
+ require 'json'
2
+ require 'rest-client'
3
+ require 'postcodeinfo/exceptions'
4
+
5
+ require 'byebug'
6
+
7
+
8
+ module PostcodeInfo
9
+ class Client
10
+
11
+ attr_accessor :auth_token, :api_uri
12
+
13
+ # params:
14
+ # auth_token: 'your auth token' (optional)
15
+ # api_url: 'url of a postcodeinfo server' (optional)
16
+ # If this is not supplied, it will be inferred from the params below
17
+ # If no value can be inferred, it will default to http://localhost:8000/
18
+ # env: (development|test|staging|production) (optional - default is development)
19
+ # If provided, the API url will be looked up in .api_urls by
20
+ # this value.
21
+ # If not provided, it will look for a RAILS_ENV environment variable
22
+ # and use that.
23
+ # If it still can't work out the environment, it will default to development
24
+ def initialize(opts={})
25
+ @auth_token = opts[:auth_token]
26
+ @api_uri = URI.parse(infer_api_url(opts))
27
+ end
28
+
29
+ def api_url
30
+ @api_uri.to_s
31
+ end
32
+
33
+ def api_url=(url)
34
+ @api_uri = URI.parse(url)
35
+ end
36
+
37
+ def lookup_postcode(postcode)
38
+ begin
39
+ pc = Postcode.new(postcode, self)
40
+ pc.lookup_info!
41
+ pc.lookup_addresses!
42
+ pc
43
+ rescue RestClient::ResourceNotFound => e
44
+ raise PostcodeInfo::UnrecognisedPostcode.new(e, nil)
45
+ end
46
+ end
47
+
48
+ def valid?(postcode)
49
+ begin
50
+ response = make_request('/postcodes/' + postcode)
51
+ case response.code
52
+ when 200 then true
53
+ when /^5[0-9]{2}/ then nil
54
+ when 404 then false
55
+ end
56
+
57
+ rescue RestClient::ResourceNotFound => e
58
+ false
59
+ end
60
+ end
61
+
62
+ def addresses(postcode)
63
+ response = make_request('/addresses/?postcode=' + postcode)
64
+ handle_response(response)
65
+ end
66
+
67
+ def info(postcode)
68
+ response = make_request('/postcodes/' + postcode)
69
+ handle_response(response)
70
+ end
71
+
72
+ def make_request(endpoint)
73
+ headers = {
74
+ 'Authorization' => 'Token ' + @auth_token
75
+ }
76
+ begin
77
+ response = RestClient::Request.execute( method: :get,
78
+ url: URI.join(@api_uri, endpoint).to_s,
79
+ headers: headers,
80
+ timeout: 5
81
+ )
82
+
83
+ rescue Exception => ex
84
+ raise wrapped_exception(ex, response)
85
+ end
86
+ end
87
+
88
+ protected
89
+
90
+ def wrapped_exception(exception, response)
91
+ case exception
92
+ when RestClient::Unauthorized
93
+ PostcodeInfo::InvalidAuthToken.new(exception, response)
94
+ when RestClient::InternalServerError
95
+ PostcodeInfo::ServerError.new(exception, response)
96
+ when SocketError
97
+ PostcodeInfo::ServiceUnavailable.new(exception, response)
98
+ else
99
+ exception
100
+ end
101
+ end
102
+
103
+ def handle_response(response)
104
+ JSON.parse(response.body, symbolize_names: true)
105
+ end
106
+
107
+ def infer_api_url(opts={})
108
+ opts[:api_url] ||
109
+ from_env( effective_env(opts) )
110
+ end
111
+
112
+ def effective_env(opts)
113
+ opts[:env] || ENV['RAILS_ENV'] || :development
114
+ end
115
+
116
+ def from_env(env)
117
+ self.class.api_urls[env.to_sym] || self.class.api_urls[:development]
118
+ end
119
+
120
+ def self.api_urls
121
+ {
122
+ development: 'http://localhost:8000/',
123
+ test: 'http://localhost:8000/',
124
+ staging: 'https://postcodeinfo.dsd.io/',
125
+ production: 'https://postcodeinfo.service.gov.uk/'
126
+ }
127
+ end
128
+ end
129
+ end