ruby-dbus 0.16.0 → 0.18.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.
Files changed (79) hide show
  1. checksums.yaml +4 -4
  2. data/NEWS.md +160 -0
  3. data/README.md +3 -5
  4. data/Rakefile +18 -8
  5. data/VERSION +1 -1
  6. data/doc/Reference.md +106 -7
  7. data/examples/doc/_extract_examples +7 -0
  8. data/examples/gdbus/gdbus +31 -24
  9. data/examples/no-introspect/nm-test.rb +2 -0
  10. data/examples/no-introspect/tracker-test.rb +3 -1
  11. data/examples/rhythmbox/playpause.rb +2 -1
  12. data/examples/service/call_service.rb +2 -1
  13. data/examples/service/complex-property.rb +21 -0
  14. data/examples/service/service_newapi.rb +1 -1
  15. data/examples/simple/call_introspect.rb +1 -0
  16. data/examples/simple/get_id.rb +2 -1
  17. data/examples/simple/properties.rb +2 -0
  18. data/examples/utils/listnames.rb +1 -0
  19. data/examples/utils/notify.rb +1 -0
  20. data/lib/dbus/api_options.rb +9 -0
  21. data/lib/dbus/auth.rb +20 -15
  22. data/lib/dbus/bus.rb +123 -75
  23. data/lib/dbus/bus_name.rb +12 -8
  24. data/lib/dbus/core_ext/class/attribute.rb +1 -1
  25. data/lib/dbus/data.rb +821 -0
  26. data/lib/dbus/emits_changed_signal.rb +83 -0
  27. data/lib/dbus/error.rb +4 -2
  28. data/lib/dbus/introspect.rb +132 -31
  29. data/lib/dbus/logger.rb +3 -1
  30. data/lib/dbus/marshall.rb +247 -296
  31. data/lib/dbus/matchrule.rb +16 -16
  32. data/lib/dbus/message.rb +44 -37
  33. data/lib/dbus/message_queue.rb +16 -10
  34. data/lib/dbus/object.rb +358 -24
  35. data/lib/dbus/object_path.rb +11 -6
  36. data/lib/dbus/proxy_object.rb +22 -1
  37. data/lib/dbus/proxy_object_factory.rb +13 -7
  38. data/lib/dbus/proxy_object_interface.rb +63 -30
  39. data/lib/dbus/raw_message.rb +91 -0
  40. data/lib/dbus/type.rb +318 -86
  41. data/lib/dbus/xml.rb +32 -17
  42. data/lib/dbus.rb +14 -7
  43. data/ruby-dbus.gemspec +7 -3
  44. data/spec/async_spec.rb +2 -0
  45. data/spec/binding_spec.rb +2 -0
  46. data/spec/bus_and_xml_backend_spec.rb +2 -0
  47. data/spec/bus_driver_spec.rb +2 -0
  48. data/spec/bus_name_spec.rb +3 -1
  49. data/spec/bus_spec.rb +2 -0
  50. data/spec/byte_array_spec.rb +2 -0
  51. data/spec/client_robustness_spec.rb +4 -2
  52. data/spec/data/marshall.yaml +1667 -0
  53. data/spec/data_spec.rb +673 -0
  54. data/spec/emits_changed_signal_spec.rb +58 -0
  55. data/spec/err_msg_spec.rb +2 -0
  56. data/spec/introspect_xml_parser_spec.rb +2 -0
  57. data/spec/introspection_spec.rb +2 -0
  58. data/spec/main_loop_spec.rb +3 -1
  59. data/spec/node_spec.rb +23 -0
  60. data/spec/object_path_spec.rb +3 -0
  61. data/spec/object_spec.rb +138 -0
  62. data/spec/packet_marshaller_spec.rb +41 -0
  63. data/spec/packet_unmarshaller_spec.rb +248 -0
  64. data/spec/property_spec.rb +192 -5
  65. data/spec/proxy_object_spec.rb +2 -0
  66. data/spec/server_robustness_spec.rb +2 -0
  67. data/spec/server_spec.rb +2 -0
  68. data/spec/service_newapi.rb +70 -70
  69. data/spec/session_bus_spec.rb +3 -1
  70. data/spec/session_bus_spec_manual.rb +2 -0
  71. data/spec/signal_spec.rb +5 -3
  72. data/spec/spec_helper.rb +37 -9
  73. data/spec/thread_safety_spec.rb +2 -0
  74. data/spec/tools/dbus-limited-session.conf +4 -0
  75. data/spec/type_spec.rb +214 -6
  76. data/spec/value_spec.rb +16 -1
  77. data/spec/variant_spec.rb +4 -2
  78. data/spec/zzz_quit_spec.rb +16 -0
  79. metadata +34 -8
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # This file is part of the ruby-dbus project
2
4
  # Copyright (C) 2007 Arnaud Cornet and Paul van Tilburg
