ruby-dbus 0.16.0 → 0.18.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/NEWS.md +160 -0
- data/README.md +3 -5
- data/Rakefile +18 -8
- data/VERSION +1 -1
- data/doc/Reference.md +106 -7
- data/examples/doc/_extract_examples +7 -0
- data/examples/gdbus/gdbus +31 -24
- data/examples/no-introspect/nm-test.rb +2 -0
- data/examples/no-introspect/tracker-test.rb +3 -1
- data/examples/rhythmbox/playpause.rb +2 -1
- data/examples/service/call_service.rb +2 -1
- data/examples/service/complex-property.rb +21 -0
- data/examples/service/service_newapi.rb +1 -1
- data/examples/simple/call_introspect.rb +1 -0
- data/examples/simple/get_id.rb +2 -1
- data/examples/simple/properties.rb +2 -0
- data/examples/utils/listnames.rb +1 -0
- data/examples/utils/notify.rb +1 -0
- data/lib/dbus/api_options.rb +9 -0
- data/lib/dbus/auth.rb +20 -15
- data/lib/dbus/bus.rb +123 -75
- data/lib/dbus/bus_name.rb +12 -8
- data/lib/dbus/core_ext/class/attribute.rb +1 -1
- data/lib/dbus/data.rb +821 -0
- data/lib/dbus/emits_changed_signal.rb +83 -0
- data/lib/dbus/error.rb +4 -2
- data/lib/dbus/introspect.rb +132 -31
- data/lib/dbus/logger.rb +3 -1
- data/lib/dbus/marshall.rb +247 -296
- data/lib/dbus/matchrule.rb +16 -16
- data/lib/dbus/message.rb +44 -37
- data/lib/dbus/message_queue.rb +16 -10
- data/lib/dbus/object.rb +358 -24
- data/lib/dbus/object_path.rb +11 -6
- data/lib/dbus/proxy_object.rb +22 -1
- data/lib/dbus/proxy_object_factory.rb +13 -7
- data/lib/dbus/proxy_object_interface.rb +63 -30
- data/lib/dbus/raw_message.rb +91 -0
- data/lib/dbus/type.rb +318 -86
- data/lib/dbus/xml.rb +32 -17
- data/lib/dbus.rb +14 -7
- data/ruby-dbus.gemspec +7 -3
- data/spec/async_spec.rb +2 -0
- data/spec/binding_spec.rb +2 -0
- data/spec/bus_and_xml_backend_spec.rb +2 -0
- data/spec/bus_driver_spec.rb +2 -0
- data/spec/bus_name_spec.rb +3 -1
- data/spec/bus_spec.rb +2 -0
- data/spec/byte_array_spec.rb +2 -0
- data/spec/client_robustness_spec.rb +4 -2
- data/spec/data/marshall.yaml +1667 -0
- data/spec/data_spec.rb +673 -0
- data/spec/emits_changed_signal_spec.rb +58 -0
- data/spec/err_msg_spec.rb +2 -0
- data/spec/introspect_xml_parser_spec.rb +2 -0
- data/spec/introspection_spec.rb +2 -0
- data/spec/main_loop_spec.rb +3 -1
- data/spec/node_spec.rb +23 -0
- data/spec/object_path_spec.rb +3 -0
- data/spec/object_spec.rb +138 -0
- data/spec/packet_marshaller_spec.rb +41 -0
- data/spec/packet_unmarshaller_spec.rb +248 -0
- data/spec/property_spec.rb +192 -5
- data/spec/proxy_object_spec.rb +2 -0
- data/spec/server_robustness_spec.rb +2 -0
- data/spec/server_spec.rb +2 -0
- data/spec/service_newapi.rb +70 -70
- data/spec/session_bus_spec.rb +3 -1
- data/spec/session_bus_spec_manual.rb +2 -0
- data/spec/signal_spec.rb +5 -3
- data/spec/spec_helper.rb +37 -9
- data/spec/thread_safety_spec.rb +2 -0
- data/spec/tools/dbus-limited-session.conf +4 -0
- data/spec/type_spec.rb +214 -6
- data/spec/value_spec.rb +16 -1
- data/spec/variant_spec.rb +4 -2
- data/spec/zzz_quit_spec.rb +16 -0
- metadata +34 -8
    
        data/lib/dbus/type.rb
    CHANGED
    
    | @@ -1,3 +1,5 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 1 3 | 
             
            # dbus/type.rb - module containing low-level D-Bus data type information
         | 
| 2 4 | 
             
            #
         | 
| 3 5 | 
             
            # This file is part of the ruby-dbus project
         | 
| @@ -9,13 +11,33 @@ | |
| 9 11 | 
             
            # See the file "COPYING" for the exact licensing terms.
         | 
| 10 12 |  | 
| 11 13 | 
             
            module DBus
         | 
| 12 | 
            -
              #  | 
| 14 | 
            +
              # Like a {Signature} but containing only a single complete type.
         | 
| 15 | 
            +
              #
         | 
| 16 | 
            +
              # For documentation purposes only.
         | 
| 17 | 
            +
              class SingleCompleteType < String; end
         | 
| 18 | 
            +
             | 
| 19 | 
            +
              # Zero or more {SingleCompleteType}s; its own type code is "g".
         | 
| 20 | 
            +
              # For example "ssv" for a method taking two Strings and a Variant/
         | 
| 21 | 
            +
              #
         | 
| 22 | 
            +
              # For documentation purposes only.
         | 
| 23 | 
            +
              class Signature < String; end
         | 
| 24 | 
            +
             | 
| 25 | 
            +
              # Similar to {Signature} but for {DBus::Object.define_method},
         | 
| 26 | 
            +
              # contains names and direction of the parameters.
         | 
| 27 | 
            +
              # For example "in query:s, in case_sensitive:b, out results:ao".
         | 
| 13 28 | 
             
              #
         | 
