ruby-dbus 0.18.0.beta5 → 0.18.0.beta8
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/NEWS.md +43 -0
- data/VERSION +1 -1
- data/doc/Reference.md +13 -4
- data/lib/dbus/bus.rb +3 -7
- data/lib/dbus/data.rb +165 -68
- data/lib/dbus/emits_changed_signal.rb +83 -0
- data/lib/dbus/introspect.rb +44 -4
- data/lib/dbus/marshall.rb +6 -3
- data/lib/dbus/object.rb +84 -22
- data/lib/dbus/proxy_object_factory.rb +2 -0
- data/lib/dbus/proxy_object_interface.rb +37 -9
- data/lib/dbus/type.rb +26 -2
- data/lib/dbus/xml.rb +4 -0
- data/lib/dbus.rb +1 -0
- data/spec/data_spec.rb +342 -14
- data/spec/emits_changed_signal_spec.rb +58 -0
- data/spec/object_spec.rb +138 -0
- data/spec/packet_unmarshaller_spec.rb +2 -16
- data/spec/property_spec.rb +35 -2
- data/spec/service_newapi.rb +13 -0
- data/spec/type_spec.rb +40 -0
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6d6ace164222b10bbf03ab5ac9e2ec3799c8847c4a8f94e1d7f509944bf3e806
|
4
|
+
data.tar.gz: 9e8a61b9fa885b36ef21d04f4eb03d4d5a5ab8ec78d5ae258e2433a9e4e5cabe
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a6f4e56b35c43975202769d8085cd690c95f345b09e5c78cd2e89f373105ee0e7edc0d9954ac3c647678a41c18ffb06dbaa806f9bed269b832ad6052a9449afe
|
7
|
+
data.tar.gz: 986c96e6a2f74668cd70e111c9fd57c4dd1c30a2e1b2ed66252406bc8fc67a6ec56bc663bae111b0e331e0f8544419d7fb4facabec1a14e1407ca903695d43c9
|
data/NEWS.md
CHANGED
@@ -2,6 +2,49 @@
|
|
2
2
|
|
3
3
|
## Unreleased
|
4
4
|
|
5
|
+
## Ruby D-Bus 0.18.0.beta8 - 2022-06-21
|
6
|
+
|
7
|
+
Bug fixes:
|
8
|
+
* Introduced Object#dbus_properties_changed to send correctly typed property
|
9
|
+
values ([#115][]). Avoid calling PropertiesChanged directly as it will
|
10
|
+
guess the types.
|
11
|
+
* Fix Object.dbus_reader to work with attr_accessor and automatically produce
|
12
|
+
dbus_properties_changed for properties that are read-write at
|
13
|
+
implementation side and read-only at D-Bus side ([#96][])
|
14
|
+
|
15
|
+
[#96]: https://github.com/mvidner/ruby-dbus/issues/96
|
16
|
+
|
17
|
+
API:
|
18
|
+
* Service side `emits_changed_signal` to control emission of
|
19
|
+
PropertiesChanged: can be assigned within `dbus_interface` or as an option
|
20
|
+
when declaring properties ([#117][]).
|
21
|
+
|
22
|
+
[#115]: https://github.com/mvidner/ruby-dbus/issues/115
|
23
|
+
[#117]: https://github.com/mvidner/ruby-dbus/pulls/117
|
24
|
+
|
25
|
+
## Ruby D-Bus 0.18.0.beta7 - 2022-05-29
|
26
|
+
|
27
|
+
API:
|
28
|
+
* DBus.variant(type, value) is deprecated in favor of
|
29
|
+
Data::Variant.new(value, member_type:)
|
30
|
+
|
31
|
+
Bug fixes:
|
32
|
+
* Client-side properties: When calling Properties.Set in
|
33
|
+
ProxyObjectInterface#[]=, use the correct type ([#108][]).
|
34
|
+
|
35
|
+
[#108]: https://github.com/mvidner/ruby-dbus/issues/108
|
36
|
+
|
37
|
+
## Ruby D-Bus 0.18.0.beta6 - 2022-05-25
|
38
|
+
|
39
|
+
API:
|
40
|
+
* Data::Base#value returns plain Ruby types;
|
41
|
+
Data::Container#exact_value contains Data::Base ([#114][]).
|
42
|
+
* Data::Base#initialize and .from_typed allow plain or exact values, validate
|
43
|
+
argument types.
|
44
|
+
* Implement #== (converting) and #eql? (strict) for Data::Base and DBus::Type.
|
45
|
+
|
46
|
+
[#114]: https://github.com/mvidner/ruby-dbus/pull/114
|
47
|
+
|
5
48
|
## Ruby D-Bus 0.18.0.beta5 - 2022-04-27
|
6
49
|
|
7
50
|
API:
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.18.0.
|
1
|
+
0.18.0.beta8
|
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/bus.rb
CHANGED
@@ -171,15 +171,11 @@ module DBus
|
|
171
171
|
"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
|
172
172
|
'
|
173
173
|
xml += "<node name=\"#{node_opath}\">\n"
|
174
|
-
|
174
|
+
each_key do |k|
|
175
175
|
xml += " <node name=\"#{k}\" />\n"
|
176
176
|
end
|
177
|
-
@object&.intfs&.
|
178
|
-
xml +=
|
179
|
-
v.methods.each_value { |m| xml += m.to_xml }
|
180
|
-
v.signals.each_value { |m| xml += m.to_xml }
|
181
|
-
v.properties.each_value { |m| xml += m.to_xml }
|
182
|
-
xml += " </interface>\n"
|
177
|
+
@object&.intfs&.each_value do |v|
|
178
|
+
xml += v.to_xml
|
183
179
|
end
|
184
180
|
xml += "</node>"
|
185
181
|
xml
|
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)
|
@@ -58,9 +58,13 @@ 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",
|
@@ -91,11 +95,18 @@ module DBus
|
|
91
95
|
|
92
96
|
# Hash key equality
|
93
97
|
# See https://ruby-doc.org/core-3.0.0/Object.html#method-i-eql-3F
|
94
|
-
|
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
|
95
105
|
|
96
106
|
# @param type [Type]
|
97
107
|
def self.assert_type_matches_class(type)
|
98
|
-
raise ArgumentError
|
108
|
+
raise ArgumentError, "Expecting #{type_code.inspect} for class #{self}, got #{type.sigtype.inspect}" \
|
109
|
+
unless type.sigtype == type_code
|
99
110
|
end
|
100
111
|
end
|
101
112
|
|
@@ -480,7 +491,7 @@ module DBus
|
|
480
491
|
Byte
|
481
492
|
end
|
482
493
|
|
483
|
-
# @return [Array<Type>]
|
494
|
+
# @return [::Array<Type>]
|
484
495
|
def self.validate_raw!(value)
|
485
496
|
DBus.types(value)
|
486
497
|
rescue Type::SignatureException => e
|
@@ -510,6 +521,29 @@ module DBus
|
|
510
521
|
# For containers, the type varies among instances
|
511
522
|
# @see Base#type
|
512
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
|
513
547
|
end
|
514
548
|
|
515
549
|
# An Array, or a Dictionary (Hash).
|
@@ -538,16 +572,17 @@ module DBus
|
|
538
572
|
# @param type [Type]
|
539
573
|
# @return [Data::Array]
|
540
574
|
def self.from_typed(value, type:)
|
541
|
-
|
542
|
-
|
543
|
-
member_type = type.child
|
575
|
+
new(value, type: type) # initialize(::Array<Data::Base>)
|
576
|
+
end
|
544
577
|
|
545
|
-
|
546
|
-
|
547
|
-
|
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
|
548
585
|
end
|
549
|
-
|
550
|
-
new(items, type: type) # initialize(::Array<Data::Base>)
|
551
586
|
end
|
552
587
|
|
553
588
|
# FIXME: should Data::Array be mutable?
|
@@ -556,13 +591,29 @@ module DBus
|
|
556
591
|
# TODO: specify type or guess type?
|
557
592
|
# Data is the exact type, so its constructor should be exact
|
558
593
|
# and guesswork should be clearly labeled
|
594
|
+
|
595
|
+
# @param value [Data::Array,Enumerable]
|
559
596
|
# @param type [SingleCompleteType,Type]
|
560
597
|
def initialize(value, type:)
|
561
|
-
type =
|
598
|
+
type = Type::Factory.make_type(type)
|
562
599
|
self.class.assert_type_matches_class(type)
|
563
600
|
@type = type
|
564
|
-
|
565
|
-
|
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)
|
566
617
|
end
|
567
618
|
end
|
568
619
|
|
@@ -590,25 +641,74 @@ module DBus
|
|
590
641
|
# @param type [Type]
|
591
642
|
# @return [Struct]
|
592
643
|
def self.from_typed(value, type:)
|
593
|
-
|
594
|
-
member_types = type.members
|
595
|
-
raise unless value.size == member_types.size
|
596
|
-
|
597
|
-
items = member_types.zip(value).map do |item_type, item|
|
598
|
-
Data.make_typed(item_type, item)
|
599
|
-
end
|
600
|
-
|
601
|
-
new(items, type: type) # initialize(::Array<Data::Base>)
|
644
|
+
new(value, type: type)
|
602
645
|
end
|
603
646
|
|
647
|
+
# @param value [Data::Struct,Enumerable]
|
648
|
+
# @param type [SingleCompleteType,Type]
|
604
649
|
def initialize(value, type:)
|
650
|
+
type = Type::Factory.make_type(type)
|
605
651
|
self.class.assert_type_matches_class(type)
|
606
652
|
@type = type
|
607
|
-
|
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
|
675
|
+
|
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
|
683
|
+
end
|
684
|
+
end
|
685
|
+
end
|
686
|
+
|
687
|
+
# Dictionary/Hash entry.
|
688
|
+
# TODO: shouldn't instantiate?
|
689
|
+
class DictEntry < Struct
|
690
|
+
def self.type_code
|
691
|
+
"e"
|
692
|
+
end
|
693
|
+
|
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)
|
608
706
|
end
|
609
707
|
end
|
610
708
|
|
611
|
-
# A generic type
|
709
|
+
# A generic type.
|
710
|
+
#
|
711
|
+
# Implementation note: @value is a {Data::Base}.
|
612
712
|
class Variant < Container
|
613
713
|
def self.type_code
|
614
714
|
"v"
|
@@ -618,6 +718,10 @@ module DBus
|
|
618
718
|
1
|
619
719
|
end
|
620
720
|
|
721
|
+
def value
|
722
|
+
@value.value
|
723
|
+
end
|
724
|
+
|
621
725
|
# @param member_type [Type]
|
622
726
|
def self.from_items(value, mode:, member_type:)
|
623
727
|
return value if mode == :plain
|
@@ -631,7 +735,7 @@ module DBus
|
|
631
735
|
def self.from_typed(value, type:)
|
632
736
|
assert_type_matches_class(type)
|
633
737
|
|
634
|
-
# decide on type of value
|
738
|
+
# nil: decide on type of value
|
635
739
|
new(value, member_type: nil)
|
636
740
|
end
|
637
741
|
|
@@ -651,66 +755,59 @@ module DBus
|
|
651
755
|
# @return [Type]
|
652
756
|
attr_reader :member_type
|
653
757
|
|
758
|
+
# Determine the type of *value*
|
759
|
+
# @param value [::Object]
|
760
|
+
# @return [Type]
|
761
|
+
# @api private
|
762
|
+
# See also {PacketMarshaller.make_variant}
|
654
763
|
def self.guess_type(value)
|
655
764
|
sct, = PacketMarshaller.make_variant(value)
|
656
765
|
DBus.type(sct)
|
657
766
|
end
|
658
767
|
|
659
|
-
# @param member_type [Type,nil]
|
768
|
+
# @param member_type [SingleCompleteType,Type,nil]
|
660
769
|
def initialize(value, member_type:)
|
770
|
+
member_type = Type::Factory.make_type(member_type) if member_type
|
661
771
|
# TODO: validate that the given *member_type* matches *value*
|
662
|
-
|
772
|
+
case value
|
773
|
+
when Data::Variant
|
663
774
|
# Copy the contained value instead of boxing it more
|
664
775
|
# TODO: except perhaps for round-tripping in exact mode?
|
665
776
|
@member_type = value.member_type
|
666
|
-
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
|
667
782
|
else
|
668
783
|
@member_type = member_type || self.class.guess_type(value)
|
784
|
+
value = Data.make_typed(@member_type, value)
|
669
785
|
end
|
670
786
|
super(value)
|
671
787
|
end
|
672
|
-
end
|
673
|
-
|
674
|
-
# Dictionary/Hash entry.
|
675
|
-
# TODO: shouldn't instantiate?
|
676
|
-
class DictEntry < Container
|
677
|
-
def self.type_code
|
678
|
-
"e"
|
679
|
-
end
|
680
|
-
|
681
|
-
def self.alignment
|
682
|
-
8
|
683
|
-
end
|
684
|
-
|
685
|
-
# @param value [::Array]
|
686
|
-
def self.from_items(value, mode:, type:) # rubocop:disable Lint/UnusedMethodArgument
|
687
|
-
value.freeze
|
688
|
-
# DictEntry ignores the :exact mode
|
689
|
-
value
|
690
|
-
end
|
691
788
|
|
692
|
-
#
|
693
|
-
#
|
694
|
-
#
|
695
|
-
def
|
696
|
-
|
697
|
-
|
698
|
-
|
699
|
-
|
700
|
-
|
701
|
-
|
702
|
-
|
703
|
-
items = member_types.zip(value).map do |item_type, item|
|
704
|
-
Data.make_typed(item_type, item)
|
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}"
|
705
800
|
end
|
801
|
+
end
|
706
802
|
|
707
|
-
|
803
|
+
# @see #[]
|
804
|
+
def first
|
805
|
+
self[0]
|
708
806
|
end
|
709
807
|
|
710
|
-
|
711
|
-
|
712
|
-
|
713
|
-
super(value)
|
808
|
+
# @see #[]
|
809
|
+
def last
|
810
|
+
self[1]
|
714
811
|
end
|
715
812
|
end
|
716
813
|
|
@@ -0,0 +1,83 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# This file is part of the ruby-dbus project
|
4
|
+
# Copyright (C) 2022 Martin Vidner
|
5
|
+
#
|
6
|
+
# This library is free software; you can redistribute it and/or
|
7
|
+
# modify it under the terms of the GNU Lesser General Public
|
8
|
+
# License, version 2.1 as published by the Free Software Foundation.
|
9
|
+
# See the file "COPYING" for the exact licensing terms.
|
10
|
+
|
11
|
+
module DBus
|
12
|
+
# Describes the behavior of PropertiesChanged signal, for a single property
|
13
|
+
# or for an entire interface.
|
14
|
+
#
|
15
|
+
# The possible values are:
|
16
|
+
#
|
17
|
+
# - *true*: the signal is emitted with the value included.
|
18
|
+
# - *:invalidates*: the signal is emitted but the value is not included
|
19
|
+
# in the signal.
|
20
|
+
# - *:const*: the property never changes value during the lifetime
|
21
|
+
# of the object it belongs to, and hence the signal
|
22
|
+
# is never emitted for it (but clients can cache the value)
|
23
|
+
# - *false*: the signal won't be emitted (clients should re-Get the property value)
|
24
|
+
#
|
25
|
+
# The default is:
|
26
|
+
# - for an interface: *true*
|
27
|
+
# - for a property: what the parent interface specifies
|
28
|
+
#
|
29
|
+
# @see DBus::Object.emits_changed_signal
|
30
|
+
# @see DBus::Object.dbus_attr_accessor
|
31
|
+
# @see https://dbus.freedesktop.org/doc/dbus-specification.html#introspection-format
|
32
|
+
#
|
33
|
+
# Immutable once constructed.
|
34
|
+
class EmitsChangedSignal
|
35
|
+
# @return [true,false,:const,:invalidates]
|
36
|
+
attr_reader :value
|
37
|
+
|
38
|
+
# @param value [true,false,:const,:invalidates,nil]
|
39
|
+
# See class-level description above, {EmitsChangedSignal}.
|
40
|
+
# @param interface [Interface,nil]
|
41
|
+
# If the (property-level) *value* is unspecified (nil), this is the
|
42
|
+
# containing {Interface} to get the value from.
|
43
|
+
def initialize(value, interface: nil)
|
44
|
+
if value.nil?
|
45
|
+
raise ArgumentError, "Both arguments are nil" if interface.nil?
|
46
|
+
|
47
|
+
@value = interface.emits_changed_signal.value
|
48
|
+
else
|
49
|
+
expecting = [true, false, :const, :invalidates]
|
50
|
+
unless expecting.include?(value)
|
51
|
+
raise ArgumentError, "Expecting one of #{expecting.inspect}. Seen #{value.inspect}"
|
52
|
+
end
|
53
|
+
|
54
|
+
@value = value
|
55
|
+
end
|
56
|
+
|
57
|
+
freeze
|
58
|
+
end
|
59
|
+
|
60
|
+
# Return introspection XML string representation
|
61
|
+
# @return [String]
|
62
|
+
def to_xml
|
63
|
+
return "" if @value == true
|
64
|
+
|
65
|
+
" <annotation name=\"org.freedesktop.DBus.Property.EmitsChangedSignal\" value=\"#{@value}\"/>\n"
|
66
|
+
end
|
67
|
+
|
68
|
+
def to_s
|
69
|
+
@value.to_s
|
70
|
+
end
|
71
|
+
|
72
|
+
def ==(other)
|
73
|
+
if other.is_a?(self.class)
|
74
|
+
other.value == @value
|
75
|
+
else
|
76
|
+
other == value
|
77
|
+
end
|
78
|
+
end
|
79
|
+
alias eql? ==
|
80
|
+
|
81
|
+
DEFAULT_ECS = EmitsChangedSignal.new(true)
|
82
|
+
end
|
83
|
+
end
|
data/lib/dbus/introspect.rb
CHANGED
@@ -26,7 +26,7 @@ module DBus
|
|
26
26
|
# method call instantiates and configures this class for us.
|
27
27
|
#
|
28
28
|
# It also is the local definition of interface exported by the program.
|
29
|
-
# At the client side, see ProxyObjectInterface
|
29
|
+
# At the client side, see {ProxyObjectInterface}.
|
30
30
|
class Interface
|
31
31
|
# @return [String] The name of the interface.
|
32
32
|
attr_reader :name
|
@@ -38,6 +38,9 @@ module DBus
|
|
38
38
|
# @return [Hash{Symbol => Property}]
|
39
39
|
attr_reader :properties
|
40
40
|
|
41
|
+
# @return [EmitsChangedSignal]
|
42
|
+
attr_reader :emits_changed_signal
|
43
|
+
|
41
44
|
# Creates a new interface with a given _name_.
|
42
45
|
def initialize(name)
|
43
46
|
validate_name(name)
|
@@ -45,6 +48,20 @@ module DBus
|
|
45
48
|
@methods = {}
|
46
49
|
@signals = {}
|
47
50
|
@properties = {}
|
51
|
+
@emits_changed_signal = EmitsChangedSignal::DEFAULT_ECS
|
52
|
+
end
|
53
|
+
|
54
|
+
# Helper for {Object.emits_changed_signal=}.
|
55
|
+
# @api private
|
56
|
+
def emits_changed_signal=(ecs)
|
57
|
+
raise TypeError unless ecs.is_a? EmitsChangedSignal
|
58
|
+
# equal?: object identity
|
59
|
+
unless @emits_changed_signal.equal?(EmitsChangedSignal::DEFAULT_ECS) ||
|
60
|
+
@emits_changed_signal.value == ecs.value
|
61
|
+
raise "emits_change_signal was assigned more than once"
|
62
|
+
end
|
63
|
+
|
64
|
+
@emits_changed_signal = ecs
|
48
65
|
end
|
49
66
|
|
50
67
|
# Validates a service _name_.
|
@@ -85,6 +102,18 @@ module DBus
|
|
85
102
|
define(m)
|
86
103
|
end
|
87
104
|
alias declare_method define_method
|
105
|
+
|
106
|
+
# Return introspection XML string representation of the property.
|
107
|
+
# @return [String]
|
108
|
+
def to_xml
|
109
|
+
xml = " <interface name=\"#{name}\">\n"
|
110
|
+
xml += emits_changed_signal.to_xml
|
111
|
+
methods.each_value { |m| xml += m.to_xml }
|
112
|
+
signals.each_value { |m| xml += m.to_xml }
|
113
|
+
properties.each_value { |m| xml += m.to_xml }
|
114
|
+
xml += " </interface>\n"
|
115
|
+
xml
|
116
|
+
end
|
88
117
|
end
|
89
118
|
|
90
119
|
# = A formal parameter has a name and a type
|
@@ -190,6 +219,7 @@ module DBus
|
|
190
219
|
end
|
191
220
|
|
192
221
|
# Return an XML string representation of the method interface elment.
|
222
|
+
# @return [String]
|
193
223
|
def to_xml
|
194
224
|
xml = " <method name=\"#{@name}\">\n"
|
195
225
|
@params.each do |param|
|
@@ -238,19 +268,20 @@ module DBus
|
|
238
268
|
# An (exported) property
|
239
269
|
# https://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-properties
|
240
270
|
class Property
|
241
|
-
# @return [
|
271
|
+
# @return [Symbol] The name of the property, for example FooBar.
|
242
272
|
attr_reader :name
|
243
273
|
# @return [SingleCompleteType]
|
244
274
|
attr_reader :type
|
245
275
|
# @return [Symbol] :read :write or :readwrite
|
246
276
|
attr_reader :access
|
247
277
|
|
248
|
-
# @return [Symbol] What to call at Ruby side.
|
278
|
+
# @return [Symbol,nil] What to call at Ruby side.
|
249
279
|
# (Always without the trailing `=`)
|
280
|
+
# It is `nil` IFF representing a client-side proxy.
|
250
281
|
attr_reader :ruby_name
|
251
282
|
|
252
283
|
def initialize(name, type, access, ruby_name:)
|
253
|
-
@name = name
|
284
|
+
@name = name.to_sym
|
254
285
|
@type = type
|
255
286
|
@access = access
|
256
287
|
@ruby_name = ruby_name
|
@@ -270,5 +301,14 @@ module DBus
|
|
270
301
|
def to_xml
|
271
302
|
" <property type=\"#{@type}\" name=\"#{@name}\" access=\"#{@access}\"/>\n"
|
272
303
|
end
|
304
|
+
|
305
|
+
# @param xml_node [AbstractXML::Node]
|
306
|
+
# @return [Property]
|
307
|
+
def self.from_xml(xml_node)
|
308
|
+
name = xml_node["name"].to_sym
|
309
|
+
type = xml_node["type"]
|
310
|
+
access = xml_node["access"].to_sym
|
311
|
+
new(name, type, access, ruby_name: nil)
|
312
|
+
end
|
273
313
|
end
|
274
314
|
end
|
data/lib/dbus/marshall.rb
CHANGED
@@ -250,10 +250,10 @@ module DBus
|
|
250
250
|
when Type::VARIANT
|
251
251
|
append_variant(val)
|
252
252
|
when Type::ARRAY
|
253
|
-
val = val.
|
253
|
+
val = val.exact_value if val.is_a?(Data::Array)
|
254
254
|
append_array(type.child, val)
|
255
255
|
when Type::STRUCT, Type::DICT_ENTRY
|
256
|
-
val = val.
|
256
|
+
val = val.exact_value if val.is_a?(Data::Struct) || val.is_a?(Data::DictEntry)
|
257
257
|
unless val.is_a?(Array) || val.is_a?(Struct)
|
258
258
|
type_name = Type::TYPE_MAPPING[type.sigtype].first
|
259
259
|
raise TypeException, "#{type_name} expects an Array or Struct, seen #{val.class}"
|
@@ -284,7 +284,10 @@ module DBus
|
|
284
284
|
vartype = nil
|
285
285
|
if val.is_a?(DBus::Data::Variant)
|
286
286
|
vartype = val.member_type
|
287
|
-
vardata = val.
|
287
|
+
vardata = val.exact_value
|
288
|
+
elsif val.is_a?(DBus::Data::Container)
|
289
|
+
vartype = val.type
|
290
|
+
vardata = val.exact_value
|
288
291
|
elsif val.is_a?(DBus::Data::Base)
|
289
292
|
vartype = val.type
|
290
293
|
vardata = val.value
|