cvrvaelger 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
+ SHA256:
3
+ metadata.gz: b4c8df3ad4e794628d2f3e5a0010b9a9aa4e35123a64370926196639cb119eb6
4
+ data.tar.gz: 7395f85cc2c4bb3cf458b80d61da01602af672b893f2317e900e833257a64601
5
+ SHA512:
6
+ metadata.gz: 3623ddc0be170cf6cdbed892a4ea9d18dee2958687945e23982b5271a19e45eb5c33e3c095c3e249177ae442d9c31b103e3f6739f4501b15532efd681c379c96
7
+ data.tar.gz: c622efb3b0d2001065bc756baf0b1bc9be9b746a67875e553b7aa40b4006c682c02f555204095587c241ac7c2f13628ea47442af83f19c4a6150e713db1c85cd
data/.env.example ADDED
@@ -0,0 +1,7 @@
1
+ # Free Datafordeler IT-system API key (no demo default in the gem).
2
+ # Create at https://datafordeler.dk/ → Administration → IT-system → API key.
3
+ CVRVAELGER_API_KEY=
4
+ # Optional alias:
5
+ # DATAFORDELER_API_KEY=
6
+ # Optional endpoint override (default https://graphql.datafordeler.dk/CVR/v2):
7
+ # CVRVAELGER_BASE_URL=
data/.rubocop.yml ADDED
@@ -0,0 +1,55 @@
1
+ plugins:
2
+ - rubocop-minitest
3
+ - rubocop-rake
4
+
5
+ AllCops:
6
+ NewCops: enable
7
+ TargetRubyVersion: 3.3
8
+ SuggestExtensions: false
9
+ Exclude:
10
+ - "vendor/**/*"
11
+ - "tmp/**/*"
12
+ - "pkg/**/*"
13
+
14
+ Style/Documentation:
15
+ Enabled: false
16
+
17
+ Style/StringLiterals:
18
+ EnforcedStyle: double_quotes
19
+
20
+ Layout/LineLength:
21
+ Max: 120
22
+
23
+ Metrics/MethodLength:
24
+ Max: 30
25
+ Exclude:
26
+ - "test/**/*"
27
+
28
+ Metrics/ClassLength:
29
+ Max: 200
30
+ Exclude:
31
+ - "test/**/*"
32
+
33
+ Metrics/AbcSize:
34
+ Max: 40
35
+ Exclude:
36
+ - "test/**/*"
37
+
38
+ Metrics/CyclomaticComplexity:
39
+ Max: 12
40
+ Exclude:
41
+ - "test/**/*"
42
+
43
+ Metrics/PerceivedComplexity:
44
+ Max: 12
45
+ Exclude:
46
+ - "test/**/*"
47
+
48
+ Metrics/BlockLength:
49
+ Exclude:
50
+ - "test/**/*"
51
+ - "*.gemspec"
52
+ - "Rakefile"
53
+
54
+ Minitest/MultipleAssertions:
55
+ Max: 10
data/CHANGELOG.md ADDED
@@ -0,0 +1,11 @@
1
+ # Changelog
2
+
3
+ ## 0.1.0
4
+
5
+ - Initial public release: Datafordeler CVR GraphQL v2 client (`lookup` / `search`).
6
+ - Returns company name, light address fields, and status for an 8-digit CVR or
7
+ exact registered name match. Optional `at:` sets GraphQL `virkningstid`.
8
+ - Requires a free Datafordeler API key (`CVRVAELGER_API_KEY`); no demo secret.
9
+ - VCR cassettes for LEGO, Salling Group, empty searches, and the public query
10
+ surface (API keys redacted).
11
+ - RuboCop in CI (`bundle exec rake rubocop`).
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Rasmus Bergholdt
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.
data/README.md ADDED
@@ -0,0 +1,102 @@
1
+ # Cvrvaelger
2
+
3
+ Ruby client for **Det Centrale Virksomhedsregister (CVR)** via
4
+ [Datafordeler GraphQL](https://datafordeler.dk/dataoversigt/det-centrale-virksomhedsregister-cvr/cvr-graphql/).
5
+
6
+ Denmark only — look up an 8-digit CVR or registered company name and return
7
+ picker-shaped fields (name, light address, status).
8
+
9
+ ## Install
10
+
11
+ ```ruby
12
+ # Gemfile
13
+ gem "cvrvaelger"
14
+ ```
15
+
16
+ ```sh
17
+ bundle add cvrvaelger
18
+ # or: gem install cvrvaelger
19
+ ```
20
+
21
+ Requires Ruby 3.3+. No Rails dependency.
22
+
23
+ ## Usage
24
+
25
+ ```ruby
26
+ require "cvrvaelger"
27
+
28
+ client = Cvrvaelger::Client.new(
29
+ api_key: ENV.fetch("CVRVAELGER_API_KEY")
30
+ )
31
+
32
+ company = client.lookup("47458714")
33
+ company.cvr # => "47458714"
34
+ company.name # => "LEGO SYSTEM A/S"
35
+ company.address_line # => "Åstvej 1"
36
+ company.postal_code # => "7190"
37
+ company.city # => "Billund"
38
+ company.status # => "aktiv"
39
+
40
+ # Picker: 8 digits → lookup; otherwise exact, case-sensitive name match.
41
+ # Datafordeler string filters are `eq` / `in` only (no contains / fuzzy).
42
+ hits = client.search("LEGO SYSTEM A/S")
43
+ client.search("lego") # => []
44
+
45
+ # Optional bitemporal cut-off (GraphQL `virkningstid`, default: now)
46
+ client.lookup("47458714", at: Time.utc(2020, 1, 1))
47
+ ```
48
+
49
+ Environment variables:
50
+
51
+ | Variable | Purpose |
52
+ | --- | --- |
53
+ | `CVRVAELGER_API_KEY` | Datafordeler API key (preferred) |
54
+ | `DATAFORDELER_API_KEY` | Accepted alias |
55
+ | `CVRVAELGER_BASE_URL` | Override GraphQL endpoint (default `https://graphql.datafordeler.dk/CVR/v2`) |
56
+
57
+ ## API key
58
+
59
+ There is **no demo/default secret**. Create a free user + IT-system API key in
60
+ [Datafordeler Administration](https://datafordeler.dk/). Company entities do not
61
+ require a special CVR access request; `CVRPerson` is out of scope for this gem.
62
+
63
+ ## Testing
64
+
65
+ ```sh
66
+ bundle exec rake test
67
+ bundle exec rake rubocop
68
+ ```
69
+
70
+ Unit tests stub HTTP via an injected callable. Live examples use
71
+ [VCR](https://github.com/vcr/vcr) cassettes recorded against the real API
72
+ (API keys redacted as `<API_KEY>`). CI uses `record: :none` (fail-closed).
73
+ To refresh cassettes locally:
74
+
75
+ ```sh
76
+ VCR_RECORD=all bundle exec rake test TEST=test/client_live_test.rb
77
+ VCR_RECORD=all bundle exec rake test TEST=test/graphql_features_test.rb
78
+ ```
79
+
80
+ Never hand-write cassette response bodies.
81
+
82
+ ## Attribution
83
+
84
+ Company data via [Datafordeler](https://datafordeler.dk/) / Erhvervsstyrelsen CVR.
85
+ This gem is an independent open-source client and is not affiliated with or
86
+ endorsed by those agencies.
87
+
88
+ ## Releasing
89
+
90
+ 1. Bump `Cvrvaelger::VERSION` in `lib/cvrvaelger/version.rb` (gemspec reads it).
91
+ 2. Update `CHANGELOG.md` for that version.
92
+ 3. Commit and push to `main`.
93
+ 4. Tag and push: `git tag vX.Y.Z && git push origin vX.Y.Z`
94
+ (or create a GitHub Release for `vX.Y.Z` — that also pushes the tag).
95
+ 5. Tag **must** match the gem version (`v0.1.0` ↔ `0.1.0`). The
96
+ [push_gem](.github/workflows/push_gem.yml) workflow verifies this, then
97
+ publishes via [RubyGems Trusted Publishing](https://guides.rubygems.org/trusted-publishing/)
98
+ (`rubygems/release-gem`, OIDC — no `RUBYGEMS_API_KEY` secret).
99
+
100
+ ## License
101
+
102
+ MIT. See [LICENSE.txt](LICENSE.txt).
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "lib/cvrvaelger/version"
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "cvrvaelger"
7
+ spec.version = Cvrvaelger::VERSION
8
+ spec.authors = ["Rasmus Bergholdt"]
9
+ spec.email = ["rasmus.bergholdt@gmail.com"]
10
+
11
+ spec.summary = "Ruby client for Danish CVR company lookup via Datafordeler GraphQL."
12
+ spec.description = <<~DESC
13
+ HTTP client for Det Centrale Virksomhedsregister (CVR) on Datafordeler GraphQL:
14
+ verify an 8-digit CVR number or exact registered name and return the company
15
+ name plus light address fields for picker UX. No Rails dependency.
16
+ DESC
17
+ spec.homepage = "https://github.com/bergholdt/cvrvaelger"
18
+ spec.license = "MIT"
19
+ spec.required_ruby_version = ">= 3.3.0"
20
+
21
+ spec.metadata["homepage_uri"] = spec.homepage
22
+ spec.metadata["source_code_uri"] = "https://github.com/bergholdt/cvrvaelger/tree/v#{spec.version}"
23
+ spec.metadata["changelog_uri"] = "https://github.com/bergholdt/cvrvaelger/blob/v#{spec.version}/CHANGELOG.md"
24
+ spec.metadata["bug_tracker_uri"] = "https://github.com/bergholdt/cvrvaelger/issues"
25
+ spec.metadata["rubygems_mfa_required"] = "true"
26
+
27
+ spec.files = Dir.chdir(__dir__) do
28
+ `git ls-files -z`.split("\x0").reject do |f|
29
+ f.start_with?(*%w[bin/ test/ .git .github Gemfile Rakefile AGENTS.md])
30
+ end
31
+ end
32
+ spec.require_paths = ["lib"]
33
+ end
@@ -0,0 +1,238 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "net/http"
4
+ require "json"
5
+ require "uri"
6
+
7
+ require_relative "company"
8
+
9
+ module Cvrvaelger
10
+ # HTTP client for Det Centrale Virksomhedsregister via Datafordeler GraphQL.
11
+ #
12
+ # Official endpoint: https://graphql.datafordeler.dk/CVR/v2
13
+ # Auth: free API key from Datafordeler Administration (query param `apiKey`).
14
+ # No demo/default secret — configure CVRVAELGER_API_KEY or pass api_key:.
15
+ class Client
16
+ DEFAULT_BASE_URL = "https://graphql.datafordeler.dk/CVR/v2"
17
+
18
+ # Datafordeler allows one root field per query. Name match is exact (`eq`);
19
+ # there is no contains/fuzzy operator. `virkningstid` selects the bitemporal row.
20
+ VIRKSOMHED_BY_CVR_QUERY = <<~GRAPHQL
21
+ query LookupVirksomhed($cvr: Long!, $at: DafDateTime!) {
22
+ CVR_Virksomhed(first: 1, virkningstid: $at, where: { CVRNummer: { eq: $cvr } }) {
23
+ nodes { id CVRNummer status }
24
+ }
25
+ }
26
+ GRAPHQL
27
+
28
+ VIRKSOMHED_BY_ID_QUERY = <<~GRAPHQL
29
+ query VirksomhedById($id: String!, $at: DafDateTime!) {
30
+ CVR_Virksomhed(first: 1, virkningstid: $at, where: { id: { eq: $id } }) {
31
+ nodes { id CVRNummer status }
32
+ }
33
+ }
34
+ GRAPHQL
35
+
36
+ NAVN_BY_ID_QUERY = <<~GRAPHQL
37
+ query NavnById($id: String!, $at: DafDateTime!) {
38
+ CVR_Navn(first: 1, virkningstid: $at, where: { CVREnhedsId: { eq: $id } }) {
39
+ nodes { vaerdi }
40
+ }
41
+ }
42
+ GRAPHQL
43
+
44
+ NAVN_BY_VALUE_QUERY = <<~GRAPHQL
45
+ query SearchNavn($q: String!, $at: DafDateTime!) {
46
+ CVR_Navn(first: 10, virkningstid: $at, where: { vaerdi: { eq: $q } }) {
47
+ nodes { CVREnhedsId vaerdi }
48
+ }
49
+ }
50
+ GRAPHQL
51
+
52
+ ADRESSE_BY_ID_QUERY = <<~GRAPHQL
53
+ query AdresseById($id: String!, $at: DafDateTime!) {
54
+ CVR_Adressering(first: 5, virkningstid: $at, where: { CVREnhedsId: { eq: $id } }) {
55
+ nodes {
56
+ AdresseringAnvendelse
57
+ CVRAdresse_vejnavn
58
+ CVRAdresse_husnummerFra
59
+ CVRAdresse_postnummer
60
+ CVRAdresse_postdistrikt
61
+ }
62
+ }
63
+ }
64
+ GRAPHQL
65
+
66
+ attr_reader :base_url, :api_key
67
+
68
+ def initialize(api_key: nil, base_url: nil, http: nil)
69
+ @api_key = present_string(api_key) || present_string(ENV.fetch("CVRVAELGER_API_KEY", nil)) ||
70
+ present_string(ENV.fetch("DATAFORDELER_API_KEY", nil))
71
+ @base_url = present_string(base_url) || present_string(ENV.fetch("CVRVAELGER_BASE_URL", nil)) || DEFAULT_BASE_URL
72
+ @http = http
73
+ end
74
+
75
+ # Verify an 8-digit CVR and return Company, or nil when not found.
76
+ # `at` is the bitemporal virkningstid (default: now).
77
+ def lookup(cvr, at: Time.now)
78
+ normalized = Company.normalize_cvr(cvr)
79
+ return nil unless present?(normalized)
80
+
81
+ ensure_api_key!
82
+ stamp = format_time(at)
83
+ payload = post_graphql(VIRKSOMHED_BY_CVR_QUERY, cvr: normalized.to_i, at: stamp)
84
+ node = first_node(payload)
85
+ return nil unless present?(node)
86
+
87
+ company_from_virksomhed(node, stamp)
88
+ end
89
+
90
+ # Picker search: 8 digits → lookup; otherwise exact, case-sensitive name match.
91
+ def search(query, at: Time.now)
92
+ q = query.to_s.strip
93
+ return [] if q.length < 2
94
+
95
+ digits = Company.normalize_cvr(q)
96
+ if digits
97
+ company = lookup(digits, at: at)
98
+ return company ? [company] : []
99
+ end
100
+
101
+ ensure_api_key!
102
+ stamp = format_time(at)
103
+ payload = post_graphql(NAVN_BY_VALUE_QUERY, q: q, at: stamp)
104
+ Array(nodes(payload)).filter_map { |node| node["CVREnhedsId"] }.uniq.filter_map do |id|
105
+ company_from_id(id, stamp)
106
+ end
107
+ end
108
+
109
+ private
110
+
111
+ attr_reader :http
112
+
113
+ def ensure_api_key!
114
+ return if present?(api_key)
115
+
116
+ raise ConfigurationError,
117
+ "CVRVAELGER_API_KEY (or DATAFORDELER_API_KEY) is required — " \
118
+ "create a free API key in Datafordeler Administration"
119
+ end
120
+
121
+ def company_from_id(id, stamp)
122
+ payload = post_graphql(VIRKSOMHED_BY_ID_QUERY, id: id, at: stamp)
123
+ node = first_node(payload)
124
+ return nil unless present?(node)
125
+
126
+ company_from_virksomhed(node, stamp)
127
+ end
128
+
129
+ def company_from_virksomhed(node, stamp)
130
+ id = node["id"]
131
+ return nil unless present?(id)
132
+
133
+ name = first_node(post_graphql(NAVN_BY_ID_QUERY, id: id, at: stamp))&.dig("vaerdi")
134
+ address = preferred_address(nodes(post_graphql(ADRESSE_BY_ID_QUERY, id: id, at: stamp)))
135
+ company = Company.from_node(
136
+ "cvrNummer" => format("%08d", node["CVRNummer"].to_i),
137
+ "navn" => name,
138
+ "status" => node["status"],
139
+ "adresse" => address_fields(address)
140
+ )
141
+ return nil unless present?(company.cvr) && present?(company.name)
142
+
143
+ company
144
+ end
145
+
146
+ def preferred_address(list)
147
+ rows = Array(list).grep(Hash)
148
+ rows.find { |row| row["AdresseringAnvendelse"] == "beliggenhedsadresse" } || rows.first
149
+ end
150
+
151
+ def address_fields(address)
152
+ return {} unless address.is_a?(Hash)
153
+
154
+ {
155
+ "vejnavn" => address["CVRAdresse_vejnavn"],
156
+ "husnummer" => address["CVRAdresse_husnummerFra"],
157
+ "postnummer" => address["CVRAdresse_postnummer"],
158
+ "postdistrikt" => address["CVRAdresse_postdistrikt"]
159
+ }
160
+ end
161
+
162
+ def format_time(time)
163
+ time.getutc.strftime("%Y-%m-%dT%H:%M:%S.000000Z")
164
+ end
165
+
166
+ def first_node(payload)
167
+ nodes(payload).first
168
+ end
169
+
170
+ def nodes(payload)
171
+ data = payload["data"]
172
+ return [] unless data.is_a?(Hash)
173
+
174
+ connection = data["CVREnhed"] || data["CVR_Virksomhed"] || data["Virksomhed"] || data.values.first
175
+ return [] unless connection.is_a?(Hash)
176
+
177
+ Array(connection["nodes"] || connection["items"] || connection["edges"]&.filter_map do |e|
178
+ e.is_a?(Hash) ? e["node"] : nil
179
+ end)
180
+ end
181
+
182
+ def post_graphql(query, **variables)
183
+ uri = URI(base_url)
184
+ query_params = URI.decode_www_form(uri.query.to_s).to_h
185
+ query_params["apiKey"] = api_key
186
+ uri.query = URI.encode_www_form(query_params)
187
+
188
+ body = JSON.generate(query: query, variables: variables)
189
+ request = Net::HTTP::Post.new(uri)
190
+ request["Accept"] = "application/json"
191
+ request["Content-Type"] = "application/json"
192
+ request["User-Agent"] = "Cvrvaelger/#{VERSION}"
193
+ request.body = body
194
+
195
+ response = perform(uri, request)
196
+ raise ProviderError, "Datafordeler CVR error (#{response.code})" unless response.is_a?(Net::HTTPSuccess)
197
+
198
+ begin
199
+ payload = JSON.parse(response.body)
200
+ rescue JSON::ParserError
201
+ raise ProviderError, "Datafordeler CVR returned invalid JSON"
202
+ end
203
+
204
+ if payload["errors"].is_a?(Array) && payload["errors"].any?
205
+ message = payload["errors"].map { |err| err.is_a?(Hash) ? err["message"] : err }.compact.first
206
+ raise ProviderError, "Datafordeler CVR GraphQL error (#{message || 'unknown'})"
207
+ end
208
+
209
+ payload
210
+ end
211
+
212
+ def perform(uri, request)
213
+ return http.call(uri, request) if http
214
+
215
+ Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == "https", open_timeout: 10,
216
+ read_timeout: 30) do |client|
217
+ client.request(request)
218
+ end
219
+ rescue Net::OpenTimeout, Net::ReadTimeout, Errno::ECONNREFUSED, SocketError => e
220
+ raise ProviderError, "Datafordeler CVR unreachable (#{e.class})"
221
+ end
222
+
223
+ def blank?(value)
224
+ value.nil? || (value.respond_to?(:empty?) && value.empty?) ||
225
+ (value.is_a?(String) && value.strip.empty?)
226
+ end
227
+
228
+ def present?(value)
229
+ !blank?(value)
230
+ end
231
+
232
+ def present_string(value)
233
+ return nil if blank?(value)
234
+
235
+ value.to_s
236
+ end
237
+ end
238
+ end
@@ -0,0 +1,78 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Cvrvaelger
4
+ PROVIDER = "datafordeler_cvr"
5
+
6
+ # Verified company hit from CVR (picker-shaped; no host-app persistence).
7
+ Company = Data.define(
8
+ :cvr,
9
+ :name,
10
+ :address_line,
11
+ :postal_code,
12
+ :city,
13
+ :provider,
14
+ :status
15
+ ) do
16
+ def self.from_node(node)
17
+ cvr = normalize_cvr(node["cvrNummer"] || node["CVRNummer"] || node["cvr"])
18
+ name = extract_name(node)
19
+ address = node["adresse"] || node["beliggenhedsadresse"] || {}
20
+ address = {} unless address.is_a?(Hash)
21
+
22
+ new(
23
+ cvr: cvr,
24
+ name: name,
25
+ address_line: build_address_line(address, node),
26
+ postal_code: present_string(scalar(address["postnummer"] || address["postnr"] || node["postnummer"])),
27
+ city: present_string(scalar(address["postdistrikt"] || address["postnummerNavn"] || node["bynavn"])),
28
+ provider: PROVIDER,
29
+ status: present_string(scalar(node["status"] || node["virksomhedsstatus"]))
30
+ )
31
+ end
32
+
33
+ def self.normalize_cvr(value)
34
+ digits = value.to_s.gsub(/\D/, "")
35
+ digits.match?(/\A\d{8}\z/) ? digits : nil
36
+ end
37
+
38
+ def self.extract_name(node)
39
+ raw = node["navn"] || node["navne"] || node["name"]
40
+ case raw
41
+ when String then present_string(raw)
42
+ when Hash then present_string(scalar(raw["navn"] || raw["name"]))
43
+ when Array
44
+ first = raw.find { |row| row.is_a?(Hash) } || raw.first
45
+ if first.is_a?(Hash)
46
+ present_string(scalar(first["navn"] || first["name"]))
47
+ else
48
+ present_string(first)
49
+ end
50
+ end
51
+ end
52
+
53
+ def self.build_address_line(address, node)
54
+ if address["vejnavn"]
55
+ parts = [scalar(address["vejnavn"]), scalar(address["husnummer"] || address["husnr"])]
56
+ joined = parts.compact.map { |part| part.to_s.strip }.reject(&:empty?).join(" ")
57
+ return present_string(joined)
58
+ end
59
+
60
+ present_string(scalar(node["address"] || node["adressebetegnelse"]))
61
+ end
62
+
63
+ def self.scalar(value)
64
+ return nil if value.nil? || value.is_a?(Hash) || value.is_a?(Array)
65
+
66
+ value
67
+ end
68
+
69
+ def self.present_string(value)
70
+ return nil if value.nil?
71
+
72
+ string = value.to_s.strip
73
+ string.empty? ? nil : string
74
+ end
75
+
76
+ private_class_method :build_address_line, :scalar, :present_string
77
+ end
78
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Cvrvaelger
4
+ class Error < StandardError
5
+ end
6
+
7
+ # Raised when the Datafordeler CVR API fails, returns invalid JSON, or is unreachable.
8
+ class ProviderError < Error
9
+ end
10
+
11
+ # Raised when no API key is configured (no invented demo secret).
12
+ class ConfigurationError < Error
13
+ end
14
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Cvrvaelger
4
+ VERSION = "0.1.0"
5
+ end
data/lib/cvrvaelger.rb ADDED
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "cvrvaelger/version"
4
+ require_relative "cvrvaelger/error"
5
+ require_relative "cvrvaelger/company"
6
+ require_relative "cvrvaelger/client"
7
+
8
+ # Ruby client for Det Centrale Virksomhedsregister (CVR) via Datafordeler GraphQL.
9
+ #
10
+ # Denmark only. Rails controllers, Stimulus pickers, and persistence belong in the
11
+ # host application (same split as adressevaelger).
12
+ module Cvrvaelger
13
+ end
metadata ADDED
@@ -0,0 +1,59 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: cvrvaelger
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Rasmus Bergholdt
8
+ bindir: bin
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies: []
12
+ description: |
13
+ HTTP client for Det Centrale Virksomhedsregister (CVR) on Datafordeler GraphQL:
14
+ verify an 8-digit CVR number or exact registered name and return the company
15
+ name plus light address fields for picker UX. No Rails dependency.
16
+ email:
17
+ - rasmus.bergholdt@gmail.com
18
+ executables: []
19
+ extensions: []
20
+ extra_rdoc_files: []
21
+ files:
22
+ - ".env.example"
23
+ - ".rubocop.yml"
24
+ - CHANGELOG.md
25
+ - LICENSE.txt
26
+ - README.md
27
+ - cvrvaelger.gemspec
28
+ - lib/cvrvaelger.rb
29
+ - lib/cvrvaelger/client.rb
30
+ - lib/cvrvaelger/company.rb
31
+ - lib/cvrvaelger/error.rb
32
+ - lib/cvrvaelger/version.rb
33
+ homepage: https://github.com/bergholdt/cvrvaelger
34
+ licenses:
35
+ - MIT
36
+ metadata:
37
+ homepage_uri: https://github.com/bergholdt/cvrvaelger
38
+ source_code_uri: https://github.com/bergholdt/cvrvaelger/tree/v0.1.0
39
+ changelog_uri: https://github.com/bergholdt/cvrvaelger/blob/v0.1.0/CHANGELOG.md
40
+ bug_tracker_uri: https://github.com/bergholdt/cvrvaelger/issues
41
+ rubygems_mfa_required: 'true'
42
+ rdoc_options: []
43
+ require_paths:
44
+ - lib
45
+ required_ruby_version: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - ">="
48
+ - !ruby/object:Gem::Version
49
+ version: 3.3.0
50
+ required_rubygems_version: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ requirements: []
56
+ rubygems_version: 4.0.20
57
+ specification_version: 4
58
+ summary: Ruby client for Danish CVR company lookup via Datafordeler GraphQL.
59
+ test_files: []