This is a Request for Comments for the Ruby PureMVC implementation: updated (2009-10-27)1. Package naming & distribution
The gem (package) should be published under a lowercase-underscore name,
which is somewhat a ruby convention for gems (yes, not all adhere to this one, i know).
Nevertheless 'puremvc_multicore' and 'puremvc_standard' would be appropriate names.
With gemcutter.org getting more popular it might be a good platform to publish upcoming
versions, with a fallback on rubyforge.org.2. Folder structure
As ruby's "require"
is different from AS3's "import"
the reversed domain notation
is unnecessary. Rubyist tend to have there namespaces cohere with their
folder-structure, at least to some degree.
puremvc_multicore\ # <- gem root3. Namespaces
As for now, the ruby standard port has NO namespaces, though this might not
be a problem at first sight, its bad style and limits usability when many moving
parts (gems) are involved. I've chosen PureMVC as main namespace in which
all PureMVC related project should be embedded.
So the MultiCore port lies in PureMVC::MultiCore, while the Standard port
will reside under PureMVC::Standard.
Other Project like Pipes will be under PureMVC::MultiCore::Utilities::Pipes.
This gives developers a cleaner way to access certain classes. For now i ignored
the subspaces ::Core and ::Pattern, but if there is demand for implementing those,
it's like five minutes of refactoring.
If you are concerned that the namespaces are to long, you could always "include"
the module (somewhat closer to AS3's "import"
), thus getting rid off all the namespaces.
(e.g. import PureMVC::MultiCore, would make Facade directly available in Object)4. Constants, Symbols and Strings
Ruby is very indulgent and sometimes this tends to result in bad code.
As for now i just enforce symbols on multiton keys. this is done because
ruby hashes allow nearly any kind of key, let's look at an example:
a_hash = Hash.new
a_hash[nil] = "not nil at all"
a_hash[false] = "might be true"
a_hash["key"] = "value"
a_hash[:key] = :another_value
All of the above statements are valid uses of a hash, but just because they're
valid uses doesn't mean they are always good ones. I could think of use-cases
when it might be desirable, to bind nil or false to a certain value, for example
in some kind of error handler, but as a name of a Facade or a Notification it's
inappropriate. Furthermore, People new to ruby often like to mix strings
with symbols, which leads to confusion when a_hash["key"] is not a_hash[:key].
Symbols are only instantiated once, so will only use memory once,
and their purpose is "to stand for something else"
, hence the name symbol.
However one might argue that assigning a string to a constant solves this problem,
which is true, but if the representation within the string is only used for
comparison, it's best practice to use a symbol.
So, i ask you if the implementation of Notification should enforce symbols too,
as you never need their actual 'name' just to compare that :a is not :b.
Remember, you can still use constants for a clean programing style, just their
assigned value needs to be a symbol.
(e.g. MyStartupNotification = :my_startup_notification)5. Mediator implementation and meta-programing
Mediators hinder ruby's meta-programing strength. I modified the current
implementation, by changing the way notification_interests and _handling is
done, to enable the use of mixins (called modules in ruby). this allows to bind
certain methods to one or more notifications and vice versa.
The good news, its fully backward compatible with any project already written
(which to this point would only be the one i wrote, hehe) and still abides
to the Reference, because normally one would override #list_notification_interests()
and #handle_notification() anyway.
I introduced three methods:
#initialize_mediator(), #add_notification_handler(), #remove_notification_handler()
with the first one being called by #initialize() and the second one is called within
#initialite_mediator() or #initialize() to bind instance methods to Notifications.
The third one might even be used for heavy meta-programing.
The only way to break this would be to override the @notification_handlers variable
which holds the handlers and NOT to override list_notification_interests()
and #handle_notification() before the mediator gets registered with the facade.
This is very unlikely and i could not think of a mediator which does not have
any notification interests BUT overrides the @notification_handlers variable.
For more information see ./lib/puremvc/multicore/patterns/mediator/mediator.rb
Documentation still needs some tuning and example uses for most methods.