rsmp_schema 0.1.0 → 0.2.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.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +1 -1
  3. data/lib/rsmp_schema/convert/export/json_schema.rb +96 -54
  4. data/lib/rsmp_schema/schema.rb +80 -24
  5. data/lib/rsmp_schema/version.rb +1 -1
  6. data/lib/rsmp_schema.rb +2 -0
  7. data/schemas/tlc/1.0.10/sxl.yaml +20 -65
  8. data/schemas/tlc/1.0.13/sxl.yaml +20 -80
  9. data/schemas/tlc/1.0.14/sxl.yaml +20 -80
  10. data/schemas/tlc/1.0.15/sxl.yaml +20 -87
  11. data/schemas/tlc/1.0.7/sxl.yaml +20 -61
  12. data/schemas/tlc/1.0.8/sxl.yaml +20 -65
  13. data/schemas/tlc/1.0.9/sxl.yaml +20 -65
  14. data/schemas/tlc/1.1/alarms/A0303.json +111 -0
  15. data/schemas/tlc/1.1/alarms/A0304.json +137 -0
  16. data/schemas/tlc/1.1/alarms/alarms.json +33 -1
  17. data/schemas/tlc/1.1/commands/M0001.json +2 -2
  18. data/schemas/tlc/1.1/commands/M0005.json +1 -1
  19. data/schemas/tlc/1.1/commands/M0013.json +1 -1
  20. data/schemas/tlc/1.1/commands/M0019.json +1 -1
  21. data/schemas/tlc/1.1/commands/M0022.json +335 -0
  22. data/schemas/tlc/1.1/commands/M0023.json +64 -0
  23. data/schemas/tlc/1.1/commands/commands.json +32 -0
  24. data/schemas/tlc/1.1/statuses/S0001.json +3 -3
  25. data/schemas/tlc/1.1/statuses/S0002.json +1 -1
  26. data/schemas/tlc/1.1/statuses/S0003.json +1 -1
  27. data/schemas/tlc/1.1/statuses/S0004.json +1 -1
  28. data/schemas/tlc/1.1/statuses/S0007.json +1 -1
  29. data/schemas/tlc/1.1/statuses/S0008.json +1 -1
  30. data/schemas/tlc/1.1/statuses/S0009.json +1 -1
  31. data/schemas/tlc/1.1/statuses/S0010.json +1 -1
  32. data/schemas/tlc/1.1/statuses/S0011.json +1 -1
  33. data/schemas/tlc/1.1/statuses/S0012.json +1 -1
  34. data/schemas/tlc/1.1/statuses/S0013.json +2 -2
  35. data/schemas/tlc/1.1/statuses/S0020.json +1 -1
  36. data/schemas/tlc/1.1/statuses/S0032.json +96 -0
  37. data/schemas/tlc/1.1/statuses/S0033.json +93 -0
  38. data/schemas/tlc/1.1/statuses/S0034.json +40 -0
  39. data/schemas/tlc/1.1/statuses/S0205.json +8 -2
  40. data/schemas/tlc/1.1/statuses/S0206.json +8 -2
  41. data/schemas/tlc/1.1/statuses/S0207.json +8 -2
  42. data/schemas/tlc/1.1/statuses/S0208.json +72 -18
  43. data/schemas/tlc/1.1/statuses/statuses.json +48 -0
  44. data/schemas/tlc/1.1/sxl.yaml +596 -241
  45. metadata +9 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 07e5fccae77303733072ab27976c1cb1991ea9cd1add360dbac63e8da97baf8b
4
- data.tar.gz: 364e6d5569d3fa262a96de68b80bec855d4fd3bb06c754ee47c5bcc3ea9300c4
3
+ metadata.gz: d77598d55d8ad5356f08539dae9c80c2f0887240f3d7cc45fe8f81a39e22467f
4
+ data.tar.gz: 376dde9dc8d380588293178dba3b968ac8a558c52832804e0aea5c0d065627f1
5
5
  SHA512:
