ruby-dbus 0.18.0.beta2 → 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 +35 -0
- data/VERSION +1 -1
- data/lib/dbus/data.rb +109 -110
- data/lib/dbus/marshall.rb +22 -8
- data/lib/dbus/type.rb +120 -14
- data/spec/data/marshall.yaml +28 -0
- data/spec/data_spec.rb +70 -23
- data/spec/packet_marshaller_spec.rb +7 -0
- data/spec/property_spec.rb +73 -2
- data/spec/service_newapi.rb +19 -1
- data/spec/spec_helper.rb +2 -0
- data/spec/type_spec.rb +105 -0
- data/spec/zzz_quit_spec.rb +16 -0
- metadata +3 -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,41 @@
|
|
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
|
+
|
22
|
+
## Ruby D-Bus 0.18.0.beta4 - 2022-04-21
|
23
|
+
|
24
|
+
Bug fixes:
|
25
|
+
* Service-side properties: Fix Properties.Get, Properties.GetAll for
|
26
|
+
properties that contain arrays, on other than outermost level ([#109][]).
|
27
|
+
* Sending variants: fixed make_variant to correctly guess the signature
|
28
|
+
for UInt64 and number-keyed hashes/dictionaries.
|
29
|
+
|
30
|
+
[#109]: https://github.com/mvidner/ruby-dbus/pull/109
|
31
|
+
|
32
|
+
## Ruby D-Bus 0.18.0.beta3 - 2022-04-10
|
33
|
+
|
34
|
+
Bug fixes:
|
35
|
+
* Service-side properties: Fix Properties.Get, Properties.GetAll for Array,
|
36
|
+
Dict, and Variant types ([#105][]).
|
37
|
+
|
38
|
+
[#105]: https://github.com/mvidner/ruby-dbus/pull/105
|
39
|
+
|
5
40
|
## Ruby D-Bus 0.18.0.beta2 - 2022-04-04
|
6
41
|
|
7
42
|
API:
|
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,39 +146,14 @@ 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
|
|
166
152
|
# Represents integers
|
167
153
|
class Int < Fixed
|
154
|
+
# @!method self.range
|
155
|
+
# @return [Range] the full range of allowed values
|
156
|
+
|
168
157
|
# @param value [::Integer,DBus::Data::Int]
|
169
158
|
# @raise RangeError
|
170
159
|
def initialize(value)
|
@@ -174,10 +163,6 @@ module DBus
|
|
174
163
|
|
175
164
|
super(value)
|
176
165
|
end
|
177
|
-
|
178
|
-
def self.range
|
179
|
-
raise NotImplementedError, "Abstract"
|
180
|
-
end
|
181
166
|
end
|
182
167
|
|
183
168
|
# Byte.
|
@@ -399,6 +384,23 @@ module DBus
|
|
399
384
|
end
|
400
385
|
end
|
401
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
|
+
|
402
404
|
# UTF-8 encoded string.
|
403
405
|
class String < StringLike
|
404
406
|
def self.type_code
|
@@ -495,6 +497,21 @@ module DBus
|
|
495
497
|
end
|
496
498
|
end
|
497
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
|
+
|
498
515
|
# An Array, or a Dictionary (Hash).
|
499
516
|
class Array < Container
|
500
517
|
def self.type_code
|
@@ -505,44 +522,32 @@ module DBus
|
|
505
522
|
4
|
506
523
|
end
|
507
524
|
|
508
|
-
# @return [Type]
|
509
|
-
attr_reader :member_type
|
510
|
-
|
511
|
-
def type
|
512
|
-
return @type if @type
|
513
|
-
|
514
|
-
# TODO: reconstructing the type is cumbersome; have #initialize take *type* instead?
|
515
|
-
# TODO: or rather add Type::Array[t]
|
516
|
-
@type = Type.new("a")
|
517
|
-
@type << member_type
|
518
|
-
@type
|
519
|
-
end
|
520
|
-
|
521
525
|
# TODO: check that Hash keys are basic types
|
522
526
|
# @param mode [:plain,:exact]
|
523
|
-
# @param
|
527
|
+
# @param type [Type]
|
524
528
|
# @param hash [Boolean] are we unmarshalling an ARRAY of DICT_ENTRY
|
525
529
|
# @return [Data::Array]
|
526
|
-
def self.from_items(value, mode:,
|
530
|
+
def self.from_items(value, mode:, type:, hash: false)
|
527
531
|
value = Hash[value] if hash
|
528
532
|
return value if mode == :plain
|
529
533
|
|
530
|
-
new(value,
|
534
|
+
new(value, type: type)
|
531
535
|
end
|
532
536
|
|
533
537
|
# @param value [::Object]
|
534
|
-
# @param
|
538
|
+
# @param type [Type]
|
535
539
|
# @return [Data::Array]
|
536
|
-
def self.from_typed(value,
|
540
|
+
def self.from_typed(value, type:)
|
541
|
+
assert_type_matches_class(type)
|
537
542
|
# TODO: validation
|
538
|
-
member_type =
|
543
|
+
member_type = type.child
|
539
544
|
|
540
545
|
# TODO: Dict??
|
541
546
|
items = value.map do |i|
|
542
547
|
Data.make_typed(member_type, i)
|
543
548
|
end
|
544
549
|
|
545
|
-
new(items) # initialize(::Array<Data::Base>)
|
550
|
+
new(items, type: type) # initialize(::Array<Data::Base>)
|
546
551
|
end
|
547
552
|
|
548
553
|
# FIXME: should Data::Array be mutable?
|
@@ -551,12 +556,12 @@ module DBus
|
|
551
556
|
# TODO: specify type or guess type?
|
552
557
|
# Data is the exact type, so its constructor should be exact
|
553
558
|
# and guesswork should be clearly labeled
|
554
|
-
# @param
|
555
|
-
def initialize(value,
|
556
|
-
|
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
|
557
564
|
# TODO: copy from another Data::Array
|
558
|
-
@member_type = member_type
|
559
|
-
@type = nil
|
560
565
|
super(value)
|
561
566
|
end
|
562
567
|
end
|
@@ -573,48 +578,32 @@ module DBus
|
|
573
578
|
8
|
574
579
|
end
|
575
580
|
|
576
|
-
# @return [::Array<Type>]
|
577
|
-
attr_reader :member_types
|
578
|
-
|
579
|
-
def type
|
580
|
-
return @type if @type
|
581
|
-
|
582
|
-
# TODO: reconstructing the type is cumbersome; have #initialize take *type* instead?
|
583
|
-
# TODO: or rather add Type::Struct[t1, t2, ...]
|
584
|
-
@type = Type.new(self.class.type_code, abstract: true)
|
585
|
-
@member_types.each do |member_type|
|
586
|
-
@type << member_type
|
587
|
-
end
|
588
|
-
@type
|
589
|
-
end
|
590
|
-
|
591
581
|
# @param value [::Array]
|
592
|
-
def self.from_items(value, mode:,
|
582
|
+
def self.from_items(value, mode:, type:)
|
593
583
|
value.freeze
|
594
584
|
return value if mode == :plain
|
595
585
|
|
596
|
-
new(value,
|
586
|
+
new(value, type: type)
|
597
587
|
end
|
598
588
|
|
599
589
|
# @param value [::Object] (#size, #each)
|
600
|
-
# @param
|
590
|
+
# @param type [Type]
|
601
591
|
# @return [Struct]
|
602
|
-
def self.from_typed(value,
|
592
|
+
def self.from_typed(value, type:)
|
603
593
|
# TODO: validation
|
594
|
+
member_types = type.members
|
604
595
|
raise unless value.size == member_types.size
|
605
596
|
|
606
|
-
@member_types = member_types
|
607
|
-
|
608
597
|
items = member_types.zip(value).map do |item_type, item|
|
609
598
|
Data.make_typed(item_type, item)
|
610
599
|
end
|
611
600
|
|
612
|
-
new(items,
|
601
|
+
new(items, type: type) # initialize(::Array<Data::Base>)
|
613
602
|
end
|
614
603
|
|
615
|
-
def initialize(value,
|
616
|
-
|
617
|
-
@type =
|
604
|
+
def initialize(value, type:)
|
605
|
+
self.class.assert_type_matches_class(type)
|
606
|
+
@type = type
|
618
607
|
super(value)
|
619
608
|
end
|
620
609
|
end
|
@@ -637,20 +626,26 @@ module DBus
|
|
637
626
|
end
|
638
627
|
|
639
628
|
# @param value [::Object]
|
640
|
-
# @param
|
629
|
+
# @param type [Type]
|
641
630
|
# @return [Variant]
|
642
|
-
def self.from_typed(value,
|
643
|
-
|
631
|
+
def self.from_typed(value, type:)
|
632
|
+
assert_type_matches_class(type)
|
644
633
|
|
645
634
|
# decide on type of value
|
646
|
-
new(value)
|
635
|
+
new(value, member_type: nil)
|
647
636
|
end
|
648
637
|
|
649
|
-
#
|
638
|
+
# @return [Type]
|
639
|
+
def self.type
|
640
|
+
# memoize
|
641
|
+
@type ||= Type.new(type_code).freeze
|
642
|
+
end
|
643
|
+
|
644
|
+
# Note that for Variants type.to_s=="v",
|
650
645
|
# for the specific see {Variant#member_type}
|
651
646
|
# @return [Type] the exact type of this value
|
652
647
|
def type
|
653
|
-
|
648
|
+
self.class.type
|
654
649
|
end
|
655
650
|
|
656
651
|
# @return [Type]
|
@@ -687,30 +682,34 @@ module DBus
|
|
687
682
|
8
|
688
683
|
end
|
689
684
|
|
690
|
-
# @return [::Array<Type>]
|
691
|
-
attr_reader :member_types
|
692
|
-
|
693
|
-
def type
|
694
|
-
return @type if @type
|
695
|
-
|
696
|
-
# TODO: reconstructing the type is cumbersome; have #initialize take *type* instead?
|
697
|
-
@type = Type.new(self.class.type_code, abstract: true)
|
698
|
-
@member_types.each do |member_type|
|
699
|
-
@type << member_type
|
700
|
-
end
|
701
|
-
@type
|
702
|
-
end
|
703
|
-
|
704
685
|
# @param value [::Array]
|
705
|
-
def self.from_items(value, mode:,
|
686
|
+
def self.from_items(value, mode:, type:) # rubocop:disable Lint/UnusedMethodArgument
|
706
687
|
value.freeze
|
707
688
|
# DictEntry ignores the :exact mode
|
708
689
|
value
|
709
690
|
end
|
710
691
|
|
711
|
-
|
712
|
-
|
713
|
-
|
692
|
+
# @param value [::Object] (#size, #each)
|
693
|
+
# @param type [Type]
|
694
|
+
# @return [DictEntry]
|
695
|
+
def self.from_typed(value, type:)
|
696
|
+
assert_type_matches_class(type)
|
697
|
+
member_types = type.members
|
698
|
+
# assert member_types.size == 2
|
699
|
+
# TODO: duplicated from Struct. Inherit/delegate?
|
700
|
+
# TODO: validation
|
701
|
+
raise unless value.size == member_types.size
|
702
|
+
|
703
|
+
items = member_types.zip(value).map do |item_type, item|
|
704
|
+
Data.make_typed(item_type, item)
|
705
|
+
end
|
706
|
+
|
707
|
+
new(items, type: type) # initialize(::Array<Data::Base>)
|
708
|
+
end
|
709
|
+
|
710
|
+
def initialize(value, type:)
|
711
|
+
self.class.assert_type_matches_class(type)
|
712
|
+
@type = type
|
714
713
|
super(value)
|
715
714
|
end
|
716
715
|
end
|
data/lib/dbus/marshall.rb
CHANGED
@@ -102,6 +102,8 @@ module DBus
|
|
102
102
|
packet = data_class.from_raw(value, mode: mode)
|
103
103
|
elsif data_class.basic?
|
104
104
|
size = aligned_read_value(data_class.size_class)
|
105
|
+
# @raw_msg.align(data_class.alignment)
|
106
|
+
# ^ is not necessary because we've just read a suitably-aligned *size*
|
105
107
|
value = @raw_msg.read(size)
|
106
108
|
nul = @raw_msg.read(1)
|
107
109
|
if nul != "\u0000"
|
@@ -116,7 +118,7 @@ module DBus
|
|
116
118
|
values = signature.members.map do |child_sig|
|
117
119
|
do_parse(child_sig, mode: mode)
|
118
120
|
end
|
119
|
-
packet = data_class.from_items(values, mode: mode,
|
121
|
+
packet = data_class.from_items(values, mode: mode, type: signature)
|
120
122
|
|
121
123
|
when Type::VARIANT
|
122
124
|
data_sig = do_parse(Data::Signature.type, mode: :exact) # -> Data::Signature
|
@@ -145,7 +147,7 @@ module DBus
|
|
145
147
|
items << item
|
146
148
|
end
|
147
149
|
is_hash = signature.child.sigtype == Type::DICT_ENTRY
|
148
|
-
packet = data_class.from_items(items, mode: mode,
|
150
|
+
packet = data_class.from_items(items, mode: mode, type: signature, hash: is_hash)
|
149
151
|
end
|
150
152
|
end
|
151
153
|
packet
|
@@ -248,9 +250,10 @@ module DBus
|
|
248
250
|
when Type::VARIANT
|
249
251
|
append_variant(val)
|
250
252
|
when Type::ARRAY
|
253
|
+
val = val.value if val.is_a?(Data::Array)
|
251
254
|
append_array(type.child, val)
|
252
255
|
when Type::STRUCT, Type::DICT_ENTRY
|
253
|
-
val = val.value if val.is_a?(Data::Struct)
|
256
|
+
val = val.value if val.is_a?(Data::Struct) || val.is_a?(Data::DictEntry)
|
254
257
|
unless val.is_a?(Array) || val.is_a?(Struct)
|
255
258
|
type_name = Type::TYPE_MAPPING[type.sigtype].first
|
256
259
|
raise TypeException, "#{type_name} expects an Array or Struct, seen #{val.class}"
|
@@ -279,8 +282,11 @@ module DBus
|
|
279
282
|
|
280
283
|
def append_variant(val)
|
281
284
|
vartype = nil
|
282
|
-
if val.is_a?(DBus::Data::
|
283
|
-
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
|
284
290
|
vardata = val.value
|
285
291
|
elsif val.is_a?(Array) && val.size == 2
|
286
292
|
case val[0]
|
@@ -351,15 +357,23 @@ module DBus
|
|
351
357
|
elsif value.is_a? Hash
|
352
358
|
h = {}
|
353
359
|
value.each_key { |k| h[k] = make_variant(value[k]) }
|
354
|
-
|
360
|
+
key_type = if value.empty?
|
361
|
+
"s"
|
362
|
+
else
|
363
|
+
t, = make_variant(value.first.first)
|
364
|
+
t
|
365
|
+
end
|
366
|
+
["a{#{key_type}v}", h]
|
355
367
|
elsif value.respond_to? :to_str
|
356
368
|
["s", value.to_str]
|
357
369
|
elsif value.respond_to? :to_int
|
358
370
|
i = value.to_int
|
359
|
-
if
|
371
|
+
if Data::Int32.range.cover?(i)
|
360
372
|
["i", i]
|
361
|
-
|
373
|
+
elsif Data::Int64.range.cover?(i)
|
362
374
|
["x", i]
|
375
|
+
else
|
376
|
+
["t", i]
|
363
377
|
end
|
364
378
|
end
|
365
379
|
end
|
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/marshall.yaml
CHANGED
@@ -1534,6 +1534,34 @@
|
|
1534
1534
|
- [0xDE, 0xAD, 0xBE, 0xEF]
|
1535
1535
|
exc: DBus::InvalidPacketException
|
1536
1536
|
msg: ''
|
1537
|
+
- sig: a{oq}
|
1538
|
+
end: little
|
1539
|
+
buf:
|
1540
|
+
# body size
|
1541
|
+
- [0, 0, 0, 0]
|
1542
|
+
# padding
|
1543
|
+
- [0, 0, 0, 0]
|
1544
|
+
val: {}
|
1545
|
+
- sig: a{oq}
|
1546
|
+
end: little
|
1547
|
+
buf:
|
1548
|
+
# body size
|
1549
|
+
- [26, 0, 0, 0]
|
1550
|
+
# dict_entry padding
|
1551
|
+
- [0, 0, 0, 0]
|
1552
|
+
# key, padding, value
|
1553
|
+
- [2, 0, 0, 0, "/7", 0]
|
1554
|
+
- 0
|
1555
|
+
- [7, 0]
|
1556
|
+
# dict_entry padding
|
1557
|
+
- [0, 0, 0, 0, 0, 0]
|
1558
|
+
# key, padding, value
|
1559
|
+
- [2, 0, 0, 0, "/9", 0]
|
1560
|
+
- 0
|
1561
|
+
- [9, 0]
|
1562
|
+
val:
|
1563
|
+
/7: 7
|
1564
|
+
/9: 9
|
1537
1565
|
- sig: "(qq)"
|
1538
1566
|
end: little
|
1539
1567
|
buf:
|
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
|
@@ -183,6 +185,14 @@ describe DBus::Data do
|
|
183
185
|
|
184
186
|
include_examples "constructor accepts plain or typed values", good
|
185
187
|
include_examples "constructor rejects values from this list", bad
|
188
|
+
|
189
|
+
describe ".alignment" do
|
190
|
+
# this overly specific test avoids a redundant alignment call
|
191
|
+
# in the production code
|
192
|
+
it "returns the correct value" do
|
193
|
+
expect(described_class.alignment).to eq 4
|
194
|
+
end
|
195
|
+
end
|
186
196
|
end
|
187
197
|
|
188
198
|
describe DBus::Data::ObjectPath do
|
@@ -198,6 +208,14 @@ describe DBus::Data do
|
|
198
208
|
|
199
209
|
include_examples "constructor accepts plain or typed values", good
|
200
210
|
include_examples "constructor rejects values from this list", bad
|
211
|
+
|
212
|
+
describe ".alignment" do
|
213
|
+
# this overly specific test avoids a redundant alignment call
|
214
|
+
# in the production code
|
215
|
+
it "returns the correct value" do
|
216
|
+
expect(described_class.alignment).to eq 4
|
217
|
+
end
|
218
|
+
end
|
201
219
|
end
|
202
220
|
|
203
221
|
describe DBus::Data::Signature do
|
@@ -215,35 +233,50 @@ describe DBus::Data do
|
|
215
233
|
|
216
234
|
include_examples "constructor accepts plain or typed values", good
|
217
235
|
include_examples "constructor rejects values from this list", bad
|
236
|
+
|
237
|
+
describe ".alignment" do
|
238
|
+
# this overly specific test avoids a redundant alignment call
|
239
|
+
# in the production code
|
240
|
+
it "returns the correct value" do
|
241
|
+
expect(described_class.alignment).to eq 1
|
242
|
+
end
|
243
|
+
end
|
218
244
|
end
|
219
245
|
end
|
220
246
|
|
221
247
|
describe "containers" do
|
222
248
|
describe DBus::Data::Array do
|
223
249
|
good = [
|
224
|
-
# [[1, 2, 3],
|
225
|
-
[[1, 2, 3], {
|
226
|
-
[[1, 2, 3], {
|
227
|
-
[[1, 2, 3], {
|
228
|
-
[[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"] }]
|
229
255
|
# TODO: others
|
230
256
|
]
|
231
257
|
|
232
258
|
bad = [
|
233
259
|
# undesirable type guessing
|
234
|
-
## [[1, 2, 3], {
|
235
|
-
## [[1, 2, 3], {
|
260
|
+
## [[1, 2, 3], { type: nil }, DBus::InvalidPacketException, "Unknown type code"],
|
261
|
+
## [[1, 2, 3], { type: "!" }, DBus::InvalidPacketException, "Unknown type code"]
|
236
262
|
# TODO: others
|
237
263
|
]
|
238
264
|
|
239
265
|
include_examples "constructor (kwargs) accepts values", good
|
240
266
|
include_examples "constructor (kwargs) rejects values", bad
|
267
|
+
|
268
|
+
describe ".from_typed" do
|
269
|
+
it "creates new instance from given object and type" do
|
270
|
+
type = T::Array[String]
|
271
|
+
expect(described_class.from_typed(["test", "lest"], type: type)).to be_a(described_class)
|
272
|
+
end
|
273
|
+
end
|
241
274
|
end
|
242
275
|
|
243
276
|
describe DBus::Data::Struct do
|
244
277
|
three_words = ::Struct.new(:a, :b, :c)
|
245
278
|
|
246
|
-
qqq = [
|
279
|
+
qqq = T::Struct[T::UINT16, T::UINT16, T::UINT16]
|
247
280
|
integers = [1, 2, 3]
|
248
281
|
uints = [DBus::Data::UInt16.new(1), DBus::Data::UInt16.new(2), DBus::Data::UInt16.new(3)]
|
249
282
|
|
@@ -260,36 +293,50 @@ describe DBus::Data do
|
|
260
293
|
# TODO: also check data ownership: reasonable to own the data?
|
261
294
|
# can make it explicit?
|
262
295
|
good = [
|
263
|
-
# from plain array; various
|
264
|
-
[integers, {
|
265
|
-
[integers, {
|
266
|
-
[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")] }],
|
267
301
|
# plain array of data
|
268
|
-
[uints, {
|
302
|
+
[uints, { type: qqq }],
|
269
303
|
# ::Struct
|
270
|
-
[three_words.new(*integers), {
|
271
|
-
[three_words.new(*uints), {
|
304
|
+
[three_words.new(*integers), { type: qqq }],
|
305
|
+
[three_words.new(*uints), { type: qqq }]
|
272
306
|
# TODO: others
|
273
307
|
]
|
274
308
|
|
309
|
+
# check these only when canonicalizing @value, because that will
|
310
|
+
# type-check the value deeply
|
275
311
|
_bad_but_valid = [
|
276
|
-
# Wrong member_types arg:
|
277
|
-
# hmm this is another reason to pass the type
|
278
|
-
# as the entire struct type, not the members:
|
279
|
-
# empty struct will be caught naturally
|
280
|
-
[integers, { member_types: [] }, ArgumentError, "???"],
|
281
|
-
[integers, { member_types: ["!"] }, DBus::InvalidPacketException, "Unknown type code"],
|
282
312
|
# STRUCT specific: member count mismatch
|
283
|
-
[[1, 2], {
|
284
|
-
[[1, 2, 3, 4], {
|
313
|
+
[[1, 2], { type: qqq }, ArgumentError, "???"],
|
314
|
+
[[1, 2, 3, 4], { type: qqq }, ArgumentError, "???"]
|
285
315
|
# TODO: others
|
286
316
|
]
|
287
317
|
|
288
318
|
include_examples "constructor (kwargs) accepts values", good
|
289
319
|
# include_examples "constructor (kwargs) rejects values", bad
|
320
|
+
|
321
|
+
describe ".from_typed" do
|
322
|
+
it "creates new instance from given object and type" do
|
323
|
+
type = T::Struct[T::STRING, T::STRING]
|
324
|
+
expect(described_class.from_typed(["test", "lest"].freeze, type: type))
|
325
|
+
.to be_a(described_class)
|
326
|
+
end
|
327
|
+
end
|
290
328
|
end
|
291
329
|
|
292
330
|
describe DBus::Data::Variant do
|
331
|
+
describe ".from_typed" do
|
332
|
+
it "creates new instance from given object and type" do
|
333
|
+
type = DBus.type(T::VARIANT)
|
334
|
+
value = described_class.from_typed("test", type: type)
|
335
|
+
expect(value).to be_a(described_class)
|
336
|
+
expect(value.type.to_s).to eq "v"
|
337
|
+
expect(value.member_type.to_s).to eq "s"
|
338
|
+
end
|
339
|
+
end
|
293
340
|
end
|
294
341
|
|
295
342
|
describe DBus::Data::DictEntry do
|
@@ -29,6 +29,13 @@ describe DBus::PacketMarshaller do
|
|
29
29
|
subject.append(signature, t.val)
|
30
30
|
expect(subject.packet).to eq(expected)
|
31
31
|
end
|
32
|
+
|
33
|
+
it "writes a '#{signature}' with typed value #{t.val.inspect} (#{endianness})" do
|
34
|
+
subject = described_class.new(endianness: endianness)
|
35
|
+
typed_val = DBus::Data.make_typed(signature, t.val)
|
36
|
+
subject.append(signature, typed_val)
|
37
|
+
expect(subject.packet).to eq(expected)
|
38
|
+
end
|
32
39
|
end
|
33
40
|
end
|
34
41
|
end
|
data/spec/property_spec.rb
CHANGED
@@ -4,6 +4,14 @@
|
|
4
4
|
require_relative "spec_helper"
|
5
5
|
require "dbus"
|
6
6
|
|
7
|
+
# FIXME: factor out DBus::TestFixtures::Value in spec_helper
|
8
|
+
require "ostruct"
|
9
|
+
require "yaml"
|
10
|
+
|
11
|
+
data_dir = File.expand_path("data", __dir__)
|
12
|
+
marshall_yaml_s = File.read("#{data_dir}/marshall.yaml")
|
13
|
+
marshall_yaml = YAML.safe_load(marshall_yaml_s)
|
14
|
+
|
7
15
|
describe "PropertyTest" do
|
8
16
|
before(:each) do
|
9
17
|
@session_bus = DBus::ASessionBus.new
|
@@ -52,7 +60,7 @@ describe "PropertyTest" do
|
|
52
60
|
|
53
61
|
it "tests get all" do
|
54
62
|
all = @iface.all_properties
|
55
|
-
expect(all.keys.sort).to eq(["MyStruct", "ReadMe", "ReadOrWriteMe"])
|
63
|
+
expect(all.keys.sort).to eq(["MyArray", "MyDict", "MyStruct", "MyVariant", "ReadMe", "ReadOrWriteMe"])
|
56
64
|
end
|
57
65
|
|
58
66
|
it "tests get all on a V1 object" do
|
@@ -60,7 +68,7 @@ describe "PropertyTest" do
|
|
60
68
|
iface = obj["org.ruby.SampleInterface"]
|
61
69
|
|
62
70
|
all = iface.all_properties
|
63
|
-
expect(all.keys.sort).to eq(["MyStruct", "ReadMe", "ReadOrWriteMe"])
|
71
|
+
expect(all.keys.sort).to eq(["MyArray", "MyDict", "MyStruct", "MyVariant", "ReadMe", "ReadOrWriteMe"])
|
64
72
|
end
|
65
73
|
|
66
74
|
it "tests unknown property reading" do
|
@@ -147,4 +155,67 @@ describe "PropertyTest" do
|
|
147
155
|
expect(reply).to match(/variant\s+struct {\s+string "three"\s+string "strings"\s+string "in a struct"\s+}/)
|
148
156
|
end
|
149
157
|
end
|
158
|
+
|
159
|
+
context "an array-typed property" do
|
160
|
+
it "gets read as an array" do
|
161
|
+
val = @iface["MyArray"]
|
162
|
+
expect(val).to eq([42, 43])
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
context "a dict-typed property" do
|
167
|
+
it "gets read as a hash" do
|
168
|
+
val = @iface["MyDict"]
|
169
|
+
expect(val).to eq({
|
170
|
+
"one" => 1,
|
171
|
+
"two" => "dva",
|
172
|
+
"three" => [3, 3, 3]
|
173
|
+
})
|
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
|
192
|
+
end
|
193
|
+
|
194
|
+
context "a variant-typed property" do
|
195
|
+
it "gets read at all" do
|
196
|
+
obj = @svc.object("/org/ruby/MyDerivedInstance")
|
197
|
+
iface = obj["org.ruby.SampleInterface"]
|
198
|
+
val = iface["MyVariant"]
|
199
|
+
expect(val).to eq([42, 43])
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
context "marshall.yaml round-trip via a VARIANT property" do
|
204
|
+
marshall_yaml.each do |test|
|
205
|
+
t = OpenStruct.new(test)
|
206
|
+
next if t.val.nil?
|
207
|
+
|
208
|
+
# Round trips do not work yet because the properties
|
209
|
+
# must present a plain Ruby value so the exact D-Bus type is lost.
|
210
|
+
# Round trips will work once users can declare accepting DBus::Data
|
211
|
+
# in properties and method arguments.
|
212
|
+
it "Sets #{t.sig.inspect}:#{t.val.inspect} and Gets something back" do
|
213
|
+
before = DBus::Data.make_typed(t.sig, t.val)
|
214
|
+
expect { @iface["MyVariant"] = before }.to_not raise_error
|
215
|
+
expect { _after = @iface["MyVariant"] }.to_not raise_error
|
216
|
+
# round-trip:
|
217
|
+
# expect(after).to eq(before.value)
|
218
|
+
end
|
219
|
+
end
|
220
|
+
end
|
150
221
|
end
|
data/spec/service_newapi.rb
CHANGED
@@ -13,16 +13,30 @@ PROPERTY_INTERFACE = "org.freedesktop.DBus.Properties"
|
|
13
13
|
class Test < DBus::Object
|
14
14
|
Point2D = Struct.new(:x, :y)
|
15
15
|
|
16
|
+
attr_writer :main_loop
|
17
|
+
|
16
18
|
INTERFACE = "org.ruby.SampleInterface"
|
17
19
|
def initialize(path)
|
18
20
|
super path
|
19
21
|
@read_me = "READ ME"
|
20
22
|
@read_or_write_me = "READ OR WRITE ME"
|
21
23
|
@my_struct = ["three", "strings", "in a struct"].freeze
|
24
|
+
@my_array = [42, 43]
|
25
|
+
@my_dict = {
|
26
|
+
"one" => 1,
|
27
|
+
"two" => "dva",
|
28
|
+
"three" => [3, 3, 3]
|
29
|
+
}
|
30
|
+
@my_variant = @my_array.dup
|
31
|
+
@main_loop = nil
|
22
32
|
end
|
23
33
|
|
24
34
|
# Create an interface aggregating all upcoming dbus_method defines.
|
25
35
|
dbus_interface INTERFACE do
|
36
|
+
dbus_method :quit, "" do
|
37
|
+
@main_loop&.quit
|
38
|
+
end
|
39
|
+
|
26
40
|
dbus_method :hello, "in name:s, in name2:s" do |name, name2|
|
27
41
|
puts "hello(#{name}, #{name2})"
|
28
42
|
end
|
@@ -93,7 +107,10 @@ class Test < DBus::Object
|
|
93
107
|
end
|
94
108
|
dbus_reader :explosive, "s"
|
95
109
|
|
96
|
-
|
110
|
+
dbus_attr_accessor :my_struct, "(sss)"
|
111
|
+
dbus_attr_accessor :my_array, "aq"
|
112
|
+
dbus_attr_accessor :my_dict, "a{sv}"
|
113
|
+
dbus_attr_accessor :my_variant, "v"
|
97
114
|
end
|
98
115
|
|
99
116
|
# closing and reopening the same interface
|
@@ -193,6 +210,7 @@ end
|
|
193
210
|
puts "listening, with ruby-#{RUBY_VERSION}"
|
194
211
|
main = DBus::Main.new
|
195
212
|
main << bus
|
213
|
+
myobj.main_loop = main
|
196
214
|
begin
|
197
215
|
main.run
|
198
216
|
rescue SystemCallError
|
data/spec/spec_helper.rb
CHANGED
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
|
@@ -0,0 +1,16 @@
|
|
1
|
+
#!/usr/bin/env rspec
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require_relative "spec_helper"
|
5
|
+
require "dbus"
|
6
|
+
|
7
|
+
describe "Quit the service" do
|
8
|
+
it "Tells the service to quit and waits, to collate coverage data" do
|
9
|
+
session_bus = DBus::ASessionBus.new
|
10
|
+
@svc = session_bus.service("org.ruby.service")
|
11
|
+
@obj = @svc.object("/org/ruby/MyInstance")
|
12
|
+
@obj.default_iface = "org.ruby.SampleInterface"
|
13
|
+
@obj.quit
|
14
|
+
sleep 3
|
15
|
+
end
|
16
|
+
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
|
@@ -197,6 +197,7 @@ files:
|
|
197
197
|
- spec/type_spec.rb
|
198
198
|
- spec/value_spec.rb
|
199
199
|
- spec/variant_spec.rb
|
200
|
+
- spec/zzz_quit_spec.rb
|
200
201
|
homepage: https://github.com/mvidner/ruby-dbus
|
201
202
|
licenses:
|
202
203
|
- LGPL-2.1
|