em-ruby-dbus 0.11.0

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.
Files changed (76) hide show
  1. checksums.yaml +7 -0
  2. data/COPYING +504 -0
  3. data/NEWS +253 -0
  4. data/README.md +93 -0
  5. data/Rakefile +58 -0
  6. data/VERSION +1 -0
  7. data/doc/Reference.md +207 -0
  8. data/doc/Tutorial.md +480 -0
  9. data/doc/ex-calling-methods.body.rb +8 -0
  10. data/doc/ex-calling-methods.rb +3 -0
  11. data/doc/ex-properties.body.rb +9 -0
  12. data/doc/ex-properties.rb +3 -0
  13. data/doc/ex-setup.rb +7 -0
  14. data/doc/ex-signal.body.rb +20 -0
  15. data/doc/ex-signal.rb +3 -0
  16. data/doc/example-helper.rb +6 -0
  17. data/em-ruby-dbus.gemspec +20 -0
  18. data/examples/gdbus/gdbus +255 -0
  19. data/examples/gdbus/gdbus.glade +184 -0
  20. data/examples/gdbus/launch.sh +4 -0
  21. data/examples/no-introspect/nm-test.rb +21 -0
  22. data/examples/no-introspect/tracker-test.rb +16 -0
  23. data/examples/rhythmbox/playpause.rb +25 -0
  24. data/examples/service/call_service.rb +25 -0
  25. data/examples/service/service_newapi.rb +51 -0
  26. data/examples/simple/call_introspect.rb +34 -0
  27. data/examples/simple/properties.rb +19 -0
  28. data/examples/utils/listnames.rb +11 -0
  29. data/examples/utils/notify.rb +19 -0
  30. data/lib/dbus.rb +82 -0
  31. data/lib/dbus/auth.rb +269 -0
  32. data/lib/dbus/bus.rb +739 -0
  33. data/lib/dbus/core_ext/array/extract_options.rb +31 -0
  34. data/lib/dbus/core_ext/class/attribute.rb +129 -0
  35. data/lib/dbus/core_ext/kernel/singleton_class.rb +8 -0
  36. data/lib/dbus/core_ext/module/remove_method.rb +14 -0
  37. data/lib/dbus/error.rb +46 -0
  38. data/lib/dbus/export.rb +128 -0
  39. data/lib/dbus/introspect.rb +219 -0
  40. data/lib/dbus/logger.rb +31 -0
  41. data/lib/dbus/loop-em.rb +19 -0
  42. data/lib/dbus/marshall.rb +434 -0
  43. data/lib/dbus/matchrule.rb +101 -0
  44. data/lib/dbus/message.rb +276 -0
  45. data/lib/dbus/message_queue.rb +166 -0
  46. data/lib/dbus/proxy_object.rb +149 -0
  47. data/lib/dbus/proxy_object_factory.rb +41 -0
  48. data/lib/dbus/proxy_object_interface.rb +128 -0
  49. data/lib/dbus/type.rb +193 -0
  50. data/lib/dbus/xml.rb +161 -0
  51. data/test/async_spec.rb +47 -0
  52. data/test/binding_spec.rb +74 -0
  53. data/test/bus_and_xml_backend_spec.rb +39 -0
  54. data/test/bus_driver_spec.rb +20 -0
  55. data/test/bus_spec.rb +20 -0
  56. data/test/byte_array_spec.rb +38 -0
  57. data/test/err_msg_spec.rb +42 -0
  58. data/test/introspect_xml_parser_spec.rb +26 -0
  59. data/test/introspection_spec.rb +32 -0
  60. data/test/main_loop_spec.rb +82 -0
  61. data/test/property_spec.rb +53 -0
  62. data/test/server_robustness_spec.rb +66 -0
  63. data/test/server_spec.rb +53 -0
  64. data/test/service_newapi.rb +217 -0
  65. data/test/session_bus_spec_manual.rb +15 -0
  66. data/test/signal_spec.rb +90 -0
  67. data/test/spec_helper.rb +33 -0
  68. data/test/thread_safety_spec.rb +31 -0
  69. data/test/tools/dbus-launch-simple +35 -0
  70. data/test/tools/dbus-limited-session.conf +28 -0
  71. data/test/tools/test_env +13 -0
  72. data/test/tools/test_server +39 -0
  73. data/test/type_spec.rb +19 -0
  74. data/test/value_spec.rb +81 -0
  75. data/test/variant_spec.rb +66 -0
  76. metadata +145 -0