| 14 | 
            -
              #  | 
| 15 | 
            -
               | 
| 16 | 
            -
             | 
| 29 | 
            +
              # For documentation purposes only.
         | 
| 30 | 
            +
              class Prototype < String; end
         | 
| 31 | 
            +
             | 
| 32 | 
            +
              # Represents the D-Bus types.
         | 
| 33 | 
            +
              #
         | 
| 34 | 
            +
              # Corresponds to {SingleCompleteType}.
         | 
| 35 | 
            +
              # Instances are immutable/frozen once fully constructed.
         | 
| 36 | 
            +
              #
         | 
| 37 | 
            +
              # See also {DBus::Data::Signature} which is "type on the wire".
         | 
| 38 | 
            +
              class Type
         | 
| 17 39 | 
             
                # Mapping from type number to name and alignment.
         | 
| 18 | 
            -
                 | 
| 40 | 
            +
                TYPE_MAPPING = {
         | 
| 19 41 | 
             
                  0 => ["INVALID", nil],
         | 
| 20 42 | 
             
                  "y" => ["BYTE", 1],
         | 
| 21 43 | 
             
                  "b" => ["BOOLEAN", 4],
         | 
| @@ -36,7 +58,7 @@ module DBus | |
| 36 58 | 
             
                  "h" => ["UNIX_FD", 4]
         | 
| 37 59 | 
             
                }.freeze
         | 
| 38 60 | 
             
                # Defines the set of constants
         | 
| 39 | 
            -
                 | 
| 61 | 
            +
                TYPE_MAPPING.each_pair do |key, value|
         | 
| 40 62 | 
             
                  Type.const_set(value.first, key)
         | 
| 41 63 | 
             
                end
         | 
| 42 64 |  | 
| @@ -44,87 +66,140 @@ module DBus | |
| 44 66 | 
             
                class SignatureException < Exception
         | 
| 45 67 | 
             
                end
         | 
| 46 68 |  | 
| 47 | 
            -
                #  | 
| 69 | 
            +
                # Formerly this was a Module and there was a DBus::Type::Type class
         | 
| 70 | 
            +
                # but the class got too prominent to keep its double double name.
         | 
| 71 | 
            +
                # This is for backward compatibility.
         | 
| 72 | 
            +
                Type = self # rubocop:disable Naming/ConstantName
         | 
| 73 | 
            +
             | 
| 74 | 
            +
                # @return [String] the signature type character, eg "s" or "e".
         | 
| 75 | 
            +
                attr_reader :sigtype
         | 
| 76 | 
            +
                # @return [Array<Type>] contained member types.
         | 
| 77 | 
            +
                attr_reader :members
         | 
| 78 | 
            +
             | 
| 79 | 
            +
                # Use {DBus.type} instead, because this allows constructing
         | 
| 80 | 
            +
                # incomplete or invalid types, for backward compatibility.
         | 
| 48 81 | 
             
                #
         | 
| 49 | 
            -
                #  | 
| 50 | 
            -
                 | 
| 51 | 
            -
             | 
| 52 | 
            -
                   | 
| 53 | 
            -
             | 
| 54 | 
            -
             | 
| 55 | 
            -
             | 
| 56 | 
            -
             | 
| 57 | 
            -
             | 
| 58 | 
            -
                     | 
| 59 | 
            -
                      raise SignatureException, "Unknown  | 
| 82 | 
            +
                # @param abstract [Boolean] allow abstract types "r" and "e"
         | 
| 83 | 
            +
                #   (Enabled for internal usage by {Parser}.)
         | 
| 84 | 
            +
                def initialize(sigtype, abstract: false)
         | 
| 85 | 
            +
                  if !TYPE_MAPPING.keys.member?(sigtype)
         | 
| 86 | 
            +
                    case sigtype
         | 
| 87 | 
            +
                    when ")"
         | 
| 88 | 
            +
                      raise SignatureException, "STRUCT unexpectedly closed: )"
         | 
| 89 | 
            +
                    when "}"
         | 
| 90 | 
            +
                      raise SignatureException, "DICT_ENTRY unexpectedly closed: }"
         | 
| 91 | 
            +
                    else
         | 
| 92 | 
            +
                      raise SignatureException, "Unknown type code #{sigtype.inspect}"
         | 
| 60 93 | 
             
                    end
         | 
| 61 | 
            -
                    @sigtype = sigtype
         | 
| 62 | 
            -
                    @members = []
         | 
| 63 | 
            -
                  end
         | 
| 64 | 
            -
             | 
| 65 | 
            -
                  # Return the required alignment for the type.
         | 
| 66 | 
            -
                  def alignment
         | 
| 67 | 
            -
                    TypeMapping[@sigtype].last
         | 
| 68 94 | 
             
                  end
         | 
| 69 95 |  | 
| 70 | 
            -
                   | 
| 71 | 
            -
             | 
| 72 | 
            -
                  def to_s
         | 
| 73 | 
            -
                    case @sigtype
         | 
| 96 | 
            +
                  unless abstract
         | 
| 97 | 
            +
                    case sigtype
         | 
| 74 98 | 
             
                    when STRUCT
         | 
| 75 | 
            -
                      " | 
| 76 | 
            -
                    when ARRAY
         | 
| 77 | 
            -
                      "a" + child.to_s
         | 
| 99 | 
            +
                      raise SignatureException, "Abstract STRUCT, use \"(...)\" instead of \"#{STRUCT}\""
         | 
| 78 100 | 
             
                    when DICT_ENTRY
         | 
| 79 | 
            -
                      "{"  | 
| 80 | 
            -
                    else
         | 
| 81 | 
            -
                      if !TypeMapping.keys.member?(@sigtype)
         | 
| 82 | 
            -
                        raise NotImplementedError
         | 
| 83 | 
            -
                      end
         | 
| 84 | 
            -
                      @sigtype.chr
         | 
