ruby-dbus 0.18.0.beta5 → 0.18.0.beta8
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 +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
|