class Orocos::Async::ObjectBase

Attributes

emitting[RW]
event_loop[R]
name[RW]
options[R]
pending_adds[R]

Queue of listener that are going to be added by callbacks registered in the event loop. This is filled and processed by add_listener and remove_listener

Some entries might be nil if remove_listener has been called before the event loop processed the addition callbacks.

@return [Array<EventLoop,nil>]

Public Class Methods

define_event(name) click to toggle source
# File lib/orocos/async/object_base.rb, line 119
def define_event(name)
    define_events(name)
end
define_events(*names) click to toggle source
# File lib/orocos/async/object_base.rb, line 123
def define_events(*names)
    names.flatten!
    names.each do |n|
        raise "Cannot add event #{n}. It is already added" if event_names.include? n
        event_names << n
        str =  %Q{ def on_#{n}(use_last_value = true,&block)
                    on_event #{n.inspect},use_last_value,&block
                end
                def once_on_#{n}(use_last_value = true,&block)
                    l = on_event #{n.inspect},use_last_value do |*args|
                           block.call(*args)
                           l.stop
                        end
                end
                def emit_#{n}(*args)
                    event #{n.inspect},*args
                end }
        class_eval(str)
    end
end
event_names() click to toggle source
# File lib/orocos/async/object_base.rb, line 111
def event_names
    @event_names ||= if self != ObjectBase
                         superclass.event_names.dup
                     else
                         []
                     end
end
new(name,event_loop) click to toggle source
# File lib/orocos/async/object_base.rb, line 173
def initialize(name,event_loop)
    raise ArgumentError, "no name was given" if !name
    @listeners ||= Hash.new{ |hash,key| hash[key] = []}
    @proxy_listeners ||= Hash.new{|hash,key| hash[key] = Hash.new}
    @name ||= name
    @event_loop ||= event_loop
    @options ||= Hash.new
    @emitting = true
    @pending_adds = Array.new
    invalidate_delegator!
    on_error do |e|
        if e.kind_of?(Orocos::ComError)
            unreachable!(:error => e)
        end
    end
end
valid_event?(name) click to toggle source
# File lib/orocos/async/object_base.rb, line 144
def valid_event?(name)
    event_names.include?(name)
end
validate_event(name) click to toggle source
# File lib/orocos/async/object_base.rb, line 148
def validate_event(name)
    name = name.to_sym
    if !valid_event?(name)
        raise "event #{name} is not emitted by #{self}. The following events are emitted #{event_names.join(", ")}"
    end
    name
end

Public Instance Methods

add_listener(listener) click to toggle source
# File lib/orocos/async/object_base.rb, line 275
def add_listener(listener)
    event = validate_event listener.event
    return listener if pending_adds.include? listener
    pending_adds << listener
    event_loop.once do
        expected = pending_adds.shift
        # 'expected' is nil if the listener has been removed before this
        # block got processed
        if expected
            if expected != listener
                raise RuntimeError, "internal error in #{self}#add_listener: pending addition and expected addition mismatch"
            end
            really_add_listener(listener)
        end
    end
    listener
end
disable_emitting(&block) click to toggle source
# File lib/orocos/async/object_base.rb, line 202
def disable_emitting(&block)
    emitting(false,&block)
end
event(event_name,*args,&block) click to toggle source

calls all listener which are registered for the given event the next step

# File lib/orocos/async/object_base.rb, line 334
def event(event_name,*args,&block)
    validate_event event_name
    return unless @emitting
    @event_loop.once do
        process_event event_name,*args,&block
    end
    self
end
event_names() click to toggle source
# File lib/orocos/async/object_base.rb, line 215
def event_names
    self.class.event_names
end
invalidate_delegator!() click to toggle source
# File lib/orocos/async/object_base.rb, line 190
def invalidate_delegator!
    @delegator_obj = DelegatorDummy.new self,@name,@event_loop
end
listener?(listener) click to toggle source

returns true if the listener is active

# File lib/orocos/async/object_base.rb, line 231
def listener?(listener)
    @listeners[listener.event].include? listener
end
listeners(event) click to toggle source

returns the listeners for the given event

# File lib/orocos/async/object_base.rb, line 236
def listeners(event)
    event = validate_event event
    @listeners[event]
end
number_of_listeners(event) click to toggle source

returns the number of listener for the given event

# File lib/orocos/async/object_base.rb, line 225
def number_of_listeners(event)
    event = validate_event event
    @listeners[event].size
