rsmp_schema 0.1.0 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
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