Class: DBus::ProxyObject

Inherits:
Object
  • Object
show all
Defined in:
lib/dbus/proxy_object.rb

Overview

Represents a remote object in an external application. Typically, calling a method on an instance of a ProxyObject sends a message over the bus so that the method is executed remotely on the corresponding object.

Constant Summary collapse

OPEN_QUOTE =
RUBY_VERSION >= "3.4" ? "'" : "`"

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(bus, dest, path, api: ApiOptions::CURRENT) ⇒ ProxyObject

Creates a new proxy object living on the given bus at destination dest on the given path.



40
41
42
43
44
45
46
47
48
# File 'lib/dbus/proxy_object.rb', line 40

def initialize(bus, dest, path, api: ApiOptions::CURRENT)
  @bus = bus
  @destination = dest
  @path = ObjectPath.new(path)
  @introspected = false
  @interfaces = {}
  @subnodes = []
  @api = api
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(name, *args, &reply_handler) ⇒ Object (private)

Handles all unkown methods, mostly to route method calls to the default interface.



151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
# File 'lib/dbus/proxy_object.rb', line 151

def method_missing(name, *args, &reply_handler)
  unless @default_iface && has_iface?(@default_iface)
    # TODO: distinguish:
    # - di not specified
    # TODO
    # - di is specified but not found in introspection data
    raise NoMethodError, "undefined method #{OPEN_QUOTE}#{name}' for DBus interface "\
                         "#{OPEN_QUOTE}#{@default_iface}' on object #{OPEN_QUOTE}#{@path}'"
  end

  begin
    @interfaces[@default_iface].method(name).call(*args, &reply_handler)
  rescue NameError => e
    # interesting, foo.method("unknown")
    # raises NameError, not NoMethodError
    raise unless e.to_s =~ /undefined method #{OPEN_QUOTE}#{name}'/

    # BTW e.exception("...") would preserve the class.
    raise NoMethodError, "undefined method #{OPEN_QUOTE}#{name}' for DBus interface "\
                         "#{OPEN_QUOTE}#{@default_iface}' on object #{OPEN_QUOTE}#{@path}'"
  end
end

Instance Attribute Details

#apiApiOptions (readonly)

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns:



34
35
36
# File 'lib/dbus/proxy_object.rb', line 34

def api
  @api
end

#busObject (readonly)

The bus the object is reachable via.



29
30
31
# File 'lib/dbus/proxy_object.rb', line 29

def bus
  @bus
end

#default_ifaceString

Returns The name of the default interface of the object.

Returns:

  • (String)

    The name of the default interface of the object.



31
32
33
# File 'lib/dbus/proxy_object.rb', line 31

def default_iface
  @default_iface
end

#destinationObject (readonly)

The (remote) destination of the object.



24
25
26
# File 'lib/dbus/proxy_object.rb', line 24

def destination
  @destination
end

#introspectedBoolean

Flag determining whether the object has been introspected.

Returns:

  • (Boolean)


22
23
24
# File 'lib/dbus/proxy_object.rb', line 22

def introspected
  @introspected
end

#pathObjectPath (readonly)

The path to the object.

Returns:



27
28
29
# File 'lib/dbus/proxy_object.rb', line 27

def path
  @path
end

#subnodesObject

The names of direct subnodes of the object in the tree.



19
20
21
# File 'lib/dbus/proxy_object.rb', line 19

def subnodes
  @subnodes
end

Instance Method Details

#[](intfname) ⇒ ProxyObjectInterface

Retrieves an interface of the proxy object

Parameters:

  • intfname (String)

Returns:

Raises:



60
61
62
63
64
65
66
# File 'lib/dbus/proxy_object.rb', line 60

def [](intfname)
  introspect unless introspected
  ifc = @interfaces[intfname]
  raise DBus::Error, "no such interface #{OPEN_QUOTE}#{intfname}' on object #{OPEN_QUOTE}#{@path}'" unless ifc

  ifc
end

#[]=(intfname, intf) ⇒ ProxyObjectInterface

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Maps the given interface name intfname to the given interface _intf.

Parameters:

Returns:



73
74
75
# File 'lib/dbus/proxy_object.rb', line 73

def []=(intfname, intf)
  @interfaces[intfname] = intf
end

#define_shortcut_methodsObject

For each non duplicated method name in any interface present on the caller, defines a shortcut method dynamically. This function is automatically called when a DBus::ProxyObject is introspected.



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
# File 'lib/dbus/proxy_object.rb', line 91

def define_shortcut_methods
  # builds a list of duplicated methods
  dup_meths = []
  univocal_meths = {}
  @interfaces.each_value do |intf|
    intf.methods.each_value do |meth|
      name = meth.name.to_sym
      # don't overwrite instance methods!
      next if dup_meths.include?(name)
      next if self.class.instance_methods.include?(name)

      if univocal_meths.include? name
        univocal_meths.delete name
        dup_meths << name
      else
        univocal_meths[name] = intf
      end
    end
  end
  univocal_meths.each do |name, intf|
    # creates a shortcut function that forwards each call to the method on
    # the appropriate intf
    singleton_class.class_eval do
      redefine_method name do |*args, &reply_handler|
        intf.method(name).call(*args, &reply_handler)
      end
    end
  end
end

#has_iface?(name) ⇒ Boolean

Returns whether the object has an interface with the given name.

Returns:

  • (Boolean)


122
123
124
125
# File 'lib/dbus/proxy_object.rb', line 122

def has_iface?(name)
  introspect unless introspected
  @interfaces.key?(name)
end

#interfacesArray<String>

Returns the interfaces of the object.

Returns:

  • (Array<String>)

    names of the interfaces



52
53
54
55
# File 'lib/dbus/proxy_object.rb', line 52

def interfaces
  introspect unless introspected
  @interfaces.keys
end

#introspectObject

Introspects the remote object. Allows you to find and select interfaces on the object.



79
80
81
82
83
84
85
# File 'lib/dbus/proxy_object.rb', line 79

def introspect
  # Synchronous call here.
  xml = @bus.introspect_data(@destination, @path)
  ProxyObjectFactory.introspect_into(self, xml)
  define_shortcut_methods
  xml
end

#on_signal(name, &block) ⇒ void

This method returns an undefined value.

Registers a handler, the code block, for a signal with the given name. It uses default_iface which must have been set.



130
131
132
133
134
135
136
137
# File 'lib/dbus/proxy_object.rb', line 130

def on_signal(name, &block)
  unless @default_iface && has_iface?(@default_iface)
    raise NoMethodError, "undefined signal #{OPEN_QUOTE}#{name}' for DBus interface "\
                         "#{OPEN_QUOTE}#{@default_iface}' on object #{OPEN_QUOTE}#{@path}'"
  end

  @interfaces[@default_iface].on_signal(name, &block)
end