ruby-dbus 0.18.0.beta4 → 0.18.0.beta7

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.
data/lib/dbus/marshall.rb CHANGED
@@ -118,7 +118,7 @@ module DBus
118
118
  values = signature.members.map do |child_sig|
119
119
  do_parse(child_sig, mode: mode)
120
120
  end
121
- packet = data_class.from_items(values, mode: mode, member_types: signature.members)
121
+ packet = data_class.from_items(values, mode: mode, type: signature)
122
122
 
123
123
  when Type::VARIANT
124
124
  data_sig = do_parse(Data::Signature.type, mode: :exact) # -> Data::Signature
@@ -147,7 +147,7 @@ module DBus
147
147
  items << item
148
148
  end
149
149
  is_hash = signature.child.sigtype == Type::DICT_ENTRY
150
- packet = data_class.from_items(items, mode: mode, member_type: signature.child, hash: is_hash)
150
+ packet = data_class.from_items(items, mode: mode, type: signature, hash: is_hash)
151
151
  end
152
152
  end
153
153
  packet
@@ -250,10 +250,10 @@ module DBus
250
250
  when Type::VARIANT
251
251
  append_variant(val)
252
252
  when Type::ARRAY
253
- val = val.value if val.is_a?(Data::Array)
253
+ val = val.exact_value if val.is_a?(Data::Array)
254
254
  append_array(type.child, val)
255
255
  when Type::STRUCT, Type::DICT_ENTRY
256
- val = val.value if val.is_a?(Data::Struct) || val.is_a?(Data::DictEntry)
256
+ val = val.exact_value if val.is_a?(Data::Struct) || val.is_a?(Data::DictEntry)
257
257
  unless val.is_a?(Array) || val.is_a?(Struct)
258
258
  type_name = Type::TYPE_MAPPING[type.sigtype].first
259
259
  raise TypeException, "#{type_name} expects an Array or Struct, seen #{val.class}"
@@ -282,8 +282,14 @@ module DBus
282
282
 
283
283
  def append_variant(val)
284
284
  vartype = nil
285
- if val.is_a?(DBus::Data::Base)
286
- vartype = val.type # FIXME: box or unbox another variant?
285
+ if val.is_a?(DBus::Data::Variant)
286
+ vartype = val.member_type
287
+ vardata = val.exact_value
288
+ elsif val.is_a?(DBus::Data::Container)
289
+ vartype = val.type
290
+ vardata = val.exact_value
291
+ elsif val.is_a?(DBus::Data::Base)
292
+ vartype = val.type
287
293
  vardata = val.value
288
294
  elsif val.is_a?(Array) && val.size == 2
289
295
  case val[0]
@@ -29,11 +29,13 @@ module DBus
29
29
  # @param pobj [ProxyObject]
30
30
  # @param xml [String]
31
31
  def self.introspect_into(pobj, xml)
32
+ # intfs [Array<Interface>], subnodes [Array<String>]
32
33
  intfs, pobj.subnodes = IntrospectXMLParser.new(xml).parse
33
34
  intfs.each do |i|
34
35
  poi = ProxyObjectInterface.new(pobj, i.name)
35
36
  i.methods.each_value { |m| poi.define(m) }
36
37
  i.signals.each_value { |s| poi.define(s) }
38
+ i.properties.each_value { |p| poi.define(p) }
37
39
  pobj[i.name] = poi
38
40
  end
39
41
  pobj.introspected = true
@@ -15,13 +15,16 @@ module DBus
15
15
  # A class similar to the normal Interface used as a proxy for remote
16
16
  # object interfaces.
17
17
  class ProxyObjectInterface
18
- # The proxied methods contained in the interface.
19
- attr_accessor :methods
20
- # The proxied signals contained in the interface.
21
- attr_accessor :signals
22
- # 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.
23
26
  attr_reader :object
24
- # The name of the interface.
27
+ # @return [String] The name of the interface.
25
28
  attr_reader :name
26
29
 
27
30
  # Creates a new proxy interface for the given proxy _object_
@@ -31,6 +34,7 @@ module DBus
31
34
  @name = name
32
35
  @methods = {}
33
36
  @signals = {}
37
+ @properties = {}
34
38
  end
35
39
 
36
40
  # Returns the string representation of the interface (the name).
@@ -81,13 +85,21 @@ module DBus
81
85
  @signals[sig.name] = sig
82
86
  end
83
87
 
88
+ # @param prop [Property]
89
+ def define_property_from_descriptor(prop)
90
+ @properties[prop.name] = prop
91
+ end
92
+
84
93
  # Defines a signal or method based on the descriptor _ifc_el_.
94
+ # @param ifc_el [DBus::Method,Signal,Property]
85
95
  def define(ifc_el)
86
96
  case ifc_el
87
97
  when Method
88
98
  define_method_from_descriptor(ifc_el)
89
99
  when Signal
90
100
  define_signal_from_descriptor(ifc_el)
