ruby-dbus 0.18.0.beta6 → 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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 54a45385340217271e3fb445cddf6afcddb9892c4bf75b503e7859390f4d2ed7
4
- data.tar.gz: 3c4f71745992c5afece87e34909e67f451717c9398ac6efb6235cc64ad1d1b0c
3
+ metadata.gz: 56815cd47f001f19c6d74cc02f0f1017e6e17d8df44e0949f020e4932adbc622
4
+ data.tar.gz: 4aeda5f0c4972671adf6ae24554aa08ce5e6208846f87f5793562e73b8e7d632
5
5
  SHA512:
6
- metadata.gz: 864aaaaa867ea04247515d875d836560a558b7a3d780712a41dcd52214d95e47e857d640d66a3573eaf4df778a0320f89ad2c59918c005a2fc80adb8a63074cb
7
- data.tar.gz: cabd9d699d8b7aad7c5f77a83aa07389b59c11b34b1219822909a031774b078d0bf001a1bce9bb5912be42caa4adba7608906ebc76dde57ff9f06d13afd7850f
6
+ metadata.gz: 2432d8ada23410027d00c7995c7514e3e927430844cf037fa8496509c47b10b4f5a431335762206bfc9966724d6d84014f57d9bbe31613bfd253145e25b82b77
7
+ data.tar.gz: c1b480afebcdaf53b6fbe084f6150b7c9758d1329a207b4941dd8256cbc3786d42341564b3b8220d9e897e7487d281fede15eab8a31d81741582272519e1ac19
data/NEWS.md CHANGED
@@ -2,6 +2,18 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ## Ruby D-Bus 0.18.0.beta7 - 2022-05-29
6
+
7
+ API:
8
+ * DBus.variant(type, value) is deprecated in favor of
9
+ Data::Variant.new(value, member_type:)
10
+
11
+ Bug fixes:
12
+ * Client-side properties: When calling Properties.Set in
13
+ ProxyObjectInterface#[]=, use the correct type ([#108][]).
14
+
15
+ [#108]: https://github.com/mvidner/ruby-dbus/issues/108
16
+
5
17
  ## Ruby D-Bus 0.18.0.beta6 - 2022-05-25
6
18
 
7
19
  API:
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.18.0.beta6
1
+ 0.18.0.beta7
data/doc/Reference.md CHANGED
@@ -166,12 +166,21 @@ D-Bus has stricter typing than Ruby, so the library must decide
166
166
  which D-Bus type to choose. Most of the time the choice is dictated
167
167
  by the D-Bus signature.
168
168
 
169
+ For exact representation of D-Bus data types, use subclasses
170
+ of {DBus::Data::Base}, such as {DBus::Data::Int16} or {DBus::Data::UInt64}.
171
+
169
172
  ##### Variants
170
173
 
171
174
  If the signature expects a Variant
172
175
  (which is the case for all Properties!) then an explicit mechanism is needed.
173
176
 
174
- 1. A pair [{DBus::Type}, value] specifies to marshall *value* as
177
+ 1. Any {DBus::Data::Base}.
178
+
179
+ 2. A {DBus::Data::Variant} made by {DBus.variant}(signature, value).
180
+ (Formerly this produced the type+value pair below, now it is just an alias
181
+ to the Variant constructor.)
182
+
183
+ 3. A pair [{DBus::Type}, value] specifies to marshall *value* as
175
184
  that specified type.
176
185
  The pair can be produced by {DBus.variant}(signature, value) which
177
186
  gives the same result as [{DBus.type}(signature), value].
@@ -181,13 +190,13 @@ If the signature expects a Variant
181
190
 
182
191
  `foo_i["Bar"] = DBus.variant("au", [0, 1, 1, 2, 3, 5, 8])`
183
192
 
184
- 2. Other values are tried to fit one of these:
193
+ 4. Other values are tried to fit one of these:
185
194
  Boolean, Double, Array of Variants, Hash of String keyed Variants,
186
195
  String, Int32, Int64.
187
196
 
188
- 3. **Deprecated:** A pair [String, value], where String is a valid
197
+ 5. **Deprecated:** A pair [String, value], where String is a valid
189
198
  signature of a single complete type, marshalls value as that
190
- type. This will hit you when you rely on method (2) but happen to have
199
+ type. This will hit you when you rely on method (4) but happen to have
191
200
  a particular string value in an array.
192
201
 
193
202
  ##### Structs
data/lib/dbus/data.rb CHANGED
@@ -601,8 +601,10 @@ module DBus
601
601
 
602
602
  typed_value = case value
603
603
  when Data::Array
604
- raise ArgumentError, "Specified type is #{type} but value type is #{value.type}" \
605
- unless value.type == type
604
+ unless value.type == type
605
+ raise ArgumentError,
606
+ "Specified type is #{type.inspect} but value type is #{value.type.inspect}"
607
+ end
606
608
 
607
609
  value.exact_value
608
610
  else
@@ -651,8 +653,10 @@ module DBus
651
653
 
652
654
  typed_value = case value
653
655
  when self.class
654
- raise ArgumentError, "Specified type is #{type} but value type is #{value.type}" \
655
- unless value.type == type
656
+ unless value.type == type
657
+ raise ArgumentError,
658
+ "Specified type is #{type.inspect} but value type is #{value.type.inspect}"
659
+ end
656
660
 
657
661
  value.exact_value
658
662
  else
@@ -751,13 +755,19 @@ module DBus
751
755
  # @return [Type]
752
756
  attr_reader :member_type
753
757
 
758
+ # Determine the type of *value*
759
+ # @param value [::Object]
760
+ # @return [Type]
761
+ # @api private
762
+ # See also {PacketMarshaller.make_variant}
754
763
  def self.guess_type(value)
755
764
  sct, = PacketMarshaller.make_variant(value)
756
765
  DBus.type(sct)
757
766
  end
758
767
 
759
- # @param member_type [Type,nil]
768
+ # @param member_type [SingleCompleteType,Type,nil]
760
769
  def initialize(value, member_type:)
770
+ member_type = Type::Factory.make_type(member_type) if member_type
761
771
  # TODO: validate that the given *member_type* matches *value*
762
772
  case value
763
773
  when Data::Variant
@@ -775,6 +785,30 @@ module DBus
775
785
  end
776
786
  super(value)
777
787
  end
788
+
789
+ # Internal helpers to keep the {DBus.variant} method working.
790
+ # Formerly it returned just a pair of [DBus.type(string_type), value]
791
+ # so let's provide [0], [1], .first, .last
792
+ def [](index)
793
+ case index
794
+ when 0
795
+ member_type
796
+ when 1
797
+ value
798
+ else
799
+ raise ArgumentError, "DBus.variant can only be indexed with 0 or 1, seen #{index.inspect}"
800
+ end
801
+ end
802
+
803
+ # @see #[]
804
+ def first
805
+ self[0]
806
+ end
807
+
808
+ # @see #[]
809
+ def last
810
+ self[1]
811
+ end
778
812
  end
779
813
 
780
814
  consts = constants.map { |c_sym| const_get(c_sym) }
@@ -238,19 +238,20 @@ module DBus
238
238
  # An (exported) property
239
239
  # https://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-properties
240
240
  class Property
241
- # @return [String] The name of the property, for example FooBar.
241
+ # @return [Symbol] The name of the property, for example FooBar.
242
242
  attr_reader :name
243
243
  # @return [SingleCompleteType]
244
244
  attr_reader :type
245
245
  # @return [Symbol] :read :write or :readwrite
246
246
  attr_reader :access
247
247
 
248
- # @return [Symbol] What to call at Ruby side.
248
+ # @return [Symbol,nil] What to call at Ruby side.
249
249
  # (Always without the trailing `=`)
250
+ # It is `nil` IFF representing a client-side proxy.
250
251
  attr_reader :ruby_name
251
252
 
252
253
  def initialize(name, type, access, ruby_name:)
253
- @name = name
254
+ @name = name.to_sym
254
255
  @type = type
255
256
  @access = access
256
257
  @ruby_name = ruby_name
@@ -270,5 +271,14 @@ module DBus
270
271
  def to_xml
271
272
  " <property type=\"#{@type}\" name=\"#{@name}\" access=\"#{@access}\"/>\n"
272
273
  end
274
+
275
+ # @param xml_node [AbstractXML::Node]
276
+ # @return [Property]
277
+ def self.from_xml(xml_node)
278
+ name = xml_node["name"].to_sym
279
+ type = xml_node["type"]
280
+ access = xml_node["access"].to_sym
281
+ new(name, type, access, ruby_name: nil)
282
+ end
273
283
  end
274
284
  end
@@ -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
@@ -415,8 +415,9 @@ module DBus
415
415
  # @param string_type [SingleCompleteType]
416
416
  # @param value [::Object]
417
417
  # @return [Array(DBus::Type::Type,::Object)]
418
+ # @deprecated Use {Data::Variant.new} instead
418
419
  def variant(string_type, value)
419
- [type(string_type), value]
420
+ Data::Variant.new(value, member_type: string_type)
420
421
  end
421
422
  module_function :variant
422
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
data/spec/data_spec.rb CHANGED
@@ -193,7 +193,7 @@ RSpec.shared_examples "constructor rejects values from this list" do |bad_list|
193
193
  describe "#initialize" do
194
194
  bad_list.each do |(value, exc_class, msg_substr)|
195
195
  it "rejects #{value.inspect} with #{exc_class}: #{msg_substr}" do
196
- msg_re = Regexp.new(Regexp.quote(msg_substr))
196
+ msg_re = Regexp.try_convert(msg_substr) || Regexp.new(Regexp.quote(msg_substr))
197
197
  expect { described_class.new(value) }.to raise_error(exc_class, msg_re)
198
198
  end
199
199
  end
@@ -204,7 +204,7 @@ RSpec.shared_examples "constructor (kwargs) rejects values" do |bad_list|
204
204
  describe "#initialize" do
205
205
  bad_list.each do |(value, kwargs_hash, exc_class, msg_substr)|
206
206
  it "rejects #{value.inspect}, #{kwargs_hash.inspect} with #{exc_class}: #{msg_substr}" do
207
- msg_re = Regexp.new(Regexp.quote(msg_substr))
207
+ msg_re = Regexp.try_convert(msg_substr) || Regexp.new(Regexp.quote(msg_substr))
208
208
  expect { described_class.new(value, **kwargs_hash) }.to raise_error(exc_class, msg_re)
209
209
  end
210
210
  end
@@ -387,8 +387,9 @@ describe DBus::Data do
387
387
 
388
388
  describe "containers" do
389
389
  describe DBus::Data::Array do
390
+ aq = DBus::Data::Array.new([1, 2, 3], type: "aq")
391
+
390
392
  good = [
391
- # [[1, 2, 3], type: nil],
392
393
  [[1, 2, 3], { type: "aq" }],
393
394
  [[1, 2, 3], { type: T::Array[T::UINT16] }],
394
395
  [[1, 2, 3], { type: T::Array["q"] }],
@@ -398,9 +399,14 @@ describe DBus::Data do
398
399
 
399
400
  bad = [
400
401
  # undesirable type guessing
401
- ## [[1, 2, 3], { type: nil }, DBus::InvalidPacketException, "Unknown type code"],
402
- ## [[1, 2, 3], { type: "!" }, DBus::InvalidPacketException, "Unknown type code"]
403
- # TODO: others
402
+ [[1, 2, 3], { type: nil }, ArgumentError, /Expecting DBus::Type.*got nil/],
403
+ [[1, 2, 3], { type: "!" }, DBus::Type::SignatureException, "Unknown type code"],
404
+ [aq, { type: "q" }, ArgumentError, "Expecting \"a\""],
405
+ [aq, { type: "ao" }, ArgumentError,
406
+ "Specified type is ARRAY: [OBJECT_PATH] but value type is ARRAY: [UINT16]"]
407
+ # TODO: how to handle these?
408
+ # [{1 => 2, 3 => 4}, { type: "aq" }, ArgumentError, "?"],
409
+ # [/i am not an array/, { type: "aq" }, ArgumentError, "?"],
404
410
  ]
405
411
 
406
412
  include_examples "#== and #eql? work for container types (inequal)",
@@ -506,7 +512,7 @@ describe DBus::Data do
506
512
  value2 = result1
507
513
  type2 = "(xxx)"
508
514
  expect { described_class.new(value2, type: type2) }
509
- .to raise_error(ArgumentError, /value type is .uuu./)
515
+ .to raise_error(ArgumentError, /value type is STRUCT.*UINT32/)
510
516
  end
511
517
 
512
518
  it "checks that size of type and value match" do
@@ -553,7 +559,7 @@ describe DBus::Data do
553
559
  value2 = result1
554
560
  type2 = T::Hash[T::UINT64, T::UINT64].child
555
561
  expect { described_class.new(value2, type: type2) }
556
- .to raise_error(ArgumentError, /value type is .uu./)
562
+ .to raise_error(ArgumentError, /value type is DICT_ENTRY.*UINT32/)
557
563
  end
558
564
 
559
565
  it "checks that size of type and value match" do
@@ -632,6 +638,36 @@ describe DBus::Data do
632
638
 
633
639
  include_examples "#== and #eql? work for container types (1 value)",
634
640
  "/foo", { member_type: DBus.type(T::STRING) }
641
+
642
+ describe "DBus.variant compatibility" do
643
+ let(:v) { DBus.variant("o", "/foo") }
644
+
645
+ describe "#[]" do
646
+ it "returns the type for 0" do
647
+ expect(v[0]).to eq DBus.type(DBus::Type::OBJECT_PATH)
648
+ end
649
+
650
+ it "returns the value for 1" do
651
+ expect(v[1]).to eq DBus::ObjectPath.new("/foo")
652
+ end
653
+
654
+ it "returns an error for other indices" do
655
+ expect { v[2] }.to raise_error(ArgumentError, /DBus.variant can only be indexed with 0 or 1/)
656
+ end
657
+ end
658
+
659
+ describe "#first" do
660
+ it "returns the type" do
661
+ expect(v.first).to eq DBus.type(DBus::Type::OBJECT_PATH)
662
+ end
663
+ end
664
+
665
+ describe "#last" do
666
+ it "returns the value" do
667
+ expect(v.last).to eq DBus::ObjectPath.new("/foo")
668
+ end
669
+ end
670
+ end
635
671
  end
636
672
  end
637
673
  end
@@ -60,7 +60,7 @@ describe "PropertyTest" do
60
60
 
61
61
  it "tests get all" do
62
62
  all = @iface.all_properties
63
- expect(all.keys.sort).to eq(["MyArray", "MyDict", "MyStruct", "MyVariant", "ReadMe", "ReadOrWriteMe"])
63
+ expect(all.keys.sort).to eq(["MyArray", "MyByte", "MyDict", "MyStruct", "MyVariant", "ReadMe", "ReadOrWriteMe"])
64
64
  end
65
65
 
66
66
  it "tests get all on a V1 object" do
@@ -68,7 +68,7 @@ describe "PropertyTest" do
68
68
  iface = obj["org.ruby.SampleInterface"]
69
69
 
70
70
  all = iface.all_properties
71
- expect(all.keys.sort).to eq(["MyArray", "MyDict", "MyStruct", "MyVariant", "ReadMe", "ReadOrWriteMe"])
71
+ expect(all.keys.sort).to eq(["MyArray", "MyByte", "MyDict", "MyStruct", "MyVariant", "ReadMe", "ReadOrWriteMe"])
72
72
  end
73
73
 
74
74
  it "tests unknown property reading" do
@@ -200,6 +200,36 @@ describe "PropertyTest" do
200
200
  end
201
201
  end
202
202
 
203
+ context "a byte-typed property" do
204
+ # Slightly advanced RSpec:
205
+ # https://rspec.info/documentation/3.9/rspec-expectations/RSpec/Matchers.html#satisfy-instance_method
206
+ let(:a_byte_in_a_variant) do
207
+ satisfying { |x| x.is_a?(DBus::Data::Variant) && x.member_type.to_s == DBus::Type::BYTE }
208
+ # ^ This formatting keeps the matcher on a single line
209
+ # which enables RSpect to cite it if it fails, instead of saying "block".
210
+ end
211
+
212
+ let(:prop_iface) { @obj[DBus::PROPERTY_INTERFACE] }
213
+
214
+ it "gets set with a correct type (#108)" do
215
+ expect(prop_iface).to receive(:Set).with(
216
+ "org.ruby.SampleInterface",
217
+ "MyByte",
218
+ a_byte_in_a_variant
219
+ )
220
+ @iface["MyByte"] = 1
221
+ end
222
+
223
+ it "gets set with a correct type (#108), when using the DBus.variant workaround" do
224
+ expect(prop_iface).to receive(:Set).with(
225
+ "org.ruby.SampleInterface",
226
+ "MyByte",
227
+ a_byte_in_a_variant
228
+ )
229
+ @iface["MyByte"] = DBus.variant("y", 1)
230
+ end
231
+ end
232
+
203
233
  context "marshall.yaml round-trip via a VARIANT property" do
204
234
  marshall_yaml.each do |test|
205
235
  t = OpenStruct.new(test)
@@ -28,6 +28,8 @@ class Test < DBus::Object
28
28
  "three" => [3, 3, 3]
29
29
  }
30
30
  @my_variant = @my_array.dup
31
+ # 201 is a RET instruction for ZX Spectrum which has turned 40 recently
32
+ @my_byte = 201
31
33
  @main_loop = nil
32
34
  end
33
35
 
@@ -111,6 +113,8 @@ class Test < DBus::Object
111
113
  dbus_attr_accessor :my_array, "aq"
112
114
  dbus_attr_accessor :my_dict, "a{sv}"
113
115
  dbus_attr_accessor :my_variant, "v"
116
+
117
+ dbus_attr_accessor :my_byte, "y"
114
118
  end
115
119
 
116
120
  # closing and reopening the same interface
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby-dbus
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.18.0.beta6
4
+ version: 0.18.0.beta7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ruby DBus Team
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-05-25 00:00:00.000000000 Z
11
+ date: 2022-05-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rexml