ruby-dbus 0.18.0.beta6 → 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.
- checksums.yaml +4 -4
- data/NEWS.md +68 -0
- data/VERSION +1 -1
- data/doc/Reference.md +13 -4
- data/lib/dbus/bus.rb +3 -7
- data/lib/dbus/data.rb +39 -5
- data/lib/dbus/emits_changed_signal.rb +83 -0
- data/lib/dbus/introspect.rb +44 -4
- data/lib/dbus/object.rb +84 -22
- data/lib/dbus/proxy_object_factory.rb +2 -0
- data/lib/dbus/proxy_object_interface.rb +37 -9
- data/lib/dbus/type.rb +2 -1
- data/lib/dbus/xml.rb +4 -0
- data/lib/dbus.rb +1 -0
- data/spec/data_spec.rb +44 -8
- data/spec/emits_changed_signal_spec.rb +58 -0
- data/spec/object_spec.rb +138 -0
- data/spec/property_spec.rb +35 -2
- data/spec/service_newapi.rb +13 -0
- metadata +12 -8
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: 07f1f2fd26d13923b2601c9c3f29ccf57afd42c0348b937bceea0804eece6d66
         | 
| 4 | 
            +
              data.tar.gz: 5ad80792234951e7ed422b6eba16e7f6e55b41f24a116ef40afaa7f32cdeef74
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: acbe18b2d9695f8959ef6d51a3871e989600291076d6eef870a9215768ed6c7afd599d3af2741e13a733fe2f5cc9f75fdf075a130cafd0a9144b4ca00bd80dc9
         | 
| 7 | 
            +
              data.tar.gz: 0363375dd8c4465aa2650649d0bd62a4f95431b78178edb624a84f5326e395476e0c54e4755b27fedc86caf94b7c059abbdc15af28832417ec1d3e4770ea9ae0
         | 
    
        data/NEWS.md
    CHANGED
    
    | @@ -2,6 +2,74 @@ | |
| 2 2 |  | 
| 3 3 | 
             
            ## Unreleased
         | 
| 4 4 |  | 
| 5 | 
            +
            ## Ruby D-Bus 0.18.1 - 2022-07-13
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            No changes since 0.18.0.beta8.
         | 
| 8 | 
            +
            Repeating the most important changes since 0.17.0:
         | 
| 9 | 
            +
             | 
| 10 | 
            +
            API:
         | 
| 11 | 
            +
             * Introduced DBus::Data classes, use them in Properties.Get,
         | 
