europe 0.0.4 → 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 4a0fc2ed7821eb1f8561bdb6421f9921fd23c49a
4
- data.tar.gz: 59242fee45c24eb9f258ee7bcaaa8882e0ecad56
3
+ metadata.gz: b117fbde4812a7c55c95dfe21f6c1c52d792e529
4
+ data.tar.gz: 1029b7ad3e8c5c310f41e887eb0bb074d1589a09
5
5
  SHA512:
6
- metadata.gz: adf482a84c8abb1906cc19e9d3cff143b96696dc648c31aae191b1720d04ba8bd8d47acbb4dcf3e902ce1520554258149d3acbf8fe5ef2bf5214036209e39f1c
7
- data.tar.gz: 568c9933adfc50a8de039bbdbb9110e166d254de368cb0dbedd10640e77ca3150fe498793cd33ab481933c259641e97cda56d7aa419b5b97c278695cc4ab431f
6
+ metadata.gz: f7383ca5b11d95988b4e0da4939646379429cca04bfa4a0fa38d2edbff0f89b5de1517817cf609ec2afb305b00fc516395cada25f38b3ad7aa61d1eb5b55c88c
7
+ data.tar.gz: 854180e88ab6348b08c0bc2ac1e7a335ffbc88c110ef439a62d4782bb3ed2ea29056607d5088bbb2153717dcbf07a14a5fd3acaf38218db9d0655f495bd117ca
data/.gitignore CHANGED
@@ -13,3 +13,4 @@
13
13
  *.a
14
14
  mkmf.log
15
15
  .DS_Store
