rsmp_schema 0.9.1 → 0.10.1

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.
@@ -1,186 +1,210 @@
1
1
  require 'json_schemer'
2
2
 
3
+ # RSMP (Road Side Message Protocol) schema validation library.
3
4
  module RSMP
4
- end
5
-
6
- module RSMP::Schema
7
- @@schemas = nil
8
-
9
- def self.setup
10
- @@schemas = {}
11
- schemas_path = File.expand_path( File.join(__dir__,'..','..','schemas') )
12
- Dir.glob("#{schemas_path}/*").select {|f| File.directory? f}.each do |type_path|
13
- type = File.basename(type_path).to_sym
14
- load_schema_type type, type_path
5
+ # Provides JSON Schema validation for RSMP messages across core and SXL versions.
6
+ module Schema
7
+ @schemas = nil
8
+
9
+ def self.setup
10
+ @schemas = {}
11
+ schemas_path = File.expand_path(File.join(__dir__, '..', '..', 'schemas'))
12
+ Dir.glob("#{schemas_path}/*").select { |f| File.directory? f }.each do |type_path|
13
+ type = File.basename(type_path).to_sym
14
+ load_schema_type type, type_path
15
+ end
15
16
  end
16
- end
17
17
 
18
- # load an schema from a folder. schemas are organized by version, and contain
19
- # json schema files, with the entry point being rsmp.jspon, eg:
20
- # tlc
21
- # 1.0.7
22
- # rsmp.json
23
- # other jon schema files...
24
- # 1.0.8
25
- # ...
26
- #
27
- # an error is raised if the schema type already exists, and force is not set to true
28
- def self.load_schema_type type, type_path, force:false
29
- raise RuntimeError.new("Schema type #{type} already loaded") if @@schemas[type] && force!=true
30
- @@schemas[type] = {}
31
- Dir.glob("#{type_path}/*").select {|f| File.directory? f}.each do |schema_path|
32
- version = File.basename(schema_path)
33
- file_path = File.join(schema_path,'rsmp.json')
34
- if File.exist? file_path
35
- @@schemas[type][version] = JSONSchemer.schema(
36
- Pathname.new(File.join(schema_path,'rsmp.json'))
18
+ # load an schema from a folder. schemas are organized by version, and contain
19
+ # json schema files, with the entry point being rsmp.jspon, eg:
20
+ # tlc
21
+ # 1.0.7
22
+ # rsmp.json
23
+ # other jon schema files...
24
+ # 1.0.8
25
+ # ...
26
+ #
27
+ # an error is raised if the schema type already exists, and force is not set to true
28
+ def self.load_schema_type(type, type_path, force: false)
29
+ raise "Schema type #{type} already loaded" if @schemas[type] && force != true
30
+
31
+ @schemas[type] = {}
32
+ Dir.glob("#{type_path}/*").select { |f| File.directory? f }.each do |schema_path|
33
+ version = File.basename(schema_path)
34
+ file_path = File.join(schema_path, 'rsmp.json')
35
+ next unless File.exist? file_path
36
+
37
+ @schemas[type][version] = JSONSchemer.schema(
38
+ Pathname.new(File.join(schema_path, 'rsmp.json'))
37
39
  )
38
40
  end
39
41
  end
40
- end
41
42
 
42
- # remove a schema type
43
- def self.remove_schema_type type
44
- schemas.delete type
45
- end
43
+ # remove a schema type
44
+ def self.remove_schema_type(type)
45
+ schemas.delete type
46
+ end
46
47
 
47
- # get schemas types
48
- def self.schema_types
49
- schemas.keys
50
- end
48
+ # get schemas types
49
+ def self.schema_types
50
+ schemas.keys
51
+ end
51
52
 
52
- # get all schemas, oganized by type and version
53
- def self.schemas
54
- raise RuntimeError.new("No schemas available, perhaps Schema.setup was never called?") unless @@schemas
55
- @@schemas
56
- end
53
+ # get all schemas, oganized by type and version
54
+ def self.schemas
55
+ raise 'No schemas available, perhaps Schema.setup was never called?' unless @schemas
57
56
 
58
- # get array of core schema versions
59
- def self.core_versions
60
- versions :core
61
- end
57
+ @schemas
58
+ end
62
59
 
63
- # get earliest core schema version
64
- def self.earliest_core_version
65
- earliest_version :core
66
- end
60
+ # get array of core schema versions
61
+ def self.core_versions
62
+ versions :core
63
+ end
67
64
 
68
- # get latesty core schema version
69
- def self.latest_core_version
70
- latest_version :core
71
- end
65
+ # get earliest core schema version
66
+ def self.earliest_core_version
67
+ earliest_version :core
68
+ end
72
69
 
73
- # get array of schema versions for a particular schema type
74
- def self.versions type
75
- schemas = find_schemas!(type).keys
76
- sort_versions(schemas)
77
- end
70
+ # get latesty core schema version
71
+ def self.latest_core_version
72
+ latest_version :core
73
+ end
78
74
 
79
- # get earliest schema version for a particular schema type
80
- def self.earliest_version type
81
- schemas = find_schemas!(type).keys
82
- sort_versions(schemas).first
83
- end
75
+ # get array of schema versions for a particular schema type
76
+ def self.versions(type)
77
+ schemas = find_schemas!(type).keys
78
+ sort_versions(schemas)
79
+ end
84
80
 
85
- # get latest schema version for a particular schema type
86
- def self.latest_version type
87
- schemas = find_schemas!(type).keys
88
- sort_versions(schemas).last
89
- end
81
+ # get earliest schema version for a particular schema type
82
+ def self.earliest_version(type)
83
+ schemas = find_schemas!(type).keys
84
+ sort_versions(schemas).first
85
+ end
90
86
 
91
- # validate an rsmp messages using a schema object
92
- def self.validate_using_schema message, schema
93
- raise ArgumentError.new("message missing") unless message
94
- raise ArgumentError.new("schema missing") unless schema
95
- unless schema.valid? message
96
- schema.validate(message).map do |item|
97
- [item['data_pointer'],item['type'],item['details']]
87
+ # get latest schema version for a particular schema type
88
+ def self.latest_version(type)
89
+ schemas = find_schemas!(type).keys
90
+ sort_versions(schemas).last
91
+ end
92
+
93
+ # validate an rsmp messages using a schema object
94
+ def self.validate_using_schema(message, schema)
95
+ raise ArgumentError, 'message missing' unless message
96
+ raise ArgumentError, 'schema missing' unless schema
97
+
98
+ if schema.valid? message
99
+ []
100
+ else
101
+ schema.validate(message).map do |item|
102
+ [item['data_pointer'], item['type'], item['details']]
103
+ end
98
104
  end
99
- else
100
- []
101
105
  end
102
- end
103
106
 
104
- # sort version strings
105
- def self.sort_versions versions
106
- versions.sort_by { |k| Gem::Version.new(k) }
107
- end
107
+ # sort version strings
108
+ def self.sort_versions(versions)
109
+ versions.sort_by { |k| Gem::Version.new(k) }
110
+ end
108
111
 
109
- # find schemas versions for particular schema type
110
- # return nil if type not found
111
- def self.find_schemas type
112
- raise ArgumentError.new("type missing") unless type
113
- schemas = @@schemas[type.to_sym]
114
- end
112
+ # find schemas versions for particular schema type
113
+ # return nil if type not found
114
+ def self.find_schemas(type)
115
+ raise ArgumentError, 'type missing' unless type
115
116
 
116
- # find schemas versions for particular schema type
117
- # raise error if not found
118
- def self.find_schemas! type
119
- schemas = find_schemas type
120
- raise UnknownSchemaTypeError.new("Unknown schema type #{type}") unless schemas
121
- schemas
122
- end
117
+ @schemas[type.to_sym]
118
+ end
123
119
 
124
- # find schema for a particular schema and version
125
- # return nil if not found
126
- def self.find_schema type, version, options={}
127
- raise ArgumentError.new("version missing") unless version
128
- version = sanitize_version version if options[:lenient]
129
- if version
120
+ # find schemas versions for particular schema type
121
+ # raise error if not found
122
+ def self.find_schemas!(type)
130
123
  schemas = find_schemas type
131
- return schemas[version] if schemas
124
+ raise UnknownSchemaTypeError, "Unknown schema type #{type}" unless schemas
125
+
126
+ schemas
132
127
  end
133
- nil
134
- end
135
128
 
136
- # get major.minor.patch part of a version string, where patch is optional
137
- # ignore trailing characters, e.g.
138
- # 3.1.3.32A => 3.1.3
139
- # 3.1A3r3 >= 3.1
140
- # return nil if string doesn't match
141
- def self.sanitize_version version
142
- # match normal semver z.y.z format
143
- if matched = /^\d+\.\d+\.\d+/.match(version)
144
- matched.to_s
145
- # match x.y format, and add patch version zero to get z.y.0
146
- elsif matched = /^\d+\.\d+/.match(version)
147
- "#{matched.to_s}.0"
129
+ # find schema for a particular schema and version
130
+ # return nil if not found
131
+ def self.find_schema(type, version, options = {})
132
+ raise ArgumentError, 'version missing' unless version
133
+
134
+ version = sanitize_version version if options[:lenient]
135
+ if version
136
+ schemas = find_schemas type
137
+ return schemas[version] if schemas
138
+ end
139
+ nil
148
140
  end
149
- end
150
141
 
151
- # find schema for a particular schema and version
152
- # raise error if not found
153
- def self.find_schema! type, version, options={}
154
- schema = find_schema type, version, options
155
- raise ArgumentError.new("version missing") unless version
156
- version = sanitize_version version if options[:lenient]
157
- if version
158
- schemas = find_schemas! type
159
- schema = schemas[version]
160
- return schema if schema
161
- end
162
- raise UnknownSchemaVersionError.new("Unknown schema version #{type} #{version}")
163
- end
142
+ # get major.minor.patch part of a version string, where patch is optional
143
+ # ignore trailing characters, e.g.
144
+ # 3.1.3.32A => 3.1.3
145
+ # 3.1A3r3 >= 3.1
146
+ # return nil if string doesn't match
147
+ def self.sanitize_version(version)
148
+ # match normal semver z.y.z format
149
+ if (matched = /^\d+\.\d+\.\d+/.match(version))
150
+ matched.to_s
151
+ # match x.y format, and add patch version zero to get z.y.0
152
+ elsif (matched = /^\d+\.\d+/.match(version))
153
+ "#{matched}.0"
154
+ end
155
+ end
164
156
 
165
- # true if a particular schema type and version found
166
- def self.has_schema? type, version, options={}
167
- find_schema(type,version, options) != nil
168
- end
157
+ # find schema for a particular schema and version
158
+ # raise error if not found
159
+ def self.find_schema!(type, version, options = {})
160
+ schema = find_schema type, version, options
161
+ raise ArgumentError, 'version missing' unless version
162
+
163
+ version = sanitize_version version if options[:lenient]
164
+ if version
165
+ schemas = find_schemas! type
166
+ schema = schemas[version]
167
+ return schema if schema
168
+ end
169
+ raise UnknownSchemaVersionError, "Unknown schema version #{type} #{version}"
170
+ end
169
171
 
170
- # validate using a particular schema and version
171
- # raises error if schema is not found
172
- # return nil if validation succeds, otherwise returns an array of errors
173
- def self.validate message, schemas, options={}
174
- raise ArgumentError.new("message missing") unless message
175
- raise ArgumentError.new("schemas missing") unless schemas
176
- raise ArgumentError.new("schemas must be a Hash") unless schemas.is_a?(Hash)
177
- raise ArgumentError.new("schemas cannot be empty") unless schemas.any?
178
- errors = schemas.flat_map do |type, version|
179
- schema = find_schema! type, version, options
180
- validate_using_schema(message, schema)
181
- end
182
- return nil if errors.empty?
183
- errors
184
- end
172
+ # true if a particular schema type and version found
173
+ def self.schema?(type, version, options = {})
174
+ find_schema(type, version, options) != nil
175
+ end
176
+
177
+ # return a catalogue of statuses for a particular schema type and version
178
+ # returns a hash of { status_code_id_sym => [arg_name_sym, ...] }
179
+ # raises an error if the schema type/version is not found, or has no sxl.yaml
180
+ def self.status_catalogue(type, version)
181
+ find_schema! type, version
182
+ schemas_path = File.expand_path(File.join(__dir__, '..', '..', 'schemas'))
183
+ yaml_path = File.join(schemas_path, type.to_s, version, 'sxl.yaml')
184
+ raise "No sxl.yaml for #{type} #{version}" unless File.exist?(yaml_path)
185
+
186
+ sxl = RSMP::Convert::Import::YAML.read(yaml_path)
187
+ sxl[:statuses].transform_keys(&:to_sym).transform_values do |status|
188
+ (status['arguments'] || {}).keys.map(&:to_sym)
189
+ end
190
+ end
191
+
192
+ # validate using a particular schema and version
193
+ # raises error if schema is not found
194
+ # return nil if validation succeds, otherwise returns an array of errors
195
+ def self.validate(message, schemas, options = {})
196
+ raise ArgumentError, 'message missing' unless message
197
+ raise ArgumentError, 'schemas missing' unless schemas
198
+ raise ArgumentError, 'schemas must be a Hash' unless schemas.is_a?(Hash)
199
+ raise ArgumentError, 'schemas cannot be empty' unless schemas.any?
200
+
201
+ errors = schemas.flat_map do |type, version|
202
+ schema = find_schema! type, version, options
203
+ validate_using_schema(message, schema)
204
+ end
205
+ return nil if errors.empty?
185
206
 
207
+ errors
208
+ end
209
+ end
186
210
  end
@@ -1,5 +1,6 @@
1
1
  module RSMP
2
2
  module Schema
3
- VERSION = "0.9.1"
3
+ # Current version of the rsmp_schema gem.
4
+ VERSION = '0.10.1'.freeze
4
5
  end
5
- end
6
+ end
data/lib/rsmp_schema.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  require 'yaml'
2
2
  require 'json_schemer'
3
3
 
4
- # Define module hierarchy first
4
+ # RSMP (Road Side Message Protocol) schema validation library.
5
5
  module RSMP
6
6
  end
7
7
 
@@ -11,4 +11,4 @@ require 'rsmp_schema/convert/import/yaml'
11
11
  require 'rsmp_schema/convert/export/json_schema'
12
12
  require 'rsmp_schema/version'
13
13
 
14
- RSMP::Schema.setup
14
+ RSMP::Schema.setup
data/rsmp_schema.gemspec CHANGED
@@ -1,39 +1,37 @@
1
- lib = File.expand_path("lib", __dir__)
1
+ lib = File.expand_path('lib', __dir__)
2
2
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
3
  require 'pathname'
4
- require_relative "lib/rsmp_schema/version"
4
+ require_relative 'lib/rsmp_schema/version'
5
5
 
6
6
  Gem::Specification.new do |spec|
7
- spec.name = "rsmp_schema"
7
+ spec.name = 'rsmp_schema'
8
8
  spec.version = RSMP::Schema::VERSION
9
- spec.authors = ["Emil Tin"]
10
- spec.email = ["zf0f@kk.dk"]
9
+ spec.authors = ['Emil Tin']
10
+ spec.email = ['zf0f@kk.dk']
11
11
 
12
- spec.summary = "Validate RSMP message using RSMP JSON Schema."
13
- spec.description = "Validate RSMP message using RSMP JSON Schema. Support validating against core and different SXL's, in different versions."
14
- spec.homepage = "https://github.com/rsmp-nordic/rsmp_schema"
12
+ spec.summary = 'Validate RSMP message using RSMP JSON Schema.'
13
+ spec.description = 'Validate RSMP message using RSMP JSON Schema. Support validating against ' \
14
+ "core and different SXL's, in different versions."
15
+ spec.homepage = 'https://github.com/rsmp-nordic/rsmp_schema'
15
16
  spec.licenses = ['MIT']
16
17
  spec.required_ruby_version = '>= 3.0.0'
17
18
 
18
- spec.metadata["homepage_uri"] = spec.homepage
19
- spec.metadata["source_code_uri"] = spec.homepage
20
- spec.metadata["changelog_uri"] = "#{spec.homepage}/CHANGELOG.md"
21
- spec.metadata["bug_tracker_uri"] = "#{spec.homepage}/issues"
19
+ spec.metadata['homepage_uri'] = spec.homepage
20
+ spec.metadata['source_code_uri'] = spec.homepage
21
+ spec.metadata['changelog_uri'] = "#{spec.homepage}/CHANGELOG.md"
22
+ spec.metadata['bug_tracker_uri'] = "#{spec.homepage}/issues"
23
+ spec.metadata['rubygems_mfa_required'] = 'true'
22
24
 
23
25
  # Specify which files should be added to the gem when it is released.
24
26
  # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
25
- spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
27
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
26
28
  `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
27
29
  end
28
30
 
29
- spec.bindir = "exe"
31
+ spec.bindir = 'exe'
30
32
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
31
- spec.require_paths = ["lib"]
33
+ spec.require_paths = ['lib']
32
34
 
33
- spec.add_dependency "json_schemer", "~> 2.4.0"
34
- spec.add_dependency "thor", "~> 1.4.0"
35
-
36
- spec.add_development_dependency "rake", "~> 13.3.0"
37
- spec.add_development_dependency "rspec", "~> 3.13.0"
38
- spec.add_development_dependency "rspec-expectations", "~> 3.13.0"
35
+ spec.add_dependency 'json_schemer', '~> 2.5'
36
+ spec.add_dependency 'thor', '~> 1.5'
39
37
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rsmp_schema
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.1
4
+ version: 0.10.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Emil Tin
8
8
  bindir: exe
9
9
  cert_chain: []
10
- date: 2025-09-19 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: json_schemer
@@ -15,70 +15,28 @@ dependencies:
15
15
  requirements:
16
16
  - - "~>"
17
17
  - !ruby/object:Gem::Version
18
- version: 2.4.0
18
+ version: '2.5'
19
19
  type: :runtime
20
20
  prerelease: false
21
21
  version_requirements: !ruby/object:Gem::Requirement
22
22
  requirements:
23
23
  - - "~>"
24
24
  - !ruby/object:Gem::Version
25
- version: 2.4.0
25
+ version: '2.5'
26
26
  - !ruby/object:Gem::Dependency
27
27
  name: thor
28
28
  requirement: !ruby/object:Gem::Requirement
29
29
  requirements:
30
30
  - - "~>"
31
31
  - !ruby/object:Gem::Version
32
- version: 1.4.0
32
+ version: '1.5'
33
33
  type: :runtime
34
34
  prerelease: false
35
35
  version_requirements: !ruby/object:Gem::Requirement
36
36
  requirements:
37
37
  - - "~>"
38
38
  - !ruby/object:Gem::Version
39
- version: 1.4.0
40
- - !ruby/object:Gem::Dependency
41
- name: rake
42
- requirement: !ruby/object:Gem::Requirement
43
- requirements:
44
- - - "~>"
45
- - !ruby/object:Gem::Version
46
- version: 13.3.0
47
- type: :development
48
- prerelease: false
49
- version_requirements: !ruby/object:Gem::Requirement
50
- requirements:
51
- - - "~>"
52
- - !ruby/object:Gem::Version
53
- version: 13.3.0
54
- - !ruby/object:Gem::Dependency
55
- name: rspec
56
- requirement: !ruby/object:Gem::Requirement
57
- requirements:
58
- - - "~>"
59
- - !ruby/object:Gem::Version
60
- version: 3.13.0
61
- type: :development
62
- prerelease: false
63
- version_requirements: !ruby/object:Gem::Requirement
64
- requirements:
65
- - - "~>"
66
- - !ruby/object:Gem::Version
67
- version: 3.13.0
68
- - !ruby/object:Gem::Dependency
69
- name: rspec-expectations
70
- requirement: !ruby/object:Gem::Requirement
71
- requirements:
72
- - - "~>"
73
- - !ruby/object:Gem::Version
74
- version: 3.13.0
75
- type: :development
76
- prerelease: false
77
- version_requirements: !ruby/object:Gem::Requirement
78
- requirements:
79
- - - "~>"
80
- - !ruby/object:Gem::Version
81
- version: 3.13.0
39
+ version: '1.5'
82
40
  description: Validate RSMP message using RSMP JSON Schema. Support validating against
83
41
  core and different SXL's, in different versions.
84
42
  email:
@@ -94,6 +52,7 @@ files:
94
52
  - ".github/workflows/rspec.yaml"
95
53
  - ".gitignore"
96
54
  - ".rspec"
55
+ - ".rubocop.yml"
97
56
  - ".tool-versions"
98
57
  - Gemfile
99
58
  - Gemfile.lock
@@ -966,6 +925,7 @@ metadata:
966
925
  source_code_uri: https://github.com/rsmp-nordic/rsmp_schema
967
926
  changelog_uri: https://github.com/rsmp-nordic/rsmp_schema/CHANGELOG.md
968
927
  bug_tracker_uri: https://github.com/rsmp-nordic/rsmp_schema/issues
928
+ rubygems_mfa_required: 'true'
969
929
  rdoc_options: []
970
930
  require_paths:
971
931
  - lib
@@ -980,7 +940,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
980
940
  - !ruby/object:Gem::Version
981
941
  version: '0'
982
942
  requirements: []
983
- rubygems_version: 3.6.2
943
+ rubygems_version: 4.0.3
984
944
  specification_version: 4
985
945
  summary: Validate RSMP message using RSMP JSON Schema.
986
946
  test_files: []