RDT gets Refactoring support
Well the cat is out of the bag: Mirko Stocker and his cohorts have committed their refactoring support to RDT's Subversion repository.
This means we'll be able to roll out 0.9.0 with this support. Right now we're working to get it integrated into the build process, so that it will begin showing up in our new builds. I'm pretty excited myself, because I've had little chance to try out their work.
This refactoring support joins other recent work in RDT which allows us to do some occurence marking of variables, code completion and other exciting features (thanks Jason!). There's certainly a long way yet to go to get the tools polished - for instance we still have a hard time doing code completion (or much else) on a file which is being edited while the syntax is temporarily incorrect (the JRuby parser is great, but not so forgiving) - but we're constantly marching forward.
Look for 0.9.0 to come out sometime this month (we're aiming for the 15th)!
Patterns in Ruby: Decorator revisited
A while back I wrote an article describing some possible ways to implement a
Decorator pattern in Ruby.
I've stumbled across several mentions of
yet another idiom used so often in the Rails codebase that they've extracted
it into the latest ActiveSupport. That idiom is
alias_method_chain,
and it's a good example of a decorator implementation.
This idiom is a codified example of using the alias approach I briefly mentioned in the earlier article. In that article we aliased the original implementation with anew name, and set up a new implementation of our method (often delegating to the original) with the original's name. A quick example makes this clear:
class Window
def draw
# do some drawing here...
end
# some code...
# creates a 'copy' of draw method, but gives it
# the name/selector 'original_draw'
alias :original_draw :draw
def draw
draw_vertical_scrollbar
original_draw
end
endalias_method_chain
In Rails 1.2 (ActiveSupport specifically), the Rails core team found many instances of this pattern
and codified a new method on the class Module, alias_method_chain. This class-level method encapsulates this
pattern of wrapping existing methods with additional behavior.
Here's a specific example, showing how they would wrap rendering with layouts:
alias_method :render_with_no_layout, :render
alias_method :render, :render_with_a_layoutIn this small code snippet, they are creating a small chain of methods to wrap the existing render behavior.
Now calls to render will be routed to render_with_a_layout and then on to the original render implementation
(which is now aliased to render_with_no_layout). So they coded up alias_method_chain which simply does
the wrapping for them (using naming conventions):
class Module
# Encapsulates the common pattern of:
#
# alias_method :foo_without_feature, :foo
# alias_method :foo, :foo_with_feature
#
# With this, you simply do:
#
# alias_method_chain :foo, :feature
#
# And both aliases are set up for you.
def alias_method_chain(target, feature)
alias_method "#{target}_without_#{feature}", target
alias_method target, "#{target}_with_#{feature}"
end
endPlease note that if they were to replace their existing two calls to alias_method above, they would need to tweak the naming a little
(the methods would become render_without_layout and render_with_layout as opposed to
render_with_no_layout and render_with_a_layout respectively).
Patterns in Ruby: Observer Pattern
Another easy to implement pattern in Ruby is the Observer pattern. The Observer pattern is a publish/subscribe mechanism where an objects can register to be notified of state changes (or observe changes) on another observed object. This pattern may often become refactored into a more general event framework (where objects fire events off into queues to which there are listeners subscribed).
The basic implementation
Here's a look at a simple ruby implementation:
class Observable
def initialize
@listeners = []
end
def register_listener(listener)
@listeners << listener
end
def unregister_listener(listener)
@listeners.remove(listener)
end
def run
notify_listeners("Hello!")
end
protected
def notify_listeners(event)
@listeners.each {|l| l.notify(event) }
end
end
class Listener
def initialize(observable)
observable.register_listener(self)
end
def notify(event)
puts "Notified of '#{event}'"
end
end
observable = Observable.new
listener = Listener.new(observable)
observable.run #=> Notified of 'Hello!'The pattern itself in this form is pretty general. So general, in fact, that there is a module mixin of Observer inside the standard ruby library (observer.rb). There's some good documentation in there, and it provides a simpler path to this implementation:
require "observer"
class TV
include Observable
def initialize(channel)
@channel = channel
end
def up
@channel += 1
changed
notify_observers(@channel)
end
end
class ChannelWatcher
def initialize(tv)
tv.add_observer(self)
end
def update(channel)
puts "Changed channel to #{channel}"
end
end
tv = TV.new(160)
watcher = ChannelWatcher.new(tv)
tv.up #=> Changed channel to 161Please be aware that the API is a little different from my initial example.
Moving towards events
Both of the above implementations rely on a generic observer pattern, but the Observer pattern can often evolve into a simple event mechanism. The difference is that instead of firing a generic event object via a generic notify method, the move towards events uses unique method names, and filters events to notify only those interested in the type of event occurring.
Let's see a TV example where we move towards a more specialized event firing version of the pattern:
require "observer"
class TV
def initialize(channel)
@channel = channel
@listeners = []
end
def add_listener(listener)
@listeners << listener
end
def up
@channel += 1
@listeners.each {|l| l.channel_increased(@channel) }
end
def down
@channel -= 1
@listeners.each {|l| l.channel_decreased(@channel) }
end
end
class ChannelUpWatcher
def initialize(tv)
tv.add_listener(self)
end
def channel_increased(channel)
puts "Changed channel to #{channel}"
end
def channel_decreased
# do nothing...
end
end
tv = TV.new(160)
watcher = ChannelUpWatcher.new(tv)
tv.up #=> Changed channel to 161In this instance we can fire off events for surfing the Tv upwards or downwards (in channels) separately, though we still register listeners into a generic pool, and listeners are expected to contain both event methods. Variations of this can be done to register listeners into sub-groups upon registration by calling unique methods names for each registration, or by passing in a Filter object that can be used to filter to the events the listener cares about. In filtering at registration we can avoid listeners having to implement every event firing method and minimize the number of events fired off.
One illustration of this observer based event model is the Java Swing events API.
Extending the pattern towards this event firing mechanism even further we'd likely move into using queues and firing events off to the queues themselves rather than directly to observers. Observers would then become subscribers to the queues.
Using blocks and procs
The Observer pattern as described above is the typical pattern followed in most languages without closures, lambdas or functors. In Ruby we have the ability to throw around closures/blocks so we can take the pattern a little further.
Let's revisit our original implementation, but let's add the ability to register the callback function to be performed upon notification.
class Observable
def initialize
@listeners = []
end
def register_listener(&blk)
@listeners << blk
end
def unregister_listener(&blk)
@listeners.remove(blk)
end
def run
notify_listeners("Hello!")
end
protected
def notify_listeners(event)
@listeners.each {|l| l.call(event) }
end
end
class Listener
def initialize(observable)
observable.register_listener {|event| "Notified of '#{event}'"}
end
end
observable = Observable.new
listener = Listener.new(observable)
observable.run #=> Notified of 'Hello!'This is the model illustrated in the Tk bindings for Ruby - you can see examples of usage in Programming Ruby's section on binding events in Tk. That section and their section on blocks as closures begin to broach the how closures capture the context in which they were defined - allowing for some very interesting and complex behavior in using blocks and procs as event or observer callbacks (allowing you to refer to objects available at the scope of the block definition, not when the callback/block execution occurs).
Patterns in Ruby: Singleton Pattern
The Singleton pattern is the black sheep of the pattern family. It was easy to grasp, developers everywhere applied it liberally, and an inevitable backlash came against its overuse.
I won't make any judgments or reccomendations on when to use it - but I will show you just how easy it is to apply in Ruby.
The literal translation of the pattern is to create a class level instance method and to hide the new method.
class Example
def initialize
# do something?
end
def self.instance
return @@instance if defined? @@instance
@@instance = new
end
private_class_method :new
end
puts Example.instance.object_id #=> 21783380
puts Example.instance.object_id #=> 21783380This example gives you the basic idea, but it doesn't cover many cases you'd like to handle, like cloning or duping the singleton. It also doesn't hide the class level allocate method, which means a sneaky coder could still create another instance through some hacking.
Lastly, it's not thread safe.
Luckily, Ruby already provides a module for making classes singletons. It's in the standard library, inside 'singleton.rb'. Here's how you use it:
require 'singleton'
class Example
include Singleton
endThis module will do the same thing as my example above but will also handle hiding allocate, overriding the clone and dup methods, and is thread safe. The library file itself contains a bunch of examples of its usage, and those interested should definitely read through it.
One thing to note about these implementations is that the instance method takes no arguments, so none are passed on to the object's constructor. This makes sense because the first time instance is called those will be the arguments used for this global instance. Setters are typically more appropriate for most singletons.
Since singletons are global in nature setters should be at the class level. As an extra bonus here's the implementation of the class level attr_ methods to generate the vanilla getter/setter methods (stolen from Rails).
class Class # :nodoc:
def cattr_reader(*syms)
syms.flatten.each do |sym|
class_eval(<<-EOS, __FILE__, __LINE__)
unless defined? @@#{sym}
@@#{sym} = nil
end
def self.#{sym}
@@#{sym}
end
def #{sym}
@@#{sym}
end
EOS
end
end
def cattr_writer(*syms)
syms.flatten.each do |sym|
class_eval(<<-EOS, __FILE__, __LINE__)
unless defined? @@#{sym}
@@#{sym} = nil
end
def self.#{sym}=(obj)
@@#{sym} = obj
end
def #{sym}=(obj)
@@#{sym} = obj
end
EOS
end
end
def cattr_accessor(*syms)
cattr_reader(*syms)
cattr_writer(*syms)
end
endNow we can create a more realistic singleton:
require 'singleton'
class JimmyGrimble
include Singleton
cattr_reader :boots
cattr_accessor :football
end