ruby-dbus 0.23.0.beta2 → 0.23.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c671b06e04452129a899cd4b7877cf43f9c05b8e7bc6597e75bc460e250c97e7
4
- data.tar.gz: 18f660c6e5804fd133cf8351d801f8e0d4e332f1473cc390bedf77341d71845d
3
+ metadata.gz: 2465a9a90d0b4837640d475566edfde23aee4dc1d7d439d76d1f861b71f13033
4
+ data.tar.gz: 906288ee9d180ff0bfd4e53f45982040f240da983e23c818acd91d449d9f7f05
5
5
  SHA512:
6
- metadata.gz: 5cff2ab01f4db3d069a73b28f46cf861dcc81302ed239a7fc4332f46a7583b2394d679d5d73ab13f080b674e46f8961c89fa3fccc58ce9043d0bd33c4c2d02c4
7
- data.tar.gz: 495c060e5161c2c5267b723598d3185b14d4c6517e41504f5b49971d3c355acec1ee3ab6285b7796bb7aa8cb61dfb5bd24535a2613a9f22cfb80f65ec8a1cf49
6
+ metadata.gz: f2939e81cff3f5db2dd768f9e0f1c04159b0285501c73840f14dd8f61ad9f539fbbbf35d7e408cca11847dcd31848131c1c4df69705798860f03e4255f02dedf
7
+ data.tar.gz: 553f1d4c97a284371d7a10a0f439a40d2861ff8c40c2318c09f6f818f5911644db05142dc7a8d5e377dac355ddc389fcc9858647a568184e8598fd3d3bb71154
data/NEWS.md CHANGED
@@ -2,6 +2,16 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ## Ruby D-Bus 0.23.1 - 2023-10-03
6
+
7
+ API:
8
+ * Add DBus::Object.dbus_reader_attr_accessor to declare a common use case
9
+ with a single call ([#140][]).
10
+ * BusConnection#request_name defaults to the simple use case: single owner
11
+ without queuing, failing fast; documented the complex use cases.
12
+
13
+ [#140]: https://github.com/mvidner/ruby-dbus/pull/140
14
+
5
15
  ## Ruby D-Bus 0.23.0.beta2 - 2023-06-23
6
16
 
7
17
  License:
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.23.0.beta2
1
+ 0.23.1
@@ -8,4 +8,12 @@ d = if ARGV.member?("--system")
8
8
  else
9
9
  DBus::SessionBus.instance
10
10
  end
11
- d.proxy.ListNames[0].each { |n| puts "\t#{n}" }
11
+ d.proxy.ListNames[0].each do |n|
12
+ puts "\t#{n}"
13
+ qns = d.proxy.ListQueuedOwners(n)[0]
14
+ next if qns.size == 1 && qns.first == n
15
+
16
+ qns.each do |qn|
17
+ puts "\t\t#{qn}"
18
+ end
19
+ end
data/lib/dbus/bus.rb CHANGED
@@ -55,20 +55,107 @@ module DBus
55
55
  @proxy
56
56
  end
57
57
 
58
+ # Request a well-known name so that clients can find us.
59
+ # @note Parameters other than *name* are advanced, you probably don't need them.
60
+ #
61
+ # With no boolean flags, running a second instance of a program that calls `request_name`
62
+ # will result in the second one failing, which this library translates to an exception.
63
+ # If you want the second instance to take over, you need both
64
+ # `allow_replacement: true` and `replace_existing: true.`
65
+ #
58
66
  # @param name [BusName] the requested name
59
- # @param flags [Integer] TODO: explain and add a better non-numeric API for this
60
- # @raise NameRequestError if we could not get the name
61
- # @example Usage
67
+ # @param replace_existing [Boolean]
68
+ # Replace an existing owner of the name, if that owner set *allow_replacement*.
69
+ # @param allow_replacement [Boolean]
70
+ # Other connections that specify *replace_existing* will be able to take
71
+ # the name from us. We will get {#on_name_lost NameLost}. If we specified *queue*
72
+ # we may get the name again, with {#on_name_acquired NameAcquired}.
73
+ # @param queue [Boolean]
74
+ # Affects the behavior when the bus denies the name (sooner or later).
75
+ # - If `false` (default), it is recommended to let the `NameRequestError` fall through and end your program.
76
+ # - If `true`, you should `rescue` the `NameRequestError` and set up
77
+ # {#on_name_acquired NameAcquired} and {#on_name_lost NameLost} handlers.
78
+ # Meanwhile, the bus will put us in a queue waiting for *name* (this is the "sooner" case).
79
+ # Also, if we had `allow_replacement: true`, another connection can cause us
80
+ # to lose the name. We will be moved back to the queue, waiting for when the other owners give up
81
+ # (the "later" case).
82
+ # @param flags [Integer,nil]
83
+ # If specified, overrides the boolean parameters.
84
+ # Use a bitwise sum `|` of:
85
+ # - NAME_FLAG_ALLOW_REPLACEMENT
86
+ # - NAME_FLAG_REPLACE_EXISTING
87
+ # - NAME_FLAG_DO_NOT_QUEUE
88
+ # Note that `0` implies `queue: true`.
89
+ #
90
+ # @return [REQUEST_NAME_REPLY_PRIMARY_OWNER,REQUEST_NAME_REPLY_ALREADY_OWNER] on success
91
+ # @raise [NameRequestError] with #error_code REQUEST_NAME_REPLY_EXISTS or REQUEST_NAME_REPLY_IN_QUEUE, on failure
92
+ # @raise DBus::Error another way to fail is being prohibited to own the name
93
+ # which is the default on the system bus
94
+ #
95
+ # @see https://dbus.freedesktop.org/doc/dbus-specification.html#bus-messages-request-name
96
+ #
97
+ # @example Simple usage
62
98
  # bus = DBus.session_bus
63
99
  # bus.object_server.export(DBus::Object.new("/org/example/Test"))
64
100
  # bus.request_name("org.example.Test")
65
- # @see https://dbus.freedesktop.org/doc/dbus-specification.html#bus-messages-request-name
66
- def request_name(name, flags: 0)
101
+ # # main loop
102
+ #
103
+ # @example Second instance taking over
104
+ # bus = DBus.session_bus
105
+ # bus.object_server.export(DBus::Object.new("/org/example/Test"))
106
+ # bus.on_name_lost { exit }
107
+ # bus.request_name("org.example.Test", allow_replacement: true, replace_existing: true)
108
+ # # main loop
109
+ #
110
+ # @example Second instance waiting for its turn
111
+ # bus = DBus.session_bus
112
+ # bus.object_server.export(DBus::Object.new("/org/example/Test"))
113
+ # bus.on_name_acquired { @owner = true }
114
+ # begin
115
+ # bus.request_name("org.example.Test", queue: true)
116
+ # rescue DBus::Connection::NameRequestError => e
117
+ # @owner = false
118
+ # end
119
+ # # main loop
120
+ def request_name(name,
121
+ allow_replacement: false,
122
+ replace_existing: false,
123
+ queue: false,
124
+ flags: nil)
125
+ if flags.nil?
126
+ flags = (allow_replacement ? NAME_FLAG_ALLOW_REPLACEMENT : 0) |
127
+ (replace_existing ? NAME_FLAG_REPLACE_EXISTING : 0) |
128
+ (queue ? 0 : NAME_FLAG_DO_NOT_QUEUE)
129
+ end
67
130
  name = BusName.new(name)
68
131
  r = proxy.RequestName(name, flags).first
69
132
  handle_return_of_request_name(r, name)
70
133
  end
71
134
 
135
+ # The caller has released his claim on the given name.
136
+ # Either the caller was the primary owner of the name, and the name is now unused
137
+ # or taken by somebody waiting in the queue for the name,
138
+ # or the caller was waiting in the queue for the name and has now been removed from the queue.
139
+ RELEASE_NAME_REPLY_RELEASED = 1
140
+ # The given name does not exist on this bus.
141
+ RELEASE_NAME_REPLY_NON_EXISTENT = 2
142
+ # The caller was not the primary owner of this name, and was also not waiting in the queue to own this name.
143
+ RELEASE_NAME_REPLY_NOT_OWNER = 3
144
+
145
+ # @param name [BusName] the name to release
146
+ def release_name(name)
147
+ name = BusName.new(name)
148
+ proxy.ReleaseName(name).first
149
+ end
150
+
151
+ def on_name_acquired(&handler)
152
+ proxy.on_signal("NameAcquired", &handler)
153
+ end
154
+
155
+ def on_name_lost(&handler)
156
+ proxy.on_signal("NameLost", &handler)
157
+ end
158
+
72
159
  # Asks bus to send us messages matching mr, and execute slot when
73
160
  # received
74
161
  # @param match_rule [MatchRule,#to_s]
@@ -153,17 +153,30 @@ module DBus
153
153
 
154
154
  # Exception raised when a service name is requested that is not available.
155
155
  class NameRequestError < Exception
156
+ # @return [Integer] one of
157
+ # REQUEST_NAME_REPLY_IN_QUEUE
158
+ # REQUEST_NAME_REPLY_EXISTS
159
+ attr_reader :error_code
160
+
161
+ def initialize(error_code)
162
+ @error_code = error_code
163
+ super()
164
+ end
156
165
  end
157
166
 
167
+ # In case RequestName did not succeed, raise an exception but first ask the bus who owns the name instead of us
168
+ # @param ret [Integer] what RequestName returned
169
+ # @param name Name that was requested
170
+ # @return [REQUEST_NAME_REPLY_PRIMARY_OWNER,REQUEST_NAME_REPLY_ALREADY_OWNER] on success
171
+ # @raise [NameRequestError] with #error_code REQUEST_NAME_REPLY_EXISTS or REQUEST_NAME_REPLY_IN_QUEUE, on failure
172
+ # @api private
158
173
  def handle_return_of_request_name(ret, name)
159
- details = if ret == REQUEST_NAME_REPLY_IN_QUEUE
160
- other = proxy.GetNameOwner(name).first
161
- other_creds = proxy.GetConnectionCredentials(other).first
162
- "already owned by #{other}, #{other_creds.inspect}"
163
- else
164
- "error code #{ret}"
165
- end
166
- raise NameRequestError, "Could not request #{name}, #{details}" unless ret == REQUEST_NAME_REPLY_PRIMARY_OWNER
174
+ if [REQUEST_NAME_REPLY_EXISTS, REQUEST_NAME_REPLY_IN_QUEUE].include?(ret)
175
+ other = proxy.GetNameOwner(name).first
176
+ other_creds = proxy.GetConnectionCredentials(other).first
177
+ message = "Could not request #{name}, already owned by #{other}, #{other_creds.inspect}"
178
+ raise NameRequestError.new(ret), message
179
+ end
167
180
 
168
181
  ret
169
182
  end
data/lib/dbus/object.rb CHANGED
@@ -156,18 +156,32 @@ module DBus
156
156
  dbus_accessor(ruby_name, type, dbus_name: dbus_name, emits_changed_signal: emits_changed_signal)
157
157
  end
158
158
 
159
+ # A read-only property accessing a read-write instance variable.
160
+ # A combination of `attr_accessor` and {.dbus_reader}.
161
+ #
162
+ # @param (see .dbus_attr_accessor)
163
+ # @return (see .dbus_attr_accessor)
164
+ def self.dbus_reader_attr_accessor(ruby_name, type, dbus_name: nil, emits_changed_signal: nil)
165
+ attr_accessor(ruby_name)
166
+
167
+ dbus_reader(ruby_name, type, dbus_name: dbus_name, emits_changed_signal: emits_changed_signal)
168
+ end
169
+
159
170
  # A read-only property accessing an instance variable.
160
171
  # A combination of `attr_reader` and {.dbus_reader}.
161
172
  #
173
+ # You may be instead looking for a variant which is read-write from the Ruby side:
174
+ # {.dbus_reader_attr_accessor}.
175
+ #
162
176
  # Whenever the property value gets changed from "inside" the object,
163
177
  # you should emit the `PropertiesChanged` signal by calling
164
178
  # {#dbus_properties_changed}.
165
179
  #
166
- # dbus_properties_changed(interface_name, {dbus_name.to_s => value}, [])
180
+ # dbus_properties_changed(interface_name, {dbus_name.to_s => value}, [])
167
181
  #
168
182
  # or, omitting the value in the signal,
169
183
  #
170
- # dbus_properties_changed(interface_name, {}, [dbus_name.to_s])
184
+ # dbus_properties_changed(interface_name, {}, [dbus_name.to_s])
171
185
  #
172
186
  # @param (see .dbus_attr_accessor)
173
187
  # @return (see .dbus_attr_accessor)
@@ -213,18 +227,22 @@ module DBus
213
227
  # implement it with a read-write attr_accessor. In that case this method
214
228
  # uses {.dbus_watcher} to set up the PropertiesChanged signal.
215
229
  #
216
- # attr_accessor :foo_bar
217
- # dbus_reader :foo_bar, "s"
230
+ # attr_accessor :foo_bar
231
+ # dbus_reader :foo_bar, "s"
232
+ #
233
+ # The above two declarations have a shorthand:
234
+ #
235
+ # dbus_reader_attr_accessor :foo_bar, "s"
218
236
  #
219
237
  # If the property value should change by other means than its attr_writer,
220
238
  # you should emit the `PropertiesChanged` signal by calling
221
239
  # {#dbus_properties_changed}.
222
240
  #
223
- # dbus_properties_changed(interface_name, {dbus_name.to_s => value}, [])
241
+ # dbus_properties_changed(interface_name, {dbus_name.to_s => value}, [])
224
242
  #
225
243
  # or, omitting the value in the signal,
226
244
  #
227
- # dbus_properties_changed(interface_name, {}, [dbus_name.to_s])
245
+ # dbus_properties_changed(interface_name, {}, [dbus_name.to_s])
228
246
  #
229
247
  # @param (see .dbus_attr_accessor)
230
248
  # @return (see .dbus_attr_accessor)
@@ -21,7 +21,6 @@ describe DBus::BusConnection do
21
21
  end
22
22
 
23
23
  context "when the name is taken already", tag_service: true do
24
- # formerly it returned Service, now ObjectServer takes its role
25
24
  it "raises NameRequestError... too late" do
26
25
  name = "org.ruby.service"
27
26
  expect do
@@ -50,21 +49,35 @@ describe DBus::BusConnection do
50
49
 
51
50
  describe "#request_name", tag_bus: true do
52
51
  context "when the name request succeeds" do
53
- it "returns something which can export objects" do
52
+ it "returns a success code" do
54
53
  name = "org.rubygems.ruby_dbus.RequestNameTest"
55
- expect { bus.request_name(name) }.to_not raise_error
56
- bus.proxy.ReleaseName(name)
54
+ expect(bus.request_name(name)).to eq DBus::Connection::REQUEST_NAME_REPLY_PRIMARY_OWNER
55
+ # second time, considered also a success
56
+ expect(bus.request_name(name)).to eq DBus::Connection::REQUEST_NAME_REPLY_ALREADY_OWNER
57
+ bus.release_name(name)
57
58
  end
58
59
  end
59
60
 
60
61
  context "when the name is taken already", tag_service: true do
61
- # formerly it returned Service, now ObjectServer takes its role
62
62
  it "raises NameRequestError" do
63
63
  name = "org.ruby.service"
64
64
  expect do
65
- # flags: avoid getting the name sometime later, unexpectedly
66
- bus.request_name(name, flags: DBus::Connection::NAME_FLAG_DO_NOT_QUEUE)
65
+ bus.request_name(name)
66
+ end.to raise_error(DBus::Connection::NameRequestError)
67
+ end
68
+ end
69
+
70
+ context "when the name is taken already but we request queuing", tag_service: true do
71
+ it "raises NameRequestError but we are queued" do
72
+ name = "org.ruby.service"
73
+ owning = nil
74
+ # TODO: we do not expect the handlers to run
75
+ bus.on_name_acquired { owning = true }
76
+ bus.on_name_lost { owning = false }
77
+ expect do
78
+ bus.request_name(name, queue: true)
67
79
  end.to raise_error(DBus::Connection::NameRequestError)
80
+ expect(bus.release_name(name)).to eq DBus::BusConnection::RELEASE_NAME_REPLY_RELEASED
68
81
  end
69
82
  end
70
83
 
@@ -23,7 +23,7 @@ class TestChild < DBus::Object
23
23
  end
24
24
 
25
25
  dbus_interface "org.ruby.TestChild" do
26
- dbus_attr_reader :name, "s"
26
+ dbus_reader_attr_accessor :name, "s"
27
27
  end
28
28
  end
29
29
 
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.23.0.beta2
4
+ version: 0.23.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ruby DBus Team
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-06-23 00:00:00.000000000 Z
11
+ date: 2023-10-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rexml
@@ -235,9 +235,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
235
235
  version: 2.4.0
236
236
  required_rubygems_version: !ruby/object:Gem::Requirement
237
237
  requirements:
238
- - - ">"
238
+ - - ">="
239
239
  - !ruby/object:Gem::Version
240
- version: 1.3.1
240
+ version: '0'
241
241
  requirements: []
242
242
  rubygems_version: 3.3.26
243
243
  signing_key: