ruby-dbus 0.8.0 → 0.9.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.
@@ -3,7 +3,7 @@
3
3
  # This file is part of the ruby-dbus project
4
4
  # Copyright (C) 2007 Arnaud Cornet and Paul van Tilburg
5
5
  #
6
- # This library is free software; you can redistribute it and/or
6
+ # This library is free software; you caan redistribute it and/or
7
7
  # modify it under the terms of the GNU Lesser General Public
8
8
  # License, version 2.1 as published by the Free Software Foundation.
9
9
  # See the file "COPYING" for the exact licensing terms.
@@ -49,7 +49,8 @@ module DBus
49
49
  self
50
50
  end
51
51
 
52
- # Retrieves an object (ProxyObject) at the given _path_.
52
+ # Retrieves an object at the given _path_.
53
+ # @return [ProxyObject]
53
54
  def object(path)
54
55
  node = get_node(path, true)
55
56
  if node.object.nil?
@@ -95,7 +96,7 @@ module DBus
95
96
  n = n[elem]
96
97
  end
97
98
  if n.nil?
98
- puts "Warning, unknown object #{path}" if $DEBUG
99
+ DBus.logger.debug "Warning, unknown object #{path}"
99
100
  end
100
101
  n
101
102
  end
@@ -248,7 +249,7 @@ module DBus
248
249
  @is_tcp = true
249
250
  rescue
250
251
  puts "Error: Could not establish connection to: #{@path}, will now exit."
251
- exit(0) #a little harsh
252
+ exit(1) #a little harsh
252
253
  end
253
254
  else
254
255
  #Danger, Will Robinson: the specified "path" is not usable
@@ -469,6 +470,7 @@ module DBus
469
470
  #
470
471
  # FIXME, NameRequestError cannot really be rescued as it will be raised
471
472
  # when dispatching a later call. Rework the API to better match the spec.
473
+ # @return [Service]
472
474
  def request_service(name)
473
475
  # Use RequestName, but asynchronously!
474
476
  # A synchronous call would not work with service activation, where
@@ -598,10 +600,10 @@ module DBus
598
600
  def add_match(mr, &slot)
599
601
  # check this is a signal.
600
602
  mrs = mr.to_s
601
- puts "#{@signal_matchrules.size} rules, adding #{mrs.inspect}" if $DEBUG
603
+ DBus.logger.debug "#{@signal_matchrules.size} rules, adding #{mrs.inspect}"
602
604
  # don't ask for the same match if we override it
603
605
  unless @signal_matchrules.key?(mrs)
604
- puts "Asked for a new match" if $DEBUG
606
+ DBus.logger.debug "Asked for a new match"
605
607
  proxy.AddMatch(mrs)
606
608
  end
607
609
  @signal_matchrules[mrs] = slot
@@ -625,7 +627,7 @@ module DBus
625
627
  raise InvalidPacketException if m.reply_serial == nil
626
628
  mcs = @method_call_replies[m.reply_serial]
627
629
  if not mcs
628
- puts "DEBUG: no return code for mcs: #{mcs.inspect} m: #{m.inspect}" if $DEBUG
630
+ DBus.logger.debug "no return code for mcs: #{mcs.inspect} m: #{m.inspect}"
629
631
  else
630
632
  if m.message_type == Message::ERROR
631
633
  mcs.call(Error.new(m))
@@ -637,7 +639,7 @@ module DBus
637
639
  end
638
640
  when DBus::Message::METHOD_CALL
639
641
  if m.path == "/org/freedesktop/DBus"
640
- puts "DEBUG: Got method call on /org/freedesktop/DBus" if $DEBUG
642
+ DBus.logger.debug "Got method call on /org/freedesktop/DBus"
641
643
  end
642
644
  node = @service.get_node(m.path)
643
645
  if not node
@@ -664,11 +666,12 @@ module DBus
664
666
  end
665
667
  end
666
668
  else
667
- puts "DEBUG: Unknown message type: #{m.message_type}" if $DEBUG
669
+ DBus.logger.debug "Unknown message type: #{m.message_type}"
668
670
  end
669
671
  end
670
672
 
671
673
  # Retrieves the Service with the given _name_.
674
+ # @return [Service]
672
675
  def service(name)
673
676
  # The service might not exist at this time so we cannot really check
674
677
  # anything
@@ -704,7 +707,7 @@ module DBus
704
707
  m.member = "Hello"
705
708
  send_sync(m) do |rmsg|
706
709
  @unique_name = rmsg.destination
707
- puts "Got hello reply. Our unique_name is #{@unique_name}" if $DEBUG
710
+ DBus.logger.debug "Got hello reply. Our unique_name is #{@unique_name}"
708
711
  end
709
712
  @service = Service.new(@unique_name, self)
710
713
  end
@@ -794,12 +797,14 @@ module DBus
794
797
  include Singleton
795
798
  end
796
799
 
797
- # Shortcut for the SystemBus instance
800
+ # Shortcut for the {SystemBus} instance
801
+ # @return [Connection]
798
802
  def DBus.system_bus
799
803
  SystemBus.instance
800
804
  end
801
805
 
802
- # Shortcut for the SessionBus instance
806
+ # Shortcut for the {SessionBus} instance
807
+ # @return [Connection]
803
808
  def DBus.session_bus
804
809
  SessionBus.instance
805
810
  end
@@ -247,50 +247,34 @@ module DBus
247
247
  (class << self ; self ; end)
248
248
  end
249
249
 
250
- # FIXME
251
- def check_for_eval(s)
252
- raise RuntimeError, "invalid internal data '#{s}'" if not s.to_s =~ /^[A-Za-z0-9_]*$/
253
- end
254
-
255
- # FIXME
256
- def check_for_quoted_eval(s)
257
- raise RuntimeError, "invalid internal data '#{s}'" if not s.to_s =~ /^[^"]+$/
258
- end
259
-
260
250
  # Defines a method on the interface from the Method descriptor _m_.
261
251
  def define_method_from_descriptor(m)
262
- check_for_eval(m.name)
263
- check_for_quoted_eval(@name)
264
- methdef = "def #{m.name}("
265
- methdef += (0..(m.params.size - 1)).to_a.collect { |n|
266
- "arg#{n}"
267
- }.push("&reply_handler").join(", ")
268
- methdef += %{)
269
- msg = Message.new(Message::METHOD_CALL)
270
- msg.path = @object.path
271
- msg.interface = "#{@name}"
272
- msg.destination = @object.destination
273
- msg.member = "#{m.name}"
274
- msg.sender = @object.bus.unique_name
275
- }
276
- idx = 0
277
252
  m.params.each do |fpar|
278
253
  par = fpar.type
279
- check_for_quoted_eval(par)
280
-
281
254
  # This is the signature validity check
282
255
  Type::Parser.new(par).parse