101
+ when Property
102
+ define_property_from_descriptor(ifc_el)
91
103
  end
92
104
  end
93
105
 
@@ -129,10 +141,26 @@ module DBus
129
141
  end
130
142
 
131
143
  # Write a property.
132
- # @param propname [String]
144
+ # @param property_name [String]
133
145
  # @param value [Object]
134
- def []=(propname, value)
135
- 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)
136
164
  end
137
165
 
138
166
  # Read all properties at once, as a hash.
data/lib/dbus/type.rb CHANGED
@@ -29,14 +29,12 @@ module DBus
29
29
  # For documentation purposes only.
30
30
  class Prototype < String; end
31
31
 
32
- # = D-Bus type module
33
- #
34
- # This module containts the constants of the types specified in the D-Bus
35
- # protocol.
32
+ # Represents the D-Bus types.
36
33
  #
37
34
  # Corresponds to {SingleCompleteType}.
35
+ # Instances are immutable/frozen once fully constructed.
38
36
  #
39
- # See also {DBus::Data::Signature}
37
+ # See also {DBus::Data::Signature} which is "type on the wire".
40
38
  class Type
41
39
  # Mapping from type number to name and alignment.
42
40
  TYPE_MAPPING = {
@@ -104,8 +102,32 @@ module DBus
104
102
  end
105
103
  end
106
104
 
107
- @sigtype = sigtype
108
- @members = []
105
+ @sigtype = sigtype.freeze
106
+ @members = [] # not frozen yet, Parser#parse_one or Factory will do it
107
+ freeze
108
+ end
109
+
110
+ # A Type is equal to
111
+ # - another Type with the same string representation
112
+ # - a String ({SingleCompleteType}) describing the type
113
+ def ==(other)
114
+ case other
115
+ when ::String
116
+ to_s == other
117
+ else
118
+ eql?(other)
119
+ end
120
+ end
121
+
122
+ # A Type is eql? to
123
+ # - another Type with the same string representation
124
+ #
125
+ # Hash key equality
126
+ # See https://ruby-doc.org/core-3.0.0/Object.html#method-i-eql-3F
127
+ def eql?(other)
128
+ return false unless other.is_a?(Type)
129
+
130
+ @sigtype == other.sigtype && @members == other.members
109
131
  end
110
132
 
111
133
  # Return the required alignment for the type.
@@ -124,16 +146,15 @@ module DBus
124
146
  when DICT_ENTRY
125
147
  "{#{@members.collect(&:to_s).join}}"
126
148
  else
127
- if !TYPE_MAPPING.keys.member?(@sigtype)
128
- raise NotImplementedError
129
- end
130
-
131
149
  @sigtype.chr
132
150
  end
133
151
  end
134
152
 
135
153
  # Add a new member type _item_.
154
+ # @param item [Type]
136
155
  def <<(item)
156
+ raise ArgumentError unless item.is_a?(Type)
157
+
137
158
  if ![STRUCT, ARRAY, DICT_ENTRY].member?(@sigtype)
138
159
  raise SignatureException
139
160
  end
@@ -159,7 +180,7 @@ module DBus
159
180
 
160
181
  def inspect
161
182
  s = TYPE_MAPPING[@sigtype].first
162
- if [STRUCT, ARRAY].member?(@sigtype)
183
+ if [STRUCT, ARRAY, DICT_ENTRY].member?(@sigtype)
163
184
  s += ": #{@members.inspect}"
164
185
  end
165
186
  s
@@ -232,6 +253,7 @@ module DBus
232
253
  else
233
254
  res = Type.new(char)
234
255
  end
256
+ res.members.freeze
235
257
  res
236
258
  end
237
259
 
@@ -243,7 +265,7 @@ module DBus
243
265
  while (c = nextchar)
244
266
  ret << parse_one(c)
245
267
  end
246
- ret
268
+ ret.freeze
247
269
  end
248
270
 
249
271
  # Parse one {SingleCompleteType}
@@ -255,9 +277,116 @@ module DBus
255
277
  t = parse_one(c)
256
278
  raise SignatureException, "Has more than a Single Complete Type: #{@signature}" unless nextchar.nil?
257
279
 
280
+ t.freeze
281
+ end
282
+ end
283
+
284
+ class Factory
285
+ # @param type [Type,SingleCompleteType,Class]
286
+ # @see from_plain_class
287
+ # @return [Type] (frozen)
288
+ def self.make_type(type)
289
+ case type
290
+ when Type
291
+ type
292
+ when String
293
+ DBus.type(type)
294
+ when Class
295
+ from_plain_class(type)
296
+ else
297
+ msg = "Expecting DBus::Type, DBus::SingleCompleteType(aka ::String), or Class, got #{type.inspect}"
298
+ raise ArgumentError, msg
299
+ end
300
+ end
301
+
302
+ # Make a {Type} corresponding to some plain classes:
303
+ # - String
304
+ # - Float
305
+ # - DBus::ObjectPath
306
+ # - DBus::Signature, DBus::SingleCompleteType
307
+ # @param klass [Class]
308
+ # @return [Type] (frozen)
309
+ def self.from_plain_class(klass)
310
+ @signature_type ||= DBus.type(SIGNATURE)
311
+ @class_to_type ||= {
312
+ DBus::ObjectPath => DBus.type(OBJECT_PATH),
313
+ DBus::Signature => @signature_type,
314
+ DBus::SingleCompleteType => @signature_type,
315
+ String => DBus.type(STRING),
316
+ Float => DBus.type(DOUBLE)
317
+ }
318
+ t = @class_to_type[klass]
319
+ raise ArgumentError, "Cannot convert plain class #{klass} to a D-Bus type" if t.nil?
320
+
258
321
  t
259
322
  end
260
323
  end
324
+
325
+ # Syntactic helper for constructing an array Type.
326
+ # You may be looking for {Data::Array} instead.
327
+ # @example
328
+ # t = Type::Array[Type::INT16]
329
+ class ArrayFactory < Factory
330
+ # @param member_type [Type,SingleCompleteType]
331
+ # @return [Type] (frozen)
332
+ def self.[](member_type)
333
+ t = Type.new(ARRAY)
334
+ t << make_type(member_type)
335
+ t.members.freeze
336
+ t
337
+ end
338
+ end
339
+
340
+ # @example
341
+ # t = Type::Array[Type::INT16]
342
+ Array = ArrayFactory
343
+
344
+ # Syntactic helper for constructing a hash Type.
345
+ # You may be looking for {Data::Array} and {Data::DictEntry} instead.
346
+ # @example
347
+ # t = Type::Hash[Type::STRING, Type::VARIANT]
348
+ class HashFactory < Factory
349
+ # @param key_type [Type,SingleCompleteType]
350
+ # @param value_type [Type,SingleCompleteType]
351
+ # @return [Type] (frozen)
352
+ def self.[](key_type, value_type)
353
+ t = Type.new(ARRAY)
354
+ de = Type.new(DICT_ENTRY, abstract: true)
355
+ de << make_type(key_type)
356
+ de << make_type(value_type)
357
+ de.members.freeze
358
+ t << de
359
+ t.members.freeze
360
+ t
361
+ end
362
+ end
363
+
364
+ # @example
365
+ # t = Type::Hash[Type::INT16]
366
+ Hash = HashFactory
367
+
368
+ # Syntactic helper for constructing a struct Type.
369
+ # You may be looking for {Data::Struct} instead.
370
+ # @example
371
+ # t = Type::Struct[Type::INT16, Type::STRING]
372
+ class StructFactory < Factory
373
+ # @param member_types [::Array<Type,SingleCompleteType>]
374
+ # @return [Type] (frozen)
375
+ def self.[](*member_types)
376
+ raise ArgumentError if member_types.empty?
377
+
378
+ t = Type.new(STRUCT, abstract: true)
379
+ member_types.each do |mt|
380
+ t << make_type(mt)
381
+ end
382
+ t.members.freeze
383
+ t
384
+ end
385
+ end
386
+
387
+ # @example
388
+ # t = Type::Struct[Type::INT16, Type::STRING]
389
+ Struct = StructFactory
261
390
  end
262
391
 
263
392
  # shortcuts
@@ -266,7 +395,7 @@ module DBus
266
395
  # This is prefered to {Type#initialize} which allows
267
396
  # incomplete or invalid types.
268
397
  # @param string_type [SingleCompleteType]
269
- # @return [DBus::Type]
398
+ # @return [DBus::Type] (frozen)
270
399
  # @raise SignatureException
271
400
  def type(string_type)
272
401
  Type::Parser.new(string_type).parse1
@@ -275,7 +404,7 @@ module DBus
275
404
 
276
405
  # Parse a String to zero or more {DBus::Type}s.
277
406
  # @param string_type [Signature]
278
- # @return [Array<DBus::Type>]
407
+ # @return [Array<DBus::Type>] (frozen)
279
408
  # @raise SignatureException
280
409
  def types(string_type)
281
410
  Type::Parser.new(string_type).parse
@@ -286,8 +415,9 @@ module DBus
286
415
  # @param string_type [SingleCompleteType]
287
416
  # @param value [::Object]
288
417
  # @return [Array(DBus::Type::Type,::Object)]
418
+ # @deprecated Use {Data::Variant.new} instead
289
419
  def variant(string_type, value)
290
- [type(string_type), value]
420
+ Data::Variant.new(value, member_type: string_type)
291
421
  end
292
422
  module_function :variant
293
423
  end
data/lib/dbus/xml.rb CHANGED
@@ -134,6 +134,10 @@ module DBus
134
134
  parse_methsig(se, s)
135
135
  i << s
136
136
  end
137
+ e.each("property") do |pe|
138
+ p = Property.from_xml(pe)
139
+ i << p
140
+ end
137
141
  end
138
142
  d = Time.now - t
139
143
  if d > 2