Class: RBus::Proxy

Inherits:
BlankSlate show all
Defined in:
lib/rbus/bus/proxy.rb

Overview

The object that represents the remote bus object.

Direct Known Subclasses

Bus

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(bus, well_known_name, object_path) ⇒ Proxy

Returns a new instance of Proxy.



67
68
69
70
71
72
73
# File 'lib/rbus/bus/proxy.rb', line 67

def initialize(bus, well_known_name, object_path)
  @bus = bus
  @message_loop = @bus.message_loop
  @well_known_name = well_known_name
  @object_path = object_path
  Introspect()
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(name, *args, &block) ⇒ Object

Routes all method calls to remote object



193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
# File 'lib/rbus/bus/proxy.rb', line 193

def method_missing(name, *args, &block) # :nodoc:
  
  method = name.to_s
  
  Log.debug('Proxy method called: ' + method)
  
  unless method.match(VALID_METHOD_NAME)
    raise InvalidNameException, "Invalid method name '#{name}'"
  end
  
  call = MethodCall.new do |m|
    m.destination = @well_known_name
    m.object_path = @object_path
    m.interface = @interface if @interface
    m.member = method
    if !args.empty?
      begin
        # always walk arguments because 'key:value' is always a valid arg
        signature = parse_arguments!(args)
      rescue RuntimeError => e
        # re-bomb unless other signature
        raise e unless @methods.has_key?(method)
      end
      if !@methods.has_key?(method)
        method!(name, signature)
      end
      Log.debug('Signature: ' + @methods[method])
      m.signature = @methods[method]
    end
    m.arguments = args
  end
  Log.debug(block_given? ? 'Block given' : 'Block NOT given')
  @message_loop.send_message(call, block_given? ? block : nil)
end

Class Method Details

.parse_introspect(xml) ⇒ Object

Parses Introspect() XML into a hash with => signature



53
54
55
56
57
58
59
60
61
62
63
64
65
# File 'lib/rbus/bus/proxy.rb', line 53

def self.parse_introspect(xml)
  methods = {}
  doc = REXML::Document.new(xml)
  doc.elements.each("//method") do |method|
    name = method.attribute('name').to_s
    signature = ''
    method.elements.each("*[@direction!='out']") do |arg|
      signature << arg.attribute('type').to_s
    end
    methods[name] = signature
  end
  methods
end

Instance Method Details

#connect!(signal, options = {}, &block) ⇒ Object

Connect block to a signal

Raises:



98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
# File 'lib/rbus/bus/proxy.rb', line 98

def connect!(signal, options = {}, &block)
  raise MessageException, "connect! needs a block" unless block_given?
  
  rules = {
    :type => 'signal',
    :member => signal.to_s,
    :path => @object_path,
    #:sender => @well_known_name
  }
  rules['interface'] = @interface if @interface
  
  rules.merge!(options)
  
  Log.debug(rules)
  @bus.AddMatch(rules, &block)
end

#interface!(interface) ⇒ Object

Set interface and return or yield self. If a block is given, a copy of the object will be the new interface will only be set for that block, and reset afterwards.



87
88
89
90
91
92
93
94
95
# File 'lib/rbus/bus/proxy.rb', line 87

def interface!(interface)
  old_i = @interface
  @interface = interface
  if block_given?
    yield self
    @interface = old_i
  end
  self
end

#IntrospectObject

:nodoc:



74
75
76
77
78
79
80
81
# File 'lib/rbus/bus/proxy.rb', line 74

def Introspect # :nodoc:
  # TODO: store interfaces as well, if ever needed
  interface = @interface
  @interface = 'org.freedesktop.DBus.Introspectable'
  @methods = Proxy.parse_introspect(method_missing(:Introspect))
  Log.debug("Methods from introspect: " + @methods.inspect)
  @interface = interface
end

#method!(name, signature) ⇒ Object

Define a method with signature. name can be a string or a symbol.



117
118
119
# File 'lib/rbus/bus/proxy.rb', line 117

def method!(name, signature)
  @methods[name.to_s] = signature
end

#parse_arguments!(arguments) ⇒ Object

Parse arguments and guess signature from a few types Handles [dr]bus-send type arguments also



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
179
180
181
182
183
184
185
186
187
188
189
190
# File 'lib/rbus/bus/proxy.rb', line 123

def parse_arguments!(arguments)
  
  strip = lambda{|s|s.sub!(/^'/,'');s.sub!(/'$/,'')}

  signature = ''
  array = false
  arguments.map! do |value|
    case value
      when TrueClass, FalseClass
        signature << 'b'
      when Float
        signature << 'd'
      when Hash
        signature << 'a{'
        fail "Can't guess signature for empty hash" if value.empty?
        k_sig = parse_arguments!([value.keys.first])
        v_sig = parse_arguments!([value.values.first])
        signature << k_sig
        signature << v_sig
        signature << '}'
      when Array
        a_sig = parse_arguments!(value)
        #puts a_sig
        
        # TODO: this only covers simple types
        sq = a_sig.squeeze
        if sq.length == 1 || sq[0] == ?a && sq.length == 2
          signature << 'a' << sq
        else
          signature << "(#{a_sig})"
        end
      when Symbol
        signature << 's'  
      when String
        type, arg = value.split(':',2)
        if PREFIX_TO_SIG.has_key?(type)
          signature << PREFIX_TO_SIG[type]
          strip.call(arg)
          case type
            when 'dict'
              key_s,val_s,arg = arg.split(':',3)
              strip.call(arg)
              value = arg.nil? ? {} : Hash[*arg.split(/'?,'?/)]
              signature << PREFIX_TO_SIG[key_s]
              signature << PREFIX_TO_SIG[val_s]
              signature << '}'
            when 'array'
              array = true
              value = arg
              redo
            when 'variant'
              value = arg
              redo
            else
              value = (array) ? arg.split(/'?,'?/) : arg
              array = false
          end              
        else
          signature << 's'
        end
      else
        fail "Failed to guess signature for '#{value.class}'"
    end
    value
  end
  
  return signature
end