em-ruby-dbus 0.11.0

Sign up to get free protection for your applications and to get access to all the features.
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
+