3
5
  # Copyright (C) 2009-2014 Martin Vidner
@@ -13,13 +15,16 @@ module DBus
13
15
  # A class similar to the normal Interface used as a proxy for remote
14
16
  # object interfaces.
15
17
  class ProxyObjectInterface
16
- # The proxied methods contained in the interface.
17
- attr_accessor :methods
18
- # The proxied signals contained in the interface.
19
- attr_accessor :signals
20
- # The proxy object to which this interface belongs.
18
+ # @return [Hash{String => DBus::Method}]
19
+ attr_reader :methods
20
+ # @return [Hash{String => Signal}]
21
+ attr_reader :signals
22
+ # @return [Hash{Symbol => Property}]
23
+ attr_reader :properties
24
+
25
+ # @return [ProxyObject] The proxy object to which this interface belongs.
21
26
  attr_reader :object
22
- # The name of the interface.
27
+ # @return [String] The name of the interface.
23
28
  attr_reader :name
24
29
 
25
30
  # Creates a new proxy interface for the given proxy _object_
@@ -29,6 +34,7 @@ module DBus
29
34
  @name = name
30
35
  @methods = {}
31
36
  @signals = {}
37
+ @properties = {}
32
38
  end
33
39
 
34
40
  # Returns the string representation of the interface (the name).
@@ -36,27 +42,28 @@ module DBus
36
42
  @name
37
43
  end
38
44
 
39
- # Defines a method on the interface from the Method descriptor _m_.
40
- def define_method_from_descriptor(m)
41
- m.params.each do |fpar|
45
+ # Defines a method on the interface from the Method descriptor _method_.
46
+ # @param method [Method]
47
+ def define_method_from_descriptor(method)
48
+ method.params.each do |fpar|
42
49
  par = fpar.type
43
50
  # This is the signature validity check
44
51
  Type::Parser.new(par).parse
45
52
  end
46
53
 
47
54
  singleton_class.class_eval do
48
- define_method m.name do |*args, &reply_handler|
49
- if m.params.size != args.size
50
- raise ArgumentError, "wrong number of arguments (#{args.size} for #{m.params.size})"
55
+ define_method method.name do |*args, &reply_handler|
56
+ if method.params.size != args.size
57
+ raise ArgumentError, "wrong number of arguments (#{args.size} for #{method.params.size})"
51
58
  end
52
59
 
53
60
  msg = Message.new(Message::METHOD_CALL)
54
61
  msg.path = @object.path
55
62
  msg.interface = @name
56
63
  msg.destination = @object.destination
57
- msg.member = m.name
64
+ msg.member = method.name
58
65
  msg.sender = @object.bus.unique_name
59
- m.params.each do |fpar|
66
+ method.params.each do |fpar|
60
67
  par = fpar.type
61
68
  msg.add_param(par, args.shift)
62
69
  end
@@ -64,25 +71,35 @@ module DBus
64
71
  if ret.nil? || @object.api.proxy_method_returns_array
65
72
  ret
66
73
  else
67
- m.rets.size == 1 ? ret.first : ret
74
+ method.rets.size == 1 ? ret.first : ret
68
75
  end
69
76
  end
70
77
  end
71
78
 
72
- @methods[m.name] = m
79
+ @methods[method.name] = method
73
80
  end
74
81
 
75
- # Defines a signal from the descriptor _s_.
76
- def define_signal_from_descriptor(s)
77
- @signals[s.name] = s
82
+ # Defines a signal from the descriptor _sig_.
83
+ # @param sig [Signal]
84
+ def define_signal_from_descriptor(sig)
85
+ @signals[sig.name] = sig
78
86
  end
79
87
 
80
- # Defines a signal or method based on the descriptor _m_.
81
- def define(m)
82
- if m.is_a?(Method)
83
- define_method_from_descriptor(m)
84
- elsif m.is_a?(Signal)
85
- define_signal_from_descriptor(m)
88
+ # @param prop [Property]
89
+ def define_property_from_descriptor(prop)
90
+ @properties[prop.name] = prop
91
+ end
92
+
93
+ # Defines a signal or method based on the descriptor _ifc_el_.
94
+ # @param ifc_el [DBus::Method,Signal,Property]
95
+ def define(ifc_el)
96
+ case ifc_el
97
+ when Method
98
+ define_method_from_descriptor(ifc_el)
99
+ when Signal
100
+ define_signal_from_descriptor(ifc_el)
101
+ when Property
102
+ define_property_from_descriptor(ifc_el)
86
103
  end
