ruby-dbus 0.18.0.beta7 → 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 +20 -0
- data/VERSION +1 -1
- data/lib/dbus/bus.rb +3 -7
- data/lib/dbus/emits_changed_signal.rb +83 -0
- data/lib/dbus/introspect.rb +31 -1
- data/lib/dbus/object.rb +84 -22
- data/lib/dbus/type.rb +1 -1
- data/lib/dbus.rb +1 -0
- data/spec/emits_changed_signal_spec.rb +58 -0
- data/spec/object_spec.rb +138 -0
- data/spec/property_spec.rb +4 -1
- data/spec/service_newapi.rb +9 -0
- metadata +10 -6
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,26 @@
|
|
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
|
+
|
5
25
|
## Ruby D-Bus 0.18.0.beta7 - 2022-05-29
|
6
26
|
|
7
27
|
API:
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.18.0.
|
1
|
+
0.18.0.beta8
|
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
|
@@ -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|
|
data/lib/dbus/object.rb
CHANGED
@@ -102,6 +102,18 @@ module DBus
|
|
102
102
|
end
|
103
103
|
end
|
104
104
|
|
105
|
+
# Declare the behavior of PropertiesChanged signal,
|
106
|
+
# common for all properties in this interface
|
107
|
+
# (individual properties may override it)
|
108
|
+
# @example
|
109
|
+
# self.emits_changed_signal = :invalidates
|
110
|
+
# @param [true,false,:const,:invalidates] value
|
111
|
+
def self.emits_changed_signal=(value)
|
112
|
+
raise UndefinedInterface, :emits_changed_signal if @@cur_intf.nil?
|
113
|
+
|
114
|
+
@@cur_intf.emits_changed_signal = EmitsChangedSignal.new(value)
|
115
|
+
end
|
116
|
+
|
105
117
|
# A read-write property accessing an instance variable.
|
106
118
|
# A combination of `attr_accessor` and {.dbus_accessor}.
|
107
119
|
#
|
@@ -114,11 +126,13 @@ module DBus
|
|
114
126
|
# @param dbus_name [String] if not given it is made
|
115
127
|
# by CamelCasing the ruby_name. foo_bar becomes FooBar
|
116
128
|
# to convert the Ruby convention to the DBus convention.
|
129
|
+
# @param emits_changed_signal [true,false,:const,:invalidates]
|
130
|
+
# see {EmitsChangedSignal}; if unspecified, ask the interface.
|
117
131
|
# @return [void]
|
118
|
-
def self.dbus_attr_accessor(ruby_name, type, dbus_name: nil)
|
132
|
+
def self.dbus_attr_accessor(ruby_name, type, dbus_name: nil, emits_changed_signal: nil)
|
119
133
|
attr_accessor(ruby_name)
|
120
134
|
|
121
|
-
dbus_accessor(ruby_name, type, dbus_name: dbus_name)
|
135
|
+
dbus_accessor(ruby_name, type, dbus_name: dbus_name, emits_changed_signal: emits_changed_signal)
|
122
136
|
end
|
123
137
|
|
124
138
|
# A read-only property accessing an instance variable.
|
@@ -126,19 +140,20 @@ module DBus
|
|
126
140
|
#
|
127
141
|
# Whenever the property value gets changed from "inside" the object,
|
128
142
|
# you should emit the `PropertiesChanged` signal by calling
|
143
|
+
# {#dbus_properties_changed}.
|
129
144
|
#
|
130
|
-
#
|
145
|
+
# dbus_properties_changed(interface_name, {dbus_name.to_s => value}, [])
|
131
146
|
#
|
132
147
|
# or, omitting the value in the signal,
|
133
148
|
#
|
134
|
-
#
|
149
|
+
# dbus_properties_changed(interface_name, {}, [dbus_name.to_s])
|
135
150
|
#
|
136
151
|
# @param (see .dbus_attr_accessor)
|
137
152
|
# @return (see .dbus_attr_accessor)
|
138
|
-
def self.dbus_attr_reader(ruby_name, type, dbus_name: nil)
|
153
|
+
def self.dbus_attr_reader(ruby_name, type, dbus_name: nil, emits_changed_signal: nil)
|
139
154
|
attr_reader(ruby_name)
|
140
155
|
|
141
|
-
dbus_reader(ruby_name, type, dbus_name: dbus_name)
|
156
|
+
dbus_reader(ruby_name, type, dbus_name: dbus_name, emits_changed_signal: emits_changed_signal)
|
142
157
|
end
|
143
158
|
|
144
159
|
# A write-only property accessing an instance variable.
|
@@ -146,10 +161,10 @@ module DBus
|
|
146
161
|
#
|
147
162
|
# @param (see .dbus_attr_accessor)
|
148
163
|
# @return (see .dbus_attr_accessor)
|
149
|
-
def self.dbus_attr_writer(ruby_name, type, dbus_name: nil)
|
164
|
+
def self.dbus_attr_writer(ruby_name, type, dbus_name: nil, emits_changed_signal: nil)
|
150
165
|
attr_writer(ruby_name)
|
151
166
|
|
152
|
-
dbus_writer(ruby_name, type, dbus_name: dbus_name)
|
167
|
+
dbus_writer(ruby_name, type, dbus_name: dbus_name, emits_changed_signal: emits_changed_signal)
|
153
168
|
end
|
154
169
|
|
155
170
|
# A read-write property using a pair of reader/writer methods
|
@@ -160,36 +175,49 @@ module DBus
|
|
160
175
|
#
|
161
176
|
# @param (see .dbus_attr_accessor)
|
162
177
|
# @return (see .dbus_attr_accessor)
|
163
|
-
def self.dbus_accessor(ruby_name, type, dbus_name: nil)
|
178
|
+
def self.dbus_accessor(ruby_name, type, dbus_name: nil, emits_changed_signal: nil)
|
164
179
|
raise UndefinedInterface, ruby_name if @@cur_intf.nil?
|
165
180
|
|
166
181
|
dbus_name = make_dbus_name(ruby_name, dbus_name: dbus_name)
|
167
182
|
property = Property.new(dbus_name, type, :readwrite, ruby_name: ruby_name)
|
168
183
|
@@cur_intf.define(property)
|
169
184
|
|
170
|
-
dbus_watcher(ruby_name, dbus_name: dbus_name)
|
185
|
+
dbus_watcher(ruby_name, dbus_name: dbus_name, emits_changed_signal: emits_changed_signal)
|
171
186
|
end
|
172
187
|
|
173
188
|
# A read-only property accessing a reader method (which must already exist).
|
174
189
|
# (To directly access an instance variable, use {.dbus_attr_reader} instead)
|
175
190
|
#
|
176
|
-
#
|
191
|
+
# At the D-Bus side the property is read only but it makes perfect sense to
|
192
|
+
# implement it with a read-write attr_accessor. In that case this method
|
193
|
+
# uses {.dbus_watcher} to set up the PropertiesChanged signal.
|
194
|
+
#
|
195
|
+
# attr_accessor :foo_bar
|
196
|
+
# dbus_reader :foo_bar, "s"
|
197
|
+
#
|
198
|
+
# If the property value should change by other means than its attr_writer,
|
177
199
|
# you should emit the `PropertiesChanged` signal by calling
|
200
|
+
# {#dbus_properties_changed}.
|
178
201
|
#
|
179
|
-
#
|
202
|
+
# dbus_properties_changed(interface_name, {dbus_name.to_s => value}, [])
|
180
203
|
#
|
181
204
|
# or, omitting the value in the signal,
|
182
205
|
#
|
183
|
-
#
|
206
|
+
# dbus_properties_changed(interface_name, {}, [dbus_name.to_s])
|
184
207
|
#
|
185
208
|
# @param (see .dbus_attr_accessor)
|
186
209
|
# @return (see .dbus_attr_accessor)
|
187
|
-
def self.dbus_reader(ruby_name, type, dbus_name: nil)
|
210
|
+
def self.dbus_reader(ruby_name, type, dbus_name: nil, emits_changed_signal: nil)
|
188
211
|
raise UndefinedInterface, ruby_name if @@cur_intf.nil?
|
189
212
|
|
190
213
|
dbus_name = make_dbus_name(ruby_name, dbus_name: dbus_name)
|
191
214
|
property = Property.new(dbus_name, type, :read, ruby_name: ruby_name)
|
192
215
|
@@cur_intf.define(property)
|
216
|
+
|
217
|
+
ruby_name_eq = "#{ruby_name}=".to_sym
|
218
|
+
return unless method_defined?(ruby_name_eq)
|
219
|
+
|
220
|
+
dbus_watcher(ruby_name, dbus_name: dbus_name, emits_changed_signal: emits_changed_signal)
|
193
221
|
end
|
194
222
|
|
195
223
|
# A write-only property accessing a writer method (which must already exist).
|
@@ -199,14 +227,14 @@ module DBus
|
|
199
227
|
#
|
200
228
|
# @param (see .dbus_attr_accessor)
|
201
229
|
# @return (see .dbus_attr_accessor)
|
202
|
-
def self.dbus_writer(ruby_name, type, dbus_name: nil)
|
230
|
+
def self.dbus_writer(ruby_name, type, dbus_name: nil, emits_changed_signal: nil)
|
203
231
|
raise UndefinedInterface, ruby_name if @@cur_intf.nil?
|
204
232
|
|
205
233
|
dbus_name = make_dbus_name(ruby_name, dbus_name: dbus_name)
|
206
234
|
property = Property.new(dbus_name, type, :write, ruby_name: ruby_name)
|
207
235
|
@@cur_intf.define(property)
|
208
236
|
|
209
|
-
dbus_watcher(ruby_name, dbus_name: dbus_name)
|
237
|
+
dbus_watcher(ruby_name, dbus_name: dbus_name, emits_changed_signal: emits_changed_signal)
|
210
238
|
end
|
211
239
|
|
212
240
|
# Enables automatic sending of the PropertiesChanged signal.
|
@@ -218,11 +246,13 @@ module DBus
|
|
218
246
|
# @param dbus_name [String] if not given it is made
|
219
247
|
# by CamelCasing the ruby_name. foo_bar becomes FooBar
|
220
248
|
# to convert the Ruby convention to the DBus convention.
|
249
|
+
# @param emits_changed_signal [true,false,:const,:invalidates]
|
250
|
+
# see {EmitsChangedSignal}; if unspecified, ask the interface.
|
221
251
|
# @return [void]
|
222
|
-
def self.dbus_watcher(ruby_name, dbus_name: nil)
|
252
|
+
def self.dbus_watcher(ruby_name, dbus_name: nil, emits_changed_signal: nil)
|
223
253
|
raise UndefinedInterface, ruby_name if @@cur_intf.nil?
|
224
254
|
|
225
|
-
|
255
|
+
interface_name = @@cur_intf.name
|
226
256
|
|
227
257
|
ruby_name = ruby_name.to_s.sub(/=$/, "").to_sym
|
228
258
|
ruby_name_eq = "#{ruby_name}=".to_sym
|
@@ -230,14 +260,27 @@ module DBus
|
|
230
260
|
|
231
261
|
dbus_name = make_dbus_name(ruby_name, dbus_name: dbus_name)
|
232
262
|
|
263
|
+
emits_changed_signal = EmitsChangedSignal.new(emits_changed_signal, interface: @@cur_intf)
|
264
|
+
|
233
265
|
# the argument order is alias_method(new_name, existing_name)
|
234
266
|
alias_method original_ruby_name_eq, ruby_name_eq
|
235
267
|
define_method ruby_name_eq do |value|
|
236
|
-
public_send(original_ruby_name_eq, value)
|
268
|
+
result = public_send(original_ruby_name_eq, value)
|
269
|
+
|
270
|
+
case emits_changed_signal.value
|
271
|
+
when true
|
272
|
+
# signature: "interface:s, changed_props:a{sv}, invalidated_props:as"
|
273
|
+
dbus_properties_changed(interface_name, { dbus_name.to_s => value }, [])
|
274
|
+
when :invalidates
|
275
|
+
dbus_properties_changed(interface_name, {}, [dbus_name.to_s])
|
276
|
+
when :const
|
277
|
+
# Oh my, seeing a value change of a supposedly constant property.
|
278
|
+
# Maybe should have raised at declaration time, don't make a fuss now.
|
279
|
+
when false
|
280
|
+
# Do nothing
|
281
|
+
end
|
237
282
|
|
238
|
-
|
239
|
-
# PropertiesChanged, "interface:s, changed_properties:a{sv}, invalidated_properties:as"
|
240
|
-
PropertiesChanged(cur_intf.name, { dbus_name.to_s => value }, [])
|
283
|
+
result
|
241
284
|
end
|
242
285
|
end
|
243
286
|
|
@@ -301,6 +344,25 @@ module DBus
|
|
301
344
|
dbus_name.to_sym
|
302
345
|
end
|
303
346
|
|
347
|
+
# Use this instead of calling PropertiesChanged directly. This one
|
348
|
+
# considers not only the PC signature (which says that all property values
|
349
|
+
# are variants) but also the specific property type.
|
350
|
+
# @param interface_name [String] interface name like "org.example.ManagerManager"
|
351
|
+
# @param changed_props [Hash{String => ::Object}]
|
352
|
+
# changed properties (D-Bus names) and their values.
|
353
|
+
# @param invalidated_props [Array<String>]
|
354
|
+
# names of properties whose changed value is not specified
|
355
|
+
def dbus_properties_changed(interface_name, changed_props, invalidated_props)
|
356
|
+
typed_changed_props = changed_props.map do |dbus_name, value|
|
357
|
+
property = dbus_lookup_property(interface_name, dbus_name)
|
358
|
+
type = property.type
|
359
|
+
typed_value = Data.make_typed(type, value)
|
360
|
+
variant = Data::Variant.new(typed_value, member_type: type)
|
361
|
+
[dbus_name, variant]
|
362
|
+
end.to_h
|
363
|
+
PropertiesChanged(interface_name, typed_changed_props, invalidated_props)
|
364
|
+
end
|
365
|
+
|
304
366
|
# @param interface_name [String]
|
305
367
|
# @param property_name [String]
|
306
368
|
# @return [Property]
|
data/lib/dbus/type.rb
CHANGED
@@ -415,7 +415,7 @@ module DBus
|
|
415
415
|
# @param string_type [SingleCompleteType]
|
416
416
|
# @param value [::Object]
|
417
417
|
# @return [Array(DBus::Type::Type,::Object)]
|
418
|
-
# @deprecated Use {Data::Variant
|
418
|
+
# @deprecated Use {Data::Variant#initialize} instead
|
419
419
|
def variant(string_type, value)
|
420
420
|
Data::Variant.new(value, member_type: string_type)
|
421
421
|
end
|
data/lib/dbus.rb
CHANGED
@@ -15,6 +15,7 @@ require_relative "dbus/auth"
|
|
15
15
|
require_relative "dbus/bus"
|
16
16
|
require_relative "dbus/bus_name"
|
17
17
|
require_relative "dbus/data"
|
18
|
+
require_relative "dbus/emits_changed_signal"
|
18
19
|
require_relative "dbus/error"
|
19
20
|
require_relative "dbus/introspect"
|
20
21
|
require_relative "dbus/logger"
|
@@ -0,0 +1,58 @@
|
|
1
|
+
#!/usr/bin/env rspec
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require_relative "spec_helper"
|
5
|
+
require "dbus"
|
6
|
+
|
7
|
+
describe DBus::EmitsChangedSignal do
|
8
|
+
describe "#initialize" do
|
9
|
+
it "accepts a simple value" do
|
10
|
+
expect(described_class.new(:const).value).to eq :const
|
11
|
+
end
|
12
|
+
|
13
|
+
it "avoids nil by asking the interface" do
|
14
|
+
ifc = DBus::Interface.new("org.example.Foo")
|
15
|
+
ifc.emits_changed_signal = described_class.new(:invalidates)
|
16
|
+
|
17
|
+
expect(described_class.new(nil, interface: ifc).value).to eq :invalidates
|
18
|
+
end
|
19
|
+
|
20
|
+
it "fails for unknown value" do
|
21
|
+
expect { described_class.new(:huh) }.to raise_error(ArgumentError, /Seen :huh/)
|
22
|
+
end
|
23
|
+
|
24
|
+
it "fails for 2 nils" do
|
25
|
+
expect { described_class.new(nil, interface: nil) }.to raise_error(ArgumentError, /Both/)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
describe "#==" do
|
30
|
+
it "is true for two different objects with the same value" do
|
31
|
+
const_a = described_class.new(:const)
|
32
|
+
const_b = described_class.new(:const)
|
33
|
+
expect(const_a == const_b).to be true
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
describe "#to_xml" do
|
38
|
+
it "uses a string value" do
|
39
|
+
expect(described_class.new(:const).to_xml)
|
40
|
+
.to eq " <annotation name=\"org.freedesktop.DBus.Property.EmitsChangedSignal\" value=\"const\"/>\n"
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
describe "#to_s" do
|
45
|
+
it "uses a string value" do
|
46
|
+
expect(described_class.new(:const).to_s).to eq "const"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
describe DBus::Interface do
|
52
|
+
describe ".emits_changed_signal=" do
|
53
|
+
it "only allows an EmitsChangedSignal as argument" do
|
54
|
+
ifc = described_class.new("org.ruby.Interface")
|
55
|
+
expect { ifc.emits_changed_signal = :const }.to raise_error(TypeError)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
data/spec/object_spec.rb
ADDED
@@ -0,0 +1,138 @@
|
|
1
|
+
#!/usr/bin/env rspec
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require_relative "spec_helper"
|
5
|
+
require "dbus"
|
6
|
+
|
7
|
+
class ObjectTest < DBus::Object
|
8
|
+
T = DBus::Type unless const_defined? "T"
|
9
|
+
|
10
|
+
dbus_interface "org.ruby.ServerTest" do
|
11
|
+
dbus_attr_writer :write_me, T::Struct[String, String]
|
12
|
+
|
13
|
+
attr_accessor :read_only_for_dbus
|
14
|
+
|
15
|
+
dbus_reader :read_only_for_dbus, T::STRING, emits_changed_signal: :invalidates
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
describe DBus::Object do
|
20
|
+
describe ".dbus_attr_writer" do
|
21
|
+
describe "the declared assignment method" do
|
22
|
+
# Slightly advanced RSpec:
|
23
|
+
# https://rspec.info/documentation/3.9/rspec-expectations/RSpec/Matchers.html#satisfy-instance_method
|
24
|
+
let(:a_struct_in_a_variant) do
|
25
|
+
satisfying { |x| x.is_a?(DBus::Data::Variant) && x.member_type.to_s == "(ss)" }
|
26
|
+
# ^ This formatting keeps the matcher on a single line
|
27
|
+
# which enables RSpec to cite it if it fails, instead of saying "block".
|
28
|
+
end
|
29
|
+
|
30
|
+
it "emits PropertyChanged with correctly typed argument" do
|
31
|
+
obj = ObjectTest.new("/test")
|
32
|
+
expect(obj).to receive(:PropertiesChanged).with(
|
33
|
+
"org.ruby.ServerTest",
|
34
|
+
{
|
35
|
+
"WriteMe" => a_struct_in_a_variant
|
36
|
+
},
|
37
|
+
[]
|
38
|
+
)
|
39
|
+
# bug: call PC with simply the assigned value,
|
40
|
+
# which will need type guessing
|
41
|
+
obj.write_me = ["two", "strings"]
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
describe ".dbus_accessor" do
|
47
|
+
it "can only be used within a dbus_interface" do
|
48
|
+
expect do
|
49
|
+
ObjectTest.instance_exec do
|
50
|
+
dbus_accessor :foo, DBus::Type::STRING
|
51
|
+
end
|
52
|
+
end.to raise_error(DBus::Object::UndefinedInterface)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
describe ".dbus_reader" do
|
57
|
+
it "can only be used within a dbus_interface" do
|
58
|
+
expect do
|
59
|
+
ObjectTest.instance_exec do
|
60
|
+
dbus_reader :foo, DBus::Type::STRING
|
61
|
+
end
|
62
|
+
end.to raise_error(DBus::Object::UndefinedInterface)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
describe ".dbus_reader, when paired with attr_accessor" do
|
67
|
+
describe "the declared assignment method" do
|
68
|
+
it "emits PropertyChanged" do
|
69
|
+
obj = ObjectTest.new("/test")
|
70
|
+
expect(obj).to receive(:PropertiesChanged).with(
|
71
|
+
"org.ruby.ServerTest",
|
72
|
+
{},
|
73
|
+
["ReadOnlyForDbus"]
|
74
|
+
)
|
75
|
+
obj.read_only_for_dbus = "myvalue"
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
describe ".dbus_writer" do
|
81
|
+
it "can only be used within a dbus_interface" do
|
82
|
+
expect do
|
83
|
+
ObjectTest.instance_exec do
|
84
|
+
dbus_writer :foo, DBus::Type::STRING
|
85
|
+
end
|
86
|
+
end.to raise_error(DBus::Object::UndefinedInterface)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
describe ".dbus_watcher" do
|
91
|
+
it "can only be used within a dbus_interface" do
|
92
|
+
expect do
|
93
|
+
ObjectTest.instance_exec do
|
94
|
+
dbus_watcher :foo
|
95
|
+
end
|
96
|
+
end.to raise_error(DBus::Object::UndefinedInterface)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
describe ".dbus_method" do
|
101
|
+
it "can only be used within a dbus_interface" do
|
102
|
+
expect do
|
103
|
+
ObjectTest.instance_exec do
|
104
|
+
dbus_method :foo do
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end.to raise_error(DBus::Object::UndefinedInterface)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
describe ".emits_changed_signal" do
|
112
|
+
it "raises UndefinedInterface when so" do
|
113
|
+
expect { ObjectTest.emits_changed_signal = false }
|
114
|
+
.to raise_error DBus::Object::UndefinedInterface
|
115
|
+
end
|
116
|
+
|
117
|
+
it "assigns to the current interface" do
|
118
|
+
ObjectTest.instance_exec do
|
119
|
+
dbus_interface "org.ruby.Interface" do
|
120
|
+
self.emits_changed_signal = false
|
121
|
+
end
|
122
|
+
end
|
123
|
+
ecs = ObjectTest.intfs["org.ruby.Interface"].emits_changed_signal
|
124
|
+
expect(ecs).to eq false
|
125
|
+
end
|
126
|
+
|
127
|
+
it "only can be assigned once" do
|
128
|
+
expect do
|
129
|
+
Class.new(DBus::Object) do
|
130
|
+
dbus_interface "org.ruby.Interface" do
|
131
|
+
self.emits_changed_signal = false
|
132
|
+
self.emits_changed_signal = :invalidates
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end.to raise_error(RuntimeError, /assigned more than once/)
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
data/spec/property_spec.rb
CHANGED
@@ -110,6 +110,7 @@ describe "PropertyTest" do
|
|
110
110
|
end
|
111
111
|
|
112
112
|
@iface["ReadOrWriteMe"] = "VALUE"
|
113
|
+
@iface.SetTwoProperties("REAMDE", 255)
|
113
114
|
|
114
115
|
# loop to process the signal. complicated :-( see signal_spec.rb
|
115
116
|
loop = DBus::Main.new
|
@@ -123,6 +124,8 @@ describe "PropertyTest" do
|
|
123
124
|
quitter.join
|
124
125
|
|
125
126
|
expect(received["ReadOrWriteMe"]).to eq("VALUE")
|
127
|
+
expect(received["ReadMe"]).to eq("REAMDE")
|
128
|
+
expect(received["MyByte"]).to eq(255)
|
126
129
|
end
|
127
130
|
|
128
131
|
context "a struct-typed property" do
|
@@ -206,7 +209,7 @@ describe "PropertyTest" do
|
|
206
209
|
let(:a_byte_in_a_variant) do
|
207
210
|
satisfying { |x| x.is_a?(DBus::Data::Variant) && x.member_type.to_s == DBus::Type::BYTE }
|
208
211
|
# ^ This formatting keeps the matcher on a single line
|
209
|
-
# which enables
|
212
|
+
# which enables RSpec to cite it if it fails, instead of saying "block".
|
210
213
|
end
|
211
214
|
|
212
215
|
let(:prop_iface) { @obj[DBus::PROPERTY_INTERFACE] }
|
data/spec/service_newapi.rb
CHANGED
@@ -115,6 +115,15 @@ class Test < DBus::Object
|
|
115
115
|
dbus_attr_accessor :my_variant, "v"
|
116
116
|
|
117
117
|
dbus_attr_accessor :my_byte, "y"
|
118
|
+
|
119
|
+
# to test dbus_properties_changed
|
120
|
+
dbus_method :SetTwoProperties, "in read_me:s, in byte:y" do |read_me, byte|
|
121
|
+
@read_me = read_me
|
122
|
+
@my_byte = byte
|
123
|
+
dbus_properties_changed(INTERFACE,
|
124
|
+
{ "ReadMe" => read_me, "MyByte" => byte },
|
125
|
+
[])
|
126
|
+
end
|
118
127
|
end
|
119
128
|
|
120
129
|
# closing and reopening the same interface
|
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.beta8
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ruby DBus Team
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-06-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rexml
|
@@ -146,6 +146,7 @@ files:
|
|
146
146
|
- lib/dbus/core_ext/class/attribute.rb
|
147
147
|
- lib/dbus/core_ext/module/redefine_method.rb
|
148
148
|
- lib/dbus/data.rb
|
149
|
+
- lib/dbus/emits_changed_signal.rb
|
149
150
|
- lib/dbus/error.rb
|
150
151
|
- lib/dbus/introspect.rb
|
151
152
|
- lib/dbus/logger.rb
|
@@ -172,12 +173,14 @@ files:
|
|
172
173
|
- spec/client_robustness_spec.rb
|
173
174
|
- spec/data/marshall.yaml
|
174
175
|
- spec/data_spec.rb
|
176
|
+
- spec/emits_changed_signal_spec.rb
|
175
177
|
- spec/err_msg_spec.rb
|
176
178
|
- spec/introspect_xml_parser_spec.rb
|
177
179
|
- spec/introspection_spec.rb
|
178
180
|
- spec/main_loop_spec.rb
|
179
181
|
- spec/node_spec.rb
|
180
182
|
- spec/object_path_spec.rb
|
183
|
+
- spec/object_spec.rb
|
181
184
|
- spec/packet_marshaller_spec.rb
|
182
185
|
- spec/packet_unmarshaller_spec.rb
|
183
186
|
- spec/property_spec.rb
|
@@ -202,7 +205,7 @@ homepage: https://github.com/mvidner/ruby-dbus
|
|
202
205
|
licenses:
|
203
206
|
- LGPL-2.1
|
204
207
|
metadata: {}
|
205
|
-
post_install_message:
|
208
|
+
post_install_message:
|
206
209
|
rdoc_options: []
|
207
210
|
require_paths:
|
208
211
|
- lib
|
@@ -217,8 +220,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
217
220
|
- !ruby/object:Gem::Version
|
218
221
|
version: 1.3.1
|
219
222
|
requirements: []
|
220
|
-
|
221
|
-
|
223
|
+
rubyforge_project:
|
224
|
+
rubygems_version: 2.7.6.3
|
225
|
+
signing_key:
|
222
226
|
specification_version: 4
|
223
227
|
summary: Ruby module for interaction with D-Bus
|
224
228
|
test_files: []
|