ruby-dbus 0.18.0.beta2 → 0.18.0.beta5
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/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
|