6
- metadata.gz: d9a41e3ef2a8f1ce2ed30b701867b118fdaad9fc7f2bced0ca3637a65f242bb69735715e1d41d5bf7ea20690c2280cad7bdbd3b33ce2d0e137f218517967f3d8
7
- data.tar.gz: 9885c98876461dab7abc379206ee2617ffb6747fe96a91dec3c382d9111029b3a98ad9a389a6b2ea311db1d4d98e66ead63bf8baf5a7b020c3f520878bad4d54
6
+ metadata.gz: f49e353daeca137c0a542dfad6f49f6c927786fbef5f3b8242bf9dd29f091e398ef10ba206ebf71a64c8d64f258400c0b3b24c87b4e62cc39aaa6dd3d76bbbaa
7
+ data.tar.gz: 7c0565ff56406fbfc56f6b711e1b26a42d9bf1a50b708ed659b53628963f42b37922814ed2e0f517c302dd205ffbf888d22bd11f93be9a875f88ab84d6241dbc
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- rsmp_schema (0.1.0)
4
+ rsmp_schema (0.2.1)
5
5
  json_schemer (~> 0.2.21)
6
6
  thor (~> 1.2.1)
7
7
 
@@ -21,67 +21,61 @@ module RSMP
21
21
  JSON.generate(item,@@json_options)
22
22
  end
23
23
 
24
+ # convert a yaml item to json schema
24
25
  def self.build_value item
25
26
  out = {}
27
+ out['description'] = item['description'] if item['description']
26
28
 
27
- if item['description']
28
- out["description"] = item['description']
29
+ if item['type'] =~/_list$/
30
+ handle_string_list item, out
31
+ else
32
+ handle_types item, out
33
+ handle_enum item, out
34
+ handle_pattern item, out
29
35
  end
36
+ wrap_refs out
37
+ end
30
38
 
