I am one of the developers of AspectWerkz [1] a plain Java aop implementation. During the last
months a have played a little with Ruby, and even if I am sure I haven't got yet the right ruby
mindset I see a lot of potential here.
Lately, considering that aop is one of my passions, I was looking for an aop implementation in Ruby.
I have found AspectR [2] being the only one and a couple of more or less theoretical proposals.
I have also noticed that some guys here are interested in this field (Trans, Peter Vanbroekhoven,
etc - sorry if I don't mention all the names or I am using just nicknames).
I would be very interesting to find out from more advanced Ruby users which were the hard parts they
have reached while trying to do aop in Ruby. I am asking this as I am considering to start a project
to support the full aop implementation in Ruby (probably in some places adapted to the
needs/specifics of Ruby).
many thanks for all your future answers,
:alex |.::the_mindstorm::.|
[1] http://aspectwerkz.codehaus.org/
[2] http://aspectr.sourceforge.net/
class Dog
def bark
puts "WOOF"
end
end
class Proxy
def initialize(clazz)
@clazz = clazz
end
def method_missing(meth, *parms)
@precall.call(meth, *parms)
@clazz.send(meth.to_s, *parms)
end
def precall(&block)
@precall = block
end
end
d = Dog.new
d.bark
pro=Proxy.new(d)
pro.precall { |meth,parms|
puts "Precall method #{meth.to_s}"
}
pro.bark
I think, aop-like programming is done mostly by redefining methods.
This is somewhat ugly, as you have to alias the old method.
A good example is the once macro as used in freeride or date.rb:
module Once
def once(*ids)
for id in ids
module_eval <<-"end;"
alias_method :__#{id.to_i}__, :#{id.to_s}
private :__#{id.to_i}__
def #{id.to_s}(*args, &block)
(@__#{id.to_i}__ ||= [__#{id.to_i}__(*args, &block)])[0]
end
end;
end
end
private :once
end
By using once, you can cache method results like:
class MyClass
extend Once
once :my_method
end
I can imagine a cleaner aop-style of doing this like:
aspect_around MyModule::MyClass, :my_method do |meth, *args|
( @__my_method__ ||= [ meth.call(*args) ] )[0]
end
or more generally
module Once
def once(*ids)
for id in ids
aspect_around self, id do |meth, *args|
if cache = instance_variable_get("@__#{id}__")
cache[0]
else
result = meth.call(*args)
instance_variable_set("@__#{id}__", [result])
end
end
end
end
end
:alex |.::the_mindstorm::.|
#: Matthias Georgi changed the world a bit at a time by saying on 9/14/2005 12:11 PM :#
you don't have to do that, see the implementation of this from Mauricio
Fernandez[1], based on explicitly creating an old Method instance via
#method and calling that instead of something like __old_meth.
Well, in my experience the hardest part has been dealing with name
clashes between advice and the methods they effect, though I think that
is exhaserbated with the approach we've taken (which I suspect you've
read).
Another difficulty with what I think you have in mind, is actually
tapping into those joinpoints. You will likely be needing to modify
core --which isn't very condusive to adoption.
Really the thing about Ruby is that it already offers a lot of
AOP-esque features, albiet they are a bit scatted about. Hooks and
callbacks go along way toward serving as joinpoints (though there are a
few notably missing). Method aliasing serves as a workable, albiet
slightly clumsy due to potential name cashes, means of advice. And
ObjectSpace.each_object allows one to tap into every part of the
system; certainly not the most efficient, but generally effective since
the costs are typically all up front.
T.
Firstly many thanks for taking the time to answer. Than more questions inlined :-)
> Hi Alexandru,
>
> Well, in my experience the hardest part has been dealing with name
> clashes between advice and the methods they effect, though I think that
> is exhaserbated with the approach we've taken (which I suspect you've
> read).
>
which one are you refering to?
> Another difficulty with what I think you have in mind, is actually
> tapping into those joinpoints. You will likely be needing to modify
> core --which isn't very condusive to adoption.
>
by modifying the core you mean to alter/add the Object, Module, etc functionality; or something more
deeper? indeed I might need at some moment to open/alter Object, Module, etc, but I would like to
stay at that level.
my (possible) naive thoughts are in the following direction:
- assure that aspects definitions are loaded always first, so that I can have a centralized place to
control pointcuts
- using inspection code I can plug hooks on the joinpoints matching pointcuts loaded in the first place
- using inspection code I can do mixins too
Probably the most interesting thing from this perspective (I feel that I should underline this
again: maybe naive) is how many joinpoints I will be able to watch based on existing inspection code
(I think one of the documents I have read already analysed this part).
- a more difficult part is the aspect instanciation model; well for the moment I haven't gonne so
far to imagine what would mean aspects with perthis, pertarget, perX;
- another interesting part will be the cflow/cflowbelow;
but as I usually like to start small and afterwards grow I would be happy to have at least the first
part done.
> Really the thing about Ruby is that it already offers a lot of
> AOP-esque features, albiet they are a bit scatted about. Hooks and
> callbacks go along way toward serving as joinpoints (though there are a
> few notably missing). Method aliasing serves as a workable, albiet
> slightly clumsy due to potential name cashes, means of advice. And
> ObjectSpace.each_object allows one to tap into every part of the
> system; certainly not the most efficient, but generally effective since
> the costs are typically all up front.
>
> T.
>
>
>
Surely, there are lots of hacks that can be done and get a feeling of doing aop (I don't want to
sound harsh). However, in bigger systems and for ease of solution they are not the silver bullet
(nor the aop is :-)).
please let me know what do you think,
:alex |.::the_mindstorm::.|
> Hi!
>
> I am one of the developers of AspectWerkz [1] a plain Java aop
> implementation. During the last months a have played a little with
> Ruby, and even if I am sure I haven't got yet the right ruby mindset I
> see a lot of potential here.
> I would be very interesting to find out from more advanced Ruby users
> which were the hard parts they have reached while trying to do aop in
> Ruby. I am asking this as I am considering to start a project to
> support the full aop implementation in Ruby (probably in some places
> adapted to the needs/specifics of Ruby).
It's probably not too related, but I think Context-oriented
Programming would be really cool to have in Ruby. I tried
implementing it, but I couldn't figure a good way to do it...
http://lambda-the-ultimate.org/node/view/941
> many thanks for all your future answers,
>
> :alex |.::the_mindstorm::.|
--
Christian Neukirchen <chneuk...@gmail.com> http://chneukirchen.org
What is context-oriented programming?
:alex |.::the_mindstorm::.|
One could say (although some people may disagree with that), that COP
is a kind of dynamic AOP where the layers can be changed at runtime.
For an example, see
http://p-cos.net/documents/contextl-overview.pdf
I don't have more stuff about it right now...
Ciao,
T.
there is a rather simple implementation of AOP in the Glue libarie
that acompaies Nitro and Og. Aspects are used throughout the Nitro
project. At the moment the lower level annotation system is beeing
redesigned and I expect to reimplement the AOP implementaion on top of
that.
Perhaps you could have a look at the current implementation and offer
some suggestions.
http://rubyforge.org/projects/nitro/
http://rubyforge.org/pipermail/nitro-general/
regards,
George.
--
http://www.gmosx.com
http://www.navel.gr
http://www.nitrohq.com