| 101 | 
            +
                      raise SignatureException, "Abstract DICT_ENTRY, use \"{..}\" instead of \"#{DICT_ENTRY}\""
         | 
| 85 102 | 
             
                    end
         | 
| 86 103 | 
             
                  end
         | 
| 87 104 |  | 
| 88 | 
            -
                   | 
| 89 | 
            -
                   | 
| 90 | 
            -
             | 
| 91 | 
            -
             | 
| 92 | 
            -
             | 
| 93 | 
            -
             | 
| 94 | 
            -
             | 
| 95 | 
            -
             | 
| 96 | 
            -
             | 
| 97 | 
            -
             | 
| 98 | 
            -
             | 
| 99 | 
            -
             | 
| 100 | 
            -
             | 
| 101 | 
            -
             | 
| 102 | 
            -
                      end
         | 
| 103 | 
            -
                    end
         | 
| 104 | 
            -
                    @members << a
         | 
| 105 | 
            +
                  @sigtype = sigtype.freeze
         | 
| 106 | 
            +
                  @members = [] # not frozen yet, Parser#parse_one or Factory will do it
         | 
| 107 | 
            +
                  freeze
         | 
| 108 | 
            +
                end
         | 
| 109 | 
            +
             | 
| 110 | 
            +
                # A Type is equal to
         | 
| 111 | 
            +
                # - another Type with the same string representation
         | 
| 112 | 
            +
                # - a String ({SingleCompleteType}) describing the type
         | 
| 113 | 
            +
                def ==(other)
         | 
| 114 | 
            +
                  case other
         | 
| 115 | 
            +
                  when ::String
         | 
| 116 | 
            +
                    to_s == other
         | 
| 117 | 
            +
                  else
         | 
| 118 | 
            +
                    eql?(other)
         | 
| 105 119 | 
             
                  end
         | 
| 120 | 
            +
                end
         | 
| 121 | 
            +
             | 
| 122 | 
            +
                # A Type is eql? to
         | 
| 123 | 
            +
                # - another Type with the same string representation
         | 
| 124 | 
            +
                #
         | 
| 125 | 
            +
                # Hash key equality
         | 
| 126 | 
            +
                # See https://ruby-doc.org/core-3.0.0/Object.html#method-i-eql-3F
         | 
| 127 | 
            +
                def eql?(other)
         | 
| 128 | 
            +
                  return false unless other.is_a?(Type)
         | 
| 129 | 
            +
             | 
| 130 | 
            +
                  @sigtype == other.sigtype && @members == other.members
         | 
| 131 | 
            +
                end
         | 
| 132 | 
            +
             | 
| 133 | 
            +
                # Return the required alignment for the type.
         | 
| 134 | 
            +
                def alignment
         | 
| 135 | 
            +
                  TYPE_MAPPING[@sigtype].last
         | 
| 136 | 
            +
                end
         | 
| 106 137 |  | 
| 107 | 
            -
             | 
| 108 | 
            -
             | 
| 109 | 
            -
             | 
| 138 | 
            +
                # Return a string representation of the type according to the
         | 
| 139 | 
            +
                # D-Bus specification.
         | 
| 140 | 
            +
                def to_s
         | 
| 141 | 
            +
                  case @sigtype
         | 
| 142 | 
            +
                  when STRUCT
         | 
| 143 | 
            +
                    "(#{@members.collect(&:to_s).join})"
         | 
| 144 | 
            +
                  when ARRAY
         | 
| 145 | 
            +
                    "a#{child}"
         | 
| 146 | 
            +
                  when DICT_ENTRY
         | 
| 147 | 
            +
                    "{#{@members.collect(&:to_s).join}}"
         | 
| 148 | 
            +
                  else
         | 
| 149 | 
            +
                    @sigtype.chr
         | 
| 110 150 | 
             
                  end
         | 
| 151 | 
            +
                end
         | 
| 152 | 
            +
             | 
| 153 | 
            +
                # Add a new member type _item_.
         | 
| 154 | 
            +
                # @param item [Type]
         | 
| 155 | 
            +
                def <<(item)
         | 
| 156 | 
            +
                  raise ArgumentError unless item.is_a?(Type)
         | 
| 111 157 |  | 
| 112 | 
            -
                   | 
| 113 | 
            -
                     | 
| 114 | 
            -
             | 
| 115 | 
            -
             | 
| 158 | 
            +
                  if ![STRUCT, ARRAY, DICT_ENTRY].member?(@sigtype)
         | 
| 159 | 
            +
                    raise SignatureException
         | 
| 160 | 
            +
                  end
         | 
| 161 | 
            +
                  raise SignatureException if @sigtype == ARRAY && !@members.empty?
         | 
| 162 | 
            +
             | 
| 163 | 
            +
                  if @sigtype == DICT_ENTRY
         | 
| 164 | 
            +
                    case @members.size
         | 
| 165 | 
            +
                    when 2
         | 
| 166 | 
            +
                      raise SignatureException, "DICT_ENTRY must have 2 subtypes, found 3 or more in #{@signature}"
         | 
| 167 | 
            +
                    when 0
         | 
| 168 | 
            +
                      if [STRUCT, ARRAY, DICT_ENTRY, VARIANT].member?(item.sigtype)
         | 
| 169 | 
            +
                        raise SignatureException, "DICT_ENTRY key must be basic (non-container)"
         | 
| 170 | 
            +
                      end
         | 
| 116 171 | 
             
                    end
         | 
| 117 | 
            -
                    s
         | 
| 118 172 | 
             
                  end
         | 
| 119 | 
            -
             | 
| 173 | 
            +
                  @members << item
         | 
| 174 | 
            +
                end
         | 
| 175 | 
            +
             | 
| 176 | 
            +
                # Return the first contained member type.
         | 
| 177 | 
            +
                def child
         | 
| 178 | 
            +
                  @members[0]
         | 
