ruby-dbus-openplacos 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. data/COPYING +504 -0
  2. data/NEWS +146 -0
  3. data/README +42 -0
  4. data/Rakefile +54 -0
  5. data/VERSION +1 -0
  6. data/doc/tutorial/index.markdown +480 -0
  7. data/examples/gdbus/gdbus +255 -0
  8. data/examples/gdbus/gdbus.glade +184 -0
  9. data/examples/gdbus/launch.sh +4 -0
  10. data/examples/no-introspect/nm-test.rb +21 -0
  11. data/examples/no-introspect/tracker-test.rb +16 -0
  12. data/examples/rhythmbox/playpause.rb +25 -0
  13. data/examples/service/call_service.rb +25 -0
  14. data/examples/service/service_newapi.rb +51 -0
  15. data/examples/simple/call_introspect.rb +34 -0
  16. data/examples/simple/properties.rb +19 -0
  17. data/examples/utils/listnames.rb +11 -0
  18. data/examples/utils/notify.rb +19 -0
  19. data/lib/dbus/auth.rb +258 -0
  20. data/lib/dbus/bus.rb +947 -0
  21. data/lib/dbus/core_ext/class/attribute.rb +91 -0
  22. data/lib/dbus/core_ext/kernel/singleton_class.rb +14 -0
  23. data/lib/dbus/core_ext/module/remove_method.rb +12 -0
  24. data/lib/dbus/error.rb +44 -0
  25. data/lib/dbus/export.rb +124 -0
  26. data/lib/dbus/introspect.rb +570 -0
  27. data/lib/dbus/marshall.rb +443 -0
  28. data/lib/dbus/matchrule.rb +100 -0
  29. data/lib/dbus/message.rb +310 -0
  30. data/lib/dbus/type.rb +222 -0
  31. data/lib/dbus.rb +83 -0
  32. data/ruby-dbus-openplacos.gemspec +17 -0
  33. data/test/binding_test.rb +56 -0
  34. data/test/bus_driver_test.rb +22 -0
  35. data/test/dbus-launch-simple +35 -0
  36. data/test/dbus-limited-session.conf +28 -0
  37. data/test/property_test.rb +55 -0
  38. data/test/server_robustness_test.rb +72 -0
  39. data/test/server_test.rb +53 -0
  40. data/test/service_newapi.rb +197 -0
  41. data/test/session_bus_test_manual.rb +20 -0
  42. data/test/signal_test.rb +64 -0
  43. data/test/t1 +4 -0
  44. data/test/t2.rb +66 -0
  45. data/test/t3-ticket27.rb +18 -0
  46. data/test/t5-report-dbus-interface.rb +58 -0
  47. data/test/t6-loop.rb +82 -0
  48. data/test/test_env +13 -0
  49. data/test/test_server +39 -0
  50. data/test/variant_test.rb +66 -0
  51. metadata +118 -0