| 12 | 
            +
               Properties.GetAll to return correct types as declared ([#97][]).
         | 
| 13 | 
            +
             * Introduced Object#dbus_properties_changed to send correctly typed property
         | 
| 14 | 
            +
               values ([#115][]). Avoid calling PropertiesChanged directly as it will
         | 
| 15 | 
            +
               guess the types.
         | 
| 16 | 
            +
             * Service side `emits_changed_signal` to control emission of
         | 
| 17 | 
            +
               PropertiesChanged: can be assigned within `dbus_interface` or as an option
         | 
| 18 | 
            +
               when declaring properties ([#117][]).
         | 
| 19 | 
            +
             * DBus.variant(type, value) is deprecated in favor of
         | 
| 20 | 
            +
               Data::Variant.new(value, member_type:)
         | 
| 21 | 
            +
             * Added type factories
         | 
| 22 | 
            +
               * Type::Array[type]
         | 
| 23 | 
            +
               * Type::Hash[key_type, value_type]
         | 
| 24 | 
            +
               * Type::Struct[type1, type2...]
         | 
| 25 | 
            +
             | 
| 26 | 
            +
            Bug fixes:
         | 
| 27 | 
            +
             * Fix Object.dbus_reader to work with attr_accessor and automatically produce
         | 
| 28 | 
            +
               dbus_properties_changed for properties that are read-write at
         | 
| 29 | 
            +
               implementation side and read-only at D-Bus side ([#96][])
         | 
| 30 | 
            +
             * Service-side properties: Fix Properties.Get, Properties.GetAll
         | 
| 31 | 
            +
               to use the specific property signature, not the generic
         | 
| 32 | 
            +
               Variant ([#97][], [#105][], [#109][]).
         | 
| 33 | 
            +
             * Client-side properties: When calling Properties.Set in
         | 
| 34 | 
            +
               ProxyObjectInterface#[]=, use the correct type ([#108][]).
         | 
| 35 | 
            +
             * Added thorough tests (`spec/data/marshall.yaml`) to detect nearly all
         | 
| 36 | 
            +
               invalid data at unmarshalling time.
         | 
| 37 | 
            +
             | 
| 38 | 
            +
            Requirements:
         | 
| 39 | 
            +
             * Require Ruby 2.4, because of RuboCop 1.0.
         | 
| 40 | 
            +
             | 
| 41 | 
            +
            ## Ruby D-Bus 0.18.0.beta8 - 2022-06-21
         | 
| 42 | 
            +
             | 
| 43 | 
            +
            Bug fixes:
         | 
| 44 | 
            +
             * Introduced Object#dbus_properties_changed to send correctly typed property
         | 
| 45 | 
            +
               values ([#115][]). Avoid calling PropertiesChanged directly as it will
         | 
| 46 | 
            +
               guess the types.
         | 
| 47 | 
            +
             * Fix Object.dbus_reader to work with attr_accessor and automatically produce
         | 
| 48 | 
            +
               dbus_properties_changed for properties that are read-write at
         | 
| 49 | 
            +
               implementation side and read-only at D-Bus side ([#96][])
         | 
| 50 | 
            +
             | 
| 51 | 
            +
            [#96]: https://github.com/mvidner/ruby-dbus/issues/96
         | 
| 52 | 
            +
             | 
| 53 | 
            +
            API:
         | 
| 54 | 
            +
             * Service side `emits_changed_signal` to control emission of
         | 
| 55 | 
            +
               PropertiesChanged: can be assigned within `dbus_interface` or as an option
         | 
| 56 | 
            +
               when declaring properties ([#117][]).
         | 
| 57 | 
            +
             | 
| 58 | 
            +
            [#115]: https://github.com/mvidner/ruby-dbus/issues/115
         | 
| 59 | 
            +
            [#117]: https://github.com/mvidner/ruby-dbus/pulls/117
         | 
| 60 | 
            +
             | 
| 61 | 
            +
            ## Ruby D-Bus 0.18.0.beta7 - 2022-05-29
         | 
| 62 | 
            +
             | 
| 63 | 
            +
            API:
         | 
| 64 | 
            +
             * DBus.variant(type, value) is deprecated in favor of
         | 
| 65 | 
            +
               Data::Variant.new(value, member_type:)
         | 
| 66 | 
            +
             | 
| 67 | 
            +
            Bug fixes:
         | 
| 68 | 
            +
             * Client-side properties: When calling Properties.Set in
         | 
| 69 | 
            +
               ProxyObjectInterface#[]=, use the correct type ([#108][]).
         | 
| 70 | 
            +
             | 
| 71 | 
            +
            [#108]: https://github.com/mvidner/ruby-dbus/issues/108
         | 
| 72 | 
            +
             | 
| 5 73 | 
             
            ## Ruby D-Bus 0.18.0.beta6 - 2022-05-25
         | 
| 6 74 |  | 
| 7 75 | 
             
            API:
         | 
    
        data/VERSION
    CHANGED
    
    | @@ -1 +1 @@ | |
| 1 | 
            -
            0.18. | 
| 1 | 
            +
            0.18.1
         | 
    
        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.  | 
| 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 | 
            -
             | 
| 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 | 
            -
             | 
| 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 ( | 
| 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/bus.rb
    CHANGED
    
    | @@ -171,15 +171,11 @@ module DBus | |
| 171 171 | 
             
            "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
         | 
| 172 172 | 
             
            '
         | 
| 173 173 | 
             
                  xml += "<node name=\"#{node_opath}\">\n"
         | 
| 174 | 
            -
                   | 
| 174 | 
            +
                  each_key do |k|
         | 
| 175 175 | 
             
                    xml += "  <node name=\"#{k}\" />\n"
         | 
| 176 176 | 
             
                  end
         | 
| 177 | 
            -
                  @object&.intfs&. | 
| 178 | 
            -
                    xml +=  | 
| 179 | 
            -
                    v.methods.each_value { |m| xml += m.to_xml }
         | 
| 180 | 
            -
                    v.signals.each_value { |m| xml += m.to_xml }
         | 
| 181 | 
            -
                    v.properties.each_value { |m| xml += m.to_xml }
         | 
| 182 | 
            -
                    xml += "  </interface>\n"
         | 
| 177 | 
            +
                  @object&.intfs&.each_value do |v|
         | 
| 178 | 
            +
                    xml += v.to_xml
         | 
| 183 179 | 
             
                  end
         | 
| 184 180 | 
             
                  xml += "</node>"
         | 
| 185 181 | 
             
                  xml
         | 
    
        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 | 
            -
                                     | 
| 605 | 
            -
                                       | 
| 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 | 
            -
                                     | 
| 655 | 
            -
                                       | 
| 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) }
         | 
| @@ -0,0 +1,83 @@ | |
| 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 | 
            +
              # Describes the behavior of PropertiesChanged signal, for a single property
         | 
| 13 | 
            +
              # or for an entire interface.
         | 
| 14 | 
            +
              #
         | 
| 15 | 
            +
              # The possible values are:
         | 
| 16 | 
            +
              #
         | 
| 17 | 
            +
              # - *true*: the signal is emitted with the value included.
         | 
| 18 | 
            +
              # - *:invalidates*: the signal is emitted but the value is not included
         | 
| 19 | 
            +
              #   in the signal.
         | 
| 20 | 
            +
              # - *:const*: the property never changes value during the lifetime
         | 
| 21 | 
            +
              #   of the object it belongs to, and hence the signal
         | 
| 22 | 
            +
              #   is never emitted for it (but clients can cache the value)
         | 
| 23 | 
            +
              # - *false*: the signal won't be emitted (clients should re-Get the property value)
         | 
| 24 | 
            +
              #
         | 
| 25 | 
            +
              # The default is:
         | 
| 26 | 
            +
              # - for an interface: *true*
         | 
| 27 | 
            +
              # - for a property: what the parent interface specifies
         | 
| 28 | 
            +
              #
         | 
| 29 | 
            +
              # @see DBus::Object.emits_changed_signal
         | 
| 30 | 
            +
              # @see DBus::Object.dbus_attr_accessor
         | 
| 31 | 
            +
              # @see https://dbus.freedesktop.org/doc/dbus-specification.html#introspection-format
         | 
| 32 | 
            +
              #
         | 
| 33 | 
            +
              # Immutable once constructed.
         | 
| 34 | 
            +
              class EmitsChangedSignal
         | 
| 35 | 
            +
                # @return [true,false,:const,:invalidates]
         | 
| 36 | 
            +
                attr_reader :value
         | 
| 37 | 
            +
             | 
| 38 | 
            +
                # @param value [true,false,:const,:invalidates,nil]
         | 
| 39 | 
            +
                #   See class-level description above, {EmitsChangedSignal}.
         | 
| 40 | 
            +
                # @param interface [Interface,nil]
         | 
| 41 | 
            +
                #   If the (property-level) *value* is unspecified (nil), this is the
         | 
| 42 | 
            +
                #   containing {Interface} to get the value from.
         | 
| 43 | 
            +
                def initialize(value, interface: nil)
         | 
| 44 | 
            +
                  if value.nil?
         | 
| 45 | 
            +
                    raise ArgumentError, "Both arguments are nil" if interface.nil?
         | 
| 46 | 
            +
             | 
| 47 | 
            +
                    @value = interface.emits_changed_signal.value
         | 
| 48 | 
            +
                  else
         | 
| 49 | 
            +
                    expecting = [true, false, :const, :invalidates]
         | 
| 50 | 
            +
                    unless expecting.include?(value)
         | 
| 51 | 
            +
                      raise ArgumentError, "Expecting one of #{expecting.inspect}. Seen #{value.inspect}"
         | 
| 52 | 
            +
                    end
         | 
| 53 | 
            +
             | 
| 54 | 
            +
                    @value = value
         | 
| 55 | 
            +
                  end
         | 
| 56 | 
            +
             | 
| 57 | 
            +
                  freeze
         | 
| 58 | 
            +
                end
         | 
| 59 | 
            +
             | 
| 60 | 
            +
                # Return introspection XML string representation
         | 
| 61 | 
            +
                # @return [String]
         | 
| 62 | 
            +
                def to_xml
         | 
| 63 | 
            +
                  return "" if @value == true
         | 
| 64 | 
            +
             | 
| 65 | 
            +
                  "    <annotation name=\"org.freedesktop.DBus.Property.EmitsChangedSignal\" value=\"#{@value}\"/>\n"
         | 
| 66 | 
            +
                end
         | 
| 67 | 
            +
             | 
| 68 | 
            +
                def to_s
         | 
| 69 | 
            +
                  @value.to_s
         | 
| 70 | 
            +
                end
         | 
| 71 | 
            +
             | 
| 72 | 
            +
                def ==(other)
         | 
| 73 | 
            +
                  if other.is_a?(self.class)
         | 
| 74 | 
            +
                    other.value == @value
         | 
| 75 | 
            +
                  else
         | 
| 76 | 
            +
                    other == value
         | 
| 77 | 
            +
                  end
         | 
| 78 | 
            +
                end
         | 
| 79 | 
            +
                alias eql? ==
         | 
| 80 | 
            +
             | 
| 81 | 
            +
                DEFAULT_ECS = EmitsChangedSignal.new(true)
         | 
| 82 | 
            +
              end
         | 
| 83 | 
            +
            end
         | 
    
        data/lib/dbus/introspect.rb
    CHANGED
    
    | @@ -26,7 +26,7 @@ module DBus | |
| 26 26 | 
             
              # method call instantiates and configures this class for us.
         | 
| 27 27 | 
             
              #
         | 
| 28 28 | 
             
              # It also is the local definition of interface exported by the program.
         | 
| 29 | 
            -
              # At the client side, see ProxyObjectInterface
         | 
| 29 | 
            +
              # At the client side, see {ProxyObjectInterface}.
         | 
| 30 30 | 
             
              class Interface
         | 
| 31 31 | 
             
                # @return [String] The name of the interface.
         | 
| 32 32 | 
             
                attr_reader :name
         | 
| @@ -38,6 +38,9 @@ module DBus | |
| 38 38 | 
             
                # @return [Hash{Symbol => Property}]
         | 
| 39 39 | 
             
                attr_reader :properties
         | 
| 40 40 |  | 
| 41 | 
            +
                # @return [EmitsChangedSignal]
         | 
| 42 | 
            +
                attr_reader :emits_changed_signal
         | 
| 43 | 
            +
             | 
| 41 44 | 
             
                # Creates a new interface with a given _name_.
         | 
| 42 45 | 
             
                def initialize(name)
         | 
| 43 46 | 
             
                  validate_name(name)
         | 
| @@ -45,6 +48,20 @@ module DBus | |
| 45 48 | 
             
                  @methods = {}
         | 
| 46 49 | 
             
                  @signals = {}
         | 
| 47 50 | 
             
                  @properties = {}
         | 
| 51 | 
            +
                  @emits_changed_signal = EmitsChangedSignal::DEFAULT_ECS
         | 
| 52 | 
            +
                end
         | 
| 53 | 
            +
             | 
| 54 | 
            +
                # Helper for {Object.emits_changed_signal=}.
         | 
| 55 | 
            +
                # @api private
         | 
| 56 | 
            +
                def emits_changed_signal=(ecs)
         | 
| 57 | 
            +
                  raise TypeError unless ecs.is_a? EmitsChangedSignal
         | 
| 58 | 
            +
                  # equal?: object identity
         | 
| 59 | 
            +
                  unless @emits_changed_signal.equal?(EmitsChangedSignal::DEFAULT_ECS) ||
         | 
| 60 | 
            +
                         @emits_changed_signal.value == ecs.value
         | 
| 61 | 
            +
                    raise "emits_change_signal was assigned more than once"
         | 
| 62 | 
            +
                  end
         | 
| 63 | 
            +
             | 
| 64 | 
            +
                  @emits_changed_signal = ecs
         | 
| 48 65 | 
             
                end
         | 
| 49 66 |  | 
| 50 67 | 
             
                # Validates a service _name_.
         | 
| @@ -85,6 +102,18 @@ module DBus | |
| 85 102 | 
             
                  define(m)
         | 
| 86 103 | 
             
                end
         | 
| 87 104 | 
             
                alias declare_method define_method
         | 
| 105 | 
            +
             | 
| 106 | 
            +
                # Return introspection XML string representation of the property.
         | 
| 107 | 
            +
                # @return [String]
         | 
| 108 | 
            +
                def to_xml
         | 
| 109 | 
            +
                  xml = "  <interface name=\"#{name}\">\n"
         | 
| 110 | 
            +
                  xml += emits_changed_signal.to_xml
         | 
| 111 | 
            +
                  methods.each_value { |m| xml += m.to_xml }
         | 
| 112 | 
            +
                  signals.each_value { |m| xml += m.to_xml }
         | 
| 113 | 
            +
                  properties.each_value { |m| xml += m.to_xml }
         | 
| 114 | 
            +
                  xml += "  </interface>\n"
         | 
| 115 | 
            +
                  xml
         | 
| 116 | 
            +
                end
         | 
| 88 117 | 
             
              end
         | 
| 89 118 |  | 
| 90 119 | 
             
              # = A formal parameter has a name and a type
         | 
| @@ -190,6 +219,7 @@ module DBus | |
| 190 219 | 
             
                end
         | 
| 191 220 |  | 
| 192 221 | 
             
                # Return an XML string representation of the method interface elment.
         | 
| 222 | 
            +
                # @return [String]
         | 
| 193 223 | 
             
                def to_xml
         | 
| 194 224 | 
             
                  xml = "    <method name=\"#{@name}\">\n"
         | 
| 195 225 | 
             
                  @params.each do |param|
         | 
| @@ -238,19 +268,20 @@ module DBus | |
| 238 268 | 
             
              # An (exported) property
         | 
| 239 269 | 
             
              # https://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-properties
         | 
| 240 270 | 
             
              class Property
         | 
| 241 | 
            -
                # @return [ | 
| 271 | 
            +
                # @return [Symbol] The name of the property, for example FooBar.
         | 
| 242 272 | 
             
                attr_reader :name
         | 
| 243 273 | 
             
                # @return [SingleCompleteType]
         | 
| 244 274 | 
             
                attr_reader :type
         | 
| 245 275 | 
             
                # @return [Symbol] :read :write or :readwrite
         | 
| 246 276 | 
             
                attr_reader :access
         | 
| 247 277 |  | 
| 248 | 
            -
                # @return [Symbol] What to call at Ruby side.
         | 
| 278 | 
            +
                # @return [Symbol,nil] What to call at Ruby side.
         | 
| 249 279 | 
             
                #   (Always without the trailing `=`)
         | 
| 280 | 
            +
                #   It is `nil` IFF representing a client-side proxy.
         | 
| 250 281 | 
             
                attr_reader :ruby_name
         | 
| 251 282 |  | 
| 252 283 | 
             
                def initialize(name, type, access, ruby_name:)
         | 
| 253 | 
            -
                  @name = name
         | 
| 284 | 
            +
                  @name = name.to_sym
         | 
| 254 285 | 
             
                  @type = type
         | 
| 255 286 | 
             
                  @access = access
         | 
| 256 287 | 
             
                  @ruby_name = ruby_name
         | 
| @@ -270,5 +301,14 @@ module DBus | |
| 270 301 | 
             
                def to_xml
         | 
| 271 302 | 
             
                  "    <property type=\"#{@type}\" name=\"#{@name}\" access=\"#{@access}\"/>\n"
         | 
| 272 303 | 
             
                end
         | 
| 304 | 
            +
             | 
| 305 | 
            +
                # @param xml_node [AbstractXML::Node]
         | 
| 306 | 
            +
                # @return [Property]
         | 
| 307 | 
            +
                def self.from_xml(xml_node)
         | 
| 308 | 
            +
                  name = xml_node["name"].to_sym
         | 
| 309 | 
            +
                  type = xml_node["type"]
         | 
| 310 | 
            +
                  access = xml_node["access"].to_sym
         | 
| 311 | 
            +
                  new(name, type, access, ruby_name: nil)
         | 
| 312 | 
            +
                end
         | 
| 273 313 | 
             
              end
         | 
| 274 314 | 
             
            end
         | 
    
        data/lib/dbus/object.rb
    CHANGED
    
    | @@ -102,6 +102,18 @@ module DBus | |
| 102 102 | 
             
                  end
         | 
| 103 103 | 
             
                end
         | 
| 104 104 |  | 
| 105 | 
            +
                # Declare the behavior of PropertiesChanged signal,
         | 
| 106 | 
            +
                # common for all properties in this interface
         | 
| 107 | 
            +
                # (individual properties may override it)
         | 
| 108 | 
            +
                # @example
         | 
| 109 | 
            +
                #   self.emits_changed_signal = :invalidates
         | 
| 110 | 
            +
                # @param [true,false,:const,:invalidates] value
         | 
| 111 | 
            +
                def self.emits_changed_signal=(value)
         | 
| 112 | 
            +
                  raise UndefinedInterface, :emits_changed_signal if @@cur_intf.nil?
         | 
| 113 | 
            +
             | 
| 114 | 
            +
                  @@cur_intf.emits_changed_signal = EmitsChangedSignal.new(value)
         | 
| 115 | 
            +
                end
         | 
| 116 | 
            +
             | 
| 105 117 | 
             
                # A read-write property accessing an instance variable.
         | 
| 106 118 | 
             
                # A combination of `attr_accessor` and {.dbus_accessor}.
         | 
| 107 119 | 
             
                #
         | 
| @@ -114,11 +126,13 @@ module DBus | |
| 114 126 | 
             
                # @param dbus_name [String] if not given it is made
         | 
| 115 127 | 
             
                #   by CamelCasing the ruby_name. foo_bar becomes FooBar
         | 
| 116 128 | 
             
                #   to convert the Ruby convention to the DBus convention.
         | 
| 129 | 
            +
                # @param emits_changed_signal [true,false,:const,:invalidates]
         | 
| 130 | 
            +
                #   see {EmitsChangedSignal}; if unspecified, ask the interface.
         | 
| 117 131 | 
             
                # @return [void]
         | 
| 118 | 
            -
                def self.dbus_attr_accessor(ruby_name, type, dbus_name: nil)
         | 
| 132 | 
            +
                def self.dbus_attr_accessor(ruby_name, type, dbus_name: nil, emits_changed_signal: nil)
         | 
| 119 133 | 
             
                  attr_accessor(ruby_name)
         | 
| 120 134 |  | 
| 121 | 
            -
                  dbus_accessor(ruby_name, type, dbus_name: dbus_name)
         | 
| 135 | 
            +
                  dbus_accessor(ruby_name, type, dbus_name: dbus_name, emits_changed_signal: emits_changed_signal)
         | 
| 122 136 | 
             
                end
         | 
| 123 137 |  | 
| 124 138 | 
             
                # A read-only property accessing an instance variable.
         | 
| @@ -126,19 +140,20 @@ module DBus | |
| 126 140 | 
             
                #
         | 
| 127 141 | 
             
                # Whenever the property value gets changed from "inside" the object,
         | 
| 128 142 | 
             
                # you should emit the `PropertiesChanged` signal by calling
         | 
| 143 | 
            +
                # {#dbus_properties_changed}.
         | 
| 129 144 | 
             
                #
         | 
| 130 | 
            -
                #    | 
| 145 | 
            +
                #   dbus_properties_changed(interface_name, {dbus_name.to_s => value}, [])
         | 
| 131 146 | 
             
                #
         | 
| 132 147 | 
             
                # or, omitting the value in the signal,
         | 
| 133 148 | 
             
                #
         | 
| 134 | 
            -
                #    | 
| 149 | 
            +
                #   dbus_properties_changed(interface_name, {}, [dbus_name.to_s])
         | 
| 135 150 | 
             
                #
         | 
| 136 151 | 
             
                # @param  (see .dbus_attr_accessor)
         | 
| 137 152 | 
             
                # @return (see .dbus_attr_accessor)
         | 
| 138 | 
            -
                def self.dbus_attr_reader(ruby_name, type, dbus_name: nil)
         | 
| 153 | 
            +
                def self.dbus_attr_reader(ruby_name, type, dbus_name: nil, emits_changed_signal: nil)
         | 
| 139 154 | 
             
                  attr_reader(ruby_name)
         | 
| 140 155 |  | 
| 141 | 
            -
                  dbus_reader(ruby_name, type, dbus_name: dbus_name)
         | 
| 156 | 
            +
                  dbus_reader(ruby_name, type, dbus_name: dbus_name, emits_changed_signal: emits_changed_signal)
         | 
| 142 157 | 
             
                end
         | 
| 143 158 |  | 
| 144 159 | 
             
                # A write-only property accessing an instance variable.
         | 
| @@ -146,10 +161,10 @@ module DBus | |
| 146 161 | 
             
                #
         | 
| 147 162 | 
             
                # @param  (see .dbus_attr_accessor)
         | 
| 148 163 | 
             
                # @return (see .dbus_attr_accessor)
         | 
| 149 | 
            -
                def self.dbus_attr_writer(ruby_name, type, dbus_name: nil)
         | 
| 164 | 
            +
                def self.dbus_attr_writer(ruby_name, type, dbus_name: nil, emits_changed_signal: nil)
         | 
| 150 165 | 
             
                  attr_writer(ruby_name)
         | 
| 151 166 |  | 
| 152 | 
            -
                  dbus_writer(ruby_name, type, dbus_name: dbus_name)
         | 
| 167 | 
            +
                  dbus_writer(ruby_name, type, dbus_name: dbus_name, emits_changed_signal: emits_changed_signal)
         | 
| 153 168 | 
             
                end
         | 
| 154 169 |  | 
| 155 170 | 
             
                # A read-write property using a pair of reader/writer methods
         | 
| @@ -160,36 +175,49 @@ module DBus | |
| 160 175 | 
             
                #
         | 
| 161 176 | 
             
                # @param  (see .dbus_attr_accessor)
         | 
| 162 177 | 
             
                # @return (see .dbus_attr_accessor)
         | 
| 163 | 
            -
                def self.dbus_accessor(ruby_name, type, dbus_name: nil)
         | 
| 178 | 
            +
                def self.dbus_accessor(ruby_name, type, dbus_name: nil, emits_changed_signal: nil)
         | 
| 164 179 | 
             
                  raise UndefinedInterface, ruby_name if @@cur_intf.nil?
         | 
| 165 180 |  | 
| 166 181 | 
             
                  dbus_name = make_dbus_name(ruby_name, dbus_name: dbus_name)
         | 
| 167 182 | 
             
                  property = Property.new(dbus_name, type, :readwrite, ruby_name: ruby_name)
         | 
| 168 183 | 
             
                  @@cur_intf.define(property)
         | 
| 169 184 |  | 
| 170 | 
            -
                  dbus_watcher(ruby_name, dbus_name: dbus_name)
         | 
| 185 | 
            +
                  dbus_watcher(ruby_name, dbus_name: dbus_name, emits_changed_signal: emits_changed_signal)
         | 
| 171 186 | 
             
                end
         | 
| 172 187 |  | 
| 173 188 | 
             
                # A read-only property accessing a reader method (which must already exist).
         | 
| 174 189 | 
             
                # (To directly access an instance variable, use {.dbus_attr_reader} instead)
         | 
| 175 190 | 
             
                #
         | 
| 176 | 
            -
                #  | 
| 191 | 
            +
                # At the D-Bus side the property is read only but it makes perfect sense to
         | 
| 192 | 
            +
                # implement it with a read-write attr_accessor. In that case this method
         | 
| 193 | 
            +
                # uses {.dbus_watcher} to set up the PropertiesChanged signal.
         | 
| 194 | 
            +
                #
         | 
| 195 | 
            +
                #   attr_accessor :foo_bar
         | 
| 196 | 
            +
                #   dbus_reader :foo_bar, "s"
         | 
| 197 | 
            +
                #
         | 
| 198 | 
            +
                # If the property value should change by other means than its attr_writer,
         | 
| 177 199 | 
             
                # you should emit the `PropertiesChanged` signal by calling
         | 
| 200 | 
            +
                # {#dbus_properties_changed}.
         | 
| 178 201 | 
             
                #
         | 
| 179 | 
            -
                #    | 
| 202 | 
            +
                #   dbus_properties_changed(interface_name, {dbus_name.to_s => value}, [])
         | 
| 180 203 | 
             
                #
         | 
| 181 204 | 
             
                # or, omitting the value in the signal,
         | 
| 182 205 | 
             
                #
         | 
| 183 | 
            -
                #    | 
| 206 | 
            +
                #   dbus_properties_changed(interface_name, {}, [dbus_name.to_s])
         | 
| 184 207 | 
             
                #
         | 
| 185 208 | 
             
                # @param  (see .dbus_attr_accessor)
         | 
| 186 209 | 
             
                # @return (see .dbus_attr_accessor)
         | 
| 187 | 
            -
                def self.dbus_reader(ruby_name, type, dbus_name: nil)
         | 
| 210 | 
            +
                def self.dbus_reader(ruby_name, type, dbus_name: nil, emits_changed_signal: nil)
         | 
| 188 211 | 
             
                  raise UndefinedInterface, ruby_name if @@cur_intf.nil?
         | 
| 189 212 |  | 
| 190 213 | 
             
                  dbus_name = make_dbus_name(ruby_name, dbus_name: dbus_name)
         | 
| 191 214 | 
             
                  property = Property.new(dbus_name, type, :read, ruby_name: ruby_name)
         | 
| 192 215 | 
             
                  @@cur_intf.define(property)
         | 
| 216 | 
            +
             | 
| 217 | 
            +
                  ruby_name_eq = "#{ruby_name}=".to_sym
         | 
| 218 | 
            +
                  return unless method_defined?(ruby_name_eq)
         | 
| 219 | 
            +
             | 
| 220 | 
            +
                  dbus_watcher(ruby_name, dbus_name: dbus_name, emits_changed_signal: emits_changed_signal)
         | 
| 193 221 | 
             
                end
         | 
| 194 222 |  | 
| 195 223 | 
             
                # A write-only property accessing a writer method (which must already exist).
         | 
| @@ -199,14 +227,14 @@ module DBus | |
| 199 227 | 
             
                #
         | 
| 200 228 | 
             
                # @param  (see .dbus_attr_accessor)
         | 
| 201 229 | 
             
                # @return (see .dbus_attr_accessor)
         | 
| 202 | 
            -
                def self.dbus_writer(ruby_name, type, dbus_name: nil)
         | 
| 230 | 
            +
                def self.dbus_writer(ruby_name, type, dbus_name: nil, emits_changed_signal: nil)
         | 
| 203 231 | 
             
                  raise UndefinedInterface, ruby_name if @@cur_intf.nil?
         | 
| 204 232 |  | 
| 205 233 | 
             
                  dbus_name = make_dbus_name(ruby_name, dbus_name: dbus_name)
         | 
| 206 234 | 
             
                  property = Property.new(dbus_name, type, :write, ruby_name: ruby_name)
         | 
| 207 235 | 
             
                  @@cur_intf.define(property)
         | 
| 208 236 |  | 
| 209 | 
            -
                  dbus_watcher(ruby_name, dbus_name: dbus_name)
         | 
| 237 | 
            +
                  dbus_watcher(ruby_name, dbus_name: dbus_name, emits_changed_signal: emits_changed_signal)
         | 
| 210 238 | 
             
                end
         | 
| 211 239 |  | 
| 212 240 | 
             
                # Enables automatic sending of the PropertiesChanged signal.
         | 
| @@ -218,11 +246,13 @@ module DBus | |
| 218 246 | 
             
                # @param dbus_name [String] if not given it is made
         | 
| 219 247 | 
             
                #   by CamelCasing the ruby_name. foo_bar becomes FooBar
         | 
| 220 248 | 
             
                #   to convert the Ruby convention to the DBus convention.
         | 
| 249 | 
            +
                # @param emits_changed_signal [true,false,:const,:invalidates]
         | 
| 250 | 
            +
                #   see {EmitsChangedSignal}; if unspecified, ask the interface.
         | 
| 221 251 | 
             
                # @return [void]
         | 
| 222 | 
            -
                def self.dbus_watcher(ruby_name, dbus_name: nil)
         | 
| 252 | 
            +
                def self.dbus_watcher(ruby_name, dbus_name: nil, emits_changed_signal: nil)
         | 
| 223 253 | 
             
                  raise UndefinedInterface, ruby_name if @@cur_intf.nil?
         | 
| 224 254 |  | 
| 225 | 
            -
                   | 
| 255 | 
            +
                  interface_name = @@cur_intf.name
         | 
| 226 256 |  | 
| 227 257 | 
             
                  ruby_name = ruby_name.to_s.sub(/=$/, "").to_sym
         | 
| 228 258 | 
             
                  ruby_name_eq = "#{ruby_name}=".to_sym
         | 
| @@ -230,14 +260,27 @@ module DBus | |
| 230 260 |  | 
| 231 261 | 
             
                  dbus_name = make_dbus_name(ruby_name, dbus_name: dbus_name)
         | 
| 232 262 |  | 
| 263 | 
            +
                  emits_changed_signal = EmitsChangedSignal.new(emits_changed_signal, interface: @@cur_intf)
         | 
| 264 | 
            +
             | 
| 233 265 | 
             
                  # the argument order is alias_method(new_name, existing_name)
         | 
| 234 266 | 
             
                  alias_method original_ruby_name_eq, ruby_name_eq
         | 
| 235 267 | 
             
                  define_method ruby_name_eq do |value|
         | 
| 236 | 
            -
                    public_send(original_ruby_name_eq, value)
         | 
| 268 | 
            +
                    result = public_send(original_ruby_name_eq, value)
         | 
| 269 | 
            +
             | 
| 270 | 
            +
                    case emits_changed_signal.value
         | 
| 271 | 
            +
                    when true
         | 
| 272 | 
            +
                      # signature: "interface:s, changed_props:a{sv}, invalidated_props:as"
         | 
| 273 | 
            +
                      dbus_properties_changed(interface_name, { dbus_name.to_s => value }, [])
         | 
| 274 | 
            +
                    when :invalidates
         | 
| 275 | 
            +
                      dbus_properties_changed(interface_name, {}, [dbus_name.to_s])
         | 
| 276 | 
            +
                    when :const
         | 
| 277 | 
            +
                      # Oh my, seeing a value change of a supposedly constant property.
         | 
| 278 | 
            +
                      # Maybe should have raised at declaration time, don't make a fuss now.
         | 
| 279 | 
            +
                    when false
         | 
| 280 | 
            +
                      # Do nothing
         | 
| 281 | 
            +
                    end
         | 
| 237 282 |  | 
| 238 | 
            -
                     | 
| 239 | 
            -
                    # PropertiesChanged, "interface:s, changed_properties:a{sv}, invalidated_properties:as"
         | 
| 240 | 
            -
                    PropertiesChanged(cur_intf.name, { dbus_name.to_s => value }, [])
         | 
| 283 | 
            +
                    result
         | 
| 241 284 | 
             
                  end
         | 
| 242 285 | 
             
                end
         | 
| 243 286 |  | 
| @@ -301,6 +344,25 @@ module DBus | |
| 301 344 | 
             
                  dbus_name.to_sym
         | 
| 302 345 | 
             
                end
         | 
| 303 346 |  | 
| 347 | 
            +
                # Use this instead of calling PropertiesChanged directly. This one
         | 
| 348 | 
            +
                # considers not only the PC signature (which says that all property values
         | 
| 349 | 
            +
                # are variants) but also the specific property type.
         | 
| 350 | 
            +
                # @param interface_name [String] interface name like "org.example.ManagerManager"
         | 
| 351 | 
            +
                # @param changed_props [Hash{String => ::Object}]
         | 
| 352 | 
            +
                #   changed properties (D-Bus names) and their values.
         | 
| 353 | 
            +
                # @param invalidated_props [Array<String>]
         | 
| 354 | 
            +
                #   names of properties whose changed value is not specified
         | 
| 355 | 
            +
                def dbus_properties_changed(interface_name, changed_props, invalidated_props)
         | 
| 356 | 
            +
                  typed_changed_props = changed_props.map do |dbus_name, value|
         | 
| 357 | 
            +
                    property = dbus_lookup_property(interface_name, dbus_name)
         | 
| 358 | 
            +
                    type = property.type
         | 
| 359 | 
            +
                    typed_value = Data.make_typed(type, value)
         | 
| 360 | 
            +
                    variant = Data::Variant.new(typed_value, member_type: type)
         | 
| 361 | 
            +
                    [dbus_name, variant]
         | 
| 362 | 
            +
                  end.to_h
         | 
| 363 | 
            +
                  PropertiesChanged(interface_name, typed_changed_props, invalidated_props)
         | 
| 364 | 
            +
                end
         | 
| 365 | 
            +
             | 
| 304 366 | 
             
                # @param interface_name [String]
         | 
| 305 367 | 
             
                # @param property_name [String]
         | 
| 306 368 | 
             
                # @return [Property]
         | 
| @@ -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 | 
            -
                #  | 
| 19 | 
            -
                 | 
| 20 | 
            -
                #  | 
| 21 | 
            -
                 | 
| 22 | 
            -
                #  | 
| 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  | 
| 144 | 
            +
                # @param property_name [String]
         | 
| 133 145 | 
             
                # @param value [Object]
         | 
| 134 | 
            -
                def []=( | 
| 135 | 
            -
                   | 
| 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#initialize} instead
         | 
| 418 419 | 
             
              def variant(string_type, value)
         | 
| 419 | 
            -
                 | 
| 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
    
    
    
        data/lib/dbus.rb
    CHANGED
    
    | @@ -15,6 +15,7 @@ require_relative "dbus/auth" | |
| 15 15 | 
             
            require_relative "dbus/bus"
         | 
| 16 16 | 
             
            require_relative "dbus/bus_name"
         | 
| 17 17 | 
             
            require_relative "dbus/data"
         | 
| 18 | 
            +
            require_relative "dbus/emits_changed_signal"
         | 
| 18 19 | 
             
            require_relative "dbus/error"
         | 
| 19 20 | 
             
            require_relative "dbus/introspect"
         | 
| 20 21 | 
             
            require_relative "dbus/logger"
         | 
    
        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 | 
            -
                     | 
| 402 | 
            -
                     | 
| 403 | 
            -
                     | 
| 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  | 
| 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  | 
| 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
         | 
| @@ -0,0 +1,58 @@ | |
| 1 | 
            +
            #!/usr/bin/env rspec
         | 
| 2 | 
            +
            # frozen_string_literal: true
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            require_relative "spec_helper"
         | 
| 5 | 
            +
            require "dbus"
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            describe DBus::EmitsChangedSignal do
         | 
| 8 | 
            +
              describe "#initialize" do
         | 
| 9 | 
            +
                it "accepts a simple value" do
         | 
| 10 | 
            +
                  expect(described_class.new(:const).value).to eq :const
         | 
| 11 | 
            +
                end
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                it "avoids nil by asking the interface" do
         | 
| 14 | 
            +
                  ifc = DBus::Interface.new("org.example.Foo")
         | 
| 15 | 
            +
                  ifc.emits_changed_signal = described_class.new(:invalidates)
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                  expect(described_class.new(nil, interface: ifc).value).to eq :invalidates
         | 
| 18 | 
            +
                end
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                it "fails for unknown value" do
         | 
| 21 | 
            +
                  expect { described_class.new(:huh) }.to raise_error(ArgumentError, /Seen :huh/)
         | 
| 22 | 
            +
                end
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                it "fails for 2 nils" do
         | 
| 25 | 
            +
                  expect { described_class.new(nil, interface: nil) }.to raise_error(ArgumentError, /Both/)
         | 
| 26 | 
            +
                end
         | 
| 27 | 
            +
              end
         | 
| 28 | 
            +
             | 
| 29 | 
            +
              describe "#==" do
         | 
| 30 | 
            +
                it "is true for two different objects with the same value" do
         | 
| 31 | 
            +
                  const_a = described_class.new(:const)
         | 
| 32 | 
            +
                  const_b = described_class.new(:const)
         | 
| 33 | 
            +
                  expect(const_a == const_b).to be true
         | 
| 34 | 
            +
                end
         | 
| 35 | 
            +
              end
         | 
| 36 | 
            +
             | 
| 37 | 
            +
              describe "#to_xml" do
         | 
| 38 | 
            +
                it "uses a string value" do
         | 
| 39 | 
            +
                  expect(described_class.new(:const).to_xml)
         | 
| 40 | 
            +
                    .to eq "    <annotation name=\"org.freedesktop.DBus.Property.EmitsChangedSignal\" value=\"const\"/>\n"
         | 
| 41 | 
            +
                end
         | 
| 42 | 
            +
              end
         | 
| 43 | 
            +
             | 
| 44 | 
            +
              describe "#to_s" do
         | 
| 45 | 
            +
                it "uses a string value" do
         | 
| 46 | 
            +
                  expect(described_class.new(:const).to_s).to eq "const"
         | 
| 47 | 
            +
                end
         | 
| 48 | 
            +
              end
         | 
| 49 | 
            +
            end
         | 
| 50 | 
            +
             | 
| 51 | 
            +
            describe DBus::Interface do
         | 
| 52 | 
            +
              describe ".emits_changed_signal=" do
         | 
| 53 | 
            +
                it "only allows an EmitsChangedSignal as argument" do
         | 
| 54 | 
            +
                  ifc = described_class.new("org.ruby.Interface")
         | 
| 55 | 
            +
                  expect { ifc.emits_changed_signal = :const }.to raise_error(TypeError)
         | 
| 56 | 
            +
                end
         | 
| 57 | 
            +
              end
         | 
| 58 | 
            +
            end
         | 
    
        data/spec/object_spec.rb
    ADDED
    
    | @@ -0,0 +1,138 @@ | |
| 1 | 
            +
            #!/usr/bin/env rspec
         | 
| 2 | 
            +
            # frozen_string_literal: true
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            require_relative "spec_helper"
         | 
| 5 | 
            +
            require "dbus"
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            class ObjectTest < DBus::Object
         | 
| 8 | 
            +
              T = DBus::Type unless const_defined? "T"
         | 
| 9 | 
            +
             | 
| 10 | 
            +
              dbus_interface "org.ruby.ServerTest" do
         | 
| 11 | 
            +
                dbus_attr_writer :write_me, T::Struct[String, String]
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                attr_accessor :read_only_for_dbus
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                dbus_reader :read_only_for_dbus, T::STRING, emits_changed_signal: :invalidates
         | 
| 16 | 
            +
              end
         | 
| 17 | 
            +
            end
         | 
| 18 | 
            +
             | 
| 19 | 
            +
            describe DBus::Object do
         | 
| 20 | 
            +
              describe ".dbus_attr_writer" do
         | 
| 21 | 
            +
                describe "the declared assignment method" do
         | 
| 22 | 
            +
                  # Slightly advanced RSpec:
         | 
| 23 | 
            +
                  # https://rspec.info/documentation/3.9/rspec-expectations/RSpec/Matchers.html#satisfy-instance_method
         | 
| 24 | 
            +
                  let(:a_struct_in_a_variant) do
         | 
| 25 | 
            +
                    satisfying { |x| x.is_a?(DBus::Data::Variant) && x.member_type.to_s == "(ss)" }
         | 
| 26 | 
            +
                    # ^ This formatting keeps the matcher on a single line
         | 
| 27 | 
            +
                    # which enables RSpec to cite it if it fails, instead of saying "block".
         | 
| 28 | 
            +
                  end
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                  it "emits PropertyChanged with correctly typed argument" do
         | 
| 31 | 
            +
                    obj = ObjectTest.new("/test")
         | 
| 32 | 
            +
                    expect(obj).to receive(:PropertiesChanged).with(
         | 
| 33 | 
            +
                      "org.ruby.ServerTest",
         | 
| 34 | 
            +
                      {
         | 
| 35 | 
            +
                        "WriteMe" => a_struct_in_a_variant
         | 
| 36 | 
            +
                      },
         | 
| 37 | 
            +
                      []
         | 
| 38 | 
            +
                    )
         | 
| 39 | 
            +
                    # bug: call PC with simply the assigned value,
         | 
| 40 | 
            +
                    # which will need type guessing
         | 
| 41 | 
            +
                    obj.write_me = ["two", "strings"]
         | 
| 42 | 
            +
                  end
         | 
| 43 | 
            +
                end
         | 
| 44 | 
            +
              end
         | 
| 45 | 
            +
             | 
| 46 | 
            +
              describe ".dbus_accessor" do
         | 
| 47 | 
            +
                it "can only be used within a dbus_interface" do
         | 
| 48 | 
            +
                  expect do
         | 
| 49 | 
            +
                    ObjectTest.instance_exec do
         | 
| 50 | 
            +
                      dbus_accessor :foo, DBus::Type::STRING
         | 
| 51 | 
            +
                    end
         | 
| 52 | 
            +
                  end.to raise_error(DBus::Object::UndefinedInterface)
         | 
| 53 | 
            +
                end
         | 
| 54 | 
            +
              end
         | 
| 55 | 
            +
             | 
| 56 | 
            +
              describe ".dbus_reader" do
         | 
| 57 | 
            +
                it "can only be used within a dbus_interface" do
         | 
| 58 | 
            +
                  expect do
         | 
| 59 | 
            +
                    ObjectTest.instance_exec do
         | 
| 60 | 
            +
                      dbus_reader :foo, DBus::Type::STRING
         | 
| 61 | 
            +
                    end
         | 
| 62 | 
            +
                  end.to raise_error(DBus::Object::UndefinedInterface)
         | 
| 63 | 
            +
                end
         | 
| 64 | 
            +
              end
         | 
| 65 | 
            +
             | 
| 66 | 
            +
              describe ".dbus_reader, when paired with attr_accessor" do
         | 
| 67 | 
            +
                describe "the declared assignment method" do
         | 
| 68 | 
            +
                  it "emits PropertyChanged" do
         | 
| 69 | 
            +
                    obj = ObjectTest.new("/test")
         | 
| 70 | 
            +
                    expect(obj).to receive(:PropertiesChanged).with(
         | 
| 71 | 
            +
                      "org.ruby.ServerTest",
         | 
| 72 | 
            +
                      {},
         | 
| 73 | 
            +
                      ["ReadOnlyForDbus"]
         | 
| 74 | 
            +
                    )
         | 
| 75 | 
            +
                    obj.read_only_for_dbus = "myvalue"
         | 
| 76 | 
            +
                  end
         | 
| 77 | 
            +
                end
         | 
| 78 | 
            +
              end
         | 
| 79 | 
            +
             | 
| 80 | 
            +
              describe ".dbus_writer" do
         | 
| 81 | 
            +
                it "can only be used within a dbus_interface" do
         | 
| 82 | 
            +
                  expect do
         | 
| 83 | 
            +
                    ObjectTest.instance_exec do
         | 
| 84 | 
            +
                      dbus_writer :foo, DBus::Type::STRING
         | 
| 85 | 
            +
                    end
         | 
| 86 | 
            +
                  end.to raise_error(DBus::Object::UndefinedInterface)
         | 
| 87 | 
            +
                end
         | 
| 88 | 
            +
              end
         | 
| 89 | 
            +
             | 
| 90 | 
            +
              describe ".dbus_watcher" do
         | 
| 91 | 
            +
                it "can only be used within a dbus_interface" do
         | 
| 92 | 
            +
                  expect do
         | 
| 93 | 
            +
                    ObjectTest.instance_exec do
         | 
| 94 | 
            +
                      dbus_watcher :foo
         | 
| 95 | 
            +
                    end
         | 
| 96 | 
            +
                  end.to raise_error(DBus::Object::UndefinedInterface)
         | 
| 97 | 
            +
                end
         | 
| 98 | 
            +
              end
         | 
| 99 | 
            +
             | 
| 100 | 
            +
              describe ".dbus_method" do
         | 
| 101 | 
            +
                it "can only be used within a dbus_interface" do
         | 
| 102 | 
            +
                  expect do
         | 
| 103 | 
            +
                    ObjectTest.instance_exec do
         | 
| 104 | 
            +
                      dbus_method :foo do
         | 
| 105 | 
            +
                      end
         | 
| 106 | 
            +
                    end
         | 
| 107 | 
            +
                  end.to raise_error(DBus::Object::UndefinedInterface)
         | 
| 108 | 
            +
                end
         | 
| 109 | 
            +
              end
         | 
| 110 | 
            +
             | 
| 111 | 
            +
              describe ".emits_changed_signal" do
         | 
| 112 | 
            +
                it "raises UndefinedInterface when so" do
         | 
| 113 | 
            +
                  expect { ObjectTest.emits_changed_signal = false }
         | 
| 114 | 
            +
                    .to raise_error DBus::Object::UndefinedInterface
         | 
| 115 | 
            +
                end
         | 
| 116 | 
            +
             | 
| 117 | 
            +
                it "assigns to the current interface" do
         | 
| 118 | 
            +
                  ObjectTest.instance_exec do
         | 
| 119 | 
            +
                    dbus_interface "org.ruby.Interface" do
         | 
| 120 | 
            +
                      self.emits_changed_signal = false
         | 
| 121 | 
            +
                    end
         | 
| 122 | 
            +
                  end
         | 
| 123 | 
            +
                  ecs = ObjectTest.intfs["org.ruby.Interface"].emits_changed_signal
         | 
| 124 | 
            +
                  expect(ecs).to eq false
         | 
| 125 | 
            +
                end
         | 
| 126 | 
            +
             | 
| 127 | 
            +
                it "only can be assigned once" do
         | 
| 128 | 
            +
                  expect do
         | 
| 129 | 
            +
                    Class.new(DBus::Object) do
         | 
| 130 | 
            +
                      dbus_interface "org.ruby.Interface" do
         | 
| 131 | 
            +
                        self.emits_changed_signal = false
         | 
| 132 | 
            +
                        self.emits_changed_signal = :invalidates
         | 
| 133 | 
            +
                      end
         | 
| 134 | 
            +
                    end
         | 
| 135 | 
            +
                  end.to raise_error(RuntimeError, /assigned more than once/)
         | 
| 136 | 
            +
                end
         | 
| 137 | 
            +
              end
         | 
| 138 | 
            +
            end
         | 
    
        data/spec/property_spec.rb
    CHANGED
    
    | @@ -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
         | 
| @@ -110,6 +110,7 @@ describe "PropertyTest" do | |
| 110 110 | 
             
                end
         | 
| 111 111 |  | 
| 112 112 | 
             
                @iface["ReadOrWriteMe"] = "VALUE"
         | 
| 113 | 
            +
                @iface.SetTwoProperties("REAMDE", 255)
         | 
| 113 114 |  | 
| 114 115 | 
             
                # loop to process the signal. complicated :-( see signal_spec.rb
         | 
| 115 116 | 
             
                loop = DBus::Main.new
         | 
| @@ -123,6 +124,8 @@ describe "PropertyTest" do | |
| 123 124 | 
             
                quitter.join
         | 
| 124 125 |  | 
| 125 126 | 
             
                expect(received["ReadOrWriteMe"]).to eq("VALUE")
         | 
| 127 | 
            +
                expect(received["ReadMe"]).to eq("REAMDE")
         | 
| 128 | 
            +
                expect(received["MyByte"]).to eq(255)
         | 
| 126 129 | 
             
              end
         | 
| 127 130 |  | 
| 128 131 | 
             
              context "a struct-typed property" do
         | 
| @@ -200,6 +203,36 @@ describe "PropertyTest" do | |
| 200 203 | 
             
                end
         | 
| 201 204 | 
             
              end
         | 
| 202 205 |  | 
| 206 | 
            +
              context "a byte-typed property" do
         | 
| 207 | 
            +
                # Slightly advanced RSpec:
         | 
| 208 | 
            +
                # https://rspec.info/documentation/3.9/rspec-expectations/RSpec/Matchers.html#satisfy-instance_method
         | 
| 209 | 
            +
                let(:a_byte_in_a_variant) do
         | 
| 210 | 
            +
                  satisfying { |x| x.is_a?(DBus::Data::Variant) && x.member_type.to_s == DBus::Type::BYTE }
         | 
| 211 | 
            +
                  # ^ This formatting keeps the matcher on a single line
         | 
| 212 | 
            +
                  # which enables RSpec to cite it if it fails, instead of saying "block".
         | 
| 213 | 
            +
                end
         | 
| 214 | 
            +
             | 
| 215 | 
            +
                let(:prop_iface) { @obj[DBus::PROPERTY_INTERFACE] }
         | 
| 216 | 
            +
             | 
| 217 | 
            +
                it "gets set with a correct type (#108)" do
         | 
| 218 | 
            +
                  expect(prop_iface).to receive(:Set).with(
         | 
| 219 | 
            +
                    "org.ruby.SampleInterface",
         | 
| 220 | 
            +
                    "MyByte",
         | 
| 221 | 
            +
                    a_byte_in_a_variant
         | 
| 222 | 
            +
                  )
         | 
| 223 | 
            +
                  @iface["MyByte"] = 1
         | 
| 224 | 
            +
                end
         | 
| 225 | 
            +
             | 
| 226 | 
            +
                it "gets set with a correct type (#108), when using the DBus.variant workaround" do
         | 
| 227 | 
            +
                  expect(prop_iface).to receive(:Set).with(
         | 
| 228 | 
            +
                    "org.ruby.SampleInterface",
         | 
| 229 | 
            +
                    "MyByte",
         | 
| 230 | 
            +
                    a_byte_in_a_variant
         | 
| 231 | 
            +
                  )
         | 
| 232 | 
            +
                  @iface["MyByte"] = DBus.variant("y", 1)
         | 
| 233 | 
            +
                end
         | 
| 234 | 
            +
              end
         | 
| 235 | 
            +
             | 
| 203 236 | 
             
              context "marshall.yaml round-trip via a VARIANT property" do
         | 
| 204 237 | 
             
                marshall_yaml.each do |test|
         | 
| 205 238 | 
             
                  t = OpenStruct.new(test)
         | 
    
        data/spec/service_newapi.rb
    CHANGED
    
    | @@ -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,17 @@ 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"
         | 
| 118 | 
            +
             | 
| 119 | 
            +
                # to test dbus_properties_changed
         | 
| 120 | 
            +
                dbus_method :SetTwoProperties, "in read_me:s, in byte:y" do |read_me, byte|
         | 
| 121 | 
            +
                  @read_me = read_me
         | 
| 122 | 
            +
                  @my_byte = byte
         | 
| 123 | 
            +
                  dbus_properties_changed(INTERFACE,
         | 
| 124 | 
            +
                                          { "ReadMe" => read_me, "MyByte" => byte },
         | 
| 125 | 
            +
                                          [])
         | 
| 126 | 
            +
                end
         | 
| 114 127 | 
             
              end
         | 
| 115 128 |  | 
| 116 129 | 
             
              # 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. | 
| 4 | 
            +
              version: 0.18.1
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Ruby DBus Team
         | 
| 8 | 
            -
            autorequire:
         | 
| 8 | 
            +
            autorequire: 
         | 
| 9 9 | 
             
            bindir: bin
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date: 2022- | 
| 11 | 
            +
            date: 2022-07-13 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 14 | 
             
              name: rexml
         | 
| @@ -146,6 +146,7 @@ files: | |
| 146 146 | 
             
            - lib/dbus/core_ext/class/attribute.rb
         | 
| 147 147 | 
             
            - lib/dbus/core_ext/module/redefine_method.rb
         | 
| 148 148 | 
             
            - lib/dbus/data.rb
         | 
| 149 | 
            +
            - lib/dbus/emits_changed_signal.rb
         | 
| 149 150 | 
             
            - lib/dbus/error.rb
         | 
| 150 151 | 
             
            - lib/dbus/introspect.rb
         | 
| 151 152 | 
             
            - lib/dbus/logger.rb
         | 
| @@ -172,12 +173,14 @@ files: | |
| 172 173 | 
             
            - spec/client_robustness_spec.rb
         | 
| 173 174 | 
             
            - spec/data/marshall.yaml
         | 
| 174 175 | 
             
            - spec/data_spec.rb
         | 
| 176 | 
            +
            - spec/emits_changed_signal_spec.rb
         | 
| 175 177 | 
             
            - spec/err_msg_spec.rb
         | 
| 176 178 | 
             
            - spec/introspect_xml_parser_spec.rb
         | 
| 177 179 | 
             
            - spec/introspection_spec.rb
         | 
| 178 180 | 
             
            - spec/main_loop_spec.rb
         | 
| 179 181 | 
             
            - spec/node_spec.rb
         | 
| 180 182 | 
             
            - spec/object_path_spec.rb
         | 
| 183 | 
            +
            - spec/object_spec.rb
         | 
| 181 184 | 
             
            - spec/packet_marshaller_spec.rb
         | 
| 182 185 | 
             
            - spec/packet_unmarshaller_spec.rb
         | 
| 183 186 | 
             
            - spec/property_spec.rb
         | 
| @@ -202,7 +205,7 @@ homepage: https://github.com/mvidner/ruby-dbus | |
| 202 205 | 
             
            licenses:
         | 
| 203 206 | 
             
            - LGPL-2.1
         | 
| 204 207 | 
             
            metadata: {}
         | 
| 205 | 
            -
            post_install_message:
         | 
| 208 | 
            +
            post_install_message: 
         | 
| 206 209 | 
             
            rdoc_options: []
         | 
| 207 210 | 
             
            require_paths:
         | 
| 208 211 | 
             
            - lib
         | 
| @@ -213,12 +216,13 @@ required_ruby_version: !ruby/object:Gem::Requirement | |
| 213 216 | 
             
                  version: 2.4.0
         | 
| 214 217 | 
             
            required_rubygems_version: !ruby/object:Gem::Requirement
         | 
| 215 218 | 
             
              requirements:
         | 
| 216 | 
            -
              - - " | 
| 219 | 
            +
              - - ">="
         | 
| 217 220 | 
             
                - !ruby/object:Gem::Version
         | 
| 218 | 
            -
                  version:  | 
| 221 | 
            +
                  version: '0'
         | 
| 219 222 | 
             
            requirements: []
         | 
| 220 | 
            -
             | 
| 221 | 
            -
             | 
| 223 | 
            +
            rubyforge_project: 
         | 
| 224 | 
            +
            rubygems_version: 2.7.6.3
         | 
| 225 | 
            +
            signing_key: 
         | 
| 222 226 | 
             
            specification_version: 4
         | 
| 223 227 | 
             
            summary: Ruby module for interaction with D-Bus
         | 
| 224 228 | 
             
            test_files: []
         |