ruby-dbus 0.18.0.beta4 → 0.18.0.beta7
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/NEWS.md +40 -0
- data/VERSION +1 -1
- data/doc/Reference.md +13 -4
- data/lib/dbus/data.rb +229 -152
- data/lib/dbus/introspect.rb +13 -3
- data/lib/dbus/marshall.rb +12 -6
- data/lib/dbus/proxy_object_factory.rb +2 -0
- data/lib/dbus/proxy_object_interface.rb +37 -9
- data/lib/dbus/type.rb +146 -16
- data/lib/dbus/xml.rb +4 -0
- data/spec/data_spec.rb +367 -47
- data/spec/packet_unmarshaller_spec.rb +2 -16
- data/spec/property_spec.rb +50 -3
- data/spec/service_newapi.rb +4 -0
- data/spec/type_spec.rb +145 -0
- metadata +6 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 56815cd47f001f19c6d74cc02f0f1017e6e17d8df44e0949f020e4932adbc622
|
4
|
+
data.tar.gz: 4aeda5f0c4972671adf6ae24554aa08ce5e6208846f87f5793562e73b8e7d632
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2432d8ada23410027d00c7995c7514e3e927430844cf037fa8496509c47b10b4f5a431335762206bfc9966724d6d84014f57d9bbe31613bfd253145e25b82b77
|
7
|
+
data.tar.gz: c1b480afebcdaf53b6fbe084f6150b7c9758d1329a207b4941dd8256cbc3786d42341564b3b8220d9e897e7487d281fede15eab8a31d81741582272519e1ac19
|
data/NEWS.md
CHANGED
@@ -2,6 +2,46 @@
|
|
2
2
|
|
3
3
|
## Unreleased
|
4
4
|
|
5
|
+
## Ruby D-Bus 0.18.0.beta7 - 2022-05-29
|
6
|
+
|
7
|
+
API:
|
8
|
+
* DBus.variant(type, value) is deprecated in favor of
|
9
|
+
Data::Variant.new(value, member_type:)
|
10
|
+
|
11
|
+
Bug fixes:
|
12
|
+
* Client-side properties: When calling Properties.Set in
|
13
|
+
ProxyObjectInterface#[]=, use the correct type ([#108][]).
|
14
|
+
|
15
|
+
[#108]: https://github.com/mvidner/ruby-dbus/issues/108
|
16
|
+
|
17
|
+
## Ruby D-Bus 0.18.0.beta6 - 2022-05-25
|
18
|
+
|
19
|
+
API:
|
20
|
+
* Data::Base#value returns plain Ruby types;
|
21
|
+
Data::Container#exact_value contains Data::Base ([#114][]).
|
22
|
+
* Data::Base#initialize and .from_typed allow plain or exact values, validate
|
23
|
+
argument types.
|
24
|
+
* Implement #== (converting) and #eql? (strict) for Data::Base and DBus::Type.
|
25
|
+
|
26
|
+
[#114]: https://github.com/mvidner/ruby-dbus/pull/114
|
27
|
+
|
28
|
+
## Ruby D-Bus 0.18.0.beta5 - 2022-04-27
|
29
|
+
|
30
|
+
API:
|
31
|
+
* DBus::Type instances are frozen.
|
32
|
+
* Data::Container classes (Array, Struct, DictEntry, but not Variant)
|
33
|
+
constructors (#initialize, .from_items, .from_typed) changed to have
|
34
|
+
a *type* argument instead of *member_type* or *member_types*.
|
35
|
+
* Added type factories
|
36
|
+
* Type::Array[type]
|
37
|
+
* Type::Hash[key_type, value_type]
|
38
|
+
* Type::Struct[type1, type2...]
|
39
|
+
|
40
|
+
Bug fixes:
|
41
|
+
* Properties containing Variants would return them doubly wrapped ([#111][]).
|
42
|
+
|
43
|
+
[#111]: https://github.com/mvidner/ruby-dbus/pull/111
|
44
|
+
|
5
45
|
## Ruby D-Bus 0.18.0.beta4 - 2022-04-21
|
6
46
|
|
7
47
|
Bug fixes:
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.18.0.
|
1
|
+
0.18.0.beta7
|
data/doc/Reference.md
CHANGED
@@ -166,12 +166,21 @@ D-Bus has stricter typing than Ruby, so the library must decide
|
|
166
166
|
which D-Bus type to choose. Most of the time the choice is dictated
|
167
167
|
by the D-Bus signature.
|
168
168
|
|
169
|
+
For exact representation of D-Bus data types, use subclasses
|
170
|
+
of {DBus::Data::Base}, such as {DBus::Data::Int16} or {DBus::Data::UInt64}.
|
171
|
+
|
169
172
|
##### Variants
|
170
173
|
|
171
174
|
If the signature expects a Variant
|
172
175
|
(which is the case for all Properties!) then an explicit mechanism is needed.
|
173
176
|
|
174
|
-
1.
|
177
|
+
1. Any {DBus::Data::Base}.
|
178
|
+
|
179
|
+
2. A {DBus::Data::Variant} made by {DBus.variant}(signature, value).
|
180
|
+
(Formerly this produced the type+value pair below, now it is just an alias
|
181
|
+
to the Variant constructor.)
|
182
|
+
|
183
|
+
3. A pair [{DBus::Type}, value] specifies to marshall *value* as
|
175
184
|
that specified type.
|
176
185
|
The pair can be produced by {DBus.variant}(signature, value) which
|
177
186
|
gives the same result as [{DBus.type}(signature), value].
|
@@ -181,13 +190,13 @@ If the signature expects a Variant
|
|
181
190
|
|
182
191
|
`foo_i["Bar"] = DBus.variant("au", [0, 1, 1, 2, 3, 5, 8])`
|
183
192
|
|
184
|
-
|
193
|
+
4. Other values are tried to fit one of these:
|
185
194
|
Boolean, Double, Array of Variants, Hash of String keyed Variants,
|
186
195
|
String, Int32, Int64.
|
187
196
|
|
188
|
-
|
197
|
+
5. **Deprecated:** A pair [String, value], where String is a valid
|
189
198
|
signature of a single complete type, marshalls value as that
|
190
|
-
type. This will hit you when you rely on method (
|
199
|
+
type. This will hit you when you rely on method (4) but happen to have
|
191
200
|
a particular string value in an array.
|
192
201
|
|
193
202
|
##### Structs
|
data/lib/dbus/data.rb
CHANGED
@@ -35,7 +35,7 @@ module DBus
|
|
35
35
|
# construct an appropriate {Data::Base} instance.
|
36
36
|
#
|
37
37
|
# @param type [SingleCompleteType,Type]
|
38
|
-
# @param value [::Object]
|
38
|
+
# @param value [::Object,Data::Base] a plain value; exact values also allowed
|
39
39
|
# @return [Data::Base]
|
40
40
|
# @raise TypeError
|
41
41
|
def make_typed(type, value)
|
@@ -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
|
|
@@ -58,15 +58,28 @@ module DBus
|
|
58
58
|
# @!method self.fixed?
|
59
59
|
# @return [Boolean]
|
60
60
|
|
61
|
-
# @return
|
61
|
+
# @return [::Object] a valid value, plain-Ruby typed.
|
62
|
+
# @see Data::Container#exact_value
|
62
63
|
attr_reader :value
|
63
64
|
|
65
|
+
# @!method self.type_code
|
66
|
+
# @return [String] a single-character string, for example "a" for arrays
|
67
|
+
|
64
68
|
# @!method type
|
65
69
|
# @abstract
|
66
70
|
# Note that for Variants type=="v",
|
67
71
|
# for the specific see {Variant#member_type}
|
68
72
|
# @return [Type] the exact type of this value
|
69
73
|
|
74
|
+
# @!method self.from_typed(value, type:)
|
75
|
+
# @param value [::Object]
|
76
|
+
# @param type [Type]
|
77
|
+
# @return [Base]
|
78
|
+
# @api private
|
79
|
+
# Use {Data.make_typed} instead.
|
80
|
+
# Construct an instance of the specific subclass, with a type further
|
81
|
+
# specified in the *type* argument.
|
82
|
+
|
70
83
|
# Child classes must validate *value*.
|
71
84
|
def initialize(value)
|
72
85
|
@value = value
|
@@ -82,7 +95,19 @@ module DBus
|
|
82
95
|
|
83
96
|
# Hash key equality
|
84
97
|
# See https://ruby-doc.org/core-3.0.0/Object.html#method-i-eql-3F
|
85
|
-
|
98
|
+
# Stricter than #== (RSpec: eq), 1==1.0 but 1.eql(1.0)->false
|
99
|
+
def eql?(other)
|
100
|
+
return false unless other.class == self.class
|
101
|
+
|
102
|
+
other.value.eql?(@value)
|
103
|
+
# TODO: this should work, now check derived classes, exact_value
|
104
|
+
end
|
105
|
+
|
106
|
+
# @param type [Type]
|
107
|
+
def self.assert_type_matches_class(type)
|
108
|
+
raise ArgumentError, "Expecting #{type_code.inspect} for class #{self}, got #{type.sigtype.inspect}" \
|
109
|
+
unless type.sigtype == type_code
|
110
|
+
end
|
86
111
|
end
|
87
112
|
|
88
113
|
# A value that is not a {Container}.
|
@@ -103,10 +128,10 @@ module DBus
|
|
103
128
|
end
|
104
129
|
|
105
130
|
# @param value [::Object]
|
106
|
-
# @param
|
131
|
+
# @param type [Type]
|
107
132
|
# @return [Basic]
|
108
|
-
def self.from_typed(value,
|
109
|
-
|
133
|
+
def self.from_typed(value, type:)
|
134
|
+
assert_type_matches_class(type)
|
110
135
|
new(value)
|
111
136
|
end
|
112
137
|
end
|
@@ -132,34 +157,6 @@ module DBus
|
|
132
157
|
end
|
133
158
|
end
|
134
159
|
|
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
160
|
# Format strings for String#unpack, both little- and big-endian.
|
164
161
|
Format = ::Struct.new(:little, :big)
|
165
162
|
|
@@ -398,6 +395,23 @@ module DBus
|
|
398
395
|
end
|
399
396
|
end
|
400
397
|
|
398
|
+
# {DBus::Data::String}, {DBus::Data::ObjectPath}, or {DBus::Data::Signature}.
|
399
|
+
class StringLike < Basic
|
400
|
+
def self.fixed?
|
401
|
+
false
|
402
|
+
end
|
403
|
+
|
404
|
+
def initialize(value)
|
405
|
+
if value.is_a?(self.class)
|
406
|
+
value = value.value
|
407
|
+
else
|
408
|
+
self.class.validate_raw!(value)
|
409
|
+
end
|
410
|
+
|
411
|
+
super(value)
|
412
|
+
end
|
413
|
+
end
|
414
|
+
|
401
415
|
# UTF-8 encoded string.
|
402
416
|
class String < StringLike
|
403
417
|
def self.type_code
|
@@ -477,7 +491,7 @@ module DBus
|
|
477
491
|
Byte
|
478
492
|
end
|
479
493
|
|
480
|
-
# @return [Array<Type>]
|
494
|
+
# @return [::Array<Type>]
|
481
495
|
def self.validate_raw!(value)
|
482
496
|
DBus.types(value)
|
483
497
|
rescue Type::SignatureException => e
|
@@ -494,6 +508,44 @@ module DBus
|
|
494
508
|
end
|
495
509
|
end
|
496
510
|
|
511
|
+
# Contains one or more other values.
|
512
|
+
class Container < Base
|
513
|
+
def self.basic?
|
514
|
+
false
|
515
|
+
end
|
516
|
+
|
517
|
+
def self.fixed?
|
518
|
+
false
|
519
|
+
end
|
520
|
+
|
521
|
+
# For containers, the type varies among instances
|
522
|
+
# @see Base#type
|
523
|
+
attr_reader :type
|
524
|
+
|
525
|
+
# @return something that is, or contains, {Data::Base}.
|
526
|
+
# Er, this docs kinda sucks.
|
527
|
+
def exact_value
|
528
|
+
@value
|
529
|
+
end
|
530
|
+
|
531
|
+
def value
|
532
|
+
@value.map(&:value)
|
533
|
+
end
|
534
|
+
|
535
|
+
# Hash key equality
|
536
|
+
# See https://ruby-doc.org/core-3.0.0/Object.html#method-i-eql-3F
|
537
|
+
# Stricter than #== (RSpec: eq), 1==1.0 but 1.eql(1.0)->false
|
538
|
+
def eql?(other)
|
539
|
+
return false unless other.class == self.class
|
540
|
+
|
541
|
+
other.exact_value.eql?(exact_value)
|
542
|
+
end
|
543
|
+
|
544
|
+
# def ==(other)
|
545
|
+
# eql?(other) || super
|
546
|
+
# end
|
547
|
+
end
|
548
|
+
|
497
549
|
# An Array, or a Dictionary (Hash).
|
498
550
|
class Array < Container
|
499
551
|
def self.type_code
|
@@ -504,44 +556,33 @@ module DBus
|
|
504
556
|
4
|
505
557
|
end
|
506
558
|
|
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
559
|
# TODO: check that Hash keys are basic types
|
521
560
|
# @param mode [:plain,:exact]
|
522
|
-
# @param
|
561
|
+
# @param type [Type]
|
523
562
|
# @param hash [Boolean] are we unmarshalling an ARRAY of DICT_ENTRY
|
524
563
|
# @return [Data::Array]
|
525
|
-
def self.from_items(value, mode:,
|
564
|
+
def self.from_items(value, mode:, type:, hash: false)
|
526
565
|
value = Hash[value] if hash
|
527
566
|
return value if mode == :plain
|
528
567
|
|
529
|
-
new(value,
|
568
|
+
new(value, type: type)
|
530
569
|
end
|
531
570
|
|
532
571
|
# @param value [::Object]
|
533
|
-
# @param
|
572
|
+
# @param type [Type]
|
534
573
|
# @return [Data::Array]
|
535
|
-
def self.from_typed(value,
|
536
|
-
|
537
|
-
|
574
|
+
def self.from_typed(value, type:)
|
575
|
+
new(value, type: type) # initialize(::Array<Data::Base>)
|
576
|
+
end
|
538
577
|
|
539
|
-
|
540
|
-
|
541
|
-
|
578
|
+
def value
|
579
|
+
v = super
|
580
|
+
if type.child.sigtype == Type::DICT_ENTRY
|
581
|
+
# BTW this makes a copy so mutating it is pointless
|
582
|
+
v.to_h
|
583
|
+
else
|
584
|
+
v
|
542
585
|
end
|
543
|
-
|
544
|
-
new(items, member_type: member_type) # initialize(::Array<Data::Base>)
|
545
586
|
end
|
546
587
|
|
547
588
|
# FIXME: should Data::Array be mutable?
|
@@ -550,13 +591,29 @@ module DBus
|
|
550
591
|
# TODO: specify type or guess type?
|
551
592
|
# Data is the exact type, so its constructor should be exact
|
552
593
|
# and guesswork should be clearly labeled
|
553
|
-
|
554
|
-
|
555
|
-
|
556
|
-
|
557
|
-
|
558
|
-
|
559
|
-
|
594
|
+
|
595
|
+
# @param value [Data::Array,Enumerable]
|
596
|
+
# @param type [SingleCompleteType,Type]
|
597
|
+
def initialize(value, type:)
|
598
|
+
type = Type::Factory.make_type(type)
|
599
|
+
self.class.assert_type_matches_class(type)
|
600
|
+
@type = type
|
601
|
+
|
602
|
+
typed_value = case value
|
603
|
+
when Data::Array
|
604
|
+
unless value.type == type
|
605
|
+
raise ArgumentError,
|
606
|
+
"Specified type is #{type.inspect} but value type is #{value.type.inspect}"
|
607
|
+
end
|
608
|
+
|
609
|
+
value.exact_value
|
610
|
+
else
|
611
|
+
# TODO: Dict??
|
612
|
+
value.map do |i|
|
613
|
+
Data.make_typed(type.child, i)
|
614
|
+
end
|
615
|
+
end
|
616
|
+
super(typed_value)
|
560
617
|
end
|
561
618
|
end
|
562
619
|
|
@@ -572,51 +629,86 @@ module DBus
|
|
572
629
|
8
|
573
630
|
end
|
574
631
|
|
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
632
|
# @param value [::Array]
|
591
|
-
def self.from_items(value, mode:,
|
633
|
+
def self.from_items(value, mode:, type:)
|
592
634
|
value.freeze
|
593
635
|
return value if mode == :plain
|
594
636
|
|
595
|
-
new(value,
|
637
|
+
new(value, type: type)
|
596
638
|
end
|
597
639
|
|
598
640
|
# @param value [::Object] (#size, #each)
|
599
|
-
# @param
|
641
|
+
# @param type [Type]
|
600
642
|
# @return [Struct]
|
601
|
-
def self.from_typed(value,
|
602
|
-
|
603
|
-
|
643
|
+
def self.from_typed(value, type:)
|
644
|
+
new(value, type: type)
|
645
|
+
end
|
646
|
+
|
647
|
+
# @param value [Data::Struct,Enumerable]
|
648
|
+
# @param type [SingleCompleteType,Type]
|
649
|
+
def initialize(value, type:)
|
650
|
+
type = Type::Factory.make_type(type)
|
651
|
+
self.class.assert_type_matches_class(type)
|
652
|
+
@type = type
|
653
|
+
|
654
|
+
typed_value = case value
|
655
|
+
when self.class
|
656
|
+
unless value.type == type
|
657
|
+
raise ArgumentError,
|
658
|
+
"Specified type is #{type.inspect} but value type is #{value.type.inspect}"
|
659
|
+
end
|
660
|
+
|
661
|
+
value.exact_value
|
662
|
+
else
|
663
|
+
member_types = type.members
|
664
|
+
unless value.size == member_types.size
|
665
|
+
raise ArgumentError, "Specified type has #{member_types.size} members " \
|
666
|
+
"but value has #{value.size} members"
|
667
|
+
end
|
668
|
+
|
669
|
+
member_types.zip(value).map do |item_type, item|
|
670
|
+
Data.make_typed(item_type, item)
|
671
|
+
end
|
672
|
+
end
|
673
|
+
super(typed_value)
|
674
|
+
end
|
604
675
|
|
605
|
-
|
606
|
-
|
676
|
+
def ==(other)
|
677
|
+
case other
|
678
|
+
when ::Struct
|
679
|
+
@value.size == other.size &&
|
680
|
+
@value.zip(other.to_a).all? { |i, other_i| i == other_i }
|
681
|
+
else
|
682
|
+
super
|
607
683
|
end
|
684
|
+
end
|
685
|
+
end
|
608
686
|
|
609
|
-
|
687
|
+
# Dictionary/Hash entry.
|
688
|
+
# TODO: shouldn't instantiate?
|
689
|
+
class DictEntry < Struct
|
690
|
+
def self.type_code
|
691
|
+
"e"
|
610
692
|
end
|
611
693
|
|
612
|
-
|
613
|
-
|
614
|
-
|
615
|
-
|
694
|
+
# @param value [::Array]
|
695
|
+
def self.from_items(value, mode:, type:) # rubocop:disable Lint/UnusedMethodArgument
|
696
|
+
value.freeze
|
697
|
+
# DictEntry ignores the :exact mode
|
698
|
+
value
|
699
|
+
end
|
700
|
+
|
701
|
+
# @param value [::Object] (#size, #each)
|
702
|
+
# @param type [Type]
|
703
|
+
# @return [DictEntry]
|
704
|
+
def self.from_typed(value, type:)
|
705
|
+
new(value, type: type)
|
616
706
|
end
|
617
707
|
end
|
618
708
|
|
619
|
-
# A generic type
|
709
|
+
# A generic type.
|
710
|
+
#
|
711
|
+
# Implementation note: @value is a {Data::Base}.
|
620
712
|
class Variant < Container
|
621
713
|
def self.type_code
|
622
714
|
"v"
|
@@ -626,6 +718,10 @@ module DBus
|
|
626
718
|
1
|
627
719
|
end
|
628
720
|
|
721
|
+
def value
|
722
|
+
@value.value
|
723
|
+
end
|
724
|
+
|
629
725
|
# @param member_type [Type]
|
630
726
|
def self.from_items(value, mode:, member_type:)
|
631
727
|
return value if mode == :plain
|
@@ -634,12 +730,12 @@ module DBus
|
|
634
730
|
end
|
635
731
|
|
636
732
|
# @param value [::Object]
|
637
|
-
# @param
|
733
|
+
# @param type [Type]
|
638
734
|
# @return [Variant]
|
639
|
-
def self.from_typed(value,
|
640
|
-
|
735
|
+
def self.from_typed(value, type:)
|
736
|
+
assert_type_matches_class(type)
|
641
737
|
|
642
|
-
# decide on type of value
|
738
|
+
# nil: decide on type of value
|
643
739
|
new(value, member_type: nil)
|
644
740
|
end
|
645
741
|
|
@@ -659,78 +755,59 @@ module DBus
|
|
659
755
|
# @return [Type]
|
660
756
|
attr_reader :member_type
|
661
757
|
|
758
|
+
# Determine the type of *value*
|
759
|
+
# @param value [::Object]
|
760
|
+
# @return [Type]
|
761
|
+
# @api private
|
762
|
+
# See also {PacketMarshaller.make_variant}
|
662
763
|
def self.guess_type(value)
|
663
764
|
sct, = PacketMarshaller.make_variant(value)
|
664
765
|
DBus.type(sct)
|
665
766
|
end
|
666
767
|
|
667
|
-
# @param member_type [Type,nil]
|
768
|
+
# @param member_type [SingleCompleteType,Type,nil]
|
668
769
|
def initialize(value, member_type:)
|
770
|
+
member_type = Type::Factory.make_type(member_type) if member_type
|
669
771
|
# TODO: validate that the given *member_type* matches *value*
|
670
|
-
|
772
|
+
case value
|
773
|
+
when Data::Variant
|
671
774
|
# Copy the contained value instead of boxing it more
|
672
775
|
# TODO: except perhaps for round-tripping in exact mode?
|
673
776
|
@member_type = value.member_type
|
674
|
-
value = value.
|
777
|
+
value = value.exact_value
|
778
|
+
when Data::Base
|
779
|
+
@member_type = member_type || value.type
|
780
|
+
raise ArgumentError, "Variant type #{@member_type} does not match value type #{value.type}" \
|
781
|
+
unless @member_type == value.type
|
675
782
|
else
|
676
783
|
@member_type = member_type || self.class.guess_type(value)
|
784
|
+
value = Data.make_typed(@member_type, value)
|
677
785
|
end
|
678
786
|
super(value)
|
679
787
|
end
|
680
|
-
end
|
681
788
|
|
682
|
-
|
683
|
-
|
684
|
-
|
685
|
-
def
|
686
|
-
|
687
|
-
|
688
|
-
|
689
|
-
|
690
|
-
|
691
|
-
|
692
|
-
|
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
|
789
|
+
# Internal helpers to keep the {DBus.variant} method working.
|
790
|
+
# Formerly it returned just a pair of [DBus.type(string_type), value]
|
791
|
+
# so let's provide [0], [1], .first, .last
|
792
|
+
def [](index)
|
793
|
+
case index
|
794
|
+
when 0
|
795
|
+
member_type
|
796
|
+
when 1
|
797
|
+
value
|
798
|
+
else
|
799
|
+
raise ArgumentError, "DBus.variant can only be indexed with 0 or 1, seen #{index.inspect}"
|
703
800
|
end
|
704
|
-
@type
|
705
|
-
end
|
706
|
-
|
707
|
-
# @param value [::Array]
|
708
|
-
def self.from_items(value, mode:, member_types:) # rubocop:disable Lint/UnusedMethodArgument
|
709
|
-
value.freeze
|
710
|
-
# DictEntry ignores the :exact mode
|
711
|
-
value
|
712
801
|
end
|
713
802
|
|
714
|
-
# @
|
715
|
-
|
716
|
-
|
717
|
-
def self.from_typed(value, member_types:)
|
718
|
-
# assert member_types.size == 2
|
719
|
-
# TODO: duplicated from Struct. Inherit/delegate?
|
720
|
-
# TODO: validation
|
721
|
-
raise unless value.size == member_types.size
|
722
|
-
|
723
|
-
items = member_types.zip(value).map do |item_type, item|
|
724
|
-
Data.make_typed(item_type, item)
|
725
|
-
end
|
726
|
-
|
727
|
-
new(items, member_types: member_types) # initialize(::Array<Data::Base>)
|
803
|
+
# @see #[]
|
804
|
+
def first
|
805
|
+
self[0]
|
728
806
|
end
|
729
807
|
|
730
|
-
|
731
|
-
|
732
|
-
|
733
|
-
super(value)
|
808
|
+
# @see #[]
|
809
|
+
def last
|
810
|
+
self[1]
|
734
811
|
end
|
735
812
|
end
|
736
813
|
|
data/lib/dbus/introspect.rb
CHANGED
@@ -238,19 +238,20 @@ module DBus
|
|
238
238
|
# An (exported) property
|
239
239
|
# https://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-properties
|
240
240
|
class Property
|
241
|
-
# @return [
|
241
|
+
# @return [Symbol] The name of the property, for example FooBar.
|
242
242
|
attr_reader :name
|
243
243
|
# @return [SingleCompleteType]
|
244
244
|
attr_reader :type
|
245
245
|
# @return [Symbol] :read :write or :readwrite
|
246
246
|
attr_reader :access
|
247
247
|
|
248
|
-
# @return [Symbol] What to call at Ruby side.
|
248
|
+
# @return [Symbol,nil] What to call at Ruby side.
|
249
249
|
# (Always without the trailing `=`)
|
250
|
+
# It is `nil` IFF representing a client-side proxy.
|
250
251
|
attr_reader :ruby_name
|
251
252
|
|
252
253
|
def initialize(name, type, access, ruby_name:)
|
253
|
-
@name = name
|
254
|
+
@name = name.to_sym
|
254
255
|
@type = type
|
255
256
|
@access = access
|
256
257
|
@ruby_name = ruby_name
|
@@ -270,5 +271,14 @@ module DBus
|
|
270
271
|
def to_xml
|
271
272
|
" <property type=\"#{@type}\" name=\"#{@name}\" access=\"#{@access}\"/>\n"
|
272
273
|
end
|
274
|
+
|
275
|
+
# @param xml_node [AbstractXML::Node]
|
276
|
+
# @return [Property]
|
277
|
+
def self.from_xml(xml_node)
|
278
|
+
name = xml_node["name"].to_sym
|
279
|
+
type = xml_node["type"]
|
280
|
+
access = xml_node["access"].to_sym
|
281
|
+
new(name, type, access, ruby_name: nil)
|
282
|
+
end
|
273
283
|
end
|
274
284
|
end
|