ruby-dbus 0.18.0.beta4 → 0.18.0.beta5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/NEWS.md +17 -0
- data/VERSION +1 -1
- data/lib/dbus/data.rb +84 -104
- data/lib/dbus/marshall.rb +7 -4
- data/lib/dbus/type.rb +120 -14
- data/spec/data_spec.rb +29 -37
- data/spec/property_spec.rb +18 -1
- data/spec/type_spec.rb +105 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f8b0c43d3f27f0877e52c0adfb8014374829f97bcd38be6b9fabda1d5da8413c
|
4
|
+
data.tar.gz: 000eadf163b0fab2ef4ab39de81a79714b34392cd81b3be68e12587ddfa93372
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c2206dcd935fed4e3711b88b2c0c265e5a335700f9137d2c3972f419791d9c25198d0acf9ba7aaecdbc6a25e540005c64321e5165c6c644838fb3557355861ac
|
7
|
+
data.tar.gz: 212cb8bdcd75e3f35622843f262cdb80eaa07c1919a7d17ffdf601e05c627556343b7855a014f60a220c8a757c201431d66799a6025a98d084aef6cc12f7d8bb
|
data/NEWS.md
CHANGED
@@ -2,6 +2,23 @@
|
|
2
2
|
|
3
3
|
## Unreleased
|
4
4
|
|
5
|
+
## Ruby D-Bus 0.18.0.beta5 - 2022-04-27
|
6
|
+
|
7
|
+
API:
|
8
|
+
* DBus::Type instances are frozen.
|
9
|
+
* Data::Container classes (Array, Struct, DictEntry, but not Variant)
|
10
|
+
constructors (#initialize, .from_items, .from_typed) changed to have
|
11
|
+
a *type* argument instead of *member_type* or *member_types*.
|
12
|
+
* Added type factories
|
13
|
+
* Type::Array[type]
|
14
|
+
* Type::Hash[key_type, value_type]
|
15
|
+
* Type::Struct[type1, type2...]
|
16
|
+
|
17
|
+
Bug fixes:
|
18
|
+
* Properties containing Variants would return them doubly wrapped ([#111][]).
|
19
|
+
|
20
|
+
[#111]: https://github.com/mvidner/ruby-dbus/pull/111
|
21
|
+
|
5
22
|
## Ruby D-Bus 0.18.0.beta4 - 2022-04-21
|
6
23
|
|
7
24
|
Bug fixes:
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.18.0.
|
1
|
+
0.18.0.beta5
|
data/lib/dbus/data.rb
CHANGED
@@ -43,7 +43,7 @@ module DBus
|
|
43
43
|
data_class = Data::BY_TYPE_CODE[type.sigtype]
|
44
44
|
# not nil because DBus.type validates
|
45
45
|
|
46
|
-
data_class.from_typed(value,
|
46
|
+
data_class.from_typed(value, type: type)
|
47
47
|
end
|
48
48
|
module_function :make_typed
|
49
49
|
|
@@ -67,6 +67,15 @@ module DBus
|
|
67
67
|
# for the specific see {Variant#member_type}
|
68
68
|
# @return [Type] the exact type of this value
|
69
69
|
|
70
|
+
# @!method self.from_typed(value, type:)
|
71
|
+
# @param value [::Object]
|
72
|
+
# @param type [Type]
|
73
|
+
# @return [Base]
|
74
|
+
# @api private
|
75
|
+
# Use {Data.make_typed} instead.
|
76
|
+
# Construct an instance of the specific subclass, with a type further
|
77
|
+
# specified in the *type* argument.
|
78
|
+
|
70
79
|
# Child classes must validate *value*.
|
71
80
|
def initialize(value)
|
72
81
|
@value = value
|
@@ -83,6 +92,11 @@ module DBus
|
|
83
92
|
# Hash key equality
|
84
93
|
# See https://ruby-doc.org/core-3.0.0/Object.html#method-i-eql-3F
|
85
94
|
alias eql? ==
|
95
|
+
|
96
|
+
# @param type [Type]
|
97
|
+
def self.assert_type_matches_class(type)
|
98
|
+
raise ArgumentError unless type.sigtype == type_code
|
99
|
+
end
|
86
100
|
end
|
87
101
|
|
88
102
|
# A value that is not a {Container}.
|
@@ -103,10 +117,10 @@ module DBus
|
|
103
117
|
end
|
104
118
|
|
105
119
|
# @param value [::Object]
|
106
|
-
# @param
|
120
|
+
# @param type [Type]
|
107
121
|
# @return [Basic]
|
108
|
-
def self.from_typed(value,
|
109
|
-
|
122
|
+
def self.from_typed(value, type:)
|
123
|
+
assert_type_matches_class(type)
|
110
124
|
new(value)
|
111
125
|
end
|
112
126
|
end
|
@@ -132,34 +146,6 @@ module DBus
|
|
132
146
|
end
|
133
147
|
end
|
134
148
|
|
135
|
-
# {DBus::Data::String}, {DBus::Data::ObjectPath}, or {DBus::Data::Signature}.
|
136
|
-
class StringLike < Basic
|
137
|
-
def self.fixed?
|
138
|
-
false
|
139
|
-
end
|
140
|
-
|
141
|
-
def initialize(value)
|
142
|
-
if value.is_a?(self.class)
|
143
|
-
value = value.value
|
144
|
-
else
|
145
|
-
self.class.validate_raw!(value)
|
146
|
-
end
|
147
|
-
|
148
|
-
super(value)
|
149
|
-
end
|
150
|
-
end
|
151
|
-
|
152
|
-
# Contains one or more other values.
|
153
|
-
class Container < Base
|
154
|
-
def self.basic?
|
155
|
-
false
|
156
|
-
end
|
157
|
-
|
158
|
-
def self.fixed?
|
159
|
-
false
|
160
|
-
end
|
161
|
-
end
|
162
|
-
|
163
149
|
# Format strings for String#unpack, both little- and big-endian.
|
164
150
|
Format = ::Struct.new(:little, :big)
|
165
151
|
|
@@ -398,6 +384,23 @@ module DBus
|
|
398
384
|
end
|
399
385
|
end
|
400
386
|
|
387
|
+
# {DBus::Data::String}, {DBus::Data::ObjectPath}, or {DBus::Data::Signature}.
|
388
|
+
class StringLike < Basic
|
389
|
+
def self.fixed?
|
390
|
+
false
|
391
|
+
end
|
392
|
+
|
393
|
+
def initialize(value)
|
394
|
+
if value.is_a?(self.class)
|
395
|
+
value = value.value
|
396
|
+
else
|
397
|
+
self.class.validate_raw!(value)
|
398
|
+
end
|
399
|
+
|
400
|
+
super(value)
|
401
|
+
end
|
402
|
+
end
|
403
|
+
|
401
404
|
# UTF-8 encoded string.
|
402
405
|
class String < StringLike
|
403
406
|
def self.type_code
|
@@ -494,6 +497,21 @@ module DBus
|
|
494
497
|
end
|
495
498
|
end
|
496
499
|
|
500
|
+
# Contains one or more other values.
|
501
|
+
class Container < Base
|
502
|
+
def self.basic?
|
503
|
+
false
|
504
|
+
end
|
505
|
+
|
506
|
+
def self.fixed?
|
507
|
+
false
|
508
|
+
end
|
509
|
+
|
510
|
+
# For containers, the type varies among instances
|
511
|
+
# @see Base#type
|
512
|
+
attr_reader :type
|
513
|
+
end
|
514
|
+
|
497
515
|
# An Array, or a Dictionary (Hash).
|
498
516
|
class Array < Container
|
499
517
|
def self.type_code
|
@@ -504,44 +522,32 @@ module DBus
|
|
504
522
|
4
|
505
523
|
end
|
506
524
|
|
507
|
-
# @return [Type]
|
508
|
-
attr_reader :member_type
|
509
|
-
|
510
|
-
def type
|
511
|
-
return @type if @type
|
512
|
-
|
513
|
-
# TODO: reconstructing the type is cumbersome; have #initialize take *type* instead?
|
514
|
-
# TODO: or rather add Type::Array[t]
|
515
|
-
@type = Type.new("a")
|
516
|
-
@type << member_type
|
517
|
-
@type
|
518
|
-
end
|
519
|
-
|
520
525
|
# TODO: check that Hash keys are basic types
|
521
526
|
# @param mode [:plain,:exact]
|
522
|
-
# @param
|
527
|
+
# @param type [Type]
|
523
528
|
# @param hash [Boolean] are we unmarshalling an ARRAY of DICT_ENTRY
|
524
529
|
# @return [Data::Array]
|
525
|
-
def self.from_items(value, mode:,
|
530
|
+
def self.from_items(value, mode:, type:, hash: false)
|
526
531
|
value = Hash[value] if hash
|
527
532
|
return value if mode == :plain
|
528
533
|
|
529
|
-
new(value,
|
534
|
+
new(value, type: type)
|
530
535
|
end
|
531
536
|
|
532
537
|
# @param value [::Object]
|
533
|
-
# @param
|
538
|
+
# @param type [Type]
|
534
539
|
# @return [Data::Array]
|
535
|
-
def self.from_typed(value,
|
540
|
+
def self.from_typed(value, type:)
|
541
|
+
assert_type_matches_class(type)
|
536
542
|
# TODO: validation
|
537
|
-
member_type =
|
543
|
+
member_type = type.child
|
538
544
|
|
539
545
|
# TODO: Dict??
|
540
546
|
items = value.map do |i|
|
541
547
|
Data.make_typed(member_type, i)
|
542
548
|
end
|
543
549
|
|
544
|
-
new(items,
|
550
|
+
new(items, type: type) # initialize(::Array<Data::Base>)
|
545
551
|
end
|
546
552
|
|
547
553
|
# FIXME: should Data::Array be mutable?
|
@@ -550,12 +556,12 @@ module DBus
|
|
550
556
|
# TODO: specify type or guess type?
|
551
557
|
# Data is the exact type, so its constructor should be exact
|
552
558
|
# and guesswork should be clearly labeled
|
553
|
-
# @param
|
554
|
-
def initialize(value,
|
555
|
-
|
559
|
+
# @param type [SingleCompleteType,Type]
|
560
|
+
def initialize(value, type:)
|
561
|
+
type = DBus.type(type) unless type.is_a?(Type)
|
562
|
+
self.class.assert_type_matches_class(type)
|
563
|
+
@type = type
|
556
564
|
# TODO: copy from another Data::Array
|
557
|
-
@member_type = member_type
|
558
|
-
@type = nil
|
559
565
|
super(value)
|
560
566
|
end
|
561
567
|
end
|
@@ -572,46 +578,32 @@ module DBus
|
|
572
578
|
8
|
573
579
|
end
|
574
580
|
|
575
|
-
# @return [::Array<Type>]
|
576
|
-
attr_reader :member_types
|
577
|
-
|
578
|
-
def type
|
579
|
-
return @type if @type
|
580
|
-
|
581
|
-
# TODO: reconstructing the type is cumbersome; have #initialize take *type* instead?
|
582
|
-
# TODO: or rather add Type::Struct[t1, t2, ...]
|
583
|
-
@type = Type.new(self.class.type_code, abstract: true)
|
584
|
-
@member_types.each do |member_type|
|
585
|
-
@type << member_type
|
586
|
-
end
|
587
|
-
@type
|
588
|
-
end
|
589
|
-
|
590
581
|
# @param value [::Array]
|
591
|
-
def self.from_items(value, mode:,
|
582
|
+
def self.from_items(value, mode:, type:)
|
592
583
|
value.freeze
|
593
584
|
return value if mode == :plain
|
594
585
|
|
595
|
-
new(value,
|
586
|
+
new(value, type: type)
|
596
587
|
end
|
597
588
|
|
598
589
|
# @param value [::Object] (#size, #each)
|
599
|
-
# @param
|
590
|
+
# @param type [Type]
|
600
591
|
# @return [Struct]
|
601
|
-
def self.from_typed(value,
|
592
|
+
def self.from_typed(value, type:)
|
602
593
|
# TODO: validation
|
594
|
+
member_types = type.members
|
603
595
|
raise unless value.size == member_types.size
|
604
596
|
|
605
597
|
items = member_types.zip(value).map do |item_type, item|
|
606
598
|
Data.make_typed(item_type, item)
|
607
599
|
end
|
608
600
|
|
609
|
-
new(items,
|
601
|
+
new(items, type: type) # initialize(::Array<Data::Base>)
|
610
602
|
end
|
611
603
|
|
612
|
-
def initialize(value,
|
613
|
-
|
614
|
-
@type =
|
604
|
+
def initialize(value, type:)
|
605
|
+
self.class.assert_type_matches_class(type)
|
606
|
+
@type = type
|
615
607
|
super(value)
|
616
608
|
end
|
617
609
|
end
|
@@ -634,10 +626,10 @@ module DBus
|
|
634
626
|
end
|
635
627
|
|
636
628
|
# @param value [::Object]
|
637
|
-
# @param
|
629
|
+
# @param type [Type]
|
638
630
|
# @return [Variant]
|
639
|
-
def self.from_typed(value,
|
640
|
-
|
631
|
+
def self.from_typed(value, type:)
|
632
|
+
assert_type_matches_class(type)
|
641
633
|
|
642
634
|
# decide on type of value
|
643
635
|
new(value, member_type: nil)
|
@@ -690,31 +682,19 @@ module DBus
|
|
690
682
|
8
|
691
683
|
end
|
692
684
|
|
693
|
-
# @return [::Array<Type>]
|
694
|
-
attr_reader :member_types
|
695
|
-
|
696
|
-
def type
|
697
|
-
return @type if @type
|
698
|
-
|
699
|
-
# TODO: reconstructing the type is cumbersome; have #initialize take *type* instead?
|
700
|
-
@type = Type.new(self.class.type_code, abstract: true)
|
701
|
-
@member_types.each do |member_type|
|
702
|
-
@type << member_type
|
703
|
-
end
|
704
|
-
@type
|
705
|
-
end
|
706
|
-
|
707
685
|
# @param value [::Array]
|
708
|
-
def self.from_items(value, mode:,
|
686
|
+
def self.from_items(value, mode:, type:) # rubocop:disable Lint/UnusedMethodArgument
|
709
687
|
value.freeze
|
710
688
|
# DictEntry ignores the :exact mode
|
711
689
|
value
|
712
690
|
end
|
713
691
|
|
714
692
|
# @param value [::Object] (#size, #each)
|
715
|
-
# @param
|
693
|
+
# @param type [Type]
|
716
694
|
# @return [DictEntry]
|
717
|
-
def self.from_typed(value,
|
695
|
+
def self.from_typed(value, type:)
|
696
|
+
assert_type_matches_class(type)
|
697
|
+
member_types = type.members
|
718
698
|
# assert member_types.size == 2
|
719
699
|
# TODO: duplicated from Struct. Inherit/delegate?
|
720
700
|
# TODO: validation
|
@@ -724,12 +704,12 @@ module DBus
|
|
724
704
|
Data.make_typed(item_type, item)
|
725
705
|
end
|
726
706
|
|
727
|
-
new(items,
|
707
|
+
new(items, type: type) # initialize(::Array<Data::Base>)
|
728
708
|
end
|
729
709
|
|
730
|
-
def initialize(value,
|
731
|
-
|
732
|
-
@type =
|
710
|
+
def initialize(value, type:)
|
711
|
+
self.class.assert_type_matches_class(type)
|
712
|
+
@type = type
|
733
713
|
super(value)
|
734
714
|
end
|
735
715
|
end
|
data/lib/dbus/marshall.rb
CHANGED
@@ -118,7 +118,7 @@ module DBus
|
|
118
118
|
values = signature.members.map do |child_sig|
|
119
119
|
do_parse(child_sig, mode: mode)
|
120
120
|
end
|
121
|
-
packet = data_class.from_items(values, mode: mode,
|
121
|
+
packet = data_class.from_items(values, mode: mode, type: signature)
|
122
122
|
|
123
123
|
when Type::VARIANT
|
124
124
|
data_sig = do_parse(Data::Signature.type, mode: :exact) # -> Data::Signature
|
@@ -147,7 +147,7 @@ module DBus
|
|
147
147
|
items << item
|
148
148
|
end
|
149
149
|
is_hash = signature.child.sigtype == Type::DICT_ENTRY
|
150
|
-
packet = data_class.from_items(items, mode: mode,
|
150
|
+
packet = data_class.from_items(items, mode: mode, type: signature, hash: is_hash)
|
151
151
|
end
|
152
152
|
end
|
153
153
|
packet
|
@@ -282,8 +282,11 @@ module DBus
|
|
282
282
|
|
283
283
|
def append_variant(val)
|
284
284
|
vartype = nil
|
285
|
-
if val.is_a?(DBus::Data::
|
286
|
-
vartype = val.
|
285
|
+
if val.is_a?(DBus::Data::Variant)
|
286
|
+
vartype = val.member_type
|
287
|
+
vardata = val.value
|
288
|
+
elsif val.is_a?(DBus::Data::Base)
|
289
|
+
vartype = val.type
|
287
290
|
vardata = val.value
|
288
291
|
elsif val.is_a?(Array) && val.size == 2
|
289
292
|
case val[0]
|
data/lib/dbus/type.rb
CHANGED
@@ -29,14 +29,12 @@ module DBus
|
|
29
29
|
# For documentation purposes only.
|
30
30
|
class Prototype < String; end
|
31
31
|
|
32
|
-
#
|
33
|
-
#
|
34
|
-
# This module containts the constants of the types specified in the D-Bus
|
35
|
-
# protocol.
|
32
|
+
# Represents the D-Bus types.
|
36
33
|
#
|
37
34
|
# Corresponds to {SingleCompleteType}.
|
35
|
+
# Instances are immutable/frozen once fully constructed.
|
38
36
|
#
|
39
|
-
# See also {DBus::Data::Signature}
|
37
|
+
# See also {DBus::Data::Signature} which is "type on the wire".
|
40
38
|
class Type
|
41
39
|
# Mapping from type number to name and alignment.
|
42
40
|
TYPE_MAPPING = {
|
@@ -104,8 +102,9 @@ module DBus
|
|
104
102
|
end
|
105
103
|
end
|
106
104
|
|
107
|
-
@sigtype = sigtype
|
108
|
-
@members = []
|
105
|
+
@sigtype = sigtype.freeze
|
106
|
+
@members = [] # not frozen yet, Parser#parse_one or Factory will do it
|
107
|
+
freeze
|
109
108
|
end
|
110
109
|
|
111
110
|
# Return the required alignment for the type.
|
@@ -124,16 +123,15 @@ module DBus
|
|
124
123
|
when DICT_ENTRY
|
125
124
|
"{#{@members.collect(&:to_s).join}}"
|
126
125
|
else
|
127
|
-
if !TYPE_MAPPING.keys.member?(@sigtype)
|
128
|
-
raise NotImplementedError
|
129
|
-
end
|
130
|
-
|
131
126
|
@sigtype.chr
|
132
127
|
end
|
133
128
|
end
|
134
129
|
|
135
130
|
# Add a new member type _item_.
|
131
|
+
# @param item [Type]
|
136
132
|
def <<(item)
|
133
|
+
raise ArgumentError unless item.is_a?(Type)
|
134
|
+
|
137
135
|
if ![STRUCT, ARRAY, DICT_ENTRY].member?(@sigtype)
|
138
136
|
raise SignatureException
|
139
137
|
end
|
@@ -232,6 +230,7 @@ module DBus
|
|
232
230
|
else
|
233
231
|
res = Type.new(char)
|
234
232
|
end
|
233
|
+
res.members.freeze
|
235
234
|
res
|
236
235
|
end
|
237
236
|
|
@@ -243,7 +242,7 @@ module DBus
|
|
243
242
|
while (c = nextchar)
|
244
243
|
ret << parse_one(c)
|
245
244
|
end
|
246
|
-
ret
|
245
|
+
ret.freeze
|
247
246
|
end
|
248
247
|
|
249
248
|
# Parse one {SingleCompleteType}
|
@@ -255,9 +254,116 @@ module DBus
|
|
255
254
|
t = parse_one(c)
|
256
255
|
raise SignatureException, "Has more than a Single Complete Type: #{@signature}" unless nextchar.nil?
|
257
256
|
|
257
|
+
t.freeze
|
258
|
+
end
|
259
|
+
end
|
260
|
+
|
261
|
+
class Factory
|
262
|
+
# @param type [Type,SingleCompleteType,Class]
|
263
|
+
# @see from_plain_class
|
264
|
+
# @return [Type] (frozen)
|
265
|
+
def self.make_type(type)
|
266
|
+
case type
|
267
|
+
when Type
|
268
|
+
type
|
269
|
+
when String
|
270
|
+
DBus.type(type)
|
271
|
+
when Class
|
272
|
+
from_plain_class(type)
|
273
|
+
else
|
274
|
+
msg = "Expecting DBus::Type, DBus::SingleCompleteType(aka ::String), or Class, got #{type.inspect}"
|
275
|
+
raise ArgumentError, msg
|
276
|
+
end
|
277
|
+
end
|
278
|
+
|
279
|
+
# Make a {Type} corresponding to some plain classes:
|
280
|
+
# - String
|
281
|
+
# - Float
|
282
|
+
# - DBus::ObjectPath
|
283
|
+
# - DBus::Signature, DBus::SingleCompleteType
|
284
|
+
# @param klass [Class]
|
285
|
+
# @return [Type] (frozen)
|
286
|
+
def self.from_plain_class(klass)
|
287
|
+
@signature_type ||= DBus.type(SIGNATURE)
|
288
|
+
@class_to_type ||= {
|
289
|
+
DBus::ObjectPath => DBus.type(OBJECT_PATH),
|
290
|
+
DBus::Signature => @signature_type,
|
291
|
+
DBus::SingleCompleteType => @signature_type,
|
292
|
+
String => DBus.type(STRING),
|
293
|
+
Float => DBus.type(DOUBLE)
|
294
|
+
}
|
295
|
+
t = @class_to_type[klass]
|
296
|
+
raise ArgumentError, "Cannot convert plain class #{klass} to a D-Bus type" if t.nil?
|
297
|
+
|
298
|
+
t
|
299
|
+
end
|
300
|
+
end
|
301
|
+
|
302
|
+
# Syntactic helper for constructing an array Type.
|
303
|
+
# You may be looking for {Data::Array} instead.
|
304
|
+
# @example
|
305
|
+
# t = Type::Array[Type::INT16]
|
306
|
+
class ArrayFactory < Factory
|
307
|
+
# @param member_type [Type,SingleCompleteType]
|
308
|
+
# @return [Type] (frozen)
|
309
|
+
def self.[](member_type)
|
310
|
+
t = Type.new(ARRAY)
|
311
|
+
t << make_type(member_type)
|
312
|
+
t.members.freeze
|
313
|
+
t
|
314
|
+
end
|
315
|
+
end
|
316
|
+
|
317
|
+
# @example
|
318
|
+
# t = Type::Array[Type::INT16]
|
319
|
+
Array = ArrayFactory
|
320
|
+
|
321
|
+
# Syntactic helper for constructing a hash Type.
|
322
|
+
# You may be looking for {Data::Array} and {Data::DictEntry} instead.
|
323
|
+
# @example
|
324
|
+
# t = Type::Hash[Type::STRING, Type::VARIANT]
|
325
|
+
class HashFactory < Factory
|
326
|
+
# @param key_type [Type,SingleCompleteType]
|
327
|
+
# @param value_type [Type,SingleCompleteType]
|
328
|
+
# @return [Type] (frozen)
|
329
|
+
def self.[](key_type, value_type)
|
330
|
+
t = Type.new(ARRAY)
|
331
|
+
de = Type.new(DICT_ENTRY, abstract: true)
|
332
|
+
de << make_type(key_type)
|
333
|
+
de << make_type(value_type)
|
334
|
+
de.members.freeze
|
335
|
+
t << de
|
336
|
+
t.members.freeze
|
258
337
|
t
|
259
338
|
end
|
260
339
|
end
|
340
|
+
|
341
|
+
# @example
|
342
|
+
# t = Type::Hash[Type::INT16]
|
343
|
+
Hash = HashFactory
|
344
|
+
|
345
|
+
# Syntactic helper for constructing a struct Type.
|
346
|
+
# You may be looking for {Data::Struct} instead.
|
347
|
+
# @example
|
348
|
+
# t = Type::Struct[Type::INT16, Type::STRING]
|
349
|
+
class StructFactory < Factory
|
350
|
+
# @param member_types [::Array<Type,SingleCompleteType>]
|
351
|
+
# @return [Type] (frozen)
|
352
|
+
def self.[](*member_types)
|
353
|
+
raise ArgumentError if member_types.empty?
|
354
|
+
|
355
|
+
t = Type.new(STRUCT, abstract: true)
|
356
|
+
member_types.each do |mt|
|
357
|
+
t << make_type(mt)
|
358
|
+
end
|
359
|
+
t.members.freeze
|
360
|
+
t
|
361
|
+
end
|
362
|
+
end
|
363
|
+
|
364
|
+
# @example
|
365
|
+
# t = Type::Struct[Type::INT16, Type::STRING]
|
366
|
+
Struct = StructFactory
|
261
367
|
end
|
262
368
|
|
263
369
|
# shortcuts
|
@@ -266,7 +372,7 @@ module DBus
|
|
266
372
|
# This is prefered to {Type#initialize} which allows
|
267
373
|
# incomplete or invalid types.
|
268
374
|
# @param string_type [SingleCompleteType]
|
269
|
-
# @return [DBus::Type]
|
375
|
+
# @return [DBus::Type] (frozen)
|
270
376
|
# @raise SignatureException
|
271
377
|
def type(string_type)
|
272
378
|
Type::Parser.new(string_type).parse1
|
@@ -275,7 +381,7 @@ module DBus
|
|
275
381
|
|
276
382
|
# Parse a String to zero or more {DBus::Type}s.
|
277
383
|
# @param string_type [Signature]
|
278
|
-
# @return [Array<DBus::Type>]
|
384
|
+
# @return [Array<DBus::Type>] (frozen)
|
279
385
|
# @raise SignatureException
|
280
386
|
def types(string_type)
|
281
387
|
Type::Parser.new(string_type).parse
|
data/spec/data_spec.rb
CHANGED
@@ -85,6 +85,8 @@ end
|
|
85
85
|
# TODO: Look at conversions? to_str, to_int?
|
86
86
|
|
87
87
|
describe DBus::Data do
|
88
|
+
T = DBus::Type unless const_defined? "T"
|
89
|
+
|
88
90
|
# test initialization, from user code, or from packet (from_raw)
|
89
91
|
# remember to unpack if initializing from Data::Base
|
90
92
|
# #value should recurse inside so that the user doesnt have to
|
@@ -245,18 +247,18 @@ describe DBus::Data do
|
|
245
247
|
describe "containers" do
|
246
248
|
describe DBus::Data::Array do
|
247
249
|
good = [
|
248
|
-
# [[1, 2, 3],
|
249
|
-
[[1, 2, 3], {
|
250
|
-
[[1, 2, 3], {
|
251
|
-
[[1, 2, 3], {
|
252
|
-
[[DBus::Data::UInt16.new(1), DBus::Data::UInt16.new(2), DBus::Data::UInt16.new(3)], {
|
250
|
+
# [[1, 2, 3], type: nil],
|
251
|
+
[[1, 2, 3], { type: "aq" }],
|
252
|
+
[[1, 2, 3], { type: T::Array[T::UINT16] }],
|
253
|
+
[[1, 2, 3], { type: T::Array["q"] }],
|
254
|
+
[[DBus::Data::UInt16.new(1), DBus::Data::UInt16.new(2), DBus::Data::UInt16.new(3)], { type: T::Array["q"] }]
|
253
255
|
# TODO: others
|
254
256
|
]
|
255
257
|
|
256
258
|
bad = [
|
257
259
|
# undesirable type guessing
|
258
|
-
## [[1, 2, 3], {
|
259
|
-
## [[1, 2, 3], {
|
260
|
+
## [[1, 2, 3], { type: nil }, DBus::InvalidPacketException, "Unknown type code"],
|
261
|
+
## [[1, 2, 3], { type: "!" }, DBus::InvalidPacketException, "Unknown type code"]
|
260
262
|
# TODO: others
|
261
263
|
]
|
262
264
|
|
@@ -265,8 +267,8 @@ describe DBus::Data do
|
|
265
267
|
|
266
268
|
describe ".from_typed" do
|
267
269
|
it "creates new instance from given object and type" do
|
268
|
-
type =
|
269
|
-
expect(described_class.from_typed(["test", "lest"],
|
270
|
+
type = T::Array[String]
|
271
|
+
expect(described_class.from_typed(["test", "lest"], type: type)).to be_a(described_class)
|
270
272
|
end
|
271
273
|
end
|
272
274
|
end
|
@@ -274,7 +276,7 @@ describe DBus::Data do
|
|
274
276
|
describe DBus::Data::Struct do
|
275
277
|
three_words = ::Struct.new(:a, :b, :c)
|
276
278
|
|
277
|
-
qqq = [
|
279
|
+
qqq = T::Struct[T::UINT16, T::UINT16, T::UINT16]
|
278
280
|
integers = [1, 2, 3]
|
279
281
|
uints = [DBus::Data::UInt16.new(1), DBus::Data::UInt16.new(2), DBus::Data::UInt16.new(3)]
|
280
282
|
|
@@ -291,28 +293,25 @@ describe DBus::Data do
|
|
291
293
|
# TODO: also check data ownership: reasonable to own the data?
|
292
294
|
# can make it explicit?
|
293
295
|
good = [
|
294
|
-
# from plain array; various
|
295
|
-
[integers, {
|
296
|
-
[integers, {
|
297
|
-
[integers, {
|
296
|
+
# from plain array; various *type* styles
|
297
|
+
[integers, { type: DBus.type("(qqq)") }],
|
298
|
+
[integers, { type: T::Struct["q", "q", "q"] }],
|
299
|
+
[integers, { type: T::Struct[T::UINT16, T::UINT16, T::UINT16] }],
|
300
|
+
[integers, { type: T::Struct[*DBus.types("qqq")] }],
|
298
301
|
# plain array of data
|
299
|
-
[uints, {
|
302
|
+
[uints, { type: qqq }],
|
300
303
|
# ::Struct
|
301
|
-
[three_words.new(*integers), {
|
302
|
-
[three_words.new(*uints), {
|
304
|
+
[three_words.new(*integers), { type: qqq }],
|
305
|
+
[three_words.new(*uints), { type: qqq }]
|
303
306
|
# TODO: others
|
304
307
|
]
|
305
308
|
|
309
|
+
# check these only when canonicalizing @value, because that will
|
310
|
+
# type-check the value deeply
|
306
311
|
_bad_but_valid = [
|
307
|
-
# Wrong member_types arg:
|
308
|
-
# hmm this is another reason to pass the type
|
309
|
-
# as the entire struct type, not the members:
|
310
|
-
# empty struct will be caught naturally
|
311
|
-
[integers, { member_types: [] }, ArgumentError, "???"],
|
312
|
-
[integers, { member_types: ["!"] }, DBus::InvalidPacketException, "Unknown type code"],
|
313
312
|
# STRUCT specific: member count mismatch
|
314
|
-
[[1, 2], {
|
315
|
-
[[1, 2, 3, 4], {
|
313
|
+
[[1, 2], { type: qqq }, ArgumentError, "???"],
|
314
|
+
[[1, 2, 3, 4], { type: qqq }, ArgumentError, "???"]
|
316
315
|
# TODO: others
|
317
316
|
]
|
318
317
|
|
@@ -321,8 +320,8 @@ describe DBus::Data do
|
|
321
320
|
|
322
321
|
describe ".from_typed" do
|
323
322
|
it "creates new instance from given object and type" do
|
324
|
-
type =
|
325
|
-
expect(described_class.from_typed(["test", "lest"].freeze,
|
323
|
+
type = T::Struct[T::STRING, T::STRING]
|
324
|
+
expect(described_class.from_typed(["test", "lest"].freeze, type: type))
|
326
325
|
.to be_a(described_class)
|
327
326
|
end
|
328
327
|
end
|
@@ -331,16 +330,9 @@ describe DBus::Data do
|
|
331
330
|
describe DBus::Data::Variant do
|
332
331
|
describe ".from_typed" do
|
333
332
|
it "creates new instance from given object and type" do
|
334
|
-
type = DBus
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
it "ignores the member_types argument" do
|
339
|
-
type = DBus::Type.new("s")
|
340
|
-
# Base.from_typed is a generic interface with a fixed signature;
|
341
|
-
# So it must offer the member_types parameter, which is misleading
|
342
|
-
# for a Variant
|
343
|
-
value = described_class.from_typed("test", member_types: [type])
|
333
|
+
type = DBus.type(T::VARIANT)
|
334
|
+
value = described_class.from_typed("test", type: type)
|
335
|
+
expect(value).to be_a(described_class)
|
344
336
|
expect(value.type.to_s).to eq "v"
|
345
337
|
expect(value.member_type.to_s).to eq "s"
|
346
338
|
end
|
data/spec/property_spec.rb
CHANGED
@@ -163,7 +163,7 @@ describe "PropertyTest" do
|
|
163
163
|
end
|
164
164
|
end
|
165
165
|
|
166
|
-
context "
|
166
|
+
context "a dict-typed property" do
|
167
167
|
it "gets read as a hash" do
|
168
168
|
val = @iface["MyDict"]
|
169
169
|
expect(val).to eq({
|
@@ -172,6 +172,23 @@ describe "PropertyTest" do
|
|
172
172
|
"three" => [3, 3, 3]
|
173
173
|
})
|
174
174
|
end
|
175
|
+
|
176
|
+
it "Get returns the correctly typed value (check with dbus-send)" do
|
177
|
+
cmd = "dbus-send --print-reply " \
|
178
|
+
"--dest=org.ruby.service " \
|
179
|
+
"/org/ruby/MyInstance " \
|
180
|
+
"org.freedesktop.DBus.Properties.Get " \
|
181
|
+
"string:org.ruby.SampleInterface " \
|
182
|
+
"string:MyDict"
|
183
|
+
reply = `#{cmd}`
|
184
|
+
# a bug about variant nesting lead to a "variant variant int32 1" value
|
185
|
+
match_rx = /variant \s+ array \s \[ \s+
|
186
|
+
dict \s entry\( \s+
|
187
|
+
string \s "one" \s+
|
188
|
+
variant \s+ int32 \s 1 \s+
|
189
|
+
\)/x
|
190
|
+
expect(reply).to match(match_rx)
|
191
|
+
end
|
175
192
|
end
|
176
193
|
|
177
194
|
context "a variant-typed property" do
|
data/spec/type_spec.rb
CHANGED
@@ -45,6 +45,7 @@ describe DBus do
|
|
45
45
|
["a{vs}", "DICT_ENTRY key must be basic (non-container)"],
|
46
46
|
["{sv}", "DICT_ENTRY not an immediate child of an ARRAY"],
|
47
47
|
["a({sv})", "DICT_ENTRY not an immediate child of an ARRAY"],
|
48
|
+
["a{s", "DICT_ENTRY not closed"],
|
48
49
|
["a{sv", "DICT_ENTRY not closed"],
|
49
50
|
["}", "DICT_ENTRY unexpectedly closed"],
|
50
51
|
|
@@ -79,4 +80,108 @@ describe DBus do
|
|
79
80
|
end
|
80
81
|
end
|
81
82
|
end
|
83
|
+
|
84
|
+
describe DBus::Type do
|
85
|
+
describe "#<<" do
|
86
|
+
it "raises if the argument is not a Type" do
|
87
|
+
t = DBus::Type.new(DBus::Type::ARRAY)
|
88
|
+
expect { t << "s" }.to raise_error(ArgumentError)
|
89
|
+
end
|
90
|
+
|
91
|
+
# TODO: the following raise checks do not occur in practice, as there are
|
92
|
+
# parallel checks in the parses. The code could be simplified?
|
93
|
+
it "raises if adding too much to an array" do
|
94
|
+
t = DBus::Type.new(DBus::Type::ARRAY)
|
95
|
+
b = DBus::Type.new(DBus::Type::BOOLEAN)
|
96
|
+
t << b
|
97
|
+
expect { t << b }.to raise_error(DBus::Type::SignatureException)
|
98
|
+
end
|
99
|
+
|
100
|
+
it "raises if adding too much to a dict_entry" do
|
101
|
+
t = DBus::Type.new(DBus::Type::DICT_ENTRY, abstract: true)
|
102
|
+
b = DBus::Type.new(DBus::Type::BOOLEAN)
|
103
|
+
t << b
|
104
|
+
t << b
|
105
|
+
expect { t << b }.to raise_error(DBus::Type::SignatureException)
|
106
|
+
end
|
107
|
+
|
108
|
+
it "raises if adding to a non-container" do
|
109
|
+
t = DBus::Type.new(DBus::Type::STRING)
|
110
|
+
b = DBus::Type.new(DBus::Type::BOOLEAN)
|
111
|
+
expect { t << b }.to raise_error(DBus::Type::SignatureException)
|
112
|
+
|
113
|
+
t = DBus::Type.new(DBus::Type::VARIANT)
|
114
|
+
expect { t << b }.to raise_error(DBus::Type::SignatureException)
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
describe DBus::Type::Array do
|
119
|
+
describe ".[]" do
|
120
|
+
it "takes Type argument" do
|
121
|
+
t = DBus::Type::Array[DBus::Type.new("s")]
|
122
|
+
expect(t.to_s).to eq "as"
|
123
|
+
end
|
124
|
+
|
125
|
+
it "takes 's':String argument" do
|
126
|
+
t = DBus::Type::Array["s"]
|
127
|
+
expect(t.to_s).to eq "as"
|
128
|
+
end
|
129
|
+
|
130
|
+
it "takes String:Class argument" do
|
131
|
+
t = DBus::Type::Array[String]
|
132
|
+
expect(t.to_s).to eq "as"
|
133
|
+
end
|
134
|
+
|
135
|
+
it "rejects Integer:Class argument" do
|
136
|
+
expect { DBus::Type::Array[Integer] }.to raise_error(ArgumentError)
|
137
|
+
end
|
138
|
+
|
139
|
+
it "rejects /./:Regexp argument" do
|
140
|
+
expect { DBus::Type::Array[/./] }.to raise_error(ArgumentError)
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
describe DBus::Type::Hash do
|
146
|
+
describe ".[]" do
|
147
|
+
it "takes Type arguments" do
|
148
|
+
t = DBus::Type::Hash[DBus::Type.new("s"), DBus::Type.new("v")]
|
149
|
+
expect(t.to_s).to eq "a{sv}"
|
150
|
+
end
|
151
|
+
|
152
|
+
it "takes 's':String arguments" do
|
153
|
+
t = DBus::Type::Hash["s", "v"]
|
154
|
+
expect(t.to_s).to eq "a{sv}"
|
155
|
+
end
|
156
|
+
|
157
|
+
it "takes String:Class argument" do
|
158
|
+
t = DBus::Type::Hash[String, DBus::Type::VARIANT]
|
159
|
+
expect(t.to_s).to eq "a{sv}"
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
describe DBus::Type::Struct do
|
165
|
+
describe ".[]" do
|
166
|
+
it "takes Type arguments" do
|
167
|
+
t = DBus::Type::Struct[DBus::Type.new("s"), DBus::Type.new("v")]
|
168
|
+
expect(t.to_s).to eq "(sv)"
|
169
|
+
end
|
170
|
+
|
171
|
+
it "takes 's':String arguments" do
|
172
|
+
t = DBus::Type::Struct["s", "v"]
|
173
|
+
expect(t.to_s).to eq "(sv)"
|
174
|
+
end
|
175
|
+
|
176
|
+
it "takes String:Class argument" do
|
177
|
+
t = DBus::Type::Struct[String, DBus::Type::VARIANT]
|
178
|
+
expect(t.to_s).to eq "(sv)"
|
179
|
+
end
|
180
|
+
|
181
|
+
it "raises on no arguments" do
|
182
|
+
expect { DBus::Type::Struct[] }.to raise_error(ArgumentError)
|
183
|
+
end
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|
82
187
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ruby-dbus
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.18.0.
|
4
|
+
version: 0.18.0.beta5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ruby DBus Team
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-04-
|
11
|
+
date: 2022-04-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rexml
|