cuzk-rest 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.
@@ -0,0 +1,116 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CUZK
4
+ module REST
5
+ module Resources
6
+ class Parcel < Resource
7
+ self.endpoint_path = 'Parcely'
8
+
9
+ def id
10
+ attributes['id']
11
+ end
12
+
13
+ def number
14
+ attributes['kmenoveCislo']
15
+ end
16
+
17
+ def sub_number
18
+ attributes['pododdeleniCisla']
19
+ end
20
+
21
+ def full_number
22
+ sub_number ? "#{number}/#{sub_number}" : number.to_s
23
+ end
24
+
25
+ def cadastral_unit_code
26
+ attributes['kodKatastralnihoUzemi']
27
+ end
28
+
29
+ def cadastral_unit_name
30
+ attributes['nazevKatastralnihoUzemi']
31
+ end
32
+
33
+ def area
34
+ attributes['vymera']
35
+ end
36
+
37
+ def land_type
38
+ attributes['druhPozemku']
39
+ end
40
+
41
+ def land_type_code
42
+ attributes['kodDruhuPozemku']
43
+ end
44
+
45
+ def land_use
46
+ attributes['zpusobVyuziti']
47
+ end
48
+
49
+ def land_use_code
50
+ attributes['kodZpusobuVyuziti']
51
+ end
52
+
53
+ def protection_type
54
+ attributes['zpusobOchrany']
55
+ end
56
+
57
+ def lv_number
58
+ attributes['cisloLv']
59
+ end
60
+
61
+ def map_sheet
62
+ attributes['mapovyList']
63
+ end
64
+
65
+ class << self
66
+ def find(id)
67
+ data = get("/#{id}")
68
+ build(data)
69
+ end
70
+
71
+ def search(params = {})
72
+ data = get('/Vyhledani', normalize_search_params(params))
73
+ build_collection(data, key: 'parcely')
74
+ end
75
+
76
+ def find_by_cadastral_unit(cadastral_unit_code, params = {})
77
+ search(params.merge(cadastral_unit: cadastral_unit_code))
78
+ end
79
+
80
+ def find_neighbors(parcel_id)
81
+ data = get("/SousedniParcely/#{parcel_id}")
82
+ build_collection(data, key: 'parcely')
83
+ end
84
+
85
+ private
86
+
87
+ def normalize_search_params(params)
88
+ mapping = {
89
+ cadastral_unit: 'KodKatastralnihoUzemi',
90
+ parcel_type: 'TypParcely',
91
+ numbering_type: 'DruhCislovaniParcely',
92
+ number: 'KmenoveCisloParcely',
93
+ sub_number: 'PoddeleniCislaParcely',
94
+ lv_number: 'CisloLv'
95
+ }
96
+
97
+ params.each_with_object({}) do |(key, value), result|
98
+ api_key = mapping[key] || key.to_s
99
+ result[api_key] = value
100
+ end
101
+ end
102
+ end
103
+
104
+ def neighboring_parcels
105
+ self.class.find_neighbors(id)
106
+ end
107
+
108
+ private
109
+
110
+ def summary_attributes
111
+ "id=#{id} number=#{full_number} area=#{area} cadastral_unit=#{cadastral_unit_name}"
112
+ end
113
+ end
114
+ end
115
+ end
116
+ end
@@ -0,0 +1,108 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CUZK
4
+ module REST
5
+ module Resources
6
+ class Procedure < Resource
7
+ self.endpoint_path = 'Rizeni'
8
+
9
+ def id
10
+ attributes['id']
11
+ end
12
+
13
+ def procedure_number
14
+ attributes['cisloRizeni']
15
+ end
16
+
17
+ def procedure_type
18
+ attributes['typRizeni']
19
+ end
20
+
21
+ def procedure_type_code
22
+ attributes['kodTypuRizeni']
23
+ end
24
+
25
+ def status
26
+ attributes['stav']
27
+ end
28
+
29
+ def status_code
30
+ attributes['kodStavu']
31
+ end
32
+
33
+ def cadastral_unit_code
34
+ attributes['kodKatastralnihoUzemi']
35
+ end
36
+
37
+ def cadastral_unit_name
38
+ attributes['nazevKatastralnihoUzemi']
39
+ end
40
+
41
+ def filed_date
42
+ attributes['datumPodani']
43
+ end
44
+
45
+ def resolved_date
46
+ attributes['datumVyrizeni']
47
+ end
48
+
49
+ def description
50
+ attributes['popis']
51
+ end
52
+
53
+ def active?
54
+ resolved_date.nil?
55
+ end
56
+
57
+ class << self
58
+ def find(id)
59
+ data = get("/#{id}")
60
+ build(data)
61
+ end
62
+
63
+ def search(params = {})
64
+ data = get('/Vyhledani', normalize_search_params(params))
65
+ build_collection(data, key: 'rizeni')
66
+ end
67
+
68
+ def active(params = {})
69
+ search(params.merge(status: 'aktivni'))
70
+ end
71
+
72
+ def received_on(date, params = {})
73
+ data = get('/PrijateDne', normalize_search_params(params.merge(datum: date)))
74
+ build_collection(data, key: 'rizeni')
75
+ end
76
+
77
+ def find_by_cadastral_unit(cadastral_unit_code, params = {})
78
+ search(params.merge(cadastral_unit: cadastral_unit_code))
79
+ end
80
+
81
+ private
82
+
83
+ def normalize_search_params(params)
84
+ mapping = {
85
+ cadastral_unit: 'KodKatastralnihoUzemi',
86
+ procedure_type: 'KodTypuRizeni',
87
+ status: 'Stav',
88
+ filed_from: 'DatumPodaniOd',
89
+ filed_to: 'DatumPodaniDo',
90
+ datum: 'Datum'
91
+ }
92
+
93
+ params.each_with_object({}) do |(key, value), result|
94
+ api_key = mapping[key] || key.to_s
95
+ result[api_key] = value
96
+ end
97
+ end
98
+ end
99
+
100
+ private
101
+
102
+ def summary_attributes
103
+ "id=#{id} number=#{procedure_number} type=#{procedure_type} status=#{status}"
104
+ end
105
+ end
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,86 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CUZK
4
+ module REST
5
+ module Resources
6
+ class Registry < Resource
7
+ self.endpoint_path = 'CiselnikyISKN'
8
+
9
+ def code
10
+ attributes['kod']
11
+ end
12
+
13
+ def name
14
+ attributes['nazev']
15
+ end
16
+
17
+ def description
18
+ attributes['popis']
19
+ end
20
+
21
+ def valid_from
22
+ attributes['platnostOd']
23
+ end
24
+
25
+ def valid_to
26
+ attributes['platnostDo']
27
+ end
28
+
29
+ def active?
30
+ valid_to.nil?
31
+ end
32
+
33
+ class << self
34
+ def land_types
35
+ fetch_registry('DruhyPozemku')
36
+ end
37
+
38
+ def building_types
39
+ fetch_registry('TypyStavby')
40
+ end
41
+
42
+ def building_purposes
43
+ fetch_registry('ZpusobyVyuzitiStavby')
44
+ end
45
+
46
+ def unit_types
47
+ fetch_registry('TypyJednotky')
48
+ end
49
+
50
+ def protection_types
51
+ fetch_registry('ZpusobyOchranyNemovitosti')
52
+ end
53
+
54
+ def land_use_types
55
+ fetch_registry('ZpusobyVyuzitiPozemku')
56
+ end
57
+
58
+ def translate_code(code, registry_type:)
59
+ entries = fetch_registry(registry_type)
60
+ entry = entries.find { |e| e.code.to_s == code.to_s }
61
+ entry&.name
62
+ end
63
+
64
+ def find_code(description, registry_type:)
65
+ entries = fetch_registry(registry_type)
66
+ entry = entries.find { |e| e.name&.downcase&.include?(description.downcase) }
67
+ entry&.code
68
+ end
69
+
70
+ private
71
+
72
+ def fetch_registry(type)
73
+ data = get("/#{type}")
74
+ build_collection(data, key: 'polozky')
75
+ end
76
+ end
77
+
78
+ private
79
+
80
+ def summary_attributes
81
+ "code=#{code} name=#{name}"
82
+ end
83
+ end
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,80 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CUZK
4
+ module REST
5
+ module Resources
6
+ class Territory < Resource
7
+ self.endpoint_path = 'CiselnikyUzemnichJednotek'
8
+
9
+ def code
10
+ attributes['kod']
11
+ end
12
+
13
+ def name
14
+ attributes['nazev']
15
+ end
16
+
17
+ def territory_type
18
+ attributes['typ']
19
+ end
20
+
21
+ def parent_code
22
+ attributes['kodNadrazeneho']
23
+ end
24
+
25
+ def parent_name
26
+ attributes['nazevNadrazeneho']
27
+ end
28
+
29
+ class << self
30
+ def cadastral_units(params = {})
31
+ data = get('/KatastralniUzemi', normalize_params(params))
32
+ build_collection(data, key: 'katastralniUzemi')
33
+ end
34
+
35
+ def municipalities(params = {})
36
+ data = get('/Obce', normalize_params(params))
37
+ build_collection(data, key: 'obce')
38
+ end
39
+
40
+ def municipality_parts(params = {})
41
+ data = get('/CastiObci', normalize_params(params))
42
+ build_collection(data, key: 'castiObci')
43
+ end
44
+
45
+ def districts(params = {})
46
+ data = get('/Okresy', normalize_params(params))
47
+ build_collection(data, key: 'okresy')
48
+ end
49
+
50
+ def regions
51
+ data = get('/Kraje')
52
+ build_collection(data, key: 'kraje')
53
+ end
54
+
55
+ private
56
+
57
+ def normalize_params(params)
58
+ mapping = {
59
+ region: 'KodKraje',
60
+ district: 'KodOkresu',
61
+ municipality: 'KodObce',
62
+ name: 'Nazev'
63
+ }
64
+
65
+ params.each_with_object({}) do |(key, value), result|
66
+ api_key = mapping[key] || key.to_s
67
+ result[api_key] = value
68
+ end
69
+ end
70
+ end
71
+
72
+ private
73
+
74
+ def summary_attributes
75
+ "code=#{code} name=#{name} type=#{territory_type}"
76
+ end
77
+ end
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,122 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CUZK
4
+ module REST
5
+ module Resources
6
+ class Unit < Resource
7
+ self.endpoint_path = 'Jednotky'
8
+
9
+ def id
10
+ attributes['id']
11
+ end
12
+
13
+ def number
14
+ attributes['cisloJednotky']
15
+ end
16
+
17
+ def unit_type
18
+ attributes['typJednotky']
19
+ end
20
+
21
+ def unit_type_code
22
+ attributes['kodTypuJednotky']
23
+ end
24
+
25
+ def unit_type_description
26
+ case unit_type_code
27
+ when 1, '1' then 'byt'
28
+ when 2, '2' then 'nebytový prostor'
29
+ when 3, '3' then 'ateliér'
30
+ else unit_type
31
+ end
32
+ end
33
+
34
+ def floor
35
+ attributes['podlazi']
36
+ end
37
+
38
+ def area
39
+ attributes['vymera']
40
+ end
41
+
42
+ def building_id
43
+ attributes['idStavby']
44
+ end
45
+
46
+ def cadastral_unit_code
47
+ attributes['kodKatastralnihoUzemi']
48
+ end
49
+
50
+ def cadastral_unit_name
51
+ attributes['nazevKatastralnihoUzemi']
52
+ end
53
+
54
+ def lv_number
55
+ attributes['cisloLv']
56
+ end
57
+
58
+ def share_numerator
59
+ attributes['podilCitatel']
60
+ end
61
+
62
+ def share_denominator
63
+ attributes['podilJmenovatel']
64
+ end
65
+
66
+ def ownership_share
67
+ return nil unless share_numerator && share_denominator
68
+
69
+ "#{share_numerator}/#{share_denominator}"
70
+ end
71
+
72
+ def share_percentage
73
+ return nil unless share_numerator && share_denominator&.to_f&.positive?
74
+
75
+ (share_numerator.to_f / share_denominator * 100).round(2)
76
+ end
77
+
78
+ class << self
79
+ def find(id)
80
+ data = get("/#{id}")
81
+ build(data)
82
+ end
83
+
84
+ def search(params = {})
85
+ data = get('/Vyhledani', normalize_search_params(params))
86
+ build_collection(data, key: 'jednotky')
87
+ end
88
+
89
+ def find_by_building(building_id)
90
+ search(house_number: building_id)
91
+ end
92
+
93
+ private
94
+
95
+ def normalize_search_params(params)
96
+ mapping = {
97
+ municipality_part: 'KodCastiObce',
98
+ building_type: 'TypStavby',
99
+ house_number: 'CisloDomovni',
100
+ unit_number: 'CisloJednotky'
101
+ }
102
+
103
+ params.each_with_object({}) do |(key, value), result|
104
+ api_key = mapping[key] || key.to_s
105
+ result[api_key] = value
106
+ end
107
+ end
108
+ end
109
+
110
+ def shared_ownership?
111
+ share_denominator.to_i > 1
112
+ end
113
+
114
+ private
115
+
116
+ def summary_attributes
117
+ "id=#{id} number=#{number} type=#{unit_type_description} share=#{ownership_share}"
118
+ end
119
+ end
120
+ end
121
+ end
122
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CUZK
4
+ module REST
5
+ VERSION = '0.1.0'
6
+ end
7
+ end
data/lib/cuzk/rest.rb ADDED
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'zeitwerk'
4
+ require 'faraday'
5
+ require 'faraday/retry'
6
+ require 'oj'
7
+
8
+ module CUZK
9
+ module REST
10
+ class << self
11
+ def configure
12
+ yield(configuration)
13
+ end
14
+
15
+ def configuration
16
+ @configuration ||= Configuration.new
17
+ end
18
+
19
+ def reset_configuration!
20
+ @configuration = Configuration.new
21
+ end
22
+
23
+ def loader
24
+ @loader ||= begin
25
+ loader = Zeitwerk::Loader.new
26
+ loader.tag = 'cuzk-rest'
27
+ loader.push_dir("#{__dir__}/rest", namespace: CUZK::REST)
28
+ loader.inflector.inflect('api_key' => 'APIKey')
29
+ loader.ignore("#{__dir__}/rest/version.rb")
30
+ loader.ignore("#{__dir__}/rest/errors.rb")
31
+ loader
32
+ end
33
+ end
34
+ end
35
+
36
+ loader.setup
37
+ end
38
+ end
39
+
40
+ require_relative 'rest/version'
41
+ require_relative 'rest/errors'
data/lib/cuzk-rest.rb ADDED
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'cuzk/rest'
metadata ADDED
@@ -0,0 +1,127 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: cuzk-rest
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Segfault Labs
8
+ bindir: exe
9
+ cert_chain: []
10
+ date: 2026-02-03 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: faraday
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - "~>"
17
+ - !ruby/object:Gem::Version
18
+ version: '2.12'
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - "~>"
24
+ - !ruby/object:Gem::Version
25
+ version: '2.12'
26
+ - !ruby/object:Gem::Dependency
27
+ name: faraday-retry
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - "~>"
31
+ - !ruby/object:Gem::Version
32
+ version: '2.2'
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '2.2'
40
+ - !ruby/object:Gem::Dependency
41
+ name: oj
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '3.16'
47
+ type: :runtime
48
+ prerelease: false
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: '3.16'
54
+ - !ruby/object:Gem::Dependency
55
+ name: zeitwerk
56
+ requirement: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - "~>"
59
+ - !ruby/object:Gem::Version
60
+ version: '2.7'
61
+ type: :runtime
62
+ prerelease: false
63
+ version_requirements: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - "~>"
66
+ - !ruby/object:Gem::Version
67
+ version: '2.7'
68
+ description: Idiomatic Ruby client for the Czech Real Estate Registry (ČÚZK) REST
69
+ API. Provides access to cadastral data including parcels, buildings, units, ownership
70
+ information, and reference registries.
71
+ email:
72
+ - info@segfault-labs.dev
73
+ executables: []
74
+ extensions: []
75
+ extra_rdoc_files: []
76
+ files:
77
+ - ".rspec"
78
+ - ".rubocop.yml"
79
+ - ".ruby-version"
80
+ - CHANGELOG.md
81
+ - LICENSE.txt
82
+ - README.md
83
+ - Rakefile
84
+ - lib/cuzk-rest.rb
85
+ - lib/cuzk/rest.rb
86
+ - lib/cuzk/rest/client.rb
87
+ - lib/cuzk/rest/configuration.rb
88
+ - lib/cuzk/rest/connection.rb
89
+ - lib/cuzk/rest/errors.rb
90
+ - lib/cuzk/rest/rate_limiter.rb
91
+ - lib/cuzk/rest/resource.rb
92
+ - lib/cuzk/rest/resources/app_service.rb
93
+ - lib/cuzk/rest/resources/building.rb
94
+ - lib/cuzk/rest/resources/building_right.rb
95
+ - lib/cuzk/rest/resources/ownership.rb
96
+ - lib/cuzk/rest/resources/parcel.rb
97
+ - lib/cuzk/rest/resources/procedure.rb
98
+ - lib/cuzk/rest/resources/registry.rb
99
+ - lib/cuzk/rest/resources/territory.rb
100
+ - lib/cuzk/rest/resources/unit.rb
101
+ - lib/cuzk/rest/version.rb
102
+ homepage: https://gitlab.com/segfault-labs/cuzk-rest-rb
103
+ licenses:
104
+ - MIT
105
+ metadata:
106
+ homepage_uri: https://gitlab.com/segfault-labs/cuzk-rest-rb
107
+ source_code_uri: https://gitlab.com/segfault-labs/cuzk-rest-rb
108
+ changelog_uri: https://gitlab.com/segfault-labs/cuzk-rest-rb/-/blob/main/CHANGELOG.md
109
+ rubygems_mfa_required: 'true'
110
+ rdoc_options: []
111
+ require_paths:
112
+ - lib
113
+ required_ruby_version: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: 3.1.0
118
+ required_rubygems_version: !ruby/object:Gem::Requirement
119
+ requirements:
120
+ - - ">="
121
+ - !ruby/object:Gem::Version
122
+ version: '0'
123
+ requirements: []
124
+ rubygems_version: 3.6.2
125
+ specification_version: 4
126
+ summary: Ruby client for ČÚZK Real Estate Registry REST API
127
+ test_files: []