defra_ruby_validators 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: 423deb6f44961525a9612a533db996555e296701
4
+ data.tar.gz: 3b0e8e06f17f4e5fb7999ab5e684f76453fe792d
5
+ SHA512:
6
+ metadata.gz: 86868cd7dd7b19ea0b7112599c90c534151f02491fafc1af0e3fdeb816c3ff9e90f4299b196f323da3e4791431146a1c7d8acf58295b9bc7ed7d2caffa099bdf
7
+ data.tar.gz: b39a209754d3676202d5b2c95d7af7d11a2228b3befd60c68d3084b60b0de6a9bfbdca304354864a669555bcbbcf32c9e97780f140569e1f697c1780652dc2e8
data/LICENSE ADDED
@@ -0,0 +1,8 @@
1
+ The Open Government Licence (OGL) Version 3
2
+
3
+ Copyright (c) 2019 Environment Agency
4
+
5
+ This source code is licensed under the Open Government Licence v3.0. To view this
6
+ licence, visit www.nationalarchives.gov.uk/doc/open-government-licence/version/3
7
+ or write to the Information Policy Team, The National Archives, Kew, Richmond,
8
+ Surrey, TW9 4DU.
data/README.md ADDED
@@ -0,0 +1,87 @@
1
+ <img src="/defra-ruby-validators.png" alt="Defra ruby validators logo" />
2
+
3
+ [![Build Status](https://travis-ci.com/DEFRA/defra-ruby-validators.svg?branch=master)](https://travis-ci.com/DEFRA/defra-ruby-validators)
4
+ [![Maintainability](https://api.codeclimate.com/v1/badges/a0f8611f1a879786f642/maintainability)](https://codeclimate.com/github/DEFRA/defra-ruby-validators/maintainability)
5
+ [![Test Coverage](https://api.codeclimate.com/v1/badges/a0f8611f1a879786f642/test_coverage)](https://codeclimate.com/github/DEFRA/defra-ruby-validators/test_coverage)
6
+ [![Licence](https://img.shields.io/badge/Licence-OGLv3-blue.svg)](http://www.nationalarchives.gov.uk/doc/open-government-licence/version/3)
7
+
8
+ Package of validations commonly used in Defra Rails based digital services.
9
+
10
+ ## Installation
11
+
12
+ Add this line to your application's Gemfile
13
+
14
+ ```ruby
15
+ gem "defra_ruby_validators"
16
+ ```
17
+
18
+ And then update your dependencies by calling
19
+
20
+ ```bash
21
+ bundle install
22
+ ```
23
+
24
+ ## Usage
25
+
26
+ With this gem installed, a number of active model based validators become available.
27
+
28
+ ### Companies House number
29
+
30
+ This validator checks the company registration number provided. Specifically it first checks that it matches a known format. All registration numbers are 8 characters long but can be formatted in the following ways.
31
+
32
+ - 09764739
33
+ - 10997904
34
+ - SC534714
35
+ - IP00141R
36
+
37
+ If the format is valid, it then makes a call to Companies House to validate that the number
38
+
39
+ - is recognised
40
+ - belongs to an 'active' company
41
+
42
+ A company can be in various states for example liquidation, which means for the purposes of Defra its not a valid entity. So we check the status along with the number as part of the validation.
43
+
44
+ Add it to your model or form object using
45
+
46
+ ```ruby
47
+ validates :company_no, "defra_ruby_validators/companies_house_number": true
48
+ ```
49
+
50
+ A locale hint plus help text is also available for your views, that details what a registration number is and the restrictions, e.g
51
+
52
+ ```erb
53
+ <span class="form-hint"><%= t("defra_validators.companies_house_number.hint") %></span>
54
+
55
+ <div class="form-group">
56
+ <details>
57
+ <summary>
58
+ <span class="summary"><%= t("defra_validators.companies_house_number.help.heading") %></span>
59
+ </summary>
60
+ <div class="panel panel-border-narrow">
61
+ <p><%= t("defra_validators.companies_house_number.help.#{@form.business_type}") %></p>
62
+ </div>
63
+ </details>
64
+ </div>
65
+ ```
66
+
67
+ ## Contributing to this project
68
+
69
+ If you have an idea you'd like to contribute please log an issue.
70
+
71
+ All contributions should be submitted via a pull request.
72
+
73
+ ## License
74
+
75
+ THIS INFORMATION IS LICENSED UNDER THE CONDITIONS OF THE OPEN GOVERNMENT LICENCE found at:
76
+
77
+ http://www.nationalarchives.gov.uk/doc/open-government-licence/version/3
78
+
79
+ The following attribution statement MUST be cited in your products and applications when using this information.
80
+
81
+ > Contains public sector information licensed under the Open Government license v3
82
+
83
+ ### About the license
84
+
85
+ The Open Government Licence (OGL) was developed by the Controller of Her Majesty's Stationery Office (HMSO) to enable information providers in the public sector to license the use and re-use of their information under a common open licence.
86
+
87
+ It is designed to encourage use and re-use of information freely and flexibly, with only a few conditions.
data/Rakefile ADDED
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ begin
4
+ require "bundler/setup"
5
+ rescue LoadError
6
+ puts "You must `gem install bundler` and `bundle install` to run rake tasks"
7
+ end
8
+
9
+ Bundler::GemHelper.install_tasks
10
+
11
+ # This is wrapped to prevent an error when rake is called in environments where
12
+ # rspec may not be available, e.g. production. As such we don't need to handle
13
+ # the error.
14
+ # rubocop:disable Lint/HandleExceptions
15
+ begin
16
+ require "rspec/core/rake_task"
17
+
18
+ RSpec::Core::RakeTask.new(:spec)
19
+
20
+ task default: :spec
21
+ rescue LoadError
22
+ # no rspec available
23
+ end
24
+
25
+ begin
26
+ require "github_changelog_generator/task"
27
+
28
+ GitHubChangelogGenerator::RakeTask.new :changelog do |config|
29
+ end
30
+ rescue LoadError
31
+ # no changelog available
32
+ end
33
+ # rubocop:enable Lint/HandleExceptions
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "defra/ruby/validators"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "defra_ruby_validators/engine"
4
+
5
+ module DefraRubyValidators
6
+ # See lib/defra_ruby_validators/validators.rb for the main content.
7
+ # We have this file which just require's engine.rb to support using the gem
8
+ # in a rails project.
9
+ # For our test suite, we just want the typical listing of `require "filex"`,
10
+ # as the engine references using Rails.
11
+ # We also have the gem setup to support being configured from the host app.
12
+ # This is all done in `validators.rb`, which is picked up by `engine.rb` as
13
+ # well.
14
+ end
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DefraRubyValidators
4
+ class CompaniesHouseNumberValidator < ActiveModel::EachValidator
5
+
6
+ # Examples we need to validate are
7
+ # 10997904, 09764739
8
+ # SC534714, CE000958
9
+ # IP00141R, IP27702R, SP02252R
10
+ # https://assets.publishing.service.gov.uk/government/uploads/system/uploads/attachment_data/file/426891/uniformResourceIdentifiersCustomerGuide.pdf
11
+ VALID_COMPANIES_HOUSE_REGISTRATION_NUMBER_REGEX = Regexp.new(
12
+ /\A(\d{8,8}$)|([a-zA-Z]{2}\d{6}$)|([a-zA-Z]{2}\d{5}[a-zA-Z]{1}$)\z/i
13
+ ).freeze
14
+
15
+ def validate_each(record, attribute, value)
16
+ return false unless value_is_present?(record, attribute, value)
17
+ return false unless format_is_valid?(record, attribute, value)
18
+
19
+ validate_with_companies_house(record, attribute, value)
20
+ end
21
+
22
+ private
23
+
24
+ def value_is_present?(record, attribute, value)
25
+ return true if value.present?
26
+
27
+ record.errors[attribute] << error_message("blank")
28
+ false
29
+ end
30
+
31
+ def format_is_valid?(record, attribute, value)
32
+ return true if value.match?(VALID_COMPANIES_HOUSE_REGISTRATION_NUMBER_REGEX)
33
+
34
+ record.errors[attribute] << error_message("invalid")
35
+ false
36
+ end
37
+
38
+ def validate_with_companies_house(record, attribute, value)
39
+ case CompaniesHouseService.new(value).status
40
+ when :active
41
+ true
42
+ when :inactive
43
+ record.errors[attribute] << error_message("inactive")
44
+ when :not_found
45
+ record.errors[attribute] << error_message("not_found")
46
+ end
47
+ rescue StandardError
48
+ record.errors[attribute] << error_message("error")
49
+ end
50
+
51
+ def error_message(error)
52
+ I18n.t("defra_ruby_validators.companies_house_number.errors.#{error}")
53
+ end
54
+
55
+ end
56
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rest-client"
4
+
5
+ module DefraRubyValidators
6
+ class CompaniesHouseService
7
+ def initialize(company_no)
8
+ @company_no = company_no
9
+ @url = "#{DefraRubyValidators.configuration.companies_house_host}#{@company_no}"
10
+ @api_key = DefraRubyValidators.configuration.companies_house_api_key
11
+ end
12
+
13
+ def status
14
+ response = RestClient::Request.execute(
15
+ method: :get,
16
+ url: @url,
17
+ user: @api_key,
18
+ password: ""
19
+ )
20
+
21
+ json = JSON.parse(response)
22
+
23
+ status_is_allowed?(json["company_status"]) ? :active : :inactive
24
+ rescue RestClient::ResourceNotFound
25
+ :not_found
26
+ end
27
+
28
+ private
29
+
30
+ def status_is_allowed?(status)
31
+ %w[active voluntary-arrangement].include?(status)
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "defra_ruby_validators/validators"
4
+
5
+ module DefraRubyValidators
6
+ # Engine used to load in the custom validations
7
+ class Engine < ::Rails::Engine
8
+ isolate_namespace DefraRubyValidators
9
+
10
+ # Add a load path for this specific Engine
11
+ config.autoload_paths += Dir[File.join(config.root, "lib", "**")]
12
+
13
+ # Load I18n translation files from engine before loading ones from the host app
14
+ # This means values in the host app can override those in the engine
15
+ config.before_initialize do
16
+ engine_locales = Dir["#{config.root}/config/locales/**/*.yml"]
17
+ config.i18n.load_path = engine_locales + config.i18n.load_path
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_model"
4
+ require "defra_ruby_validators/version"
5
+ require "defra_ruby_validators/companies_house_service"
6
+
7
+ require "defra_ruby_validators/companies_house_number_validator"
8
+
9
+ module DefraRubyValidators
10
+ # Enable the ability to configure the gem from its host app, rather than
11
+ # reading directly from env vars. Derived from
12
+ # https://robots.thoughtbot.com/mygem-configure-block
13
+ class << self
14
+ attr_writer :configuration
15
+
16
+ def configuration
17
+ @configuration ||= Configuration.new
18
+ end
19
+ end
20
+
21
+ def self.configure
22
+ yield(configuration)
23
+ end
24
+
25
+ class Configuration
26
+ attr_accessor :companies_house_host, :companies_house_api_key
27
+
28
+ def initialize
29
+ @companies_house_host = "https://api.companieshouse.gov.uk/company/"
30
+ @companies_house_api_key = nil
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DefraRubyValidators
4
+ VERSION = "0.1.0"
5
+ end
@@ -0,0 +1,67 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: get
5
+ uri: https://api.companieshouse.gov.uk/company/07281919
6
+ body:
7
+ encoding: US-ASCII
8
+ string: ''
9
+ headers:
10
+ Accept:
11
+ - "*/*"
12
+ Accept-Encoding:
13
+ - gzip, deflate
14
+ User-Agent:
15
+ - rest-client/2.0.2 (darwin17.3.0 x86_64) ruby/2.4.2p198
16
+ Host:
17
+ - api.companieshouse.gov.uk
18
+ Authorization:
19
+ - Basic MnZodWowb1dhYk13N2h6TnpBVWlTT2ctNktpVVRCcFhCRF83Zktibzo=
20
+ response:
21
+ status:
22
+ code: 200
23
+ message: OK
24
+ headers:
25
+ Date:
26
+ - Mon, 28 Jan 2019 09:38:50 GMT
27
+ Content-Type:
28
+ - application/json
29
+ Content-Length:
30
+ - '979'
31
+ Connection:
32
+ - keep-alive
33
+ Access-Control-Allow-Credentials:
34
+ - 'true'
35
+ Access-Control-Allow-Headers:
36
+ - X-RateLimit-Query, origin, content-type, content-length, user-agent, host,
37
+ accept, authorization
38
+ Access-Control-Expose-Headers:
39
+ - Location,www-authenticate,cache-control,pragma,content-type,expires,last-modified
40
+ - X-RateLimit-Window, X-RateLimit-Limit, X-RateLimit-Remain, X-RateLimit-Reset,
41
+ Location, www-authenticate, cache-control, pragma, content-type, expires,
42
+ last-modified
43
+ Access-Control-Max-Age:
44
+ - '3600'
45
+ Cache-Control:
46
+ - no-store, no-cache, must-revalidate, post-check=0, pre-check=0
47
+ Pragma:
48
+ - no-cache
49
+ X-Ratelimit-Limit:
50
+ - '600'
51
+ X-Ratelimit-Remain:
52
+ - '596'
53
+ X-Ratelimit-Reset:
54
+ - '1548668445'
55
+ X-Ratelimit-Window:
56
+ - 5m
57
+ Server:
58
+ - CompaniesHouse
59
+ body:
60
+ encoding: UTF-8
61
+ string: '{"sic_codes":["82990"],"company_number":"07281919","has_been_liquidated":false,"accounts":{"last_accounts":{"made_up_to":"2013-06-30","type":"total-exemption-small"},"accounting_reference_date":{"day":"30","month":"06"}},"last_full_members_list_date":"2014-06-11","status":"active","type":"ltd","date_of_creation":"2010-06-11","registered_office_address":{"postal_code":"HA8
62
+ 7EJ","locality":"Edgware","region":"Middlesex","address_line_1":"8th Floor
63
+ Elizabeth House","address_line_2":"54-58 High Street"},"undeliverable_registered_office_address":false,"company_name":"DIRECT
64
+ SKIPS UK LTD","annual_return":{"last_made_up_to":"2014-06-11"},"jurisdiction":"england-wales","etag":"1cdef5bc2a020b3e9003b086033b64b78bcb28f6","company_status":"dissolved","has_insolvency_history":false,"has_charges":false,"links":{"self":"/company/07281919","filing_history":"/company/07281919/filing-history","officers":"/company/07281919/officers"},"date_of_cessation":"2016-01-05","can_file":false}'
65
+ http_version:
66
+ recorded_at: Mon, 28 Jan 2019 09:38:50 GMT
67
+ recorded_with: VCR 4.0.0
@@ -0,0 +1,64 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: get
5
+ uri: https://api.companieshouse.gov.uk/company/99999999
6
+ body:
7
+ encoding: US-ASCII
8
+ string: ''
9
+ headers:
10
+ Accept:
11
+ - "*/*"
12
+ Accept-Encoding:
13
+ - gzip, deflate
14
+ User-Agent:
15
+ - rest-client/2.0.2 (darwin17.3.0 x86_64) ruby/2.4.2p198
16
+ Host:
17
+ - api.companieshouse.gov.uk
18
+ Authorization:
19
+ - Basic MnZodWowb1dhYk13N2h6TnpBVWlTT2ctNktpVVRCcFhCRF83Zktibzo=
20
+ response:
21
+ status:
22
+ code: 404
23
+ message: Not Found
24
+ headers:
25
+ Date:
26
+ - Mon, 28 Jan 2019 09:38:50 GMT
27
+ Content-Type:
28
+ - application/json
29
+ Content-Length:
30
+ - '70'
31
+ Connection:
32
+ - keep-alive
33
+ Access-Control-Allow-Credentials:
34
+ - 'true'
35
+ Access-Control-Allow-Headers:
36
+ - X-RateLimit-Query, origin, content-type, content-length, user-agent, host,
37
+ accept, authorization
38
+ Access-Control-Expose-Headers:
39
+ - Location,www-authenticate,cache-control,pragma,content-type,expires,last-modified
40
+ - X-RateLimit-Window, X-RateLimit-Limit, X-RateLimit-Remain, X-RateLimit-Reset,
41
+ Location, www-authenticate, cache-control, pragma, content-type, expires,
42
+ last-modified
43
+ Access-Control-Max-Age:
44
+ - '3600'
45
+ Cache-Control:
46
+ - no-store, no-cache, must-revalidate, post-check=0, pre-check=0
47
+ Pragma:
48
+ - no-cache
49
+ X-Ratelimit-Limit:
50
+ - '600'
51
+ X-Ratelimit-Remain:
52
+ - '597'
53
+ X-Ratelimit-Reset:
54
+ - '1548668445'
55
+ X-Ratelimit-Window:
56
+ - 5m
57
+ Server:
58
+ - CompaniesHouse
59
+ body:
60
+ encoding: UTF-8
61
+ string: '{"errors":[{"error":"company-profile-not-found","type":"ch:service"}]}'
62
+ http_version:
63
+ recorded_at: Mon, 28 Jan 2019 09:38:50 GMT
64
+ recorded_with: VCR 4.0.0
@@ -0,0 +1,65 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: get
5
+ uri: https://api.companieshouse.gov.uk/company/09360070
6
+ body:
7
+ encoding: US-ASCII
8
+ string: ''
9
+ headers:
10
+ Accept:
11
+ - "*/*"
12
+ Accept-Encoding:
13
+ - gzip, deflate
14
+ User-Agent:
15
+ - rest-client/2.0.2 (darwin17.3.0 x86_64) ruby/2.4.2p198
16
+ Host:
17
+ - api.companieshouse.gov.uk
18
+ Authorization:
19
+ - Basic MnZodWowb1dhYk13N2h6TnpBVWlTT2ctNktpVVRCcFhCRF83Zktibzo=
20
+ response:
21
+ status:
22
+ code: 200
23
+ message: OK
24
+ headers:
25
+ Date:
26
+ - Sun, 27 Jan 2019 23:57:58 GMT
27
+ Content-Type:
28
+ - application/json
29
+ Content-Length:
30
+ - '1178'
31
+ Connection:
32
+ - keep-alive
33
+ Access-Control-Allow-Credentials:
34
+ - 'true'
35
+ Access-Control-Allow-Headers:
36
+ - X-RateLimit-Query, origin, content-type, content-length, user-agent, host,
37
+ accept, authorization
38
+ Access-Control-Expose-Headers:
39
+ - Location,www-authenticate,cache-control,pragma,content-type,expires,last-modified
40
+ - X-RateLimit-Window, X-RateLimit-Limit, X-RateLimit-Remain, X-RateLimit-Reset,
41
+ Location, www-authenticate, cache-control, pragma, content-type, expires,
42
+ last-modified
43
+ Access-Control-Max-Age:
44
+ - '3600'
45
+ Cache-Control:
46
+ - no-store, no-cache, must-revalidate, post-check=0, pre-check=0
47
+ Pragma:
48
+ - no-cache
49
+ X-Ratelimit-Limit:
50
+ - '600'
51
+ X-Ratelimit-Remain:
52
+ - '598'
53
+ X-Ratelimit-Reset:
54
+ - '1548633621'
55
+ X-Ratelimit-Window:
56
+ - 5m
57
+ Server:
58
+ - CompaniesHouse
59
+ body:
60
+ encoding: UTF-8
61
+ string: '{"type":"ltd","company_name":"0800 WASTE LTD.","has_insolvency_history":false,"accounts":{"next_due":"2019-09-30","next_made_up_to":"2018-12-31","next_accounts":{"overdue":false,"period_start_on":"2018-01-01","due_on":"2019-09-30","period_end_on":"2018-12-31"},"accounting_reference_date":{"month":"12","day":"31"},"last_accounts":{"period_end_on":"2017-12-31","period_start_on":"2017-01-01","made_up_to":"2017-12-31"},"overdue":false},"undeliverable_registered_office_address":false,"etag":"0ec9d00cab0ffee2ef1f5d59f4f714fa5b1618f5","company_number":"09360070","registered_office_address":{"postal_code":"SM3
62
+ 9ND","locality":"Sutton","region":"Surrey","address_line_1":"21 Haslam Avenue"},"jurisdiction":"england-wales","date_of_creation":"2014-12-18","company_status":"active","has_charges":false,"sic_codes":["38110"],"last_full_members_list_date":"2015-12-18","confirmation_statement":{"overdue":false,"next_made_up_to":"2020-01-23","last_made_up_to":"2019-01-23","next_due":"2020-02-06"},"links":{"self":"/company/09360070","filing_history":"/company/09360070/filing-history","officers":"/company/09360070/officers"},"registered_office_is_in_dispute":false,"can_file":true}'
63
+ http_version:
64
+ recorded_at: Sun, 27 Jan 2019 23:57:58 GMT
65
+ recorded_with: VCR 4.0.0
@@ -0,0 +1,125 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DefraRubyValidators
4
+ RSpec.describe CompaniesHouseNumberValidator do
5
+ context "when given a valid company number" do
6
+ before do
7
+ allow_any_instance_of(CompaniesHouseService).to receive(:status).and_return(:active)
8
+ end
9
+
10
+ %w[10997904 09764739 SC534714 IP00141R].each do |company_no|
11
+ context "like #{company_no}" do
12
+ it "confirms the number is valid" do
13
+ expect(DummyCompaniesHouseNumber.new(company_no)).to be_valid
14
+ end
15
+ end
16
+ end
17
+ end
18
+
19
+ context "when given an invalid company number" do
20
+ context "because it is blank" do
21
+ subject { DummyCompaniesHouseNumber.new("") }
22
+
23
+ it "confirms the number is not valid" do
24
+ expect(subject).to_not be_valid
25
+ end
26
+ it "adds an error to the subject's errors collection" do
27
+ subject.valid?
28
+ expect(subject.errors.count).to eq(1)
29
+ end
30
+ it "adds an error with the correct message" do
31
+ subject.valid?
32
+ expect(subject.errors[:company_no][0]).to eq(I18n.t("defra_ruby_validators.companies_house_number.errors.blank"))
33
+ end
34
+ end
35
+
36
+ context "because the format is wrong" do
37
+ subject { DummyCompaniesHouseNumber.new("foobar42") }
38
+
39
+ it "confirms the number is not valid" do
40
+ expect(subject).to_not be_valid
41
+ end
42
+ it "adds an error to the subject's errors collection" do
43
+ subject.valid?
44
+ expect(subject.errors.count).to eq(1)
45
+ end
46
+ it "adds an error with the correct message" do
47
+ subject.valid?
48
+ expect(subject.errors[:company_no][0]).to eq(I18n.t("defra_ruby_validators.companies_house_number.errors.invalid"))
49
+ end
50
+ end
51
+
52
+ context "because it's not found on companies house" do
53
+ before do
54
+ allow_any_instance_of(CompaniesHouseService).to receive(:status).and_return(:not_found)
55
+ end
56
+
57
+ subject { DummyCompaniesHouseNumber.new("99999999") }
58
+
59
+ it "confirms the number is not valid" do
60
+ expect(subject).to_not be_valid
61
+ end
62
+ it "adds an error to the subject's errors collection" do
63
+ subject.valid?
64
+ expect(subject.errors.count).to eq(1)
65
+ end
66
+ it "adds an error with the correct message" do
67
+ subject.valid?
68
+ expect(subject.errors[:company_no][0]).to eq(I18n.t("defra_ruby_validators.companies_house_number.errors.not_found"))
69
+ end
70
+ end
71
+
72
+ context "because it's not 'active' on companies house" do
73
+ before do
74
+ allow_any_instance_of(CompaniesHouseService).to receive(:status).and_return(:inactive)
75
+ end
76
+
77
+ subject { DummyCompaniesHouseNumber.new("07281919") }
78
+
79
+ it "confirms the number is not valid" do
80
+ expect(subject).to_not be_valid
81
+ end
82
+ it "adds an error to the subject's errors collection" do
83
+ subject.valid?
84
+ expect(subject.errors.count).to eq(1)
85
+ end
86
+ it "adds an error with the correct message" do
87
+ subject.valid?
88
+ expect(subject.errors[:company_no][0]).to eq(I18n.t("defra_ruby_validators.companies_house_number.errors.inactive"))
89
+ end
90
+ end
91
+ end
92
+
93
+ context "when there is an error connecting with companies house" do
94
+ before do
95
+ allow_any_instance_of(CompaniesHouseService).to receive(:status).and_raise(StandardError)
96
+ end
97
+
98
+ subject { DummyCompaniesHouseNumber.new("10997904") }
99
+
100
+ it "confirms the number is not valid" do
101
+ expect(subject).to_not be_valid
102
+ end
103
+ it "adds an error to the subject's errors collection" do
104
+ subject.valid?
105
+ expect(subject.errors.count).to eq(1)
106
+ end
107
+ it "adds an error with the correct message" do
108
+ subject.valid?
109
+ expect(subject.errors[:company_no][0]).to eq(I18n.t("defra_ruby_validators.companies_house_number.errors.error"))
110
+ end
111
+ end
112
+
113
+ class DummyCompaniesHouseNumber
114
+ include ActiveModel::Model
115
+
116
+ attr_accessor :company_no
117
+
118
+ def initialize(company_no)
119
+ @company_no = company_no
120
+ end
121
+
122
+ validates :company_no, "defra_ruby_validators/companies_house_number": true
123
+ end
124
+ end
125
+ end
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DefraRubyValidators
4
+ RSpec.describe CompaniesHouseService do
5
+ let(:companies_house_service) { CompaniesHouseService.new("09360070") }
6
+
7
+ context "when a company_no is for an active company" do
8
+ it "returns :active" do
9
+ VCR.use_cassette("company_no_valid") do
10
+ expect(companies_house_service.status).to eq(:active)
11
+ end
12
+ end
13
+ end
14
+
15
+ context "when a company_no is not found" do
16
+ let(:companies_house_service) { CompaniesHouseService.new("99999999") }
17
+
18
+ it "returns :not_found" do
19
+ VCR.use_cassette("company_no_not_found") do
20
+ expect(companies_house_service.status).to eq(:not_found)
21
+ end
22
+ end
23
+ end
24
+
25
+ context "when a company_no is inactive" do
26
+ let(:companies_house_service) { CompaniesHouseService.new("07281919") }
27
+
28
+ it "returns :inactive" do
29
+ VCR.use_cassette("company_no_inactive") do
30
+ expect(companies_house_service.status).to eq(:inactive)
31
+ end
32
+ end
33
+ end
34
+
35
+ context "when the request times out" do
36
+ it "raises an exception" do
37
+ VCR.turned_off do
38
+ host = "https://api.companieshouse.gov.uk/"
39
+ stub_request(:any, /.*#{host}.*/).to_timeout
40
+ expect { companies_house_service.status }.to raise_error(StandardError)
41
+ end
42
+ end
43
+ end
44
+
45
+ context "when the request returns an error" do
46
+ it "raises an exception" do
47
+ VCR.turned_off do
48
+ host = "https://api.companieshouse.gov.uk/"
49
+ stub_request(:any, /.*#{host}.*/).to_raise(SocketError)
50
+ expect { companies_house_service.status }.to raise_error(StandardError)
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe DefraRubyValidators do
4
+ it "has a version number" do
5
+ expect(DefraRubyValidators::VERSION).not_to be nil
6
+ end
7
+ end
data/spec/examples.txt ADDED
@@ -0,0 +1,15 @@
1
+ example_id | status | run_time |
2
+ ------------------------------------------------------------------------------ | ------ | ---------------------- |
3
+ ./spec/defra_ruby_validators/companies_house_number_validator_spec.rb[1:1:1:1] | passed | 0.02962 seconds |
4
+ ./spec/defra_ruby_validators/companies_house_number_validator_spec.rb[1:1:2:1] | passed | 0.00043 seconds |
5
+ ./spec/defra_ruby_validators/companies_house_number_validator_spec.rb[1:1:3:1] | passed | 0.00026 seconds |
6
+ ./spec/defra_ruby_validators/companies_house_number_validator_spec.rb[1:1:4:1] | passed | 0.00026 seconds |
7
+ ./spec/defra_ruby_validators/companies_house_number_validator_spec.rb[1:2:1:1] | passed | 0.01795 seconds |
8
+ ./spec/defra_ruby_validators/companies_house_number_validator_spec.rb[1:2:1:2] | passed | 1 minute 29.46 seconds |
9
+ ./spec/defra_ruby_validators/companies_house_number_validator_spec.rb[1:2:2:1] | failed | 0.02416 seconds |
10
+ ./spec/defra_ruby_validators/companies_house_service_spec.rb[1:1:1] | passed | 0.0289 seconds |
11
+ ./spec/defra_ruby_validators/companies_house_service_spec.rb[1:2:1] | passed | 0.01738 seconds |
12
+ ./spec/defra_ruby_validators/companies_house_service_spec.rb[1:3:1] | passed | 0.01767 seconds |
13
+ ./spec/defra_ruby_validators/companies_house_service_spec.rb[1:4:1] | passed | 0.01833 seconds |
14
+ ./spec/defra_ruby_validators/companies_house_service_spec.rb[1:5:1] | passed | 0.01512 seconds |
15
+ ./spec/defra_ruby_validators/version_spec.rb[1:1] | passed | 0.00209 seconds |
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/setup"
4
+
5
+ # Test coverage reporting
6
+ require "simplecov"
7
+ SimpleCov.start
8
+
9
+ # Support debugging in the tests
10
+ require "byebug"
11
+ # Load env vars from a text file
12
+ require "dotenv/load"
13
+ # Need to require our actual code files
14
+ require "defra_ruby_validators/validators"
15
+
16
+ # The following line is provided for convenience purposes. It has the downside
17
+ # of increasing the boot-up time by auto-requiring all files in the support
18
+ # directory. However in a small gem like this the increase should be neglible
19
+ Dir[File.join(__dir__, "support", "**", "*.rb")].each { |f| require f }
20
+
21
+ RSpec.configure do |config|
22
+ # Allows RSpec to persist some state between runs in order to support
23
+ # the `--only-failures` and `--next-failure` CLI options. We recommend
24
+ # you configure your source control system to ignore this file.
25
+ config.example_status_persistence_file_path = "spec/examples.txt"
26
+
27
+ # Disable RSpec exposing methods globally on `Module` and `main`
28
+ config.disable_monkey_patching!
29
+
30
+ config.expect_with :rspec do |c|
31
+ c.syntax = :expect
32
+ end
33
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ DefraRubyValidators.configure do |configuration|
4
+ configuration.companies_house_api_key = ENV["COMPANIES_HOUSE_API_KEY"]
5
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Support using the locale files within our tests (else we'd rely on loading the
4
+ # gem in a rails app to confirm these are being pulled through correctly.)
5
+ require "i18n"
6
+
7
+ I18n.load_path << Dir[File.expand_path("config/locales") + "/**/*.yml"]
8
+ I18n.default_locale = :en
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Stubbing HTTP requests
4
+ require "webmock/rspec"
5
+ # Auto generate fake responses for web-requests
6
+ require "vcr"
7
+
8
+ VCR.configure do |c|
9
+ c.cassette_library_dir = "spec/cassettes"
10
+ c.hook_into :webmock
11
+
12
+ c.ignore_hosts "127.0.0.1", "codeclimate.com"
13
+
14
+ SECONDS_IN_DAY = 24 * 60 * 60
15
+
16
+ c.default_cassette_options = { re_record_interval: (14 * SECONDS_IN_DAY) }
17
+
18
+ # Strip out authorization info
19
+ c.filter_sensitive_data("Basic <API_KEY>") do |interaction|
20
+ auth = interaction.request.headers["Authorization"]
21
+ auth.first if auth.nil? || auth.empty?
22
+ end
23
+ end
metadata ADDED
@@ -0,0 +1,260 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: defra_ruby_validators
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Defra
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2019-01-30 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activemodel
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rest-client
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '2.0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '2.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: byebug
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: defra_ruby_style
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: dotenv
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: github_changelog_generator
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: i18n
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: rake
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: rspec
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: '3.0'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - "~>"
137
+ - !ruby/object:Gem::Version
138
+ version: '3.0'
139
+ - !ruby/object:Gem::Dependency
140
+ name: rubocop
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - ">="
144
+ - !ruby/object:Gem::Version
145
+ version: '0'
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - ">="
151
+ - !ruby/object:Gem::Version
152
+ version: '0'
153
+ - !ruby/object:Gem::Dependency
154
+ name: simplecov
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - ">="
158
+ - !ruby/object:Gem::Version
159
+ version: '0'
160
+ type: :development
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - ">="
165
+ - !ruby/object:Gem::Version
166
+ version: '0'
167
+ - !ruby/object:Gem::Dependency
168
+ name: vcr
169
+ requirement: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - "~>"
172
+ - !ruby/object:Gem::Version
173
+ version: '4.0'
174
+ type: :development
175
+ prerelease: false
176
+ version_requirements: !ruby/object:Gem::Requirement
177
+ requirements:
178
+ - - "~>"
179
+ - !ruby/object:Gem::Version
180
+ version: '4.0'
181
+ - !ruby/object:Gem::Dependency
182
+ name: webmock
183
+ requirement: !ruby/object:Gem::Requirement
184
+ requirements:
185
+ - - "~>"
186
+ - !ruby/object:Gem::Version
187
+ version: '3.4'
188
+ type: :development
189
+ prerelease: false
190
+ version_requirements: !ruby/object:Gem::Requirement
191
+ requirements:
192
+ - - "~>"
193
+ - !ruby/object:Gem::Version
194
+ version: '3.4'
195
+ description: Package of validations commonly used in Defra Rails based digital services
196
+ email:
197
+ - alan.cruikshanks@environment-agency.gov.uk
198
+ executables: []
199
+ extensions: []
200
+ extra_rdoc_files: []
201
+ files:
202
+ - LICENSE
203
+ - README.md
204
+ - Rakefile
205
+ - bin/console
206
+ - bin/setup
207
+ - lib/defra_ruby_validators.rb
208
+ - lib/defra_ruby_validators/companies_house_number_validator.rb
209
+ - lib/defra_ruby_validators/companies_house_service.rb
210
+ - lib/defra_ruby_validators/engine.rb
211
+ - lib/defra_ruby_validators/validators.rb
212
+ - lib/defra_ruby_validators/version.rb
213
+ - spec/cassettes/company_no_inactive.yml
214
+ - spec/cassettes/company_no_not_found.yml
215
+ - spec/cassettes/company_no_valid.yml
216
+ - spec/defra_ruby_validators/companies_house_number_validator_spec.rb
217
+ - spec/defra_ruby_validators/companies_house_service_spec.rb
218
+ - spec/defra_ruby_validators/version_spec.rb
219
+ - spec/examples.txt
220
+ - spec/spec_helper.rb
221
+ - spec/support/defra_ruby_validators.rb
222
+ - spec/support/i18n.rb
223
+ - spec/support/vcr.rb
224
+ homepage: https://github.com/DEFRA/defra-ruby-validators
225
+ licenses:
226
+ - The Open Government Licence (OGL) Version 3
227
+ metadata:
228
+ allowed_push_host: https://rubygems.org
229
+ post_install_message:
230
+ rdoc_options: []
231
+ require_paths:
232
+ - lib
233
+ required_ruby_version: !ruby/object:Gem::Requirement
234
+ requirements:
235
+ - - ">="
236
+ - !ruby/object:Gem::Version
237
+ version: '0'
238
+ required_rubygems_version: !ruby/object:Gem::Requirement
239
+ requirements:
240
+ - - ">="
241
+ - !ruby/object:Gem::Version
242
+ version: '0'
243
+ requirements: []
244
+ rubyforge_project:
245
+ rubygems_version: 2.6.13
246
+ signing_key:
247
+ specification_version: 4
248
+ summary: Defra ruby on rails validations
249
+ test_files:
250
+ - spec/spec_helper.rb
251
+ - spec/defra_ruby_validators/companies_house_service_spec.rb
252
+ - spec/defra_ruby_validators/version_spec.rb
253
+ - spec/defra_ruby_validators/companies_house_number_validator_spec.rb
254
+ - spec/examples.txt
255
+ - spec/cassettes/company_no_not_found.yml
256
+ - spec/cassettes/company_no_valid.yml
257
+ - spec/cassettes/company_no_inactive.yml
258
+ - spec/support/i18n.rb
259
+ - spec/support/vcr.rb
260
+ - spec/support/defra_ruby_validators.rb