end
on_event(event,use_last_value=true,&block) click to toggle source
# File lib/orocos/async/object_base.rb, line 219
def on_event(event,use_last_value=true,&block)
    event = validate_event event
    EventListener.new(self,event,use_last_value,&block).start
end
proxy_event(obj,*events) click to toggle source

adds a listener to obj and proxies event like it would be emitted from self

if no listener is registererd to event it also removes the listener from obj

# File lib/orocos/async/object_base.rb, line 246
def proxy_event(obj,*events)
    return if obj == self
    events = events.flatten
    events.each do |e|
        if existing = @proxy_listeners[obj].delete(e)
            existing.stop
        end
        l = @proxy_listeners[obj][e] = EventListener.new(obj,e,true) do |*val|
            process_event e,*val
        end
        l.start if number_of_listeners(e) > 0
    end
end
reachable!(obj,options = Hash.new) click to toggle source
# File lib/orocos/async/object_base.rb, line 363
def reachable!(obj,options = Hash.new)
    @delegator_obj = obj
    event :reachable if valid_delegator?
end
reachable?(&block) click to toggle source

TODO CODE BLOCK

# File lib/orocos/async/object_base.rb, line 359
def reachable?(&block)
    valid_delegator?
end
really_add_listener(listener) click to toggle source
# File lib/orocos/async/object_base.rb, line 293
def really_add_listener(listener)
    if listener.use_last_value?
        if listener.event == :reachable
            listener.call if valid_delegator?
        elsif listener.event == :unreachable
            listener.call if !valid_delegator?
        end
    end
    @proxy_listeners.each do |obj,listeners|
        if l = listeners[listener.event]
            if listener.use_last_value? && !listener.last_args
                # replay last value if requested
                obj.really_add_listener(listener)
                obj.remove_listener(listener)
            end
            l.start(false) unless l.listening?
        end
    end
    @listeners[listener.event] << listener unless @listeners[listener.event].include?(listener)
    listener
end
remove_all_listeners() click to toggle source
# File lib/orocos/async/object_base.rb, line 379
def remove_all_listeners
    !@listeners.each do |event,listeners|
        while !listeners.empty?
            remove_listener listeners.first
        end
    end
end
remove_listener(listener) click to toggle source
# File lib/orocos/async/object_base.rb, line 315
def remove_listener(listener)
    if idx = pending_adds.index(listener)
        pending_adds[idx] = nil
    end
    @listeners[listener.event].delete listener

    # Check whether the only listeners left are proxy listeners. If they
    # are, remove them
    if number_of_listeners(listener.event) == 0
        @proxy_listeners.each do |obj, listeners|
            if l = listeners[listener.event]
                obj.remove_listener(l)
            end
        end
    end
end
remove_proxy_event(obj,*events) click to toggle source
# File lib/orocos/async/object_base.rb, line 260
def remove_proxy_event(obj,*events)
    return if obj == self
    events = events.flatten
    if events.empty?
        remove_proxy_event(obj,@proxy_listeners[obj].keys)
        @proxy_listeners.delete(obj)
    else
        events.each do |e|
            if listener = @proxy_listeners[obj].delete(e)
                listener.stop
            end
        end
    end
end
unreachable!(options = Hash.new) click to toggle source
# File lib/orocos/async/object_base.rb, line 368
def unreachable!(options = Hash.new)
    if valid_delegator?
        invalidate_delegator!
        event :unreachable
    end
end
valid_delegator?() click to toggle source
# File lib/orocos/async/object_base.rb, line 375
def valid_delegator?
    !@delegator_obj.is_a? DelegatorDummy
end
valid_event?(event) click to toggle source

returns true if the event is known

# File lib/orocos/async/object_base.rb, line 207
def valid_event?(event)
    self.class.valid_event?(event)
end
validate_event(event) click to toggle source
# File lib/orocos/async/object_base.rb, line 211
def validate_event(event)
    self.class.validate_event(event)
end
wait(timeout = 5.0) click to toggle source

waits until object gets reachable raises Orocos::NotFound if the object was not reachable after the given time spawn

# File lib/orocos/async/object_base.rb, line 345
def wait(timeout = 5.0)
    time = Time.now
    @event_loop.wait_for do
        if timeout && timeout <= Time.now-time
            Utilrb::EventLoop.cleanup_backtrace do
                raise Orocos::NotFound,"#{self.class}: #{respond_to?(:full_name) ? full_name : name} is not reachable after #{timeout} seconds"
            end
        end
        reachable?
    end
    self
end