ruby-dbus 0.18.0.beta6 → 0.18.0.beta7

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