| 179 | 
            +
                end
         | 
| 180 | 
            +
             | 
| 181 | 
            +
                def inspect
         | 
| 182 | 
            +
                  s = TYPE_MAPPING[@sigtype].first
         | 
| 183 | 
            +
                  if [STRUCT, ARRAY, DICT_ENTRY].member?(@sigtype)
         | 
| 184 | 
            +
                    s += ": #{@members.inspect}"
         | 
| 185 | 
            +
                  end
         | 
| 186 | 
            +
                  s
         | 
| 187 | 
            +
                end
         | 
| 120 188 |  | 
| 121 189 | 
             
                # = D-Bus type parser class
         | 
| 122 190 | 
             
                #
         | 
| 123 191 | 
             
                # Helper class to parse a type signature in the protocol.
         | 
| 192 | 
            +
                # @api private
         | 
| 124 193 | 
             
                class Parser
         | 
| 125 194 | 
             
                  # Create a new parser for the given _signature_.
         | 
| 195 | 
            +
                  # @param signature [Signature]
         | 
| 126 196 | 
             
                  def initialize(signature)
         | 
| 127 197 | 
             
                    @signature = signature
         | 
| 198 | 
            +
                    if signature.size > 255
         | 
| 199 | 
            +
                      msg = "Potential signature is longer than 255 characters (#{@signature.size}): #{@signature}"
         | 
| 200 | 
            +
                      raise SignatureException, msg
         | 
| 201 | 
            +
                    end
         | 
| 202 | 
            +
             | 
| 128 203 | 
             
                    @idx = 0
         | 
| 129 204 | 
             
                  end
         | 
| 130 205 |  | 
| @@ -135,57 +210,214 @@ module DBus | |
| 135 210 | 
             
                    c
         | 
| 136 211 | 
             
                  end
         | 
| 137 212 |  | 
| 138 | 
            -
                  # Parse one character  | 
| 139 | 
            -
                   | 
| 213 | 
            +
                  # Parse one character _char_ of the signature.
         | 
| 214 | 
            +
                  # @param for_array [Boolean] are we parsing an immediate child of an ARRAY
         | 
| 215 | 
            +
                  # @return [Type]
         | 
| 216 | 
            +
                  def parse_one(char, for_array: false)
         | 
| 140 217 | 
             
                    res = nil
         | 
| 141 | 
            -
                    case  | 
| 218 | 
            +
                    case char
         | 
| 142 219 | 
             
                    when "a"
         | 
| 143 220 | 
             
                      res = Type.new(ARRAY)
         | 
| 144 | 
            -
                       | 
| 145 | 
            -
                      raise SignatureException, " | 
| 146 | 
            -
             | 
| 221 | 
            +
                      char = nextchar
         | 
| 222 | 
            +
                      raise SignatureException, "Empty ARRAY in #{@signature}" if char.nil?
         | 
| 223 | 
            +
             | 
| 224 | 
            +
                      child = parse_one(char, for_array: true)
         | 
| 147 225 | 
             
                      res << child
         | 
| 148 226 | 
             
                    when "("
         | 
| 149 | 
            -
                      res = Type.new(STRUCT)
         | 