data/README ADDED
@@ -0,0 +1,42 @@
1
+ = Ruby D-Bus README
2
+
3
+ Ruby D-Bus provides an implementation of the D-Bus protocol such that the
4
+ D-Bus system can be used in the Ruby programming language.
5
+
6
+ == Requirements
7
+
8
+ * Ruby 1.8 (>= 1.8.6?) or 1.9
9
+
10
+ == Installation
11
+
12
+ * gem install ruby-dbus
13
+
14
+ == Feature
15
+
16
+ Ruby D-Bus currently supports the following features:
17
+
18
+ * Connecting to local buses.
19
+ * Accessing remote services, objects and interfaces.
20
+ * Invoking methods on remote objects synchronously and asynchronously.
21
+ * Catch signals on remote objects and handle them via callbacks.
22
+ * Remote object introspection.
23
+ * Walking object trees.
24
+ * Creating services and registering them on the bus.
25
+ * Exporting objects with interfaces on a bus for remote use.
26
+ * Rubyish D-Bus object and interface syntax support that automatically
27
+ allows for introspection.
28
+ * Emitting signals on exported objects.
29
+
30
+ == Usage
31
+
32
+ See some of the examples in the examples/ subdirectory of the tarball.
33
+ Also, check out the included tutorial (in Markdown format) in doc/tutorial/
34
+ or view it online on
35
+ https://github.com/mvidner/ruby-dbus/blob/master/doc/tutorial/index.markdown .
36
+
37
+ == License
38
+
39
+ Ruby D-Bus is free software; you can redistribute it and/or modify it
40
+ under the terms of the GNU Lesser General Public License as published by the
41
+ Free Software Foundation; either version 2.1 of the License, or (at
42
+ your option) any later version.
data/Rakefile ADDED
@@ -0,0 +1,54 @@
1
+ #! /usr/bin/env ruby
2
+ require 'rake'
3
+ require 'rake/gempackagetask'
4
+ require 'fileutils'
5
+ include FileUtils
6
+ require 'rake/rdoctask'
7
+ require 'rake/testtask'
8
+
9
+ desc 'Default: run tests in the proper environment'
10
+ task :default => "env:test"
11
+
12
+ def common_test_task(t)
13
+ t.libs << "lib"
14
+ t.test_files = FileList['test/*_test.rb', 'test/t*.rb']
15
+ t.verbose = true
16
+ end
17
+ Rake::TestTask.new {|t| common_test_task t }
18
+
19
+ begin
20
+ require 'rcov/rcovtask'
21
+ Rcov::RcovTask.new {|t| common_test_task t }
22
+ rescue LoadError
23
+ # no rcov, never mind
24
+ end
25
+
26
+ %w(test rcov).each do |tname|
27
+ namespace :env do
28
+ desc "Run #{tname} in the proper environment"
29
+ task tname do |t|
30
+ cd "test" do
31
+ system "./test_env rake #{tname}"
32
+ end
33
+ end
34
+ end
35
+ end
36
+
37
+ load "ruby-dbus-openplacos.gemspec"
38
+
39
+ Rake::GemPackageTask.new(GEMSPEC) do |pkg|
40
+ # no other formats needed
41
+ end
42
+
43
+ Rake::RDocTask.new do |rd|
44
+ rd.rdoc_dir = 'doc/rdoc'
45
+ rd.rdoc_files.include("README", "lib/**/*.rb")
46
+ # rd.options << "--diagram"
47
+ # rd.options << "--all"
48
+ end
49
+
50
+ desc "Render the tutorial in HTML"
51
+ task :tutorial => "doc/tutorial/index.html"
52
+ file "doc/tutorial/index.html" => "doc/tutorial/index.markdown" do |t|
53
+ sh "markdown #{t.prerequisites[0]} > #{t.name}"
54
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.6.0
@@ -0,0 +1,480 @@
1
+ <style>
2
+ code { background-color: #F0E7E7; }
3
+ pre code { background-color: #F0DDDD; }
4
+ pre {
5
+ font-size: 90%;
6
+ overflow: hidden;
7
+ padding-left: 10pt;
8
+ border: thin solid #F0B4B4;
9
+ background-color: #F0DDDD;
10
+ }
11
+ </style>
12
+
13
+ Welcome
14
+ =======
15
+
16
+ This is the Ruby D-Bus tutorial. It aims to show you the features of Ruby
17
+ D-Bus and as you read through the tutorial also how to use them.
18
+
19
+ &copy; Arnaud Cornet and Paul van Tilburg; this tutorial is part of
20
+ free software; you can redistribute it and/or modify it under the
21
+ terms of the [GNU Lesser General Public License,
22
+ version 2.1](http://www.gnu.org/licenses/lgpl.html) as published by the
23
+ [Free Software Foundation](http://www.fsf.org/).
24
+
25
+ Introduction
26
+ ============
27
+
28
+ This is a tutorial for Ruby D-Bus, a library to access D-Bus facilities of your
29
+ system.
30
+
31
+ What is D-Bus?
32
+ --------------
33
+
34
+ D-Bus is an RPC(Remote Procedure Call) protocol. A common setup can have
35
+ multiple D-Bus daemons running that route procedure calls and signals in
36
+ the form of messages. Each of these daemons supports a bus. A bus that
37
+ is often used by modern desktop environments, and is available per session, is
38
+ called the _session bus_. Another bus that can be available, but in a
39
+ system-wide manner, is called the _system bus_. It is used for example by
40
+ the [Hardware Abstraction Layer](http://hal.freedesktop.org/) daemon. Note
41
+ that theoretically the D-Bus RPC protocol can be used without a system or
42
+ session bus. I never came across any actual use of this though.
43
+
44
+ At the desktop level, D-Bus allows some components to interact. Typically
45
+ if you are writing an application or a personal script that wants to
46
+ interact with your web browser, your music player, or that simply wants to
47
+ pop-up a desktop notification, D-Bus comes into play.
48
+
49
+ At the system level, the Hardware Abstraction Layer is a privileged daemon
50
+ that notifies other software of hardware activities. Typically, if you
51
+ want to be notified if a CD-ROM has been loaded in, of if you want to
52
+ explore hardware, the system daemon comes into play.
53
+
54
+ The D-Bus RPC system is as we will see _object oriented_.
55
+
56
+ Buses provide access to _services_ provided in turn by running or ready to
57
+ run processes. Let me introduce some D-Bus terminology before we discuss
58
+ the API of Ruby D-Bus.
59
+
60
+ Client
61
+ ------
62
+
63
+ A D-Bus client is a process that connects to a D-Bus. They issue method
64
+ calls and register to the bus for signals and events.
65
+
66
+ Service
67
+ -------
68
+
69
+ A connected client can export some of its objects and let other clients
70
+ call some of its methods. Such clients typically register a special name
71
+ like `org.freedesktop.Notifications`, the service name.
72
+
73
+ There is slightly different type of service. They are provided by
74
+ processes that can be launched by a D-Bus daemon on demand. Once they are
75
+ started by D-Bus they register a service name and behave like another
76
+ client.
77
+
78
+ Note that the buses themselves provide the `org.freedesktop.DBus` service,
79
+ and provide some features through it.
80
+
81
+ Object path
82
+ -----------
83
+
84
+ An object path is the D-Bus way to specify an object _instance_ address. A
85
+ service can provide different object instances to the outside world, so
86
+ that external processes can call methods on each of them. An object path
87
+ is an address of an instance in a very similar way that the path is an
88
+ address of a file on a file system. For example:
89
+ `/org/freedesktop/Notification` is an object path of an object provided by
90
+ the `org.freedesktop.Notification` service
91
+
92
+ **Beware**: service names and object paths can, but do _not_ have to be
93
+ related! You'll probably encounter a lot of cases though, where the
94
+ object path is a slashed version of the dotted service name.
95
+
96
+ Interface
97
+ ---------
98
+
99
+ Classically in an object model, classes can implement interfaces. That is,
100
+ some method definitions grouped in an interface. This is exactly what a
101
+ D-Bus interface is as well. In D-Bus interfaces have names. These names must be
102
+ specified on method calls.
103
+
104
+ The `org.freedesktop.Notification` service provides an object instance
105
+ called `/org/freedesktop/Notification`. This instance object implements an
106
+ interface called `org.freedesktop.Notifications`. It also provides two
107
+ special D-Bus specific interfaces: `org.freedesktop.DBus.Introspect` and
108
+ `org.freedesktop.DBus.Properties`. Again, object paths, service names,
109
+ and interface names can be related but do not have to be.
110
+
111
+ Basically the `org.freedesktop.DBus.Introspect` has an `Introspect` method,
112
+ that returns XML data describing the `/org/freedesktop/Notification` object
113
+ interfaces. This is used heavily internally by Ruby D-Bus.
114
+
115
+ Method
116
+ ------
117
+
118
+ A method is, well, a method in the classical meaning. It's a function that
119
+ is called in the context of an object instance. Methods have typed
120
+ parameters and return typed return values.
121
+
122
+ Signal
123
+ ------
124
+
125
+ Signals are simplified method calls that do not have a return value. They
126
+ do have typed parameters though.
127
+
128
+ Message
129
+ -------
130
+
131
+ Method calls, method returns, signals, errors: all are encoded as D-Bus
132
+ messages sent over a bus. They are made of a packet header with source and
133
+ destination address, a type (method call, method reply, signal) and the
134
+ body containing the parameters (for signals and method calls) or the return
135
+ values (for a method return message).
136
+
137
+ Signature
138
+ ---------
139
+
140
+ Because D-Bus is typed and dynamic, each message comes with a signature that
141
+ describes the types of the data that is contained within the message. The
142
+ signature is a string with an extremely basic language that only describes
143
+ a data type. You will need to have some knowledge of what a signature
144
+ looks like if you are setting up a service. If you are just programming a
145
+ D-Bus client, you can live without knowing about them.
146
+
147
+ Client Usage
148
+ ============
149
+
150
+ This chapter discusses basic client usage
151
+ and has the following topics:
152
+
153
+ Using the library
154
+ -----------------
155
+
156
+ If you want to use the library, you have to make Ruby load it by issuing:
157
+
158
+ require 'dbus'
159
+
160
+ That's all! Now we can move on to really using it...
161
+
162
+ Connecting to a bus
163
+ -------------------
164
+
165
+ On a typical system, two buses are running, the system bus and the session
166
+ bus. The system bus can be accessed by:
167
+
168
+ bus = DBus::SystemBus.instance
169
+
170
+ Probably you already have guessed how to access the session bus. This
171
+ can be done by:
172
+
173
+ bus = DBus::SessionBus.instance
174
+
175
+ Performing method calls
176
+ -----------------------
177
+
178
+ Let me continue this example using the session bus. Let's say that I want
179
+ to access an object of some client on the session bus. This particular
180
+ D-Bus client provides a service called `org.gnome.Rhythmbox`. Let me
181
+ access this service:
182
+
183
+ rb_service = bus.service("org.gnome.Rhythmbox")
184
+
185
+ In this example I access the `org.gnome.Rhythmbox` service, which is
186
+ provided by the application
187
+ [Rhythmbox](http://www.gnome.org/projects/rhythmbox/).
188
+ OK, I have a service handle now, and I know that it exports the object
189
+ "/org/gnome/Rhythmbox/Player". I will trivially access this remote object
190
+ using:
191
+
192
+ rb_player = rb_service.object("/org/gnome/Rhythmbox/Player")
193
+
194
+ Introspection
195
+ -------------
196
+
197
+ Well, that was easy. Let's say that I know that this particular object is
198
+ introspectable. In real life most of them are. The `rb_object` object we
199
+ have here is just a handle of a remote object, in general they are called
200
+ _proxy objects_, because they are the local handle of a remote object. It
201
+ would be nice to be able to make it have methods, and that its methods send
202
+ a D-Bus call to remotely execute the actual method in another process.
203
+ Well, instating these methods for a _introspectable_ object is trivial:
204
+
205
+ rb_player.introspect
206
+
207
+ And there you go. Note that not all services or objects can be
208
+ introspected, therefore you have to do this manually! Let me remind you
209
+ that objects in D-Bus have interfaces and interfaces have methods. Let's
210
+ now access these methods:
211
+
212
+ rb_player_iface = rb_player["org.gnome.Rhythmbox.Player"]
213
+ puts rb_player_iface.getPlayingUri
214
+
215
+ As you can see, when you want to call a method on an instance object, you have
216
+ to get the correct interface. It is a bit tedious, so we have the following
217
+ shortcut that does the same thing as before:
218
+
219
+ rb_player.default_iface = "org.gnome.Rhythmbox.Player"
220
+ puts rb_player.getPlayingUri
221
+
222
+ The `default_iface=` call specifies the default interface that should be
223
+ used when non existing methods are called directly on a proxy object, and
224
+ not on one of its interfaces.
225
+
226
+ Note that the bus itself has a corresponding introspectable object. You can
227
+ access it with `bus.proxy` method. For example, you can retrieve an array of
228
+ exported service names of a bus like this:
229
+
230
+ bus.proxy.ListNames[0]
231
+
232
+ Properties
233
+ ----------
234
+
235
+ Some D-Bus objects provide access to properties. They are accessed by
236
+ treating a proxy interface as a hash:
237
+
238
+ nm_iface = network_manager_object["org.freedesktop.NetworkManager"]
239
+ enabled = nm_iface["WirelessEnabled"]
240
+ puts "Wireless is " + (enabled ? "enabled":"disabled")
241
+ puts "Toggling wireless"
242
+ nm_iface["WirelessEnabled"] = ! enabled
243
+
244
+
245
+ Calling a method asynchronously
246
+ -------------------------------
247
+
248
+ D-Bus is _asynchronous_. This means that you do not have to wait for a
249
+ reply when you send a message. When you call a remote method that takes a
250
+ lot of time to process remotely, you don't want your application to hang,
251
+ right? Well the asychronousness exists for this reason. What if you dont'
252
+ want to wait for the return value of a method, but still you want to take
253
+ some action when you receive it?
254
+
255
+ There is a classical method to program this event-driven mechanism. You do
256
+ some computation, perform some method call, and at the same time you setup
257
+ a callback that will be triggered once you receive a reply. Then you run a
258
+ main loop that is responsible to call the callbacks properly. Here is how
259
+ you do it:
260
+
261
+ rb_player.getPlayingUri do |resp|
262
+ puts "The playing URI is #{resp}"
263
+ end
264
+ puts "See, I'm not waiting!"
265
+ loop = DBus::Main.new
266
+ loop << bus
267
+ loop.run
268
+
269
+ This code will print the following:
270
+
271
+ See, I'm not waiting!
272
+ The playing URI is file:///music/papapingoin.mp3
273
+
274
+ Waiting for a signal
275
+ --------------------
276
+
277
+ Signals are calls from the remote object to your program. As a client, you
278
+ set yourself up to receive a signal and handle it with a callback. Then running
279
+ the main loop triggers the callback. You can register a callback handler
280
+ as allows:
281
+
282
+ rb_player.on_signal("elapsedChanged") do |u|
283
+ puts u
284
+ end
285
+
286
+ More about introspection
287
+ ------------------------
288
+
289
+ There are various ways to inspect a remote service. You can simply call
290
+ `Introspect()` and read the XML output. However, in this tutorial I assume
291
+ that you want to do it using the Ruby D-Bus API.
292
+
293
+ Notice that you can introspect a service, and not only objects:
294
+
295
+ rb_service = bus.service("org.gnome.Rhythmbox")
296
+ rb_service.introspect
297
+ p rb_service.root
298
+
299
+ This dumps a tree-like structure that represents multiple object paths. In
300
+ this particular case the output is:
301
+
302
+ </: {org => {gnome => {Rhythmbox => {Player => ..fdbe625de {},Shell => ..fdbe6852e {},PlaylistManager => ..fdbe4e340 {}}>
303
+
304
+ Read this left to right: the root node is "/", it has one child node "org",
305
+ "org" has one child node "gnome", and "gnome" has one child node "Rhythmbox".
306
+ Rhythmbox has Tree child nodes "Player", "Shell" and "PlaylistManager".
307
+ These three last child nodes have a weird digit that means it has an object
308
+ instance. Such object instances are already introspected.
309
+
310
+ If the prose wasn't clear, maybe the following ASCII art will help you:
311
+
312
+ /
313
+ org
314
+ gnome
315
+ Rhythmbox
316
+ Shell (with object)
317
+ Player (with object)
318
+ PlaylistManager (with object)
319
+
320
+ ### Walking the object tree
321
+
322
+ You can have an object on any node, i.e. it is not limited to leaves.
323
+ You can access a specific node like this:
324
+
325
+ rb_player = rb_service.root["org"]["gnome"]["Rhythmbox"]["Player"]
326
+ rb_player = rb_service.object("/org/gnome/Rhythmbox/Player")
327
+
328
+ The difference between the two is that for the first one, `rb_service`
329
+ needs to have been introspected. Also the obtained `rb_player` is already
330
+ introspected whereas the second `rb_player` isn't yet.
331
+
332
+ Errors
333
+ ------
334
+
335
+ D-Bus calls can reply with an error instead of a return value. An error is
336
+ translated to a Ruby exception.
337
+
338
+ begin
339
+ network_manager.sleep
340
+ rescue DBus::Error => e
341
+ puts e unless e.name == "org.freedesktop.NetworkManager.AlreadyAsleepOrAwake"
342
+ end
343
+
344
+ Creating a Service
345
+ ==================
346
+
347
+ This chapter deals with the opposite side of the basic client usage, namely
348
+ the creation of a D-Bus service.
349
+
350
+ Registering a service
351
+ ---------------------
352
+
353
+ Now that you know how to perform D-Bus calls, and how to wait for and
354
+ handle signals, you might want to learn how to publish some object and
355
+ interface to provide them to the D-Bus world. Here is how you do that.
356
+
357
+ As you should already know, D-Bus clients that provide some object to be
358
+ called remotely are services. Here is how to allocate a name on a bus:
359
+
360
+ bus = DBus.session_bus
361
+ service = bus.request_service("org.ruby.service")
362
+
363
+ Now this client is know to the outside world as `org.ruby.service`.
364
+ Note that this is a request and it _can_ be denied! When it
365
+ is denied, an exception (`DBus::NameRequestError`) is thrown.
366
+
367
+ Exporting an object
368
+ -------------------
369
+
370
+ Now, let's define a class that we want to export:
371
+
372
+ class Test < DBus::Object
373
+ # Create an interface.
374
+ dbus_interface "org.ruby.SampleInterface" do
375
+ # Create a hello method in that interface.
376
+ dbus_method :hello, "in name:s, in name2:s" do |name, name2|
377
+ puts "hello(#{name}, #{name2})"
378
+ end
379
+ end
380
+ end
381
+
382
+ As you can see, we define a `Test` class in which we define a
383
+ `org.ruby.SampleInterface` interface. In this interface, we define a
384
+ method. The given code block is the method's implementation. This will be
385
+ executed when remote programs performs a D-Bus call. Now the annoying part:
386
+ the actual method definition. As you can guess the call
387
+
388
+ dbus_method :hello, "in name:s, in name2:s" do ...
389
+
390
+ creates a `hello` method that takes two parameters both of type string.
391
+ The _:s_ means "of type string". Let's have a look at some other common
392
+ parameter types:
393
+
394
+ - *u* means unsigned integer
395
+ - *i* means integer
396
+ - *y* means byte
397
+ - *(ui)* means a structure having a unsigned integer and a signed one.
398
+ - *a* means array, so that "ai" means array of integers
399
+ - *as* means array of string
400
+ - *a(is)* means array of structures, each having an integer and a string.
401
+
402
+ For a full description of the available D-Bus types, please refer to the
403
+ [D-Bus specification](http://dbus.freedesktop.org/doc/dbus-specification.html#message-protocol-signatures).
404
+
405
+ Now that the class has been defined, we can instantiate an object
406
+ and export it as follows:
407
+
408
+ exported_obj = Test.new("/org/ruby/MyInstance")
409
+ service.export(exported_obj)
410
+
411
+ This piece of code above instantiates a `Test` object with a D-Bus object
412
+ path. This object is reachable from the outside world after
413
+ `service.export(exported_obj)` is called.
414
+
415
+ We also need a loop which will read and process the calls coming over the bus:
416
+
417
+ loop = DBus::Main.new
418
+ loop << bus
419
+ loop.run
420
+
421
+ ### Using the exported object
422
+
423
+ Now, let's consider another program that will access our newly created service:
424
+
425
+ ruby_service = bus.service("org.ruby.service")
426
+ obj = ruby_service.object("/org/ruby/MyInstance")
427
+ obj.introspect
428
+ obj.default_iface = "org.ruby.SampleInterface"
429
+ obj.hello("giligiligiligili", "haaaaaaa")
430
+
431
+ As you can see, the object we defined earlier is automatically introspectable.
432
+ See also "Basic Client Usage".
433
+
434
+ Emitting a signal
435
+ -----------------
436
+
437
+ Let's add some example method so you can see how to return a value to the
438
+ caller and let's also define another example interface that has a signal.
439
+
440
+ class Test2 < DBus::Object
441
+ # Create an interface
442
+ dbus_interface "org.ruby.SampleInterface" do
443
+ # Create a hello method in the interface:
444
+ dbus_method :hello, "in name:s, in name2:s" do |name, name2|
445
+ puts "hello(#{name}, #{name2})"
446
+ end
447
+ # Define a signal in the interface:
448
+ dbus_signal :SomethingJustHappened, "toto:s, tutu:u"
449
+ end
450
+
451
+ dbus_interface "org.ruby.AnotherInterface" do
452
+ dbus_method :ThatsALongMethodNameIThink, "in name:s, out ret:s" do |name|
453
+ ["So your name is #{name}"]
454
+ end
455
+ end
456
+ end
457
+
458
+ Triggering the signal is a easy as calling a method, but then this time on
459
+ a local (exported) object and not on a remote/proxy object:
460
+
461
+ exported_obj.SomethingJustHappened("blah", 1)
462
+
463
+ Note that the `ThatsALongMethodNameIThink` method is returning a single
464
+ value to the caller. Notice that you always have to return an array. If
465
+ you want to return multiple values, just have an array with multiple
466
+ values.
467
+
468
+ Replying with an error
469
+ ----------------------
470
+
471
+ To reply to a dbus_method with a D-Bus error, raise a `DBus::Error`,
472
+ as constructed by the `error` convenience function:
473
+
474
+ raise DBus.error("org.example.Error.SeatOccupied"), "Seat #{seat} is occupied"
475
+
476
+ If the error name is not specified, the generic
477
+ `org.freedesktop.DBus.Error.Failed` is used.
478
+
479
+ raise DBus.error, "Seat #{seat} is occupied"
480
+ raise DBus.error