@@ -0,0 +1,31 @@
1
+ # copied from activesupport/core_ext from Rails, MIT license
2
+ # https://github.com/rails/rails/tree/5aa869861c192daceafe3a3ee50eb93f5a2b7bd2/activesupport/lib/active_support/core_ext
3
+ class Hash
4
+ # By default, only instances of Hash itself are extractable.
5
+ # Subclasses of Hash may implement this method and return
6
+ # true to declare themselves as extractable. If a Hash
7
+ # is extractable, Array#extract_options! pops it from
8
+ # the Array when it is the last element of the Array.
9
+ def extractable_options?
10
+ instance_of?(Hash)
11
+ end
12
+ end
13
+
14
+ class Array
15
+ # Extracts options from a set of arguments. Removes and returns the last
16
+ # element in the array if it's a hash, otherwise returns a blank hash.
17
+ #
18
+ # def options(*args)
19
+ # args.extract_options!
20
+ # end
21
+ #
22
+ # options(1, 2) # => {}
23
+ # options(1, 2, a: :b) # => {:a=>:b}
24
+ def extract_options!
25
+ if last.is_a?(Hash) && last.extractable_options?
26
+ pop
27
+ else
28
+ {}
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,129 @@
1
+ # copied from activesupport/core_ext from Rails, MIT license
2
+ # https://github.com/rails/rails/tree/5aa869861c192daceafe3a3ee50eb93f5a2b7bd2/activesupport/lib/active_support/core_ext
3
+ require 'dbus/core_ext/kernel/singleton_class'
4
+ require 'dbus/core_ext/module/remove_method'
5
+ require 'dbus/core_ext/array/extract_options'
6
+
7
+ class Class
8
+ # Declare a class-level attribute whose value is inheritable by subclasses.
9
+ # Subclasses can change their own value and it will not impact parent class.
10
+ #
11
+ # class Base
12
+ # class_attribute :setting
13
+ # end
14
+ #
15
+ # class Subclass < Base
16
+ # end
17
+ #
18
+ # Base.setting = true
19
+ # Subclass.setting # => true
20
+ # Subclass.setting = false
21
+ # Subclass.setting # => false
22
+ # Base.setting # => true
23
+ #
24
+ # In the above case as long as Subclass does not assign a value to setting
25
+ # by performing <tt>Subclass.setting = _something_ </tt>, <tt>Subclass.setting</tt>
26
+ # would read value assigned to parent class. Once Subclass assigns a value then
27
+ # the value assigned by Subclass would be returned.
28
+ #
29
+ # This matches normal Ruby method inheritance: think of writing an attribute
30
+ # on a subclass as overriding the reader method. However, you need to be aware
31
+ # when using +class_attribute+ with mutable structures as +Array+ or +Hash+.
32
+ # In such cases, you don't want to do changes in places but use setters:
33
+ #
34
+ # Base.setting = []
35
+ # Base.setting # => []
36
+ # Subclass.setting # => []
37
+ #
38
+ # # Appending in child changes both parent and child because it is the same object:
39
+ # Subclass.setting << :foo
40
+ # Base.setting # => [:foo]
41
+ # Subclass.setting # => [:foo]
42
+ #
43
+ # # Use setters to not propagate changes:
44
+ # Base.setting = []
45
+ # Subclass.setting += [:foo]
46
+ # Base.setting # => []
47
+ # Subclass.setting # => [:foo]
48
+ #
49
+ # For convenience, an instance predicate method is defined as well.
50
+ # To skip it, pass <tt>instance_predicate: false</tt>.
51
+ #
52
+ # Subclass.setting? # => false
53
+ #
54
+ # Instances may overwrite the class value in the same way:
55
+ #
56
+ # Base.setting = true
57
+ # object = Base.new
58
+ # object.setting # => true
59
+ # object.setting = false
60
+ # object.setting # => false
61
+ # Base.setting # => true
62
+ #
63
+ # To opt out of the instance reader method, pass <tt>instance_reader: false</tt>.
64
+ #
65
+ # object.setting # => NoMethodError
66
+ # object.setting? # => NoMethodError
67
+ #
68
+ # To opt out of the instance writer method, pass <tt>instance_writer: false</tt>.
69
+ #
70
+ # object.setting = false # => NoMethodError
71
+ #
72
+ # To opt out of both instance methods, pass <tt>instance_accessor: false</tt>.
73
+ def class_attribute(*attrs)
74
+ options = attrs.extract_options!
75
+ instance_reader = options.fetch(:instance_accessor, true) && options.fetch(:instance_reader, true)
76
+ instance_writer = options.fetch(:instance_accessor, true) && options.fetch(:instance_writer, true)
77
+ instance_predicate = options.fetch(:instance_predicate, true)
78
+
79
+ attrs.each do |name|
80
+ define_singleton_method(name) { nil }
81
+ define_singleton_method("#{name}?") { !!public_send(name) } if instance_predicate
82
+
83
+ ivar = "@#{name}"
84
+
85
+ define_singleton_method("#{name}=") do |val|
86
+ singleton_class.class_eval do
87
+ remove_possible_method(name)
88
+ define_method(name) { val }
89
+ end
90
+
91
+ if singleton_class?
92
+ class_eval do
93
+ remove_possible_method(name)
94
+ define_method(name) do
95
+ if instance_variable_defined? ivar
96
+ instance_variable_get ivar
97
+ else
98
+ singleton_class.send name
99
+ end
100
+ end
101
+ end
102
+ end
103
+ val
104
+ end
105
+
106
+ if instance_reader
107
+ remove_possible_method name
108
+ define_method(name) do
109
+ if instance_variable_defined?(ivar)
110
+ instance_variable_get ivar
111
+ else
112
+ self.class.public_send name
113
+ end
114
+ end
115
+ define_method("#{name}?") { !!public_send(name) } if instance_predicate
116
+ end
117
+
118
+ attr_writer name if instance_writer
119
+ end
120
+ end
121
+
122
+ private
123
+
124
+ unless respond_to?(:singleton_class?)
125
+ def singleton_class?
126
+ ancestors.first != self
127
+ end
128
+ end
129
+ end
@@ -0,0 +1,8 @@
1
+ # copied from activesupport/core_ext from Rails, MIT license
2
+ # https://github.com/rails/rails/tree/5aa869861c192daceafe3a3ee50eb93f5a2b7bd2/activesupport/lib/active_support/core_ext
3
+ module Kernel
4
+ # class_eval on an object acts like singleton_class.class_eval.
5
+ def class_eval(*args, &block)
6
+ singleton_class.class_eval(*args, &block)
7
+ end
8
+ end
@@ -0,0 +1,14 @@
1
+ # copied from activesupport/core_ext from Rails, MIT license
2
+ # https://github.com/rails/rails/tree/5aa869861c192daceafe3a3ee50eb93f5a2b7bd2/activesupport/lib/active_support/core_ext
3
+ class Module
4
+ def remove_possible_method(method)
5
+ if method_defined?(method) || private_method_defined?(method)
6
+ undef_method(method)
7
+ end
8
+ end
9
+
10
+ def redefine_method(method, &block)
11
+ remove_possible_method(method)
12
+ define_method(method, &block)
13
+ end
14
+ end
data/lib/dbus/error.rb ADDED
@@ -0,0 +1,46 @@
1
+ # error.rb
2
+ #
3
+ # This file is part of the ruby-dbus project
4
+ # Copyright (C) 2007 Arnaud Cornet and Paul van Tilburg
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
+ # Represents a D-Bus Error, both on the client and server side.
13
+ class Error < StandardError
14
+ # error_name. +message+ is inherited from +Exception+
15
+ attr_reader :name
16
+ # for received errors, the raw D-Bus message
17
+ attr_reader :dbus_message
18
+
19
+ # If +msg+ is a +DBus::Message+, its contents is used for initialization.
20
+ # Otherwise, +msg+ is taken as a string and +name+ is used.
21
+ def initialize(msg, name = "org.freedesktop.DBus.Error.Failed")
22
+ if msg.is_a? DBus::Message
23
+ @dbus_message = msg
24
+ @name = msg.error_name
25
+ super(msg.params[0]) # or nil
26
+ if msg.params[1].is_a? Array
27
+ set_backtrace msg.params[1]
28
+ end
29
+ else
30
+ @name = name
31
+ super(msg)
32
+ end
33
+ # TODO validate error name
34
+ end
35
+ end # class Error
36
+
37
+ # @example raise a generic error
38
+ # raise DBus.error, "message"
39
+ # @example raise a specific error
40
+ # raise DBus.error("org.example.Error.SeatOccupied"), "Seat #{n} is occupied"
41
+ def error(name = "org.freedesktop.DBus.Error.Failed")
42
+ # message will be set by Kernel.raise
43
+ DBus::Error.new(nil, name)
44
+ end
45
+ module_function :error
46
+ end # module DBus
@@ -0,0 +1,128 @@
1
+ # dbus/introspection.rb - module containing a low-level D-Bus introspection implementation
2
+ #
3
+ # This file is part of the ruby-dbus project
4
+ # Copyright (C) 2007 Arnaud Cornet and Paul van Tilburg
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
+ require 'thread'
12
+
13
+ module DBus
14
+ # Exported object type
15
+ # = Exportable D-Bus object class
16
+ #
17
+ # Objects that are going to be exported by a D-Bus service
18
+ # should inherit from this class. At the client side, use ProxyObject.
19
+ class Object
20
+ # The path of the object.
21
+ attr_reader :path
22
+ # The interfaces that the object supports. Hash: String => Interface
23
+ class_attribute :intfs
24
+ # The service that the object is exported by.
25
+ attr_writer :service
26
+
27
+ @@cur_intf = nil # Interface
28
+ @@intfs_mutex = Mutex.new
29
+
30
+ # Create a new object with a given _path_.
31
+ # Use Service#export to export it.
32
+ def initialize(path)
33
+ @path = path
34
+ @service = nil
35
+ end
36
+
37
+ # State that the object implements the given _intf_.
38
+ def implements(intf)
39
+ # use a setter
40
+ self.intfs = (self.intfs || {}).merge({intf.name => intf})
41
+ end
42
+
43
+ # Dispatch a message _msg_ to call exported methods
44
+ def dispatch(msg)
45
+ case msg.message_type
46
+ when Message::METHOD_CALL
47
+ reply = nil
48
+ begin
49
+ if not self.intfs[msg.interface]
50
+ raise DBus.error("org.freedesktop.DBus.Error.UnknownMethod"),
51
+ "Interface \"#{msg.interface}\" of object \"#{msg.path}\" doesn't exist"
52
+ end
53
+ meth = self.intfs[msg.interface].methods[msg.member.to_sym]
54
+ if not meth
55
+ raise DBus.error("org.freedesktop.DBus.Error.UnknownMethod"),
56
+ "Method \"#{msg.member}\" on interface \"#{msg.interface}\" of object \"#{msg.path}\" doesn't exist"
57
+ end
58
+ methname = Object.make_method_name(msg.interface, msg.member)
59
+ retdata = method(methname).call(*msg.params)
60
+ retdata = [*retdata]
61
+
62
+ reply = Message.method_return(msg)
63
+ meth.rets.zip(retdata).each do |rsig, rdata|
64
+ reply.add_param(rsig.type, rdata)
65
+ end
66
+ rescue => ex
67
+ dbus_msg_exc = msg.annotate_exception(ex)
68
+ reply = ErrorMessage.from_exception(dbus_msg_exc).reply_to(msg)
69
+ end
70
+ @service.bus.message_queue.push(reply)
71
+ end
72
+ end
73
+
74
+ # Select (and create) the interface that the following defined methods
75
+ # belong to.
76
+ def self.dbus_interface(s)
77
+ @@intfs_mutex.synchronize do
78
+ unless @@cur_intf = (self.intfs && self.intfs[s])
79
+ @@cur_intf = Interface.new(s)
80
+ self.intfs = (self.intfs || {}).merge({s => @@cur_intf})
81
+ end
82
+ yield
83
+ @@cur_intf = nil
84
+ end
85
+ end
86
+
87
+ # Dummy undefined interface class.
88
+ class UndefinedInterface < ScriptError
89
+ def initialize(sym)
90
+ super "No interface specified for #{sym}"
91
+ end
92
+ end
93
+
94
+ # Defines an exportable method on the object with the given name _sym_,
95
+ # _prototype_ and the code in a block.
96
+ def self.dbus_method(sym, protoype = "", &block)
97
+ raise UndefinedInterface, sym if @@cur_intf.nil?
98
+ @@cur_intf.define(Method.new(sym.to_s).from_prototype(protoype))
99
+ define_method(Object.make_method_name(@@cur_intf.name, sym.to_s), &block)
100
+ end
101
+
102
+ # Emits a signal from the object with the given _interface_, signal
103
+ # _sig_ and arguments _args_.
104
+ def emit(intf, sig, *args)
105
+ @service.bus.emit(@service, self, intf, sig, *args)
106
+ end
107
+
108
+ # Defines a signal for the object with a given name _sym_ and _prototype_.
109
+ def self.dbus_signal(sym, protoype = "")
110
+ raise UndefinedInterface, sym if @@cur_intf.nil?
111
+ cur_intf = @@cur_intf
112
+ signal = Signal.new(sym.to_s).from_prototype(protoype)
113
+ cur_intf.define(Signal.new(sym.to_s).from_prototype(protoype))
114
+ define_method(sym.to_s) do |*args|
115
+ emit(cur_intf, signal, *args)
116
+ end
117
+ end
118
+
119
+ ####################################################################
120
+ private
121
+
122
+ # Helper method that returns a method name generated from the interface
123
+ # name _intfname_ and method name _methname_.
124
+ def self.make_method_name(intfname, methname)
125
+ "#{intfname}%%#{methname}"
126
+ end
127
+ end # class Object
128
+ end # module DBus
@@ -0,0 +1,219 @@
1
+ # dbus/introspection.rb - module containing a low-level D-Bus introspection implementation
2
+ #
3
+ # This file is part of the ruby-dbus project
4
+ # Copyright (C) 2007 Arnaud Cornet and Paul van Tilburg
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
+ # Regular expressions that should match all method names.
13
+ MethodSignalRE = /^[A-Za-z][A-Za-z0-9_]*$/
14
+ # Regular expressions that should match all interface names.
15
+ InterfaceElementRE = /^[A-Za-z][A-Za-z0-9_]*$/
16
+
17
+ # Exception raised when an unknown signal is used.
18
+ class UnknownSignal < Exception
19
+ end
20
+
21
+ # Exception raised when an invalid class definition is encountered.
22
+ class InvalidClassDefinition < Exception
23
+ end
24
+
25
+ # = D-Bus interface class
26
+ #
27
+ # This class is the interface descriptor. In most cases, the Introspect()
28
+ # method call instantiates and configures this class for us.
29
+ #
30
+ # It also is the local definition of interface exported by the program.
31
+ # At the client side, see ProxyObjectInterface
32
+ class Interface
33
+ # The name of the interface. String
34
+ attr_reader :name
35
+ # The methods that are part of the interface. Hash: Symbol => DBus::Method
36
+ attr_reader :methods
37
+ # The signals that are part of the interface. Hash: Symbol => Signal
38
+ attr_reader :signals
39
+
40
+ # Creates a new interface with a given _name_.
41
+ def initialize(name)
42
+ validate_name(name)
43
+ @name = name
44
+ @methods, @signals = Hash.new, Hash.new
45
+ end
46
+
47
+ # Validates a service _name_.
48
+ def validate_name(name)
49
+ raise InvalidIntrospectionData if name.bytesize > 255
50
+ raise InvalidIntrospectionData if name =~ /^\./ or name =~ /\.$/
51
+ raise InvalidIntrospectionData if name =~ /\.\./
52
+ raise InvalidIntrospectionData if not name =~ /\./
53
+ name.split(".").each do |element|
54
+ raise InvalidIntrospectionData if not element =~ InterfaceElementRE
55
+ end
56
+ end
57
+
58
+ # Helper method for defining a method _m_.
59
+ def define(m)
60
+ if m.kind_of?(Method)
61
+ @methods[m.name.to_sym] = m
62
+ elsif m.kind_of?(Signal)
63
+ @signals[m.name.to_sym] = m
64
+ end
65
+ end
66
+ alias :<< :define
67
+
68
+ # Defines a method with name _id_ and a given _prototype_ in the
69
+ # interface.
70
+ def define_method(id, prototype)
71
+ m = Method.new(id)
72
+ m.from_prototype(prototype)
73
+ define(m)
74
+ end
75
+ end # class Interface
76
+
77
+ # = A formal parameter has a name and a type
78
+ class FormalParameter
79
+ attr_reader :name
80
+ attr_reader :type
81
+
82
+ def initialize(name, type)
83
+ @name = name
84
+ @type = type
85
+ end
86
+
87
+ # backward compatibility, deprecated
88
+ def [](index)
89
+ case index
90
+ when 0 then name
91
+ when 1 then type
92
+ else nil
93
+ end
94
+ end
95
+ end
96
+
97
+ # = D-Bus interface element class
98
+ #
99
+ # This is a generic class for entities that are part of the interface
100
+ # such as methods and signals.
101
+ class InterfaceElement
102
+ # The name of the interface element. Symbol
103
+ attr_reader :name
104
+ # The parameters of the interface element. Array: FormalParameter
105
+ attr_reader :params
106
+
107
+ # Validates element _name_.
108
+ def validate_name(name)
109
+ if (not name =~ MethodSignalRE) or (name.bytesize > 255)
110
+ raise InvalidMethodName, name
111
+ end
112
+ end
113
+
114
+ # Creates a new element with the given _name_.
115
+ def initialize(name)
116
+ validate_name(name.to_s)
117
+ @name = name
118
+ @params = Array.new
119
+ end
120
+
121
+ # Adds a formal parameter with _name_ and _signature_
122
+ # (See also Message#add_param which takes signature+value)
123
+ def add_fparam(name, signature)
124
+ @params << FormalParameter.new(name, signature)
125
+ end
126
+
127
+ # Deprecated, for backward compatibility
128
+ def add_param(name_signature_pair)
129
+ add_fparam(*name_signature_pair)
130
+ end
131
+ end # class InterfaceElement
132
+
133
+ # = D-Bus interface method class
134
+ #
135
+ # This is a class representing methods that are part of an interface.
136
+ class Method < InterfaceElement
137
+ # The list of return values for the method. Array: FormalParameter
138
+ attr_reader :rets
139
+
140
+ # Creates a new method interface element with the given _name_.
141
+ def initialize(name)
142
+ super(name)
143
+ @rets = Array.new
144
+ end
145
+
146
+ # Add a return value _name_ and _signature_.
147
+ def add_return(name, signature)
148
+ @rets << FormalParameter.new(name, signature)
149
+ end
150
+
151
+ # Add parameter types by parsing the given _prototype_.
152
+ def from_prototype(prototype)
153
+ prototype.split(/, */).each do |arg|
154
+ arg = arg.split(" ")
155
+ raise InvalidClassDefinition if arg.size != 2
156
+ dir, arg = arg
157
+ if arg =~ /:/
158
+ arg = arg.split(":")
159
+ name, sig = arg
160
+ else
161
+ sig = arg
162
+ end
163
+ case dir
164
+ when "in"
165
+ add_fparam(name, sig)
166
+ when "out"
167
+ add_return(name, sig)
168
+ end
169
+ end
170
+ self
171
+ end
172
+
173
+ # Return an XML string representation of the method interface elment.
174
+ def to_xml
175
+ xml = %{<method name="#{@name}">\n}
176
+ @params.each do |param|
177
+ name = param.name ? %{name="#{param.name}" } : ""
178
+ xml += %{<arg #{name}direction="in" type="#{param.type}"/>\n}
179
+ end
180
+ @rets.each do |param|
181
+ name = param.name ? %{name="#{param.name}" } : ""
182
+ xml += %{<arg #{name}direction="out" type="#{param.type}"/>\n}
183
+ end
184
+ xml += %{</method>\n}
185
+ xml
186
+ end
187
+ end # class Method
188
+
189
+ # = D-Bus interface signal class
190
+ #
191
+ # This is a class representing signals that are part of an interface.
192
+ class Signal < InterfaceElement
193
+ # Add parameter types based on the given _prototype_.
194
+ def from_prototype(prototype)
195
+ prototype.split(/, */).each do |arg|
196
+ if arg =~ /:/
197
+ arg = arg.split(":")
198
+ name, sig = arg
199
+ else
200
+ sig = arg
201
+ end
202
+ add_fparam(name, sig)
203
+ end
204
+ self
205
+ end
206
+
207
+ # Return an XML string representation of the signal interface elment.
208
+ def to_xml
209
+ xml = %{<signal name="#{@name}">\n}
210
+ @params.each do |param|
211
+ name = param.name ? %{name="#{param.name}" } : ""
212
+ xml += %{<arg #{name}type="#{param.type}"/>\n}
213
+ end
214
+ xml += %{</signal>\n}
215
+ xml
216
+ end
217
+ end # class Signal
218
+ end # module DBus
219
+