283
-
284
- methdef += %{
285
- msg.add_param("#{par}", arg#{idx})
286
- }
287
- idx += 1
288
256
  end
289
- methdef += "
290
- @object.bus.send_sync_or_async(msg, &reply_handler)
257
+
258
+ singleton_class.class_eval do
259
+ define_method m.name do |*args, &reply_handler|
260
+ if m.params.size != args.size
261
+ raise ArgumentError, "wrong number of arguments (#{args.size} for #{m.params.size})"
262
+ end
263
+
264
+ msg = Message.new(Message::METHOD_CALL)
265
+ msg.path = @object.path
266
+ msg.interface = @name
267
+ msg.destination = @object.destination
268
+ msg.member = m.name
269
+ msg.sender = @object.bus.unique_name
270
+ m.params.each do |fpar|
271
+ par = fpar.type
272
+ msg.add_param(par, args.shift)
273
+ end
274
+ @object.bus.send_sync_or_async(msg, &reply_handler)
275
+ end
291
276
  end
292
- "
293
- singleton_class.class_eval(methdef)
277
+
294
278
  @methods[m.name] = m
295
279
  end
296
280
 
@@ -315,9 +299,25 @@ module DBus
315
299
  define(m)
316
300
  end
317
301
 
302
+ # @overload on_signal(name, &block)
303
+ # @overload on_signal(bus, name, &block)
318
304
  # Registers a handler (code block) for a signal with _name_ arriving
319
305
  # over the given _bus_. If no block is given, the signal is unregistered.
320
- def on_signal(bus, name, &block)
306
+ # Note that specifying _bus_ is discouraged and the option is kept only for
307
+ # backward compatibility.
308
+ # @return [void]
309
+ def on_signal(*args, &block)
310
+ # Since we must function under ruby 1.8.7, it isn't possible to define the
311
+ # function as on_signal(bus = nil, name, &block)
312
+ bus = case args.size
313
+ when 1
314
+ @object.bus
315
+ when 2
316
+ args.shift
317
+ else
318
+ raise ArgumentError, "wrong number of arguments (#{args.size} for 1-2)"
319
+ end
320
+ name = args.shift
321
321
  mr = DBus::MatchRule.new.from_signal(self, name)
322
322
  if block.nil?
323
323
  bus.remove_match(mr)
@@ -339,6 +339,7 @@ module DBus
339
339
  end
340
340
 
341
341
  # Read all properties at once, as a hash.
342
+ # @return [Hash{String}]
342
343
  def all_properties
343
344
  self.object[PROPERTY_INTERFACE].GetAll(self.name)[0]
344
345
  end
@@ -361,7 +362,7 @@ module DBus
361
362
  attr_reader :path
362
363
  # The bus the object is reachable via.
363
364
  attr_reader :bus
364
- # The default interface of the object, as String.
365
+ # @return [String] The name of the default interface of the object.
365
366
  attr_accessor :default_iface
366
367
 
367
368
  # Creates a new proxy object living on the given _bus_ at destination _dest_
@@ -377,25 +378,69 @@ module DBus
377
378
  @interfaces.keys
378
379
  end
379
380
 
380
- # Retrieves an interface of the proxy object (ProxyObjectInterface instance).
381
+ # Retrieves an interface of the proxy object
382
+ # @param [String] intfname
383
+ # @return [ProxyObjectInterface]
381
384
  def [](intfname)
382
385
  @interfaces[intfname]
383
386
  end
384
387
 
385
388
  # Maps the given interface name _intfname_ to the given interface _intf.
389
+ # @param [String] intfname
390
+ # @param [ProxyObjectInterface] intf
391
+ # @return [ProxyObjectInterface]
386
392
  def []=(intfname, intf)
387
393
  @interfaces[intfname] = intf
388
394
  end
389
395
 
390
- # Introspects the remote object. Allows you to find and select
396
+ # Introspects the remote object. Allows you to find and select
391
397
  # interfaces on the object.
392
398
  def introspect
393
399
  # Synchronous call here.
394
400
  xml = @bus.introspect_data(@destination, @path)
395
401
  ProxyObjectFactory.introspect_into(self, xml)
402
+ define_shortcut_methods()
396
403
  xml
397
404
  end
398
405
 
406
+ # For each non duplicated method name in any interface present on the
407
+ # caller, defines a shortcut method dynamically.
408
+ # This function is automatically called when a {ProxyObject} is
409
+ # introspected.
410
+ def define_shortcut_methods
411
+ # builds a list of duplicated methods
412
+ dup_meths, univocal_meths = [],{}
413
+ @interfaces.each_value do |intf|
414
+ intf.methods.each_value do |meth|
415
+ # Module#instance_methods give us an array of symbols or strings,
416
+ # depending on which version
417
+ name = if RUBY_VERSION >= "1.9"
418
+ meth.name.to_sym
419
+ else
420
+ meth.name
421
+ end
422
+ # don't overwrite instance methods!
423
+ if dup_meths.include? name or self.class.instance_methods.include? name
424
+ next
425
+ elsif univocal_meths.include? name
426
+ univocal_meths.delete name
427
+ dup_meths << name
428
+ else
429
+ univocal_meths[name] = intf
430
+ end
431
+ end
432
+ end
433
+ univocal_meths.each do |name, intf|
434
+ # creates a shortcut function that forwards each call to the method on
435
+ # the appropriate intf
436
+ singleton_class.class_eval do
437
+ define_method name do |*args, &reply_handler|
438
+ intf.method(name).call(*args, &reply_handler)
439
+ end
440
+ end
441
+ end
442
+ end
443
+
399
444
  # Returns whether the object has an interface with the given _name_.
400
445
  def has_iface?(name)
401
446
  raise "Cannot call has_iface? if not introspected" if not @introspected
@@ -404,9 +449,10 @@ module DBus
404
449
 
405
450
  # Registers a handler, the code block, for a signal with the given _name_.
406
451
  # It uses _default_iface_ which must have been set.
452
+ # @return [void]
407
453
  def on_signal(name, &block)
408
454
  if @default_iface and has_iface?(@default_iface)
409
- @interfaces[@default_iface].on_signal(@bus, name, &block)
455
+ @interfaces[@default_iface].on_signal(name, &block)
410
456
  else
411
457
  # TODO improve
412
458
  raise NoMethodError
@@ -437,6 +483,11 @@ module DBus
437
483
  raise NoMethodError, "undefined method `#{name}' for DBus interface `#{@default_iface}' on object `#{@path}'"
438
484
  end
439
485
  end
486
+
487
+ # Returns the singleton class of the object.
488
+ def singleton_class
489
+ (class << self ; self ; end)
490
+ end
440
491
  end # class ProxyObject
441
492
 
442
493
  # = D-Bus proxy object factory class
@@ -0,0 +1,31 @@
1
+ # dbus/logger.rb - debug logging
2
+ #
3
+ # This file is part of the ruby-dbus project
4
+ # Copyright (C) 2012 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
+ require 'logger'
12
+
13
+ module DBus
14
+ # Get the logger for the DBus module.
15
+ # The default one logs to STDERR,
16
+ # with DEBUG if $DEBUG is set, otherwise INFO.
17
+ def logger
18
+ unless defined? @logger
19
+ @logger = Logger.new(STDERR)
20
+ @logger.level = $DEBUG ? Logger::DEBUG : Logger::INFO
21
+ end
22
+ @logger
23
+ end
24
+ module_function :logger
25
+
26
+ # Set the logger for the DBus module
27
+ def logger=(logger)
28
+ @logger = logger
29
+ end
30
+ module_function :logger=
31
+ end
@@ -101,6 +101,10 @@ module DBus
101
101
  end
102
102
  end
103
103
 
104
+ def to_s
105
+ "#{message_type} sender=#{sender} -> dest=#{destination} serial=#{serial} reply_serial=#{reply_serial} path=#{path}; interface=#{interface}; member=#{member} error_name=#{error_name}"
106
+ end
107
+
104
108
  # Create a regular reply to a message _m_.
105
109
  def self.method_return(m)
106
110
  MethodReturnMessage.new.reply_to(m)
@@ -161,64 +165,18 @@ module DBus
161
165
  marshaller.append(Type::BYTE, @protocol)
162
166
  marshaller.append(Type::UINT32, @body_length)
163
167
  marshaller.append(Type::UINT32, @serial)
164
- marshaller.array(Type::Parser.new("y").parse[0]) do
165
- if @path
166
- marshaller.struct do
167
- marshaller.append(Type::BYTE, PATH)
168
- marshaller.append(Type::BYTE, 1)
169
- marshaller.append_simple_string("o")
170
- marshaller.append(Type::OBJECT_PATH, @path)
171
- end
172
- end
173
- if @interface
174
- marshaller.struct do
175
- marshaller.append(Type::BYTE, INTERFACE)
176
- marshaller.append(Type::BYTE, 1)
177
- marshaller.append_simple_string("s")
178
- marshaller.append(Type::STRING, @interface)
179
- end
180
- end
181
- if @member
182
- marshaller.struct do
183
- marshaller.append(Type::BYTE, MEMBER)
184
- marshaller.append(Type::BYTE, 1)
185
- marshaller.append_simple_string("s")
186
- marshaller.append(Type::STRING, @member)
187
- end
188
- end
189
- if @error_name
190
- marshaller.struct do
191
- marshaller.append(Type::BYTE, ERROR_NAME)
192
- marshaller.append(Type::BYTE, 1)
193
- marshaller.append_simple_string("s")
194
- marshaller.append(Type::STRING, @error_name)
195
- end
196
- end
197
- if @reply_serial
198
- marshaller.struct do
199
- marshaller.append(Type::BYTE, REPLY_SERIAL)
200
- marshaller.append(Type::BYTE, 1)
201
- marshaller.append_simple_string("u")
202
- marshaller.append(Type::UINT32, @reply_serial)
203
- end
204
- end
205
- if @destination
206
- marshaller.struct do
207
- marshaller.append(Type::BYTE, DESTINATION)
208
- marshaller.append(Type::BYTE, 1)
209
- marshaller.append_simple_string("s")
210
- marshaller.append(Type::STRING, @destination)
211
- end
212
- end
213
- if @signature != ""
214
- marshaller.struct do
215
- marshaller.append(Type::BYTE, SIGNATURE)
216
- marshaller.append(Type::BYTE, 1)
217
- marshaller.append_simple_string("g")
218
- marshaller.append(Type::SIGNATURE, @signature)
219
- end
220
- end
221
- end
168
+
169
+ headers = []
170
+ headers << [PATH, ["o", @path]] if @path
171
+ headers << [INTERFACE, ["s", @interface]] if @interface
172
+ headers << [MEMBER, ["s", @member]] if @member
173
+ headers << [ERROR_NAME, ["s", @error_name]] if @error_name
174
+ headers << [REPLY_SERIAL, ["u", @reply_serial]] if @reply_serial
175
+ headers << [DESTINATION, ["s", @destination]] if @destination
176
+ # SENDER is not sent, the message bus fills it in instead
177
+ headers << [SIGNATURE, ["g", @signature]] if @signature != ""
178
+ marshaller.append("a(yv)", headers)
179
+
222
180
  marshaller.align(8)
223
181
  @params.each do |param|
224
182
  marshaller.append(param[0], param[1])
@@ -15,47 +15,31 @@ module DBus
15
15
  # This module containts the constants of the types specified in the D-Bus
16
16
  # protocol.
17
17
  module Type
18
- # The types.
19
- INVALID = 0
20
- BYTE = ?y
21
- BOOLEAN = ?b
22
- INT16 = ?n
23
- UINT16 = ?q
24
- INT32 = ?i
25
- UINT32 = ?u
26
- INT64 = ?x
27
- UINT64 = ?t
28
- DOUBLE = ?d
29
- STRUCT = ?r
30
- ARRAY = ?a
31
- VARIANT = ?v
32
- OBJECT_PATH = ?o
33
- STRING = ?s
34
- SIGNATURE = ?g
35
- DICT_ENTRY = ?e
36
- UNIX_FD = ?h
37
-
38
- # Mapping from type number to name.
39
- TypeName = {
40
- INVALID => "INVALID",
41
- BYTE => "BYTE",
42
- BOOLEAN => "BOOLEAN",
43
- INT16 => "INT16",
44
- UINT16 => "UINT16",
45
- INT32 => "INT32",
46
- UINT32 => "UINT32",
47
- INT64 => "INT64",
48
- UINT64 => "UINT64",
49
- DOUBLE => "DOUBLE",
50
- STRUCT => "STRUCT",
51
- ARRAY => "ARRAY",
52
- VARIANT => "VARIANT",
53
- OBJECT_PATH => "OBJECT_PATH",
54
- STRING => "STRING",
55
- SIGNATURE => "SIGNATURE",
56
- DICT_ENTRY => "DICT_ENTRY",
57
- UNIX_FD => "UNIX_FD"
18
+ # Mapping from type number to name and alignment.
19
+ TypeMapping = {
20
+ 0 => ["INVALID", nil],
21
+ ?y => ["BYTE", 1],
22
+ ?b => ["BOOLEAN", 4],
23
+ ?n => ["INT16", 2],
24
+ ?q => ["UINT16", 2],
25
+ ?i => ["INT32", 4],
26
+ ?u => ["UINT32", 4],
27
+ ?x => ["INT64", 8],
28
+ ?t => ["UINT64", 8],
29
+ ?d => ["DOUBLE", 8],
30
+ ?r => ["STRUCT", 8],
31
+ ?a => ["ARRAY", 4],
32
+ ?v => ["VARIANT", 1],
33
+ ?o => ["OBJECT_PATH", 4],
34
+ ?s => ["STRING", 4],
35
+ ?g => ["SIGNATURE", 1],
36
+ ?e => ["DICT_ENTRY", 8],
37
+ ?h => ["UNIX_FD", 4],
58
38
  }
39
+ # Defines the set of constants
40
+ TypeMapping.each_pair do |key, value|
41
+ Type.const_set(value.first, key)
42
+ end
59
43
 
60
44
  # Exception raised when an unknown/incorrect type is encountered.
61
45
  class SignatureException < Exception
@@ -72,7 +56,7 @@ module Type
72
56
 
73
57
  # Create a new type instance for type number _sigtype_.
74
58
  def initialize(sigtype)
75
- if not TypeName.keys.member?(sigtype)
59
+ if not TypeMapping.keys.member?(sigtype)
76
60
  raise SignatureException, "Unknown key in signature: #{sigtype.chr}"
77
61
  end
78
62
  @sigtype = sigtype
@@ -81,25 +65,7 @@ module Type
81
65
 
82
66
  # Return the required alignment for the type.
83
67
  def alignment
84
- {
85
- BYTE => 1,
86
- BOOLEAN => 4,
87
- INT16 => 2,
88
- UINT16 => 2,
89
- INT32 => 4,
90
- UINT32 => 4,
91
- INT64 => 8,
92
- UINT64 => 8,
93
- STRUCT => 8,
94
- DICT_ENTRY => 8,
95
- DOUBLE => 8,
96
- ARRAY => 4,
97
- VARIANT => 1,
98
- OBJECT_PATH => 4,
99
- STRING => 4,
100
- SIGNATURE => 1,
101
- UNIX_FD => 4,
102
- }[@sigtype]
68
+ TypeMapping[@sigtype].last
103
69
  end
104
70
 
105
71
  # Return a string representation of the type according to the
@@ -113,7 +79,7 @@ module Type
113
79
  when DICT_ENTRY
114
80
  "{" + @members.collect { |t| t.to_s }.join + "}"
115
81
  else
116
- if not TypeName.keys.member?(@sigtype)
82
+ if not TypeMapping.keys.member?(@sigtype)
117
83
  raise NotImplementedError
118
84
  end
119
85
  @sigtype.chr
@@ -123,7 +89,7 @@ module Type
123
89
  # Add a new member type _a_.
124
90
  def <<(a)
125
91
  if not [STRUCT, ARRAY, DICT_ENTRY].member?(@sigtype)
126
- raise SignatureException
92
+ raise SignatureException
127
93
  end
128
94
  raise SignatureException if @sigtype == ARRAY and @members.size > 0
129
95
  if @sigtype == DICT_ENTRY
@@ -145,7 +111,7 @@ module Type
145
111
  end
146
112
 
147
113
  def inspect
148
- s = TypeName[@sigtype]
114
+ s = TypeMapping[@sigtype].first
149
115
  if [STRUCT, ARRAY].member?(@sigtype)
150
116
  s += ": " + @members.inspect
151
117
  end
@@ -176,7 +142,9 @@ module Type
176
142
  case c
177
143
  when ?a
178
144
  res = Type.new(ARRAY)
179
- child = parse_one(nextchar)
145
+ c = nextchar
146
+ raise SignatureException, "Parse error in #{@signature}" if c == nil
147
+ child = parse_one(c)
180
148
  res << child
181
149
  when ?(
182
150
  res = Type.new(STRUCT)