ynl 0.2.4 → 0.3.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 +4 -4
- data/CHANGELOG.md +7 -0
- data/lib/ynl/generator.rb +186 -43
- data/lib/ynl/models.rb +28 -2
- data/lib/ynl/parser.rb +31 -7
- data/lib/ynl/version.rb +1 -1
- data/lib/ynl.rb +17 -3
- metadata +7 -6
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: e19f2ff09effa0411bc676e0eb2356129f8aa496ec4bbf1df66935268d4e6763
|
|
4
|
+
data.tar.gz: 72bfd23c64c44dd2db4b449e6863c7855e34c1ed2c774b5f2ff3e16f7fd7910f
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c3c294f02102bb2031e6681a17a5bd92dfd4bbde39db1c94302dd8775756d34b47d1bea3ff0a7c94f4f5a857569fc2c4a658ae80ff275c7b109094c0d9b208c7
|
|
7
|
+
data.tar.gz: 941d649b3233024963fabd1bd51d083b3ba22639dfb15e9b2e74df5264b948fb82ac152d86751f6352be28d2a4a283c10aba2dbddcd154744db810594bbee821
|
data/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
## v0.3.0 (2026-09-01)
|
|
6
|
+
|
|
7
|
+
- Generate notification and event message classes, multicast group metadata,
|
|
8
|
+
and typed subscription methods.
|
|
9
|
+
- Generate nested type-value attributes with their declared type-key depth.
|
|
10
|
+
- Generate methods for operations with implicit empty requests.
|
|
11
|
+
|
|
5
12
|
## v0.2.4 (2026-08-22)
|
|
6
13
|
|
|
7
14
|
- Assign correct values to attributes following `unused` entries.
|
data/lib/ynl/generator.rb
CHANGED
|
@@ -37,6 +37,12 @@ module Ynl
|
|
|
37
37
|
require 'nl'
|
|
38
38
|
RUBY
|
|
39
39
|
|
|
40
|
+
OPERATION_FLAG_DOCS = {
|
|
41
|
+
'admin-perm' => 'Requires CAP_NET_ADMIN in the initial user namespace.',
|
|
42
|
+
'uns-admin-perm' => 'Requires CAP_NET_ADMIN in the user namespace owning the network namespace.',
|
|
43
|
+
}.freeze
|
|
44
|
+
private_constant :OPERATION_FLAG_DOCS
|
|
45
|
+
|
|
40
46
|
def initialize(ynl, out)
|
|
41
47
|
@ynl = ynl
|
|
42
48
|
@out = out
|
|
@@ -58,6 +64,8 @@ module Ynl
|
|
|
58
64
|
emit_const('PROTOCOL', "Ractor.make_shareable(::Nl::Protocols::Genl.new(#{@ynl.name.as_string_literal}))")
|
|
59
65
|
end
|
|
60
66
|
|
|
67
|
+
emit_mcast_groups
|
|
68
|
+
|
|
61
69
|
emit_module('Structs') do
|
|
62
70
|
@ynl.structs.each do |name, struct|
|
|
63
71
|
emit_comment(struct.doc)
|
|
@@ -115,6 +123,7 @@ module Ynl
|
|
|
115
123
|
emit_const('TYPE', attr.value)
|
|
116
124
|
emit_const('NAME', attr.name.as_variable_name.as_symbol_literal)
|
|
117
125
|
if attr.type.is_a?(Types::NestedAttributes) ||
|
|
126
|
+
attr.type.is_a?(Types::NestTypeValue) ||
|
|
118
127
|
(attr.type.is_a?(Types::IndexedArray) && attr.type.sub_type.is_a?(Types::NestedAttributes))
|
|
119
128
|
deferred_consts << ["#{name.as_class_name}::#{attr.name.as_class_name}::DATATYPE", to_datatype(attr.type, attr.checks)]
|
|
120
129
|
else
|
|
@@ -162,58 +171,43 @@ module Ynl
|
|
|
162
171
|
%w[do dump].each do |method|
|
|
163
172
|
if request_reply = oper.public_send(method + 'it')
|
|
164
173
|
%w[request reply].to_h { [it, request_reply.public_send(it)] }.compact.each do |type, msg|
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
emit_const('ATTRIBUTES', "Ractor.make_shareable(%i[#{attribute_params.map { it.as_variable_name }.join(' ')}])")
|
|
173
|
-
oper.fixed_header.members.each do |member|
|
|
174
|
-
param = member.name
|
|
175
|
-
datatype = member.type
|
|
176
|
-
next if datatype.is_a? Types::Pad
|
|
177
|
-
next if attribute_params.include?(param)
|
|
178
|
-
emit_comment("Gets the value of `#{param}` field in the message's fixed header.")
|
|
179
|
-
emit_rbs_comment(
|
|
180
|
-
'return: ' + datatype.rbs_type,
|
|
181
|
-
)
|
|
182
|
-
emit_getter(param.as_method_name, "fixed_header.#{param.as_method_name}")
|
|
183
|
-
end if oper.fixed_header
|
|
184
|
-
attribute_params.each do |param|
|
|
185
|
-
datatype = oper.attribute_set.attributes.find { it.name == param }.type
|
|
186
|
-
next if datatype.is_a? Types::Pad
|
|
187
|
-
extending = oper.fixed_header&.members&.any? { it.name == param }
|
|
188
|
-
|
|
189
|
-
if extending
|
|
190
|
-
emit_comment("Gets the value of `#{param}` attribute or fixed header in the message.")
|
|
191
|
-
else
|
|
192
|
-
emit_comment("Gets the value of `#{param}` attribute in the message.")
|
|
193
|
-
end
|
|
194
|
-
emit_rbs_comment(
|
|
195
|
-
'return: ' + datatype.rbs_type,
|
|
196
|
-
)
|
|
197
|
-
if extending
|
|
198
|
-
# If the fixed header and the attribute set have the same-name parameter, the value from the attribute should have
|
|
199
|
-
# the precedence over that from the header.
|
|
200
|
-
emit_getter(param.as_method_name, "attributes[#{param.as_variable_name.as_symbol_literal}]&.value || fixed_header.#{param.as_method_name}")
|
|
201
|
-
else
|
|
202
|
-
emit_getter(param.as_method_name, "attributes[#{param.as_variable_name.as_symbol_literal}]&.value")
|
|
203
|
-
end
|
|
204
|
-
end
|
|
205
|
-
end
|
|
174
|
+
emit_message_class(
|
|
175
|
+
method.as_class_name + oper.name.as_class_name + type.as_class_name,
|
|
176
|
+
msg,
|
|
177
|
+
fixed_header: oper.fixed_header,
|
|
178
|
+
attribute_set: oper.attribute_set,
|
|
179
|
+
doc: operation_doc(oper),
|
|
180
|
+
)
|
|
206
181
|
end
|
|
207
182
|
end
|
|
208
183
|
end
|
|
209
184
|
end
|
|
210
185
|
end
|
|
211
186
|
|
|
187
|
+
emit_module('Notifications') do
|
|
188
|
+
notification_operations.each do |oper|
|
|
189
|
+
message, fixed_header, attribute_set = notification_layout(oper)
|
|
190
|
+
emit_message_class(
|
|
191
|
+
oper.name.as_class_name,
|
|
192
|
+
message,
|
|
193
|
+
fixed_header:,
|
|
194
|
+
attribute_set:,
|
|
195
|
+
doc: notification_doc(oper),
|
|
196
|
+
)
|
|
197
|
+
end
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
emit_const(
|
|
201
|
+
'NOTIFICATIONS',
|
|
202
|
+
"Ractor.make_shareable({#{notification_operations.map { |oper| "#{oper.notification.message.value} => Notifications::#{oper.name.as_class_name}" }.join(', ') }})",
|
|
203
|
+
rbs: 'Hash[::Integer, ::Class]',
|
|
204
|
+
)
|
|
205
|
+
|
|
212
206
|
# emit request methods
|
|
213
207
|
@ynl.operations.each do |name, oper|
|
|
214
208
|
%w[do dump].each do |method|
|
|
215
209
|
if request_reply = oper.public_send(method + 'it')
|
|
216
|
-
|
|
210
|
+
request = request_reply.request
|
|
217
211
|
|
|
218
212
|
request_class = "Messages::#{method.as_class_name}#{oper.name.as_class_name}Request"
|
|
219
213
|
reply_class = request_reply.reply ? "Messages::#{method.as_class_name}#{oper.name.as_class_name}Reply" : 'nil'
|
|
@@ -227,7 +221,7 @@ module Ynl
|
|
|
227
221
|
rbs_params = params.map { |it| "?#{it.name.as_variable_name}: #{it.type.rbs_type}" }.join(', ')
|
|
228
222
|
rbs_result = request_reply.reply ? reply_class : 'void'
|
|
229
223
|
|
|
230
|
-
emit_comment(oper
|
|
224
|
+
emit_comment(operation_doc(oper))
|
|
231
225
|
if method == 'dump'
|
|
232
226
|
emit_rbs_comment(
|
|
233
227
|
"(#{rbs_params}) -> Enumerable[#{rbs_result}]\n | (#{rbs_params}) { (#{rbs_result}) -> void } -> void",
|
|
@@ -249,6 +243,50 @@ module Ynl
|
|
|
249
243
|
end
|
|
250
244
|
end
|
|
251
245
|
end
|
|
246
|
+
|
|
247
|
+
emit_class('AsyncOperations') do
|
|
248
|
+
emit_nodoc
|
|
249
|
+
write('def initialize(&exchange)')
|
|
250
|
+
indent do
|
|
251
|
+
write('@exchange = exchange')
|
|
252
|
+
end
|
|
253
|
+
write('end')
|
|
254
|
+
|
|
255
|
+
@ynl.operations.each do |name, oper|
|
|
256
|
+
%w[do dump].each do |method|
|
|
257
|
+
next unless request_reply = oper.public_send(method + 'it')
|
|
258
|
+
|
|
259
|
+
request_class = "Messages::#{method.as_class_name}#{oper.name.as_class_name}Request"
|
|
260
|
+
reply_class = request_reply.reply ? "Messages::#{method.as_class_name}#{oper.name.as_class_name}Reply" : 'nil'
|
|
261
|
+
header_params = oper.fixed_header&.members || []
|
|
262
|
+
attribute_params = oper.attribute_set.attributes.filter { request_reply.request.attributes.include?(it.name) }
|
|
263
|
+
attribute_params.reject! {|a| header_params.any? {|h| h.name == a.name } }
|
|
264
|
+
params = (header_params + attribute_params).reject { it.type.is_a? Types::Pad }
|
|
265
|
+
rbs_params = params.map { |it| "?#{it.name.as_variable_name}: #{it.type.rbs_type}" }.join(', ')
|
|
266
|
+
result = request_reply.reply ? reply_class : 'void'
|
|
267
|
+
operation = method == 'dump' ? "::Nl::Async::Stream[#{result}]" : "::Nl::Async::Future[#{result}]"
|
|
268
|
+
|
|
269
|
+
emit_comment(operation_doc(oper))
|
|
270
|
+
emit_rbs_comment("(#{rbs_params}) -> #{operation}")
|
|
271
|
+
write("def #{method.as_method_name}_#{oper.name.as_method_name}(**args)")
|
|
272
|
+
indent do
|
|
273
|
+
write("@exchange.call(#{method.as_symbol_literal}, #{request_class}, #{reply_class}, args)")
|
|
274
|
+
end
|
|
275
|
+
write('end')
|
|
276
|
+
end
|
|
277
|
+
end
|
|
278
|
+
end
|
|
279
|
+
|
|
280
|
+
emit_comment('Returns the asynchronous operation facade for this family.')
|
|
281
|
+
emit_rbs_comment('(?stream_capacity: ::Integer?) -> AsyncOperations')
|
|
282
|
+
write('def async(stream_capacity: nil)')
|
|
283
|
+
indent do
|
|
284
|
+
write('return @async_operations ||= build_async_facade(AsyncOperations) if stream_capacity.nil?')
|
|
285
|
+
write('build_async_facade(AsyncOperations, stream_capacity:)')
|
|
286
|
+
end
|
|
287
|
+
write('end')
|
|
288
|
+
|
|
289
|
+
emit_subscription_methods unless @ynl.mcast_groups.empty?
|
|
252
290
|
end
|
|
253
291
|
|
|
254
292
|
classname
|
|
@@ -310,6 +348,109 @@ module Ynl
|
|
|
310
348
|
end
|
|
311
349
|
end
|
|
312
350
|
|
|
351
|
+
private def operation_doc(operation)
|
|
352
|
+
flag_docs = operation.flags.filter_map { OPERATION_FLAG_DOCS[it] }
|
|
353
|
+
[operation.doc, *flag_docs].compact.join("\n\n")
|
|
354
|
+
end
|
|
355
|
+
|
|
356
|
+
private def notification_operations
|
|
357
|
+
@notification_operations ||= @ynl.operations.values.select(&:notification)
|
|
358
|
+
end
|
|
359
|
+
|
|
360
|
+
private def notification_doc(operation)
|
|
361
|
+
group = operation.notification.group
|
|
362
|
+
[operation.doc, ("Multicast group: `#{group.name}`." if group)].compact.join("\n\n")
|
|
363
|
+
end
|
|
364
|
+
|
|
365
|
+
private def notification_layout(operation)
|
|
366
|
+
notification = operation.notification
|
|
367
|
+
if notification.kind == :event
|
|
368
|
+
[notification.message, operation.fixed_header, operation.attribute_set]
|
|
369
|
+
else
|
|
370
|
+
source = notification.source
|
|
371
|
+
mode = source.doit || source.dumpit
|
|
372
|
+
reply = mode&.reply
|
|
373
|
+
unless reply
|
|
374
|
+
selected = source.doit ? 'do' : 'dump'
|
|
375
|
+
raise ParseError,
|
|
376
|
+
"Notification #{operation.name.inspect} references #{source.name.inspect}, which has no #{selected} reply"
|
|
377
|
+
end
|
|
378
|
+
message = Models::Message.new(
|
|
379
|
+
value: notification.message.value,
|
|
380
|
+
attributes: reply.attributes,
|
|
381
|
+
)
|
|
382
|
+
[message, source.fixed_header, source.attribute_set]
|
|
383
|
+
end
|
|
384
|
+
end
|
|
385
|
+
|
|
386
|
+
private def emit_message_class(name, message, fixed_header:, attribute_set:, doc:)
|
|
387
|
+
emit_comment(doc)
|
|
388
|
+
emit_class(name, "#{@protocol}::Message") do
|
|
389
|
+
emit_const('TYPE', message.value)
|
|
390
|
+
emit_const('FIXED_HEADER', fixed_header&.then { 'Structs::' + it.name.as_class_name } || 'nil')
|
|
391
|
+
emit_const('ATTRIBUTE_SET', "AttributeSets::#{attribute_set.name.as_class_name}")
|
|
392
|
+
attribute_params = attribute_set.attributes.map(&:name) & message.attributes
|
|
393
|
+
emit_const('ATTRIBUTES', "Ractor.make_shareable(%i[#{attribute_params.map { it.as_variable_name }.join(' ')}])")
|
|
394
|
+
fixed_header&.members&.each do |member|
|
|
395
|
+
param = member.name
|
|
396
|
+
datatype = member.type
|
|
397
|
+
next if datatype.is_a? Types::Pad
|
|
398
|
+
next if attribute_params.include?(param)
|
|
399
|
+
emit_comment("Gets the value of `#{param}` field in the message's fixed header.")
|
|
400
|
+
emit_rbs_comment('return: ' + datatype.rbs_type)
|
|
401
|
+
emit_getter(param.as_method_name, "fixed_header.#{param.as_method_name}")
|
|
402
|
+
end
|
|
403
|
+
attribute_params.each do |param|
|
|
404
|
+
datatype = attribute_set.attributes.find { it.name == param }.type
|
|
405
|
+
next if datatype.is_a? Types::Pad
|
|
406
|
+
extending = fixed_header&.members&.any? { it.name == param }
|
|
407
|
+
|
|
408
|
+
if extending
|
|
409
|
+
emit_comment("Gets the value of `#{param}` attribute or fixed header in the message.")
|
|
410
|
+
else
|
|
411
|
+
emit_comment("Gets the value of `#{param}` attribute in the message.")
|
|
412
|
+
end
|
|
413
|
+
emit_rbs_comment('return: ' + datatype.rbs_type)
|
|
414
|
+
if extending
|
|
415
|
+
emit_getter(param.as_method_name, "attributes[#{param.as_variable_name.as_symbol_literal}]&.value || fixed_header.#{param.as_method_name}")
|
|
416
|
+
else
|
|
417
|
+
emit_getter(param.as_method_name, "attributes[#{param.as_variable_name.as_symbol_literal}]&.value")
|
|
418
|
+
end
|
|
419
|
+
end
|
|
420
|
+
end
|
|
421
|
+
end
|
|
422
|
+
|
|
423
|
+
private def emit_mcast_groups
|
|
424
|
+
groups = @ynl.mcast_groups.values
|
|
425
|
+
grouped = groups.group_by { it.name.as_variable_name }
|
|
426
|
+
if collision = grouped.find { |_name, matches| matches.length > 1 }
|
|
427
|
+
ruby_name, matches = collision
|
|
428
|
+
raise ParseError,
|
|
429
|
+
"Multicast groups #{matches.map(&:name).map(&:inspect).join(' and ')} normalize to #{ruby_name.to_sym.inspect}"
|
|
430
|
+
end
|
|
431
|
+
|
|
432
|
+
entries = groups.map do |group|
|
|
433
|
+
key = group.name.as_variable_name.as_symbol_literal
|
|
434
|
+
value = "::Nl::McastGroup.new(#{group.name.as_string_literal}, #{group.value.inspect})"
|
|
435
|
+
"#{key} => #{value}"
|
|
436
|
+
end
|
|
437
|
+
emit_const(
|
|
438
|
+
'MCAST_GROUPS',
|
|
439
|
+
"Ractor.make_shareable({#{entries.join(', ')}})",
|
|
440
|
+
rbs: 'Hash[::Symbol, ::Nl::McastGroup]',
|
|
441
|
+
)
|
|
442
|
+
end
|
|
443
|
+
|
|
444
|
+
private def emit_subscription_methods
|
|
445
|
+
group_type = @ynl.mcast_groups.values
|
|
446
|
+
.map { ":#{it.name.as_variable_name}" }
|
|
447
|
+
.join(' | ')
|
|
448
|
+
emit_rbs_comment("(*(#{group_type}) groups) -> self")
|
|
449
|
+
write('def subscribe(*groups) = super')
|
|
450
|
+
emit_rbs_comment("(*(#{group_type}) groups) -> self")
|
|
451
|
+
write('def unsubscribe(*groups) = super')
|
|
452
|
+
end
|
|
453
|
+
|
|
313
454
|
private def emit_rbs_comment(*args)
|
|
314
455
|
write('#--')
|
|
315
456
|
args.each do |arg|
|
|
@@ -337,6 +478,8 @@ module Ynl
|
|
|
337
478
|
# end
|
|
338
479
|
when Types::NestedAttributes
|
|
339
480
|
"#{@protocol}::DataTypes::NestedAttributes.new(#{type.attribute_set.name.as_class_name})"
|
|
481
|
+
when Types::NestTypeValue
|
|
482
|
+
"#{@protocol}::DataTypes::NestTypeValue.new(#{type.attribute_set.name.as_class_name}, #{type.type_values.length})"
|
|
340
483
|
when Types::IndexedArray
|
|
341
484
|
"#{@protocol}::DataTypes::IndexedArray.new(#{to_datatype(type.sub_type, nil)})"
|
|
342
485
|
when Types::SubMessage
|
data/lib/ynl/models.rb
CHANGED
|
@@ -7,6 +7,7 @@ module Ynl
|
|
|
7
7
|
def resolve
|
|
8
8
|
structs.transform_values! {|s| s.resolve(self) }
|
|
9
9
|
attribute_sets.transform_values! {|s| s.resolve(self) }
|
|
10
|
+
operations.transform_values! {|operation| operation.resolve(self) }
|
|
10
11
|
self
|
|
11
12
|
end
|
|
12
13
|
|
|
@@ -148,22 +149,47 @@ module Ynl
|
|
|
148
149
|
end
|
|
149
150
|
end
|
|
150
151
|
|
|
152
|
+
McastGroup = ::Struct.new(:name, :value, :doc)
|
|
153
|
+
|
|
151
154
|
class Operation
|
|
152
|
-
attr_reader :name, :doc, :fixed_header, :attribute_set, :doit, :dumpit
|
|
155
|
+
attr_reader :name, :doc, :flags, :fixed_header, :attribute_set, :doit, :dumpit, :notification
|
|
153
156
|
|
|
154
|
-
def initialize(name:, doc:, fixed_header:, attribute_set:, doit:, dumpit:)
|
|
157
|
+
def initialize(name:, doc:, flags:, fixed_header:, attribute_set:, doit:, dumpit:, notification:)
|
|
155
158
|
@name = name
|
|
156
159
|
@doc = doc
|
|
160
|
+
@flags = flags
|
|
157
161
|
@fixed_header = fixed_header
|
|
158
162
|
@attribute_set = attribute_set
|
|
159
163
|
@doit = doit
|
|
160
164
|
@dumpit = dumpit
|
|
165
|
+
@notification = notification
|
|
161
166
|
end
|
|
162
167
|
|
|
163
168
|
def resolve(f)
|
|
164
169
|
@doit = @doit&.resolve(f)
|
|
165
170
|
@dumpit = @dumpit&.resolve(f)
|
|
171
|
+
@notification = @notification&.resolve(f)
|
|
172
|
+
self
|
|
173
|
+
end
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
class Notification
|
|
177
|
+
attr_reader :kind, :message, :source, :group
|
|
178
|
+
|
|
179
|
+
def initialize(kind:, message:, source:, group:)
|
|
180
|
+
@kind = kind
|
|
181
|
+
@message = message
|
|
182
|
+
@source = source
|
|
183
|
+
@group = group
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
def resolve(f)
|
|
187
|
+
@message = @message.resolve(f)
|
|
188
|
+
@source = f.operations.fetch(@source) if @source
|
|
189
|
+
@group = f.mcast_groups.fetch(@group) if @group
|
|
166
190
|
self
|
|
191
|
+
rescue KeyError => error
|
|
192
|
+
raise ParseError, "Failed to resolve #{kind} notification: #{error.message}"
|
|
167
193
|
end
|
|
168
194
|
end
|
|
169
195
|
|
data/lib/ynl/parser.rb
CHANGED
|
@@ -79,7 +79,7 @@ module Ynl
|
|
|
79
79
|
end
|
|
80
80
|
end
|
|
81
81
|
end
|
|
82
|
-
@yaml
|
|
82
|
+
@yaml.dig('mcast-groups', 'list')&.each do |d|
|
|
83
83
|
parse_mcast_group(d)
|
|
84
84
|
end
|
|
85
85
|
|
|
@@ -200,8 +200,9 @@ module Ynl
|
|
|
200
200
|
)
|
|
201
201
|
when 'nest-type-value'
|
|
202
202
|
if d['nested-attributes']
|
|
203
|
-
Types::
|
|
203
|
+
Types::NestTypeValue.new(
|
|
204
204
|
attribute_set: Models::Thunk.new {|f| f.attribute_sets.fetch(d.fetch('nested-attributes')) },
|
|
205
|
+
type_values: d.fetch('type-value'),
|
|
205
206
|
)
|
|
206
207
|
else
|
|
207
208
|
Types::Binary.new(struct: nil, display_hint: nil)
|
|
@@ -384,18 +385,35 @@ module Ynl
|
|
|
384
385
|
|
|
385
386
|
doit = d['do']&.then { parse_request_reply(it, default_request_id: request_id, default_reply_id: reply_id) }
|
|
386
387
|
dumpit = d['dump']&.then { parse_request_reply(it, default_request_id: request_id, default_reply_id: reply_id) }
|
|
387
|
-
|
|
388
|
-
# TODO: notify
|
|
388
|
+
notification = parse_notification(d, default_id: reply_id)
|
|
389
389
|
|
|
390
390
|
@operations[name] = Models::Operation.new(
|
|
391
|
-
name:, doc: translate_doc(d['doc']), fixed_header:, attribute_set:,
|
|
392
|
-
doit:, dumpit:,
|
|
391
|
+
name:, doc: translate_doc(d['doc']), flags: d.fetch('flags', []), fixed_header:, attribute_set:,
|
|
392
|
+
doit:, dumpit:, notification:,
|
|
393
393
|
)
|
|
394
394
|
end
|
|
395
395
|
|
|
396
|
+
private def parse_notification(d, default_id:)
|
|
397
|
+
if source = d['notify']
|
|
398
|
+
Models::Notification.new(
|
|
399
|
+
kind: :notify,
|
|
400
|
+
message: parse_message({}, default_id:),
|
|
401
|
+
source:,
|
|
402
|
+
group: d['mcgrp'],
|
|
403
|
+
)
|
|
404
|
+
elsif event = d['event']
|
|
405
|
+
Models::Notification.new(
|
|
406
|
+
kind: :event,
|
|
407
|
+
message: parse_message(event, default_id:),
|
|
408
|
+
source: nil,
|
|
409
|
+
group: d['mcgrp'],
|
|
410
|
+
)
|
|
411
|
+
end
|
|
412
|
+
end
|
|
413
|
+
|
|
396
414
|
private def parse_request_reply(d, default_request_id:, default_reply_id:)
|
|
397
415
|
Models::RequestReply.new(
|
|
398
|
-
request: d
|
|
416
|
+
request: parse_message(d.fetch('request', {}), default_id: default_request_id),
|
|
399
417
|
reply: d['reply']&.then { parse_message(it, default_id: default_reply_id) },
|
|
400
418
|
)
|
|
401
419
|
end
|
|
@@ -405,6 +423,12 @@ module Ynl
|
|
|
405
423
|
end
|
|
406
424
|
|
|
407
425
|
private def parse_mcast_group(d)
|
|
426
|
+
name = d.fetch('name')
|
|
427
|
+
@mcast_groups[name] = Models::McastGroup.new(
|
|
428
|
+
name,
|
|
429
|
+
d['value'],
|
|
430
|
+
translate_doc(d['doc']),
|
|
431
|
+
)
|
|
408
432
|
end
|
|
409
433
|
|
|
410
434
|
private def translate_doc(doc)
|
data/lib/ynl/version.rb
CHANGED
data/lib/ynl.rb
CHANGED
|
@@ -33,7 +33,7 @@ module Ynl
|
|
|
33
33
|
end
|
|
34
34
|
|
|
35
35
|
def rbs_type
|
|
36
|
-
'
|
|
36
|
+
'::String'
|
|
37
37
|
end
|
|
38
38
|
end
|
|
39
39
|
NestedAttributes = Struct.new(:attribute_set) do
|
|
@@ -48,6 +48,20 @@ module Ynl
|
|
|
48
48
|
'AttributeSets::' + attribute_set.name.as_class_name
|
|
49
49
|
end
|
|
50
50
|
end
|
|
51
|
+
NestTypeValue = Struct.new(:attribute_set, :type_values) do
|
|
52
|
+
using Generator::Refinements
|
|
53
|
+
|
|
54
|
+
def resolve(f)
|
|
55
|
+
self.attribute_set = attribute_set.resolve(f)
|
|
56
|
+
self
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def rbs_type
|
|
60
|
+
type = 'AttributeSets::' + attribute_set.name.as_class_name
|
|
61
|
+
type_values.length.times { type = "::Hash[::Integer, #{type}]" }
|
|
62
|
+
type
|
|
63
|
+
end
|
|
64
|
+
end
|
|
51
65
|
SubMessage = Struct.new(:sub_message, :selector) do
|
|
52
66
|
def resolve(f)
|
|
53
67
|
self.sub_message = sub_message.resolve(f)
|
|
@@ -55,7 +69,7 @@ module Ynl
|
|
|
55
69
|
end
|
|
56
70
|
|
|
57
71
|
def rbs_type
|
|
58
|
-
'
|
|
72
|
+
'::String'
|
|
59
73
|
end
|
|
60
74
|
end
|
|
61
75
|
|
|
@@ -96,7 +110,7 @@ module Ynl
|
|
|
96
110
|
end
|
|
97
111
|
|
|
98
112
|
def rbs_type
|
|
99
|
-
|
|
113
|
+
"::Array[#{sub_type.rbs_type}]"
|
|
100
114
|
end
|
|
101
115
|
end
|
|
102
116
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: ynl
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.3.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Kasumi Hanazuki
|
|
@@ -15,14 +15,14 @@ dependencies:
|
|
|
15
15
|
requirements:
|
|
16
16
|
- - '='
|
|
17
17
|
- !ruby/object:Gem::Version
|
|
18
|
-
version: 0.
|
|
18
|
+
version: 0.3.0
|
|
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: 0.
|
|
25
|
+
version: 0.3.0
|
|
26
26
|
- !ruby/object:Gem::Dependency
|
|
27
27
|
name: yaml
|
|
28
28
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -37,7 +37,8 @@ dependencies:
|
|
|
37
37
|
- - ">="
|
|
38
38
|
- !ruby/object:Gem::Version
|
|
39
39
|
version: '0'
|
|
40
|
-
description:
|
|
40
|
+
description: ynl parses YAML Netlink specifications (YNL) and generates Netlink clients
|
|
41
|
+
for the interfaces they describe.
|
|
41
42
|
email:
|
|
42
43
|
- kasumi@rollingapple.net
|
|
43
44
|
executables: []
|
|
@@ -70,7 +71,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
70
71
|
requirements:
|
|
71
72
|
- - ">="
|
|
72
73
|
- !ruby/object:Gem::Version
|
|
73
|
-
version: '3.
|
|
74
|
+
version: '3.4'
|
|
74
75
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
75
76
|
requirements:
|
|
76
77
|
- - ">="
|
|
@@ -79,5 +80,5 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
79
80
|
requirements: []
|
|
80
81
|
rubygems_version: 4.0.6
|
|
81
82
|
specification_version: 4
|
|
82
|
-
summary:
|
|
83
|
+
summary: YAML Netlink specification tools for Ruby
|
|
83
84
|
test_files: []
|