| 150 | 
            -
                      while ( | 
| 151 | 
            -
                        res << parse_one( | 
| 227 | 
            +
                      res = Type.new(STRUCT, abstract: true)
         | 
| 228 | 
            +
                      while (char = nextchar) && char != ")"
         | 
| 229 | 
            +
                        res << parse_one(char)
         | 
| 152 230 | 
             
                      end
         | 
| 153 | 
            -
                      raise SignatureException, " | 
| 231 | 
            +
                      raise SignatureException, "STRUCT not closed in #{@signature}" if char.nil?
         | 
| 232 | 
            +
                      raise SignatureException, "Empty STRUCT in #{@signature}" if res.members.empty?
         | 
| 154 233 | 
             
                    when "{"
         | 
| 155 | 
            -
                       | 
| 156 | 
            -
             | 
| 157 | 
            -
             | 
| 234 | 
            +
                      raise SignatureException, "DICT_ENTRY not an immediate child of an ARRAY" unless for_array
         | 
| 235 | 
            +
             | 
| 236 | 
            +
                      res = Type.new(DICT_ENTRY, abstract: true)
         | 
| 237 | 
            +
             | 
| 238 | 
            +
                      # key type, value type
         | 
| 239 | 
            +
                      2.times do |i|
         | 
| 240 | 
            +
                        char = nextchar
         | 
| 241 | 
            +
                        raise SignatureException, "DICT_ENTRY not closed in #{@signature}" if char.nil?
         | 
| 242 | 
            +
             | 
| 243 | 
            +
                        raise SignatureException, "DICT_ENTRY must have 2 subtypes, found #{i} in #{@signature}" if char == "}"
         | 
| 244 | 
            +
             | 
| 245 | 
            +
                        res << parse_one(char)
         | 
| 158 246 | 
             
                      end
         | 
| 159 | 
            -
             | 
| 247 | 
            +
             | 
| 248 | 
            +
                      # closing "}"
         | 
| 249 | 
            +
                      char = nextchar
         | 
| 250 | 
            +
                      raise SignatureException, "DICT_ENTRY not closed in #{@signature}" if char.nil?
         | 
| 251 | 
            +
             | 
| 252 | 
            +
                      raise SignatureException, "DICT_ENTRY must have 2 subtypes, found 3 or more in #{@signature}" if char != "}"
         | 
| 160 253 | 
             
                    else
         | 
| 161 | 
            -
                      res = Type.new( | 
| 254 | 
            +
                      res = Type.new(char)
         | 
| 162 255 | 
             
                    end
         | 
| 256 | 
            +
                    res.members.freeze
         | 
| 163 257 | 
             
                    res
         | 
| 164 258 | 
             
                  end
         | 
| 165 259 |  | 
| 166 260 | 
             
                  # Parse the entire signature, return a DBus::Type object.
         | 
| 261 | 
            +
                  # @return [Array<Type>]
         | 
| 167 262 | 
             
                  def parse
         | 
| 168 263 | 
             
                    @idx = 0
         | 
| 169 264 | 
             
                    ret = []
         | 
| 170 265 | 
             
                    while (c = nextchar)
         | 
| 171 266 | 
             
                      ret << parse_one(c)
         | 
| 172 267 | 
             
                    end
         | 
| 173 | 
            -
                    ret
         | 
| 268 | 
            +
                    ret.freeze
         | 
| 269 | 
            +
                  end
         | 
| 270 | 
            +
             | 
| 271 | 
            +
                  # Parse one {SingleCompleteType}
         | 
| 272 | 
            +
                  # @return [Type]
         | 
| 273 | 
            +
                  def parse1
         | 
| 274 | 
            +
                    c = nextchar
         | 
| 275 | 
            +
                    raise SignatureException, "Empty signature, expecting a Single Complete Type" if c.nil?
         | 
| 276 | 
            +
             | 
| 277 | 
            +
                    t = parse_one(c)
         | 
| 278 | 
            +
                    raise SignatureException, "Has more than a Single Complete Type: #{@signature}" unless nextchar.nil?
         | 
| 279 | 
            +
             | 
| 280 | 
            +
                    t.freeze
         | 
| 281 | 
            +
                  end
         | 
| 282 | 
            +
                end
         | 
| 283 | 
            +
             | 
| 284 | 
            +
                class Factory
         | 
| 285 | 
            +
                  # @param type [Type,SingleCompleteType,Class]
         | 
| 286 | 
            +
                  # @see from_plain_class
         | 
| 287 | 
            +
                  # @return [Type] (frozen)
         | 
| 288 | 
            +
                  def self.make_type(type)
         | 
| 289 | 
            +
                    case type
         | 
| 290 | 
            +
                    when Type
         | 
| 291 | 
            +
                      type
         | 
| 292 | 
            +
                    when String
         | 
| 293 | 
            +
                      DBus.type(type)
         | 
| 294 | 
            +
                    when Class
         | 
| 295 | 
            +
                      from_plain_class(type)
         | 
| 296 | 
            +
                    else
         | 
| 297 | 
            +
                      msg = "Expecting DBus::Type, DBus::SingleCompleteType(aka ::String), or Class, got #{type.inspect}"
         | 
| 298 | 
            +
                      raise ArgumentError, msg
         | 
| 299 | 
            +
                    end
         | 
| 174 300 | 
             
                  end
         | 
| 175 | 
            -
             | 
| 176 | 
            -
             | 
| 301 | 
            +
             | 
| 302 | 
            +
                  # Make a {Type} corresponding to some plain classes:
         | 
| 303 | 
            +
                  # - String
         | 
| 304 | 
            +
                  # - Float
         | 
| 305 | 
            +
                  # - DBus::ObjectPath
         | 
| 306 | 
            +
                  # - DBus::Signature, DBus::SingleCompleteType
         | 
| 307 | 
            +
                  # @param klass [Class]
         | 
| 308 | 
            +
                  # @return [Type] (frozen)
         | 
| 309 | 
            +
                  def self.from_plain_class(klass)
         | 
| 310 | 
            +
                    @signature_type ||= DBus.type(SIGNATURE)
         | 
| 311 | 
            +
                    @class_to_type ||= {
         | 
| 312 | 
            +
                      DBus::ObjectPath => DBus.type(OBJECT_PATH),
         | 
| 313 | 
            +
                      DBus::Signature => @signature_type,
         | 
| 314 | 
            +
                      DBus::SingleCompleteType => @signature_type,
         | 
| 315 | 
            +
                      String => DBus.type(STRING),
         | 
| 316 | 
            +
                      Float => DBus.type(DOUBLE)
         | 
| 317 | 
            +
                    }
         | 
| 318 | 
            +
                    t = @class_to_type[klass]
         | 
| 319 | 
            +
                    raise ArgumentError, "Cannot convert plain class #{klass} to a D-Bus type" if t.nil?
         | 
| 320 | 
            +
             | 
| 321 | 
            +
                    t
         | 
| 322 | 
            +
                  end
         | 
| 323 | 
            +
                end
         | 
| 324 | 
            +
             | 
| 325 | 
            +
                # Syntactic helper for constructing an array Type.
         | 
| 326 | 
            +
                # You may be looking for {Data::Array} instead.
         | 
| 327 | 
            +
                # @example
         | 
| 328 | 
            +
                #   t = Type::Array[Type::INT16]
         | 
| 329 | 
            +
                class ArrayFactory < Factory
         | 
| 330 | 
            +
                  # @param member_type [Type,SingleCompleteType]
         | 
| 331 | 
            +
                  # @return [Type] (frozen)
         | 
| 332 | 
            +
                  def self.[](member_type)
         | 
| 333 | 
            +
                    t = Type.new(ARRAY)
         | 
| 334 | 
            +
                    t << make_type(member_type)
         | 
| 335 | 
            +
                    t.members.freeze
         | 
| 336 | 
            +
                    t
         | 
| 337 | 
            +
                  end
         | 
| 338 | 
            +
                end
         | 
| 339 | 
            +
             | 
| 340 | 
            +
                # @example
         | 
| 341 | 
            +
                #   t = Type::Array[Type::INT16]
         | 
| 342 | 
            +
                Array = ArrayFactory
         | 
| 343 | 
            +
             | 
| 344 | 
            +
                # Syntactic helper for constructing a hash Type.
         | 
| 345 | 
            +
                # You may be looking for {Data::Array} and {Data::DictEntry} instead.
         | 
| 346 | 
            +
                # @example
         | 
| 347 | 
            +
                #   t = Type::Hash[Type::STRING, Type::VARIANT]
         | 
| 348 | 
            +
                class HashFactory < Factory
         | 
| 349 | 
            +
                  # @param key_type [Type,SingleCompleteType]
         | 
| 350 | 
            +
                  # @param value_type [Type,SingleCompleteType]
         | 
| 351 | 
            +
                  # @return [Type] (frozen)
         | 
| 352 | 
            +
                  def self.[](key_type, value_type)
         | 
| 353 | 
            +
                    t = Type.new(ARRAY)
         | 
| 354 | 
            +
                    de = Type.new(DICT_ENTRY, abstract: true)
         | 
| 355 | 
            +
                    de << make_type(key_type)
         | 
| 356 | 
            +
                    de << make_type(value_type)
         | 
| 357 | 
            +
                    de.members.freeze
         | 
| 358 | 
            +
                    t << de
         | 
| 359 | 
            +
                    t.members.freeze
         | 
| 360 | 
            +
                    t
         | 
| 361 | 
            +
                  end
         | 
| 362 | 
            +
                end
         | 
| 363 | 
            +
             | 
| 364 | 
            +
                # @example
         | 
| 365 | 
            +
                #   t = Type::Hash[Type::INT16]
         | 
| 366 | 
            +
                Hash = HashFactory
         | 
| 367 | 
            +
             | 
| 368 | 
            +
                # Syntactic helper for constructing a struct Type.
         | 
| 369 | 
            +
                # You may be looking for {Data::Struct} instead.
         | 
| 370 | 
            +
                # @example
         | 
| 371 | 
            +
                #   t = Type::Struct[Type::INT16, Type::STRING]
         | 
| 372 | 
            +
                class StructFactory < Factory
         | 
| 373 | 
            +
                  # @param member_types [::Array<Type,SingleCompleteType>]
         | 
| 374 | 
            +
                  # @return [Type] (frozen)
         | 
| 375 | 
            +
                  def self.[](*member_types)
         | 
| 376 | 
            +
                    raise ArgumentError if member_types.empty?
         | 
| 377 | 
            +
             | 
| 378 | 
            +
                    t = Type.new(STRUCT, abstract: true)
         | 
| 379 | 
            +
                    member_types.each do |mt|
         | 
| 380 | 
            +
                      t << make_type(mt)
         | 
| 381 | 
            +
                    end
         | 
| 382 | 
            +
                    t.members.freeze
         | 
| 383 | 
            +
                    t
         | 
| 384 | 
            +
                  end
         | 
| 385 | 
            +
                end
         | 
| 386 | 
            +
             | 
| 387 | 
            +
                # @example
         | 
| 388 | 
            +
                #   t = Type::Struct[Type::INT16, Type::STRING]
         | 
| 389 | 
            +
                Struct = StructFactory
         | 
| 390 | 
            +
              end
         | 
| 177 391 |  | 
| 178 392 | 
             
              # shortcuts
         | 
| 179 393 |  | 
| 180 | 
            -
              # Parse a String to a DBus::Type | 
| 394 | 
            +
              # Parse a String to a valid {DBus::Type}.
         | 
| 395 | 
            +
              # This is prefered to {Type#initialize} which allows
         | 
| 396 | 
            +
              # incomplete or invalid types.
         | 
| 397 | 
            +
              # @param string_type [SingleCompleteType]
         | 
| 398 | 
            +
              # @return [DBus::Type] (frozen)
         | 
| 399 | 
            +
              # @raise SignatureException
         | 
| 181 400 | 
             
              def type(string_type)
         | 
| 182 | 
            -
                Type::Parser.new(string_type). | 
| 401 | 
            +
                Type::Parser.new(string_type).parse1
         | 
| 183 402 | 
             
              end
         | 
| 184 403 | 
             
              module_function :type
         | 
| 185 404 |  | 
| 405 | 
            +
              # Parse a String to zero or more {DBus::Type}s.
         | 
| 406 | 
            +
              # @param string_type [Signature]
         | 
| 407 | 
            +
              # @return [Array<DBus::Type>] (frozen)
         | 
| 408 | 
            +
              # @raise SignatureException
         | 
| 409 | 
            +
              def types(string_type)
         | 
| 410 | 
            +
                Type::Parser.new(string_type).parse
         | 
| 411 | 
            +
              end
         | 
| 412 | 
            +
              module_function :types
         | 
| 413 | 
            +
             | 
| 186 414 | 
             
              # Make an explicit [Type, value] pair
         | 
| 415 | 
            +
              # @param string_type [SingleCompleteType]
         | 
| 416 | 
            +
              # @param value [::Object]
         | 
| 417 | 
            +
              # @return [Array(DBus::Type::Type,::Object)]
         | 
| 418 | 
            +
              # @deprecated Use {Data::Variant#initialize} instead
         | 
| 187 419 | 
             
              def variant(string_type, value)
         | 
| 188 | 
            -
                 | 
| 420 | 
            +
                Data::Variant.new(value, member_type: string_type)
         | 
| 189 421 | 
             
              end
         | 
| 190 422 | 
             
              module_function :variant
         | 
| 191 | 
            -
            end | 
| 423 | 
            +
            end
         | 
    
        data/lib/dbus/xml.rb
    CHANGED
    
    | @@ -1,3 +1,5 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 1 3 | 
             
            # dbus/xml.rb - introspection parser, rexml/nokogiri abstraction
         | 
| 2 4 | 
             
            #
         | 
| 3 5 | 
             
            # This file is part of the ruby-dbus project
         | 
| @@ -26,14 +28,23 @@ module DBus | |
| 26 28 | 
             
                  attr_accessor :backend
         | 
| 27 29 | 
             
                end
         | 
| 28 30 | 
             
                # Creates a new parser for XML data in string _xml_.
         | 
| 31 | 
            +
                # @param xml [String]
         | 
| 29 32 | 
             
                def initialize(xml)
         | 
| 30 33 | 
             
                  @xml = xml
         | 
| 31 34 | 
             
                end
         | 
| 32 35 |  | 
| 33 36 | 
             
                class AbstractXML
         | 
| 37 | 
            +
                  # @!method initialize(xml)
         | 
| 38 | 
            +
                  # @abstract
         | 
| 39 | 
            +
             | 
| 40 | 
            +
                  # @!method each(xpath)
         | 
| 41 | 
            +
                  # @abstract
         | 
| 42 | 
            +
                  # yields nodes which match xpath of type AbstractXML::Node
         | 
| 43 | 
            +
             | 
| 34 44 | 
             
                  def self.have_nokogiri?
         | 
| 35 45 | 
             
                    Object.const_defined?("Nokogiri")
         | 
| 36 46 | 
             
                  end
         | 
| 47 | 
            +
             | 
| 37 48 | 
             
                  class Node
         | 
| 38 49 | 
             
                    def initialize(node)
         | 
| 39 50 | 
             
                      @node = node
         | 
| @@ -46,12 +57,6 @@ module DBus | |
| 46 57 | 
             
                    # yields child nodes which match xpath of type AbstractXML::Node
         | 
| 47 58 | 
             
                    def each(xpath); end
         | 
| 48 59 | 
             
                  end
         | 
| 49 | 
            -
                  # required methods
         | 
| 50 | 
            -
                  # initialize parser with xml string
         | 
| 51 | 
            -
                  def initialize(xml); end
         | 
| 52 | 
            -
             | 
| 53 | 
            -
                  # yields nodes which match xpath of type AbstractXML::Node
         | 
| 54 | 
            -
                  def each(xpath); end
         | 
| 55 60 | 
             
                end
         | 
| 56 61 |  | 
| 57 62 | 
             
                class NokogiriParser < AbstractXML
         | 
| @@ -64,7 +69,9 @@ module DBus | |
| 64 69 | 
             
                      @node.search(path).each { |node| block.call NokogiriNode.new(node) }
         | 
| 65 70 | 
             
                    end
         | 
| 66 71 | 
             
                  end
         | 
| 72 | 
            +
             | 
| 67 73 | 
             
                  def initialize(xml)
         | 
| 74 | 
            +
                    super()
         | 
| 68 75 | 
             
                    @doc = Nokogiri.XML(xml)
         | 
| 69 76 | 
             
                  end
         | 
| 70 77 |  | 
| @@ -83,7 +90,9 @@ module DBus | |
| 83 90 | 
             
                      @node.elements.each(path) { |node| block.call REXMLNode.new(node) }
         | 
| 84 91 | 
             
                    end
         | 
| 85 92 | 
             
                  end
         | 
| 93 | 
            +
             | 
| 86 94 | 
             
                  def initialize(xml)
         | 
| 95 | 
            +
                    super()
         | 
| 87 96 | 
             
                    @doc = REXML::Document.new(xml)
         | 
| 88 97 | 
             
                  end
         | 
| 89 98 |  | 
| @@ -125,6 +134,10 @@ module DBus | |
| 125 134 | 
             
                      parse_methsig(se, s)
         | 
| 126 135 | 
             
                      i << s
         | 
| 127 136 | 
             
                    end
         | 
| 137 | 
            +
                    e.each("property") do |pe|
         | 
| 138 | 
            +
                      p = Property.from_xml(pe)
         | 
| 139 | 
            +
                      i << p
         | 
| 140 | 
            +
                    end
         | 
| 128 141 | 
             
                  end
         | 
| 129 142 | 
             
                  d = Time.now - t
         | 
| 130 143 | 
             
                  if d > 2
         | 
| @@ -136,28 +149,30 @@ module DBus | |
| 136 149 | 
             
                ######################################################################
         | 
| 137 150 | 
             
                private
         | 
| 138 151 |  | 
| 139 | 
            -
                # Parses a method signature XML element  | 
| 140 | 
            -
                # method/signal  | 
| 141 | 
            -
                 | 
| 142 | 
            -
             | 
| 152 | 
            +
                # Parses a method signature XML element *elem* and initialises
         | 
| 153 | 
            +
                # method/signal *methsig*.
         | 
| 154 | 
            +
                # @param elem [AbstractXML::Node]
         | 
| 155 | 
            +
                def parse_methsig(elem, methsig)
         | 
| 156 | 
            +
                  elem.each("arg") do |ae|
         | 
| 143 157 | 
             
                    name = ae["name"]
         | 
| 144 158 | 
             
                    dir = ae["direction"]
         | 
| 145 159 | 
             
                    sig = ae["type"]
         | 
| 146 | 
            -
                     | 
| 160 | 
            +
                    case methsig
         | 
| 161 | 
            +
                    when DBus::Signal
         | 
| 147 162 | 
             
                      # Direction can only be "out", ignore it
         | 
| 148 | 
            -
                       | 
| 149 | 
            -
                     | 
| 163 | 
            +
                      methsig.add_fparam(name, sig)
         | 
| 164 | 
            +
                    when DBus::Method
         | 
| 150 165 | 
             
                      case dir
         | 
| 151 166 | 
             
                      # This is a method, so dir defaults to "in"
         | 
| 152 167 | 
             
                      when "in", nil
         | 
| 153 | 
            -
                         | 
| 168 | 
            +
                        methsig.add_fparam(name, sig)
         | 
| 154 169 | 
             
                      when "out"
         | 
| 155 | 
            -
                         | 
| 170 | 
            +
                        methsig.add_return(name, sig)
         | 
| 156 171 | 
             
                      end
         | 
| 157 172 | 
             
                    else
         | 
| 158 173 | 
             
                      raise NotImplementedError, dir
         | 
| 159 174 | 
             
                    end
         | 
| 160 175 | 
             
                  end
         | 
| 161 176 | 
             
                end
         | 
| 162 | 
            -
              end | 
| 163 | 
            -
            end | 
| 177 | 
            +
              end
         | 
| 178 | 
            +
            end
         | 
    
        data/lib/dbus.rb
    CHANGED
    
    | @@ -1,3 +1,5 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 1 3 | 
             
            # dbus.rb - Module containing the low-level D-Bus implementation
         | 
| 2 4 | 
             
            #
         | 
| 3 5 | 
             
            # This file is part of the ruby-dbus project
         | 
| @@ -12,6 +14,8 @@ require_relative "dbus/api_options" | |
| 12 14 | 
             
            require_relative "dbus/auth"
         | 
| 13 15 | 
             
            require_relative "dbus/bus"
         | 
| 14 16 | 
             
            require_relative "dbus/bus_name"
         | 
| 17 | 
            +
            require_relative "dbus/data"
         | 
| 18 | 
            +
            require_relative "dbus/emits_changed_signal"
         | 
| 15 19 | 
             
            require_relative "dbus/error"
         | 
| 16 20 | 
             
            require_relative "dbus/introspect"
         | 
| 17 21 | 
             
            require_relative "dbus/logger"
         | 
| @@ -24,31 +28,34 @@ require_relative "dbus/object_path" | |
| 24 28 | 
             
            require_relative "dbus/proxy_object"
         | 
| 25 29 | 
             
            require_relative "dbus/proxy_object_factory"
         | 
| 26 30 | 
             
            require_relative "dbus/proxy_object_interface"
         | 
| 31 | 
            +
            require_relative "dbus/raw_message"
         | 
| 27 32 | 
             
            require_relative "dbus/type"
         | 
| 28 33 | 
             
            require_relative "dbus/xml"
         | 
| 29 34 |  | 
| 30 35 | 
             
            require "socket"
         | 
| 31 | 
            -
            require "thread"
         | 
| 32 | 
            -
             | 
| 33 36 | 
             
            # = D-Bus main module
         | 
| 34 37 | 
             
            #
         | 
| 35 38 | 
             
            # Module containing all the D-Bus modules and classes.
         | 
| 36 39 | 
             
            module DBus
         | 
| 37 40 | 
             
              # Default socket name for the system bus.
         | 
| 38 | 
            -
               | 
| 41 | 
            +
              SYSTEM_BUS_ADDRESS = "unix:path=/var/run/dbus/system_bus_socket"
         | 
| 39 42 |  | 
| 40 43 | 
             
              # Byte signifying big endianness.
         | 
| 41 | 
            -
              BIG_END = "B" | 
| 44 | 
            +
              BIG_END = "B"
         | 
| 42 45 | 
             
              # Byte signifying little endianness.
         | 
| 43 | 
            -
              LIL_END = "l" | 
| 46 | 
            +
              LIL_END = "l"
         | 
| 44 47 |  | 
| 45 48 | 
             
              # Byte signifying the host's endianness.
         | 
| 46 | 
            -
              HOST_END = if [0x01020304].pack("L"). | 
| 49 | 
            +
              HOST_END = if [0x01020304].pack("L").unpack1("V") == 0x01020304
         | 
| 47 50 | 
             
                           LIL_END
         | 
| 48 51 | 
             
                         else
         | 
| 49 52 | 
             
                           BIG_END
         | 
| 50 53 | 
             
                         end
         | 
| 51 54 |  | 
| 55 | 
            +
              # Comparing symbols is faster than strings
         | 
| 56 | 
            +
              # @return [:little,:big]
         | 
| 57 | 
            +
              HOST_ENDIANNESS = RawMessage.endianness(HOST_END)
         | 
| 58 | 
            +
             | 
| 52 59 | 
             
              # General exceptions.
         | 
| 53 60 |  | 
| 54 61 | 
             
              # Exception raised when there is a problem with a type (may be unknown or
         | 
| @@ -69,4 +76,4 @@ module DBus | |
| 69 76 | 
             
              # Exception raised when invalid introspection data is parsed/used.
         | 
| 70 77 | 
             
              class InvalidIntrospectionData < Exception
         | 
| 71 78 | 
             
              end
         | 
| 72 | 
            -
            end | 
| 79 | 
            +
            end
         | 
    
        data/ruby-dbus.gemspec
    CHANGED
    
    | @@ -1,3 +1,5 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 1 3 | 
             
            # -*- ruby -*-
         | 
| 2 4 | 
             
            require "rubygems"
         | 
| 3 5 |  | 
| @@ -18,15 +20,17 @@ GEMSPEC = Gem::Specification.new do |s| | |
| 18 20 | 
             
              ]
         | 
| 19 21 | 
             
              s.require_path = "lib"
         | 
| 20 22 |  | 
| 21 | 
            -
              s.required_ruby_version = ">= 2. | 
| 23 | 
            +
              s.required_ruby_version = ">= 2.4.0"
         | 
| 24 | 
            +
             | 
| 25 | 
            +
              s.add_dependency "rexml"
         | 
| 22 26 |  | 
| 23 27 | 
             
              # This is optional
         | 
| 24 28 | 
             
              # s.add_runtime_dependency "nokogiri"
         | 
| 25 29 |  | 
| 26 | 
            -
              s.add_development_dependency "coveralls"
         | 
| 27 30 | 
             
              s.add_development_dependency "packaging_rake_tasks"
         | 
| 28 31 | 
             
              s.add_development_dependency "rake"
         | 
| 29 32 | 
             
              s.add_development_dependency "rspec", "~> 3"
         | 
| 30 | 
            -
              s.add_development_dependency "rubocop", "= 0 | 
| 33 | 
            +
              s.add_development_dependency "rubocop", "= 1.0"
         | 
| 31 34 | 
             
              s.add_development_dependency "simplecov"
         | 
| 35 | 
            +
              s.add_development_dependency "simplecov-lcov"
         | 
| 32 36 | 
             
            end
         |