Singnals ans Slots in Ruby





2
Date Submitted Wed. Aug. 9th, 2006 5:49 AM
Revision 1 of 1
Beginner plinge
Tags Ruby | signals | slots
Comments 0 comments
Well, ruby is actually so flexible that there is no real need to implement the goode olde signals & slots metaphor. But it serves nicely as demonstration of ruby properties, so here we go.

# constants
OFF = false; ON = true
# ok, I'm laaaazy, so I type this just once
module Named
  attr_accessor :name   # getter + setter
  def initialize(name)
    @name=name
  end
end

# gosh, a switch! this one emits a signal labeld :switched
class SignalingSwitch
  include Named
  include Signaling
  def switch
    print @name," switched\n"
    emit :switched
  end
end

# something to switch.. a light!
class Light
  include Named 
  @state=OFF # initial value
  attr_accessor :state # getter + setter

  def turn(x=!@state)  # default: toggle
    @state=x
    print ' ',@name,' turned ',if @state then "on" else "off" end,"\n"
  end
end

# ok, let's roll. two lights
l1 = Light.new("Light1")
l2 = Light.new("Light2")

# each light gets its own switch
s1 = SignalingSwitch.new("Switch1")
connect(s1,:switched,l1,:turn)
s2 = SignalingSwitch.new("Switch2")
connect(s2,:switched,l2,:turn)
 

s1.switch
s1.switch
s2.switch
 

Switch1 switched
  Light1 turned on
Switch1 switched
  Light1 turned off
Switch2 switched
  Light2 turned on
 

# add an all of all on switch as well
sOff = SignalingSwitch.new("Switch all off")
connect(sOff,:switched,l1,:turn,OFF)
connect(sOff,:switched,l2,:turn,OFF)
sOn = SignalingSwitch.new("Switch all on")
connect(sOn,:switched,l1,:turn,ON)
connect(sOn,:switched,l2,:turn,ON)
 

sOn.switch
sOff.switch
 

Switch all on switched
  Light1 turned on
  Light2 turned on
Switch all off switched
  Light1 turned off
  Light2 turned off
 

# Another Signals + Slots Implementation for Ruby (c) Axel Plinge 2006

# in order to avoid eval(...) cascades, all signaling Objects
# have to 'include Signaling' in order to be able to 'emit'
module Signaling   
  # connect one of our signals to one someones slot i.e. method
  def connect(signal,recipient,slot,*args)
    @connections = Hash.new unless @connections
    @connections[signal] = [] unless @connections[signal]
    @connections[signal].push [recipient.method(slot),args]
  end
 
  # emit :signal name => call associated method with args or default value
  def emit(name,*args)
    return if !@connections
    connected_slots =@connections[name]
    return if !connected_slots
    connected_slots.each do |slot|
      slot[0].call(*(slot[1]+args)) # concatenate *args lists
    end
  end
end
 
# connect sender's signal to one recipient's slot i.e. method
# called by sender.emit signal,*emit_args
#
# if *args are given, recipient.slot(*args,*emit_args) will be invoked,
# otherwise the just the args from after the emit statement are used
# recipient.slot(*emit_args)
def connect(sender,signal,recipient,slot,*args)
  sender.connect(signal,recipient,slot,*args)
end
 
Modules in Ruby can be used as namespaces in C++ or Java or, as I have done here, for multiple ineritance, just as interfaces are used in Java. Object.method(mehtod_name) gives and Method object with a method call to involke it. Since variable argument lists are arrays, we can concatenate them with + like any other array before unfolding them with *.

Axel Plinge

axel.plinge.de/dev

Comments

There are currently no comments for this snippet.

Voting