Category: Welcome
TODO: Implement
Somehow I seem to have reached a new level in my year-old C++ code. Apart form fixing some minor bugs in rare use-cases, the only parts I need to fix are NYIs (Not-Yet-Implemented Errors). Whenever I wonder why some function is not working, a few clicks into the code lead me to a method with the typical NYI body:
{
// TODO: Implement
}
Ah, well. I might as well get to it ;)
2008-07-17. 13:13:23. 70 words, 632 views. Categories: Welcome , Leave a comment » • Send a trackback »
Signals & Slots in Ruby
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. A typical signal & slots example looks like this:
# 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)
So if we call
s1.switch s1.switch s2.switchWe get the ouput
Switch1 switched Light1 turned on Switch1 switched Light1 turned off Switch2 switched Light2 turned onOk, signals and slots are a bit more powerfull. We may add
# 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)
So that via
sOn.switch sOff.switchWe get the ouput
Switch all on switched Light1 turned on Light2 turned on Switch all off switched Light1 turned off Light2 turned off
How it is made
Ok, I wrote the module Signaling and a global connect function to make it work
# 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 *.
An Observer Pattern
Well, the Observer pattern looks like a subset of signals and slots. So I just implemented it as such. Note that there is a big Observer implementation by Joel VanderWerf on RAA and, of course, some implementations in the Design Patterns collection on RubyGarden (which I, of course, read after implementing it myself... )
# Observer Pattern, (c) Axel Plinge 2006
module Observable
include Signaling
# connct oberver to our changed event
def addObserver(o)
connect(:changed,o,:update,self)
end
# notify all observers of our change
def notifyObservers(*args)
emit :changed,self,*args
end
end
module Observer
# called if observable changes
def update(o,*args)
end
end
In order to test that, here a simple example
# a list of inclomming trains
class TrainList
include Observable
def initialize()
@list = []
end
def add(train)
@list.push(train)
@list.sort!
notifyObservers
end
def del(train)
@list.delete(train)
notifyObservers
end
def to_s
s=''
@list.each do |t|
s=s+t.to_s+"\n"
end
s
end
end
# a display of incomming trains
class TrainDisplay
include Observer # actually we just have to define update(o,args)
attr_accessor :name # getter + setter
def initialize(name)
@name=name
end
def update(o,*args)
print "---"+@name+"---"+"\n"
print o.to_s
end
end
So if we call:
d1 = TrainDisplay.new("am Eingang")
d2 = TrainDisplay.new("am Gleis")
l = TrainList.new
l.addObserver(d1)
l.addObserver(d2)
t1 = Train.new("16:00", "H-Bahn SWK Abgabe")
t2 = Train.new("11:11", "S1 Kölle")
l.add t1
l.add t2
l.del t2
We get the ouput
---am Eingang--- 16:00 H-Bahn SWK Abgabe ---am Gleis--- 16:00 H-Bahn SWK Abgabe ---am Eingang--- 16:00 H-Bahn SWK Abgabe 11:11 S1 Kölle ---am Gleis--- 16:00 H-Bahn SWK Abgabe 11:11 S1 Kölle ---am Eingang--- 16:00 H-Bahn SWK Abgabe ---am Gleis--- 16:00 H-Bahn SWK AbgabeOk, just in case you are wondering, here the Train class
# schoo schooo
class Train
attr_accessor :time, :name
def initialize(time,name)
@time=time;@name=name
end
def <=>(o)
if @time==o.time then @name<=>o.name else @time<=>o.time end
end
def to_s
@time.to_s+"\t"+@name
end
end
Anyways, I hope this was a bit insightfull.
The whole code is now part of APRL, you can download
it here or view the
rdocs, if you like.01/17/06. 11:33:05 am. 918 words, 13517 views. Categories: Welcome , Leave a comment » • Send a trackback »