31
- if item['list']
32
- case item['type']
33
- when "boolean"
34
- out["$ref"] = "../../../core/3.1.1/definitions.json#/boolean_list"
35
- when "integer", "ordinal", "unit", "scale", "long"
36
- out["$ref"] = "../../../core/3.1.1/definitions.json#/integer_list"
37
- when "string"
38
- out["$ref"] = "../../../core/3.1.1/definitions.json#/string_list"
39
- else
40
- raise "Error: List of #{item['type']} is not supported: #{item.inspect}"
41
- end
42
-
43
- if item["values"]
44
- value_list = item["values"].keys.join('|')
45
- out['pattern'] = /(?-mix:^(#{value_list})(?:,(#{value_list}))*$)/
46
- end
47
-
48
- if item["pattern"]
49
- puts "Warning: Pattern not support for lists: #{item.inspect}"
50
- end
39
+ # convert an item which is not a string-list, to json schema
40
+ def self.handle_types item, out
41
+ case item['type']
42
+ when "string", "base64"
43
+ out["type"] = "string"
44
+ when "boolean"
45
+ out["$ref"] = "../../../core/3.1.1/definitions.json#/boolean"
46
+ when "timestamp"
47
+ out["$ref"] = "../../../core/3.1.1/definitions.json#/timestamp"
48
+ when "integer", "ordinal", "unit", "scale", "long"
49
+ out["$ref"] = "../../../core/3.1.1/definitions.json#/integer"
50
+ when 'array' # a json array
51
+ build_json_array item['items'], out
51
52
  else
52
- case item['type']
53
- when "string", "base64"
54
- out["type"] = "string"
55
- when "boolean"
56
- out["$ref"] = "../../../core/3.1.1/definitions.json#/boolean"
57
- when "timestamp"
58
- out["$ref"] = "../../../core/3.1.1/definitions.json#/timestamp"
59
- when "integer", "ordinal", "unit", "scale", "long"
60
- out["$ref"] = "../../../core/3.1.1/definitions.json#/integer"
61
- else
62
- out["type"] = "string"
63
- end
64
-
65
- if item["values"]
66
- case item["values"]
67
- when Hash
68
- out["enum"] = item["values"].keys.sort
69
- when Array
70
- out["enum"] = item["values"].sort
71
- else
72
- raise "Error: Values must be specified as either a Hash or an Array"
73
- end
74
-
75
- end
53
+ out["type"] = "string"
54
+ end
55
+ end
76
56
 
77
- if item["pattern"]
78
- out["pattern"] = item["pattern"]
79
- end
57
+ # convert an yaml item with type: array to json schema
58
+ def self.build_json_array item, out
59
+ required = item.select { |k,v| v['optional'] != true }.keys.sort
60
+ out.merge!({
61
+ "type" => "array",
62
+ "items" => {
63
+ "type" => "object",
64
+ "required" => required,
65
+ "additionalProperties": false
66
+ }
67
+ })
68
+ out["items"]["properties"] = {}
69
+ item.each_pair do |key,v|
70
+ out["items"]["properties"][key] = build_value(v)
80
71
  end
72
+ out
73
+ end
81
74
 
82
- # with draft-07 and older, using a $ref mean all other properties are ignored.
83
- # to avoid this we need to use an allOf.
84
- # this is changed from draft-08, but unfortunately, there is still no Ruby validator for that
75
+ # with draft-07 and older, using a $ref mean all other properties are ignored.
76
+ # to avoid this we need to use an allOf.
77
+ # this is changed from draft-08, but unfortunately, there is still no Ruby validator for that
78
+ def self.wrap_refs out
85
79
  if out.keys.include? '$ref'
86
80
  ref = out.delete '$ref'
87
81
  { "allOf" => [out,{"$ref"=>ref}]}
@@ -90,6 +84,47 @@ module RSMP
90
84
  end
91
85
  end
92
86
 
87
+ # convert a yaml item with list: true to json schema
88
+ def self.handle_string_list item, out
89
+ case item['type']
90
+ when "boolean_list"
91
+ out["$ref"] = "../../../core/3.1.1/definitions.json#/boolean_list"
92
+ when "integer_list"
93
+ out["$ref"] = "../../../core/3.1.1/definitions.json#/integer_list"
94
+ when "string_list"
95
+ out["$ref"] = "../../../core/3.1.1/definitions.json#/string_list"
96
+ else
97
+ raise "Error: List of #{item['type']} is not supported: #{item.inspect}"
98
+ end
99
+
100
+ if item["values"]
101
+ value_list = item["values"].keys.join('|')
102
+ out['pattern'] = /(?-mix:^(#{value_list})(?:,(#{value_list}))*$)/
103
+ end
104
+
105
+ puts "Warning: Pattern not support for lists: #{item.inspect}" if item["pattern"]
106
+ end
107
+
108
+ # convert yaml values to jsons schema enum
109
+ def self.handle_enum item, out
110
+ if item["values"]
111
+ case item["values"]
112
+ when Hash
113
+ out["enum"] = item["values"].keys.sort
114
+ when Array
115
+ out["enum"] = item["values"].sort
116
+ else
117
+ raise "Error: Values must be specified as either a Hash or an Array"
118
+ end
119
+ end
120
+ end
121
+
122
+ # convert yaml pattern to jsons schema
123
+ def self.handle_pattern item, out
124
+ out["pattern"] = item["pattern"] if item["pattern"]
125
+ end
126
+
127
+ # convert yaml alarm/status/command item to corresponding jsons schema
93
128
  def self.build_item item, property_key: 'v'
94
129
  json = { "allOf" => [ { "description" => item['description'] } ] }
95
130
  if item['arguments']
@@ -104,6 +139,7 @@ module RSMP
104
139
  json
105
140
  end
106
141
 
142
+ # convert alarms to json schema
107
143
  def self.output_alarms out, items
108
144
  list = items.keys.sort.map do |key|
109
145
  {
@@ -121,11 +157,13 @@ module RSMP
121
157
  items.each_pair { |key,item| output_alarm out, key, item }
122
158
  end
123
159
 
160
+ # convert an alarm to json schema
124
161
  def self.output_alarm out, key, item
125
162
  json = build_item item
126
163
  out["alarms/#{key}.json"] = output_json json
127
164
  end
128
165
 
166
+ # convert statuses to json schema
129
167
  def self.output_statuses out, items
130
168
  list = [ { "properties" => { "sCI" => { "enum"=> items.keys.sort }}} ]
131
169
  items.keys.sort.each do |key|
@@ -139,11 +177,13 @@ module RSMP
139
177
  items.each_pair { |key,item| output_status out, key, item }
140
178
  end
141
179
 
180
+ # convert a status to json schema
142
181
  def self.output_status out, key, item
143
182
  json = build_item item, property_key:'s'
144
183
  out["statuses/#{key}.json"] = output_json json
145
184
  end
146
185
 
186
+ # convert commands to json schema
147
187
  def self.output_commands out, items
148
188
  list = [ { "properties" => { "cCI" => { "enum"=> items.keys.sort }}} ]
149
189
  items.keys.sort.each do |key|
@@ -164,12 +204,14 @@ module RSMP
164
204
  items.each_pair { |key,item| output_command out, key, item }
165
205
  end
166
206
 
207
+ # convert a command to json schema
167
208
  def self.output_command out, key, item
168
209
  json = build_item item
169
210
  json["allOf"].first["properties"]['cO'] = { "const" => item['command'] }
170
211
  out["commands/#{key}.json"] = output_json json
171
212
  end
172
213
 
214
+ # output the json schema root
173
215
  def self.output_root out, meta
174
216
  json = {
175
217
  "name"=> meta['name'],
@@ -197,6 +239,7 @@ module RSMP
197
239
  out["sxl.json"] = output_json json
198
240
  end
199
241
 
242
+ # generate the json schema from a string containing yaml
200
243
  def self.generate sxl
201
244
  out = {}
202
245
  output_root out, sxl[:meta]
@@ -206,6 +249,7 @@ module RSMP
206
249
  out
207
250
  end
208
251
 
252
+ # convert yaml to json schema and write files to a folder
209
253
  def self.write sxl, folder
210
254
  out = generate sxl
211
255
  out.each_pair do |relative_path,str|
@@ -215,9 +259,7 @@ module RSMP
215
259
  file.puts str
216
260
  end
217
261
  end
218
-
219
262
  end
220
-
221
263
  end
222
264
  end
223
265
  end
@@ -6,32 +6,66 @@ end
6
6
  module RSMP::Schema
7
7
  @@schemas = nil
8
8
 
9
- def self.schemas
10
- return @@schemas if @@schemas
9
+ def self.setup
10
+ @@schemas = {}
11
11
  schemas_path = File.expand_path( File.join(__dir__,'..','..','schemas') )
12
- @@schemas = {
13
- core: {
14
- '3.1.1' => JSONSchemer.schema( Pathname.new(File.join(schemas_path, 'core','3.1.1','rsmp.json')) ),
15
- '3.1.2' => JSONSchemer.schema( Pathname.new(File.join(schemas_path, 'core','3.1.2','rsmp.json')) ),
16
- '3.1.3' => JSONSchemer.schema( Pathname.new(File.join(schemas_path, 'core','3.1.3','rsmp.json')) ),
17
- '3.1.4' => JSONSchemer.schema( Pathname.new(File.join(schemas_path, 'core','3.1.4','rsmp.json')) ),
18
- '3.1.5' => JSONSchemer.schema( Pathname.new(File.join(schemas_path, 'core','3.1.5','rsmp.json')) ),
19
- '3.2' => JSONSchemer.schema( Pathname.new(File.join(schemas_path, 'core','3.2', 'rsmp.json')) )
20
- },
21
- # note that tlc 1.0.11 and 1.0.12 does not exist (unreleased drafts)
22
- tlc: {
23
- '1.0.7' => JSONSchemer.schema( Pathname.new(File.join(schemas_path, 'tlc','1.0.7' ,'sxl.json')) ),
24
- '1.0.8' => JSONSchemer.schema( Pathname.new(File.join(schemas_path, 'tlc','1.0.8' ,'sxl.json')) ),
25
- '1.0.9' => JSONSchemer.schema( Pathname.new(File.join(schemas_path, 'tlc','1.0.9' ,'sxl.json')) ),
26
- '1.0.10' => JSONSchemer.schema( Pathname.new(File.join(schemas_path, 'tlc','1.0.10','sxl.json')) ),
27
- '1.0.13' => JSONSchemer.schema( Pathname.new(File.join(schemas_path, 'tlc','1.0.13','sxl.json')) ),
28
- '1.0.14' => JSONSchemer.schema( Pathname.new(File.join(schemas_path, 'tlc','1.0.14','sxl.json')) ),
29
- '1.0.15' => JSONSchemer.schema( Pathname.new(File.join(schemas_path, 'tlc','1.0.15','sxl.json')) ),
30
- '1.1' => JSONSchemer.schema( Pathname.new(File.join(schemas_path, 'tlc','1.1', 'sxl.json')) )
31
- }
32
- }
12
+ Dir.glob("#{schemas_path}/*").select {|f| File.directory? f}.each do |type_path|
13
+ type = File.basename(type_path).to_sym
14
+ @@schemas[type] = {}
15
+ Dir.glob("#{type_path}/*").select {|f| File.directory? f}.each do |schema_path|
16
+ version = File.basename(schema_path)
17
+ if type == :core
18
+ file = 'rsmp.json'
19
+ else
20
+ file = 'sxl.json'
21
+ end
22
+ @@schemas[type][version] = JSONSchemer.schema(
23
+ Pathname.new(File.join(schema_path,file))
24
+ )
25
+ end
26
+ end
27
+ end
28
+
29
+ # get all schemas, oganized by type and version
30
+ def self.schemas
31
+ raise RuntimeError.new("No schemas available, perhaps Schema.setup was never called?") unless @@schemas
32
+ @@schemas
33
+ end
34
+
35
+ # get array of core schema versions
36
+ def self.core_versions
37
+ versions :core
38
+ end
39
+
40
+ # get earliest core schema version
41
+ def self.earliest_core_version
42
+ earliest_version :core
33
43
  end
34
44
 
45
+ # get latesty core schema version
46
+ def self.latest_core_version
47
+ latest_version :core
48
+ end
49
+
50
+ # get array of schema versions for a particular schema type
51
+ def self.versions type
52
+ schemas = find_schemas!(type).keys
53
+ sort_versions(schemas)
54
+ end
55
+
56
+ # get earliest schema version for a particular schema type
57
+ def self.earliest_version type
58
+ schemas = find_schemas!(type).keys
59
+ sort_versions(schemas).first
60
+ end
61
+
62
+ # get latest schema version for a particular schema type
63
+ def self.latest_version type
64
+ schemas = find_schemas!(type).keys
65
+ sort_versions(schemas).last
66
+ end
67
+
68
+ # validate an rsmp messages using a schema object
35
69
  def self.validate_using_schema message, schema
36
70
  raise ArgumentError.new("message missing") unless message
37
71
  raise ArgumentError.new("schema missing") unless schema
@@ -44,17 +78,28 @@ module RSMP::Schema
44
78
  end
45
79
  end
46
80
 
81
+ # sort version strings
82
+ def self.sort_versions versions
83
+ versions.sort_by { |k| Gem::Version.new(k) }
84
+ end
85
+
86
+ # find schemas versions for particular schema type
87
+ # return nil if type not found
47
88
  def self.find_schemas type
48
89
  raise ArgumentError.new("type missing") unless type
49
- schemas[type.to_sym]
90
+ schemas = @@schemas[type.to_sym]
50
91
  end
51
92
 
93
+ # find schemas versions for particular schema type
94
+ # raise error if not found
52
95
  def self.find_schemas! type
53
96
  schemas = find_schemas type
54
97
  raise UnknownSchemaTypeError.new("Unknown schema type #{type}") unless schemas
55
98
  schemas
56
99
  end
57
100
 
101
+ # find schema for a particular schema and version
102
+ # return nil if not found
58
103
  def self.find_schema type, version, options={}
59
104
  raise ArgumentError.new("version missing") unless version
60
105
  version = sanitize_version version if options[:lenient]
@@ -65,11 +110,18 @@ module RSMP::Schema
65
110
  nil
66
111
  end
67
112
 
113
+ # get major.minor.patch part of a version string, where patch is optional
114
+ # ignore trailing characters, e.g.
115
+ # 3.1.3.32A => 3.1.3
116
+ # 3.1A3r3 >= 3.1
117
+ # return nil if string doesn't match
68
118
  def self.sanitize_version version
69
119
  matched = /^\d+\.\d+(\.\d+)?/.match version
70
120
  matched.to_s if matched
71
121
  end
72
122
 
123
+ # find schema for a particular schema and version
124
+ # raise error if not found
73
125
  def self.find_schema! type, version, options={}
74
126
  schema = find_schema type, version, options
75
127
  raise ArgumentError.new("version missing") unless version
@@ -82,10 +134,14 @@ module RSMP::Schema
82
134
  raise UnknownSchemaVersionError.new("Unknown schema version #{type} #{version}")
83
135
  end
84
136
 
137
+ # true if a particular schema type and version found
85
138
  def self.has_schema? type, version, options={}
86
139
  find_schema(type,version, options) != nil
87
140
  end
88
141
 
142
+ # validate using a particular schema and version
143
+ # raises error if schema is not found
144
+ # return nil if validation succeds, otherwise returns an array of errors
89
145
  def self.validate message, schemas, options={}
90
146
  raise ArgumentError.new("message missing") unless message
91
147
  raise ArgumentError.new("schemas missing") unless schemas
@@ -1,5 +1,5 @@
1
1
  module RSMP
2
2
  module Schema
3
- VERSION = "0.1.0"
3
+ VERSION = "0.2.1"
4
4
  end
5
5
  end
data/lib/rsmp_schema.rb CHANGED
@@ -5,3 +5,5 @@ require 'rsmp_schema/schema'
5
5
  require 'rsmp_schema/convert/import/yaml'
6
6
  require 'rsmp_schema/convert/export/json_schema'
7
7
  require 'rsmp_schema/version'
8
+
9
+ RSMP::Schema.setup