87
104
  end
88
105
 
@@ -109,7 +126,7 @@ module DBus
109
126
  end
110
127
  end
111
128
 
112
- PROPERTY_INTERFACE = "org.freedesktop.DBus.Properties".freeze
129
+ PROPERTY_INTERFACE = "org.freedesktop.DBus.Properties"
113
130
 
114
131
  # Read a property.
115
132
  # @param propname [String]
@@ -124,10 +141,26 @@ module DBus
124
141
  end
125
142
 
126
143
  # Write a property.
127
- # @param propname [String]
144
+ # @param property_name [String]
128
145
  # @param value [Object]
129
- def []=(propname, value)
130
- object[PROPERTY_INTERFACE].Set(name, propname, value)
146
+ def []=(property_name, value)
147
+ property = properties[property_name.to_sym]
148
+ if !property
149
+ raise DBus.error("org.freedesktop.DBus.Error.UnknownProperty"),
150
+ "Property '#{name}.#{property_name}' (on object '#{object.path}') not found"
151
+ end
152
+
153
+ case value
154
+ # accommodate former need to explicitly make a variant with the right type
155
+ when Data::Variant
156
+ variant = value
157
+ else
158
+ type = property.type
159
+ typed_value = Data.make_typed(type, value)
160
+ variant = Data::Variant.new(typed_value, member_type: type)
161
+ end
162
+
163
+ object[PROPERTY_INTERFACE].Set(name, property_name, variant)
131
164
  end
132
165
 
133
166
  # Read all properties at once, as a hash.
@@ -141,5 +174,5 @@ module DBus
141
174
  ret
142
175
  end
143
176
  end
144
- end # class ProxyObjectInterface
177
+ end
145
178
  end
@@ -0,0 +1,91 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This file is part of the ruby-dbus project
4
+ # Copyright (C) 2022 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
+ module DBus
12
+ # A message while it is being parsed: a binary string,
13
+ # with a position cursor (*pos*), and an *endianness* tag.
14
+ class RawMessage
15
+ # @return [String]
16
+ # attr_reader :bytes
17
+
18
+ # @return [Integer] position in the byte buffer
19
+ attr_reader :pos
20
+
21
+ # @return [:little,:big]
22
+ attr_reader :endianness
23
+
24
+ # @param bytes [String]
25
+ # @param endianness [:little,:big,nil]
26
+ # if not given, read the 1st byte of *bytes*
27
+ def initialize(bytes, endianness = nil)
28
+ @bytes = bytes
29
+ @pos = 0
30
+ @endianness = endianness || self.class.endianness(@bytes[0])
31
+ end
32
+
33
+ # Get the endiannes switch as a Symbol,
34
+ # which will make using it slightly more efficient
35
+ # @param tag_char [String]
36
+ # @return [:little,:big]
37
+ def self.endianness(tag_char)
38
+ case tag_char
39
+ when LIL_END
40
+ :little
41
+ when BIG_END
42
+ :big
43
+ else
44
+ raise InvalidPacketException, "Incorrect endianness #{tag_char.inspect}"
45
+ end
46
+ end
47
+
48
+ # @return [void]
49
+ # @raise IncompleteBufferException if there are not enough bytes remaining
50
+ def want!(size)
51
+ raise IncompleteBufferException if @pos + size > @bytes.bytesize
52
+ end
53
+
54
+ # @return [String]
55
+ # @raise IncompleteBufferException if there are not enough bytes remaining
56
+ # TODO: stress test this with encodings. always binary?
57
+ def read(size)
58
+ want!(size)
59
+ ret = @bytes.slice(@pos, size)
60
+ @pos += size
61
+ ret
62
+ end
63
+
64
+ # @return [String]
65
+ # @api private
66
+ def remaining_bytes
67
+ # This returns "" if pos is just past the end of the string,
68
+ # and nil if it is further.
69
+ @bytes[@pos..-1]
70
+ end
71
+
72
+ # Align the *pos* index on a multiple of *alignment*
73
+ # @param alignment [Integer] must be 1, 2, 4 or 8
74
+ # @return [void]
75
+ def align(alignment)
76
+ case alignment
77
+ when 1
78
+ nil
79
+ when 2, 4, 8
80
+ bits = alignment - 1
81
+ pad_size = ((@pos + bits) & ~bits) - @pos
82
+ pad = read(pad_size)
83
+ unless pad.bytes.all?(&:zero?)
84
+ raise InvalidPacketException, "Alignment bytes are not NUL"
85
+ end
86
+ else
87
+ raise ArgumentError, "Unsupported alignment #{alignment}"
88
+ end
89
+ end
90
+ end
91
+ end