File: proxy_object_interface.rb

package info (click to toggle)
ruby-dbus 0.25.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 776 kB
  • sloc: ruby: 6,584; xml: 225; sh: 38; makefile: 8
file content (178 lines) | stat: -rw-r--r-- 5,443 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
# frozen_string_literal: true

# This file is part of the ruby-dbus project
# Copyright (C) 2007 Arnaud Cornet and Paul van Tilburg
# Copyright (C) 2009-2014 Martin Vidner
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License, version 2.1 as published by the Free Software Foundation.
# See the file "COPYING" for the exact licensing terms.

module DBus
  # = D-Bus proxy object interface class
  #
  # A class similar to the normal Interface used as a proxy for remote
  # object interfaces.
  class ProxyObjectInterface
    # @return [Hash{String => DBus::Method}]
    attr_reader :methods
    # @return [Hash{String => Signal}]
    attr_reader :signals
    # @return [Hash{Symbol => Property}]
    attr_reader :properties

    # @return [ProxyObject] The proxy object to which this interface belongs.
    attr_reader :object
    # @return [String] The name of the interface.
    attr_reader :name

    # Creates a new proxy interface for the given proxy _object_
    # and the given _name_.
    def initialize(object, name)
      @object = object
      @name = name
      @methods = {}
      @signals = {}
      @properties = {}
    end

    # Returns the string representation of the interface (the name).
    def to_str
      @name
    end

    # Defines a method on the interface from the Method descriptor _method_.
    # @param method [Method]
    def define_method_from_descriptor(method)
      method.params.each do |fpar|
        par = fpar.type
        # This is the signature validity check
        Type::Parser.new(par).parse
      end

      singleton_class.class_eval do
        define_method method.name do |*args, &reply_handler|
          if method.params.size != args.size
            raise ArgumentError, "wrong number of arguments (#{args.size} for #{method.params.size})"
          end

          msg = Message.new(Message::METHOD_CALL)
          msg.path = @object.path
          msg.interface = @name
          msg.destination = @object.destination
          msg.member = method.name
          msg.sender = @object.bus.unique_name
          method.params.each do |fpar|
            par = fpar.type
            msg.add_param(par, args.shift)
          end
          ret = @object.bus.send_sync_or_async(msg, &reply_handler)
          if ret.nil? || @object.api.proxy_method_returns_array
            ret
          else
            method.rets.size == 1 ? ret.first : ret
          end
        end
      end

      @methods[method.name] = method
    end

    # Defines a signal from the descriptor _sig_.
    # @param sig [Signal]
    def define_signal_from_descriptor(sig)
      @signals[sig.name] = sig
    end

    # @param prop [Property]
    def define_property_from_descriptor(prop)
      @properties[prop.name] = prop
    end

    # Defines a signal or method based on the descriptor _ifc_el_.
    # @param ifc_el [DBus::Method,Signal,Property]
    def define(ifc_el)
      case ifc_el
      when Method
        define_method_from_descriptor(ifc_el)
      when Signal
        define_signal_from_descriptor(ifc_el)
      when Property
        define_property_from_descriptor(ifc_el)
      end
    end

    # Defines a proxied method on the interface.
    def define_method(methodname, prototype)
      m = Method.new(methodname)
      m.from_prototype(prototype)
      define(m)
    end

    # @overload on_signal(name, &block)
    # @overload on_signal(bus, name, &block)
    # Registers a handler (code block) for a signal with _name_ arriving
    # over the given _bus_. If no block is given, the signal is unregistered.
    # Note that specifying _bus_ is discouraged and the option is kept only for
    # backward compatibility.
    # @return [void]
    def on_signal(bus = @object.bus, name, &block)
      mr = DBus::MatchRule.new.from_signal(self, name)
      if block.nil?
        bus.remove_match(mr)
      else
        bus.add_match(mr) { |msg| block.call(*msg.params) }
      end
    end

    PROPERTY_INTERFACE = "org.freedesktop.DBus.Properties"

    # Read a property.
    # @param propname [String]
    def [](propname)
      ret = object[PROPERTY_INTERFACE].Get(name, propname)
      # this method always returns the single property
      if @object.api.proxy_method_returns_array
        ret[0]
      else
        ret
      end
    end

    # Write a property.
    # @param property_name [String]
    # @param value [Object]
    def []=(property_name, value)
      property = properties[property_name.to_sym]
      if !property
        raise DBus.error("org.freedesktop.DBus.Error.UnknownProperty"),
              "Property '#{name}.#{property_name}' (on object '#{object.path}') not found"
      end

      case value
      # accommodate former need to explicitly make a variant with the right type
      when Data::Variant
        variant = value
      else
        type = property.type
        typed_value = Data.make_typed(type, value)
        variant = Data::Variant.new(typed_value, member_type: type)
      end

      object[PROPERTY_INTERFACE].Set(name, property_name, variant)
    end

    # Read all properties at once, as a hash.
    # @return [Hash{String}]
    def all_properties
      ret = object[PROPERTY_INTERFACE].GetAll(name)
      # this method always returns the single property
      if @object.api.proxy_method_returns_array
        ret[0]
      else
        ret
      end
    end
  end
end