16
+ coverage
@@ -0,0 +1,3 @@
1
+ AllCops:
2
+ Exclude:
3
+ - 'europe.gemspec'
data/README.md CHANGED
@@ -1,3 +1,4 @@
1
+ ![Europe gem logo](https://s3-eu-west-1.amazonaws.com/valorsis.s3-website-eu-west-1.amazonaws.com/static/logo256.png)
1
2
  # Europe
2
3
 
3
4
  This gem provides EU governmental data, extracted from various EU / EC websites. With this gem you can validate VAT numbers, retrieve VAT tax rates and currency exchange rates matched to the Euro. How to use this gem is pretty straightforward and written below.
@@ -138,7 +139,7 @@ Response
138
139
  ```
139
140
 
140
141
  ## Retrieving country information reversed
141
- Call with optional parameters (name, currency, source_name, official_name, tld, currency and capital)
142
+ Call with optional parameters (name, currency, source_name, official_name, tld, currency and capital)
142
143
  ```ruby
143
144
  Europe::Countries::Reversed.generate('name')
144
145
  ```
@@ -157,7 +158,7 @@ Response
157
158
 
158
159
  This gem is tested with the following Ruby versions on Linux and Mac OS X:
159
160
 
160
- - Ruby MRI 1.9.3, 2.0.0, 2.1.8, 2.2.0, 2.2.3, 2.2.4
161
+ - Ruby > 2.2.2
161
162
 
162
163
  ## Todo
163
164
 
@@ -172,4 +173,4 @@ This gem is tested with the following Ruby versions on Linux and Mac OS X:
172
173
  2. Create your feature branch (`git checkout -b my-new-feature`)
173
174
  3. Commit your changes (`git commit -am 'Add some feature'`)
174
175
  4. Push to the branch (`git push origin my-new-feature`)
175
- 5. Create a new Pull Request
176
+ 5. Create a new Pull Request
data/Rakefile CHANGED
@@ -5,6 +5,7 @@ Rake::TestTask.new(:test) do |t|
5
5
  t.libs << 'test'
6
6
  t.libs << 'lib'
7
7
  t.test_files = FileList['test/**/*_test.rb']
8
+ t.warning = false
8
9
  end
9
10
 
10
11
  task default: :test
@@ -22,13 +22,16 @@ Gem::Specification.new do |spec|
22
22
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
23
23
  spec.require_paths = ['lib']
24
24
 
25
- spec.add_dependency 'nokogiri', '~> 1.6'
26
- spec.add_dependency 'savon', '~> 2.10.0'
25
+ spec.add_dependency 'nokogiri'
26
+ spec.add_dependency 'savon'
27
27
 
28
- spec.add_development_dependency 'bundler', '~> 1'
29
- spec.add_development_dependency 'rake', '~> 10.0'
28
+ spec.add_development_dependency 'bundler'
29
+ spec.add_development_dependency 'rake'
30
30
  spec.add_development_dependency 'minitest'
31
+ spec.add_development_dependency 'minitest-reporters'
31
32
  spec.add_development_dependency 'awesome_print'
32
33
  spec.add_development_dependency 'pry'
33
34
  spec.add_development_dependency 'rubocop'
35
+ spec.add_development_dependency 'simplecov'
36
+ spec.add_development_dependency 'webmock'
34
37
  end
@@ -94,6 +94,7 @@ module Europe
94
94
  UK: { name: 'United Kingdom', source_name: 'United Kingdom',
95
95
  official_name: 'United Kingdom of Great ' \
96
96
  'Britain and Northern Ireland',
97
- tld: '.uk', currency: :GBP, capital: 'London' } }
97
+ tld: '.uk', currency: :GBP, capital: 'London' }
98
+ }.freeze
98
99
  end
99
100
  end
@@ -9,8 +9,6 @@ module Europe
9
9
  end
10
10
  end
11
11
 
12
- private
13
-
14
12
  def self.reverse_handle_value(out, key, value, country_value)
15
13
  if out[value[country_value.to_sym]]
16
14
  reverse_handle_array(out, key, value, country_value)
@@ -18,6 +18,7 @@ module Europe
18
18
  HUF: { name: 'Forint', symbol: 'Ft', html: '&#70;&#116;' },
19
19
  PLN: { name: 'Zloty', symbol: 'zł', html: '&#122;&#322;' },
20
20
  RON: { name: 'Leu', symbol: 'lei', html: '&#108;&#101;&#105;' },
21
- SEK: { name: 'Krona', symbol: 'kr', html: '&#107;&#114;' } }
21
+ SEK: { name: 'Krona', symbol: 'kr', html: '&#107;&#114;' }
22
+ }.freeze
22
23
  end
23
24
  end
@@ -8,13 +8,11 @@ module Europe
8
8
  # exchange rates
9
9
  module ExchangeRates
10
10
  EXCHANGE_URL = 'http://www.ecb.europa.eu/stats/' \
11
- 'eurofxref/eurofxref-daily.xml'
11
+ 'eurofxref/eurofxref-daily.xml'.freeze
12
12
  def self.retrieve
13
13
  extract_rates(Nokogiri::XML(open(EXCHANGE_URL)))
14
14
  end
15
15
 
16
- private
17
-
18
16
  def self.extract_rates(doc)
19
17
  rates = { date: Date.parse(doc.css('Cube Cube').first['time']),
20
18
  rates: {} }
@@ -7,20 +7,19 @@ module Europe
7
7
  # Eurostat
8
8
  module Eurostat
9
9
  STAT_URL = 'http://ec.europa.eu/eurostat/wdds' \
10
- '/rest/data/v1.1/json/en/'
10
+ '/rest/data/v1.1/json/en/'.freeze
11
11
 
12
12
  def self.retrieve(dataset, filters)
13
13
  fetch_stats(dataset, filters)
14
14
  end
15
15
 
16
- private
17
-
18
16
  def self.generate_url(dataset, _filters)
19
17
  uri = URI.parse(STAT_URL + dataset)
20
18
  params = {
21
19
  precision: 1, geo: 'EU28',
22
20
  unit: 'EUR_HAB', time: '2010',
23
- indic_na: 'B1GM', unitLabel: 'code' }
21
+ indic_na: 'B1GM', unitLabel: 'code'
22
+ }
24
23
  uri.query = URI.encode_www_form(params)
25
24
  uri
26
25
  end
@@ -33,17 +33,30 @@ module Europe
33
33
  SE: /^SE\d{12}$/,
34
34
  SI: /^SI\d{8}$/,
35
35
  SK: /^SK\d{10}$/
36
- }
36
+ }.freeze
37
37
 
38
38
  def self.validate(number)
39
39
  country_code = number[0..1].to_sym
40
+ number = sanitize_number(number, country_code)
40
41
  return false unless VAT_REGEX.keys.include?(country_code)
42
+ match_vat_number(number, country_code)
43
+ end
44
+
45
+ def self.sanitize_number(number, country_code)
46
+ if [:GB, :DK, :FR].include?(country_code)
47
+ number.gsub(/\.|\t/, '').upcase
48
+ else
49
+ number.gsub(/\.|\t|\s/, '').upcase
50
+ end
51
+ end
52
+
53
+ def self.match_vat_number(number, country_code)
41
54
  if VAT_REGEX[country_code.to_sym].is_a?(Array)
42
55
  VAT_REGEX[country_code.to_sym].each do |regex|
43
56
  return true if regex.match(number)
44
57
  end
45
- else
46
- return true if VAT_REGEX[country_code.to_sym].match(number)
58
+ elsif VAT_REGEX[country_code.to_sym].match(number)
59
+ return true
47
60
  end
48
61
  false
49
62
  end
@@ -1,21 +1,15 @@
1
- require 'net/http'
2
- require 'uri'
3
- require 'nokogiri'
4
-
5
1
  module Europe
6
2
  module Vat
7
3
  # Rates
8
4
  module Rates
9
5
  RATES_URL = 'http://ec.europa.eu/taxation_customs/tic/' \
10
- 'public/vatRates/vatratesSearch.html'
6
+ 'public/vatRates/vatratesSearch.html'.freeze
11
7
  def self.retrieve
12
8
  resp = fetch_rates
13
9
  return resp if resp == :failed
14
10
  extract_rates(resp)
15
11
  end
16
12
 
17
- private
18
-
19
13
  def self.extract_country_code(data)
20
14
  Europe::Countries::Reversed.generate(:name) \
21
15
  [data.css('td').first.text.strip!]
@@ -40,7 +34,7 @@ module Europe
40
34
  params = 'listOfTypes=Standard&dateFilter=' +
41
35
  Time.new.strftime('%d/%m/%Y')
42
36
  [*1..Europe::Countries::COUNTRIES.count].each do |index|
43
- params += '&listOfMsa=' + (index).to_s
37
+ params += '&listOfMsa=' + index.to_s
44
38
  end
45
39
  [uri, params]
46
40
  end
@@ -7,19 +7,27 @@ module Europe
7
7
  # VAT
8
8
  module Vat
9
9
  WSDL = 'http://ec.europa.eu/taxation_customs/' \
10
- 'vies/checkVatService.wsdl'
11
- NS = 'urn:ec.europa.eu:taxud:vies:services:checkVat:types'
10
+ 'vies/checkVatService.wsdl'.freeze
11
+ NS = 'urn:ec.europa.eu:taxud:vies:services:checkVat:types'.freeze
12
12
  def self.validate(number)
13
13
  response = send_request(number[0..1], number[2..-1])
14
14
  return :failed unless response.success?
15
15
  response.body[:check_vat_response].tap { |x| x.delete(:@xmlns) }
16
- rescue Savon::SOAPFault => fault
17
- return :timeout \
18
- if fault.to_hash[:fault][:faultstring] == 'SERVER_BUSY'
19
- :fault
16
+ rescue Savon::HTTPError, Savon::SOAPFault
17
+ return :failed
18
+ rescue Timeout::Error
19
+ return :timeout
20
20
  end
21
21
 
22
- private
22
+ def self.charge_vat?(origin_country, number)
23
+ return false if number.nil? || number.empty?
24
+ if origin_country.to_sym == number[0..1].to_sym
25
+ true
26
+ else
27
+ Europe::Countries::COUNTRIES
28
+ .keys.include?(number[0..1].to_sym)
29
+ end
30
+ end
23
31
 
24
32
  def self.send_request(country_code, number)
25
33
  client = Savon.client(wsdl: WSDL, namespace: NS,
@@ -1,4 +1,4 @@
1
1
  # Europe version
2
2
  module Europe
3
- VERSION = '0.0.4'
3
+ VERSION = '0.0.5'.freeze
4
4
  end
@@ -11,6 +11,10 @@ module Europe
11
11
  Europe::Countries::Reversed.generate(:name)
12
12
  assert_equal reversed_hash['Netherlands'], :NL
13
13
  assert_equal reversed_hash['Ireland'], :IE
14
+
15
+ reversed_hash =
16
+ Europe::Countries::Reversed.generate(:currency)
17
+ assert_equal reversed_hash[:EUR].count, 20
14
18
  end
15
19
  end
16
20
  end
@@ -6,6 +6,10 @@ module Europe
6
6
  class ExchangeRatesTest < Minitest::Test
7
7
  include Benchmark
8
8
 
9
+ def setup
10
+ WebMock.disable!
11
+ end
12
+
9
13
  def test_retrieval_exchange_rates
10
14
  rates = Europe::Currency::ExchangeRates.retrieve
11
15
  assert rates[:rates].keys.include?(:GBP)
@@ -31,13 +31,14 @@ module Europe
31
31
  LU: 'LU99999999',
32
32
  LV: 'LV99999999999',
33
33
  MT: 'MT99999999',
34
- NL: 'NL999999999B99',
34
+ NL: %w(NL999999999B99 NL999.9999.99.B99),
35
35
  PL: 'PL9999999999',
36
36
  PT: 'PT999999999',
37
37
  RO: 'RO999999999',
38
38
  SE: 'SE999999999999',
39
39
  SI: 'SI99999999',
40
- SK: 'SK9999999999' }
40
+ SK: 'SK9999999999'
41
+ }.freeze
41
42
 
42
43
  def test_all_vat_numbers_on_format
43
44
  VAT_FORMAT_VALIDATION.each do |_country, number|
@@ -63,23 +64,27 @@ module Europe
63
64
  def check_character_and_digit(number)
64
65
  assert_equal true, Europe::Vat::Format.validate(
65
66
  number[0..1] +
66
- number[2..-1].gsub(/X/, [*('A'..'Z'), *('0'..'9')].sample))
67
+ number[2..-1].gsub(/X/, [*('A'..'Z'), *('0'..'9')].sample)
68
+ )
67
69
  end
68
70
 
69
71
  def check_integer(number)
70
- { number[0..1] + number[2..-1].gsub(/9/, [*('0'..'9')].sample) => true,
72
+ {
73
+ number[0..1] + number[2..-1].gsub(/9/, [*('0'..'9')].sample) => true,
71
74
  number.gsub(/9/, rand(10).to_s) => true,
72
75
  number.gsub(/9/, [*('A'..'Z')].sample(1).join) => false
73
- }.each do |key, value|
76
+ }.each do |key, value|
74
77
  assert_equal value, Europe::Vat::Format.validate(key)
75
78
  end
76
79
  end
77
80
 
78
81
  def check_alphanumeric(number)
79
82
  assert_equal true, Europe::Vat::Format.validate(
80
- number[0..1] + number[2..-1].gsub(/L/, [*('A'..'Z')].sample))
83
+ number[0..1] + number[2..-1].gsub(/L/, [*('A'..'Z')].sample)
84
+ )
81
85
  assert_equal false, Europe::Vat::Format.validate(
82
- number[0..1] + number[2..-1].gsub(/L/, [*('0'..'9')].sample))
86
+ number[0..1] + number[2..-1].gsub(/L/, [*('0'..'9')].sample)
87
+ )
83
88
  end
84
89
 
85
90
  def check_true_values(number)
@@ -88,9 +93,11 @@ module Europe
88
93
 
89
94
  def check_false_values(number)
90
95
  assert_equal false, Europe::Vat::Format.validate(
91
- number + [*('A'..'Z'), *('0'..'9')].sample(3).join)
96
+ number + [*('A'..'Z'), *('0'..'9')].sample(3).join
97
+ )
92
98
  assert_equal false, Europe::Vat::Format.validate(
93
- [*('A'..'Z'), *('0'..'9')].sample + number)
99
+ [*('A'..'Z'), *('0'..'9')].sample + number
100
+ )
94
101
  end
95
102
  end
96
103
  end
@@ -6,6 +6,10 @@ module Europe
6
6
  class RatesTest < Minitest::Test
7
7
  include Benchmark
8
8
 
9
+ def setup
10
+ WebMock.disable!
11
+ end
12
+
9
13
  def test_retrieval_of_vat_rates
10
14
  rates = Europe::Vat::Rates.retrieve
11
15
  assert_equal rates.count, Europe::Countries::COUNTRIES.count
@@ -6,6 +6,10 @@ module Europe
6
6
  class ValidationTest < Minitest::Test
7
7
  include Benchmark
8
8
 
9
+ def setup
10
+ WebMock.disable!
11
+ end
12
+
9
13
  def test_validation_of_false_vat_number
10
14
  validate_false_vat = Europe::Vat.validate('NL123456789B01')
11
15
  assert_equal false, validate_false_vat[:valid]
@@ -15,15 +19,30 @@ module Europe
15
19
  # PostNL
16
20
  validate_correct_vat = Europe::Vat.validate('NL009291477B01')
17
21
  assert validate_correct_vat[:valid] \
18
- unless validate_correct_vat == :fault
22
+ unless validate_correct_vat == :failed
19
23
 
20
24
  # Sky
21
25
  validate_correct_vat = Europe::Vat.validate('GB440627467')
22
- assert validate_correct_vat[:valid]
26
+ assert validate_correct_vat[:valid] \
27
+ unless validate_correct_vat == :failed
23
28
 
24
29
  # Volkswagen
25
30
  validate_correct_vat = Europe::Vat.validate('DE115235681')
26
- assert validate_correct_vat[:valid]
31
+ assert validate_correct_vat[:valid] \
32
+ unless validate_correct_vat == :failed
33
+ end
34
+
35
+ def test_failed_request_to_soap_service
36
+ WebMock.enable!
37
+ stub_request(:any, 'http://ec.europa.eu/taxation_customs' \
38
+ '/vies/checkVatService.wsdl').to_timeout
39
+ Europe::Vat.validate('DE115235681')
40
+
41
+ stub_request(:get, 'http://ec.europa.eu/taxation_customs/vies/checkVatService.wsdl')
42
+ .with(headers: { 'Accept' => '*/*', 'User-Agent' => 'Ruby' })
43
+ .to_return(status: 421, body: '')
44
+ Europe::Vat.validate('DE115235681')
45
+ WebMock.disable!
27
46
  end
28
47
  end
29
48
  end
@@ -1,5 +1,11 @@
1
+ require 'simplecov'
2
+ SimpleCov.start
3
+
1
4
  $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
2
5
  require 'europe'
3
6
  require 'minitest/autorun'
7
+ require 'webmock/minitest'
4
8
  require 'awesome_print'
5
9
  require 'benchmark'
10
+ require 'minitest/reporters'
11
+ Minitest::Reporters.use! Minitest::Reporters::SpecReporter.new
metadata CHANGED
@@ -1,71 +1,71 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: europe
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.4
4
+ version: 0.0.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - VvanGemert
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-12-21 00:00:00.000000000 Z
11
+ date: 2017-01-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: nokogiri
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - "~>"
17
+ - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: '1.6'
19
+ version: '0'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - "~>"
24
+ - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: '1.6'
26
+ version: '0'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: savon
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - "~>"
31
+ - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: 2.10.0
33
+ version: '0'
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - "~>"
38
+ - - ">="
39
39
  - !ruby/object:Gem::Version
40
- version: 2.10.0
40
+ version: '0'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: bundler
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - "~>"
45
+ - - ">="
46
46
  - !ruby/object:Gem::Version
47
- version: '1'
47
+ version: '0'
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - "~>"
52
+ - - ">="
53
53
  - !ruby/object:Gem::Version
54
- version: '1'
54
+ version: '0'
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: rake
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - "~>"
59
+ - - ">="
60
60
  - !ruby/object:Gem::Version
61
- version: '10.0'
61
+ version: '0'
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
- - - "~>"
66
+ - - ">="
67
67
  - !ruby/object:Gem::Version
68
- version: '10.0'
68
+ version: '0'
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: minitest
71
71
  requirement: !ruby/object:Gem::Requirement
@@ -80,6 +80,20 @@ dependencies:
80
80
  - - ">="
81
81
  - !ruby/object:Gem::Version
82
82
  version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: minitest-reporters
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'
83
97
  - !ruby/object:Gem::Dependency
84
98
  name: awesome_print
85
99
  requirement: !ruby/object:Gem::Requirement
@@ -122,6 +136,34 @@ dependencies:
122
136
  - - ">="
123
137
  - !ruby/object:Gem::Version
124
138
  version: '0'
139
+ - !ruby/object:Gem::Dependency
140
+ name: simplecov
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: webmock
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'
125
167
  description: Europe is a simple library for retrieving EU government data such as
126
168
  VAT information, VAT validation, currency exchange rates and country information.
127
169
  email:
@@ -133,6 +175,7 @@ files:
133
175
  - ".coveralls.yml"
134
176
  - ".gitignore"
135
177
  - ".pryrc"
178
+ - ".rubocop.yml"
136
179
  - ".travis.yml"
137
180
  - Gemfile
138
181
  - LICENSE
@@ -177,7 +220,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
177
220
  version: '0'
178
221
  requirements: []
179
222
  rubyforge_project:
180
- rubygems_version: 2.4.8
223
+ rubygems_version: 2.6.8
181
224
  signing_key:
182
225
  specification_version: 4
183
226
  summary: Europe is a gem for retrieving and validating EU government data.