[ANN] [RCR] Cut-based AOP

T

Trans

Jacob said:
How about this?

Aspect.before( '*#save*', '*#delete*' ) do
# advice
end

Implementation[1]:

module Aspect
def before( *cut_specifications, &advice )
cut_specifications.each do |spec|
unless PointCut === spec
spec = PointCut.new( spec )
end
spec.joinpoints.each do |joinpoint|
joinpoint.before &advice
end
end
end
end

[snip]

Nice "plunge into the foray" Jacob! I bet if you worked Binding into
the JointPoint you'd be even closer to what Alexandru is after. ( And
if you worked set_trace_func in there you'd be right on top of it, but
that would be SSSSLLLLOOOOWWWWW :)
 
E

Eric Mahurin

--- Peter Vanbroekhoven said:
=20
Well, for the moment the patch does not allow this (I'm not
claiming the=20
patch is perfect, or even does all that we want it to do),
but the full=20
comparison would be this:
=20
open class B < A ... end class <<b ... end
cut cut B < A ... end cut <<b ... end
=20
reopen class B ... end class <<b ... end
'recut' cut B ... end cut <<b ... end
=20
open' class B ... end
cut' cut B ... end
=20
This seems consistent enough to me.
=20
What I've always found a pity though, is that the meta-class
declaratiopn=20
does not allow naming the meta-class, maybe like this:
=20
class Meta_b << b ; end

You are starting to touch on the inconsistency by asking for
the meta_class to be named like other classes are.

modifies
--------
class A < B A
cut A < B A, B
class <<b b.meta_class
cut <<b b.meta_class
class A A
cut A A, B ??

The meta_class vs. normal forms just don't seem consistent.

I have another idea that can be implemented in pure ruby using
flgr's 'evil.rb'. I'll send out another message about it.


__________________________________________________
Do You Yahoo!?
Tired of spam? Yahoo! Mail has the best spam protection around=20
http://mail.yahoo.com=20
 
P

Peter Vanbroekhoven

You are starting to touch on the inconsistency by asking for
the meta_class to be named like other classes are.

No I'm not. My previous remarks have nothing to do with AOP. These were
side remarks. I was just saying that it would be nice to be able to name
it, not just within AOP, but in meta-programming in general. AOP involves
a lot of meta-programming, so it was only natural that I mention this
here. If it shows an inconsistency for AOP, it's there for subclassing
too.
modifies
--------
class A < B A
cut A < B A, B
class <<b b.meta_class
cut <<b b.meta_class
class A A
cut A A, B ??

One thing is that a cut indeed modifies B as well, while a subclass does
not. So if you're looking for differences there, well, they're bound to be
there because that's the idea.

cut <<b modifies the cut itself, as well as the meta_class it cuts, and
cut A indeed also modifies the cut class (in this case B). This should
complete your table above and makes it consistent again. That's if I
understand it correctly.
The meta_class vs. normal forms just don't seem consistent.

But what's not consistent. You give tables, there is something different
(which is intentional, we wouldn't need cuts if they did the same as
classes, now would we?), but what's your point?
I have another idea that can be implemented in pure ruby using
flgr's 'evil.rb'. I'll send out another message about it.

Don't tell me it uses Object#become!

Peter
 
D

Dave Burt

Trans:
On the other hand cuts are in essence classes --transparent
*subclasses* to be exact. While you do not instantiate them directly,
they get instantiated as part of the class they cut.

I've just finished catching up on this thread (phew!) and you do make a good
point here. I still think, though, that a Cut is fully a Module, but only
partly a Class; it has a superclass but cannot be instantiated. I still
think that means Cut < Module and not Cut < Class.
I think the real incongruency comes more from the fact that Class
itself is a subclass of Module. It works okay, but conceptualy it is
odd. And on occasion you have undef a method in Class that's been
defined in Module. I think Matz even metions something liek this in his
recent presentation. It think a better solution would come from having
a "ClassKernel" module which is included in Module and Class, so they
can stand on their own.

I'm don't think it's really an inconsistency in the current system, it just
makes Cut's place a little unclear.
Finally, I think cuts are simliar to singleton_classes in that
instantiating them is restricted.
...
But I don't think there's any techincal reason they could not be. It's
purposefully disallowed, I guess for conceptual reasons:

The comparison is interesting, and adds weight to your preference for class
over module, but it is a bit arbitrary in itself, and it doesn't mean
_another_ kind of class with no #new is OK.
if (FL_TEST(super, FL_SINGLETON)) {
rb_raise(rb_eTypeError, "can't make subclass of virtual class");
...
Hey, this still says "virtual class"; _why doesn't his say eigenclass!?
;)

Another RCR? =)

Cheers,
Dave
 
I

itsme213

Does this also provide a quite general form of dependency injection,
very different in nature and weight compared to something like Needle?
 
T

Trans

Does this also provide a quite general form of dependency injection,
very different in nature and weight compared to something like Needle?

Had to give this some thought. Mu immediate conjecture is that it must
since DI and AOP are closely related. But I'm no DI expert like Jim
Weirich. But in giving it some conosideration, I imagine there's not
much more to it than:

class App

def logger
nil # no logger available
end

end

cut AppContainer < App

def logger
Logger.new
end

end


T.
 
T

Trans

Christian said:
Which will make you want "multiple-inheritance" for cutpoints. :)

I thought about this some but I don't understand what you mean. How ill
it make you want MI? Aren't mixins enough?
It's not that trivial, but it certainly can be used to implement DI.

I realize that it's a trivialized rendition, but could you provided
some pointers on improving?

Thanks,
T.
 
D

Daniel Schierbeck

Trans said:
I thought about this some but I don't understand what you mean. How ill
it make you want MI? Aren't mixins enough?




I realize that it's a trivialized rendition, but could you provided
some pointers on improving?

Thanks,
T.

I can't see why there *shouldn't* be multi-inheritance for cuts, unless
you need to be able to find the exact class that's being cut by a
certain cut.

cut Kut < A, B, C
def initialize(*args, &block)
puts "ahoy, mateys! arrr!"
super
end
end


Cheers,
Daniel
 
E

Ed Howland

This is to "officially" announce an RCR that I posted to RCR archive
two days ago. I realize the RCR itself is a bit dense and techincial,
so (with thanks to ES) I thought it might be a good idea to provide a
little summary and some examples of what it's all about and why it's a
such a good approach to AOP for Ruby.

The concept seems clear to me. But I have an aditional question. Will=20
cuts be allowed on root classes that are themselves extruded from a
'C' extension? E.g. I don't really know if class IO is mostly C
extension stuff, but could a cut be applied to these class types?
Kernel? Object?

cut AspectIO < IO
def puts(*args)
# do something with the args
super
end
end

If I am understanding the syntax correctly. I don't know how the
internal hooking mechanism works here. But even if IO#puts is a
low-level C funtion, then super could just map to it, instead of the
normal ruby implementation of the method.

If so, then this could be a very powerful mechanism in Unit Testing:
(Again, forgive me if the syntax is wrong, here.)

class IOTest < Test::Unit::TestCase
@output =3D ''
cut AspectIO < IO
def puts(*args)
@output =3D args.to_s
super
end
end

def setup
@oldio =3D $stdio
$stdio =3D IO.new
end

def test_hello
puts "Hello world" # having the advantage of making @output
avail to assertions
# and spewing contents in the console.
assert_equals "Hello world", @output
end

def teardown
$stdio =3D @oldio
end
end

Is this acceptable in the RCR design? Was it already implied?

Thanks
Ed
 
T

Trans

Will cuts be allowed on root classes that are themselves extruded from a
'C' extension? E.g. I don't really know if class IO is mostly C
extension stuff, but could a cut be applied to these class types?
Kernel? Object?

Yes. It is applicable to any class (and any module via proxy-cut).
Is this acceptable in the RCR design?

Ed, you're right on the money, Right On The Money.
Was it already implied?

I believe we make a passing mention of AOP in general having applicable
to testing. But we offer no details in how cuts may be used for this.
Now you've lighted the way --and an interesing way at that. Very cool.

Thanks for sharing this.

T.
 
E

Ed Howland

Ed, you're right on the money, Right On The Money.


I believe we make a passing mention of AOP in general having applicable
to testing. But we offer no details in how cuts may be used for this.
Now you've lighted the way --and an interesing way at that. Very cool.

Thanks for sharing this.

T.

No problem, just something I've been thinking about. Brian Button (and
others,) have said in testing, don't test the disk, and don't test the
I/O subsystem, don't test the OS, and don't test the built-in std
library. So, if the application is supposed to do these things, then
they are hard to test. Which has given rise to many diverse ways of
addressing this via mocking, using interfaces, dependancy injection
and so forth.

Ruby is nice, because you can mess about with its innards, and thus
get around some of these difficulties. Although, with TDDing and
refactoring, you shouldn't paint yourself into corners in the first
place. But for legacy code, this approach has some merit, IMO.

AOP strategies for unit testing are nothing new:
http://blogs.codehaus.org/people/vmassol/archives/000138_aop_unit_testing_e=
xample.html

Another potential use of AOP with testing is in fault injection:

cut IMHacker < Kernel
def exec(command, *args)
raise SecurityError "Caught ya, you lazy good-fer-nuthing low-life"
...
end
end

def test_catchem
assert_raise(SecurityError) { exec("cat /etc/passwd") }
end

... where the exec call would really be buried in another class somewhere.

Any is there any prototypes of this available anywhere, or is it too
soon to ask that yet?
I'd vote for this, but RCRchive won't let me in.

Ed
 
I

itsme213

Ed said:
If so, then this could be a very powerful mechanism in Unit Testing:
(Again, forgive me if the syntax is wrong, here.)

Yep, since DI is a very powerful mechanism for Unit Testing.

Except the cut-style allows you to do RealObjects, MockObjects, and
PartialMocks.
 
E

Ed Howland

Yep, since DI is a very powerful mechanism for Unit Testing.

So you are saying that AOP (or cuts here for example,) can be used to creat=
e
DI where you don't already have it. Hmm.

#contrived
require 'collaborator'

class A
def initialize
@collab =3D Collaborator.new
end
# ...
end

# in TestCase
def setup
@mock_collab =3D MockCollab.new # or some DynamicMock library
end

cut NutherA < A
def initialize
@collab =3D @mock_collab # ignore super for the example
end
end

def test_add_mock_collab
a =3D A.new
assert_equals("expected", a.do_something_with_collab)
end

Is this what you were refering to with DI and Unit testing with AOP?
Except the cut-style allows you to do RealObjects, MockObjects, and
PartialMocks.

Can you expand on this a little? What are RealObjects (other than the
obvious) and PartialMocks? Aren't RealObjects just real objects that
are being mocked? How does the cut-style help?

Thanks
Ed
 
T

Trans

Ed said:
No problem, just something I've been thinking about. Brian Button (and
others,) have said in testing, don't test the disk, and don't test the
I/O subsystem, don't test the OS, and don't test the built-in std
library. So, if the application is supposed to do these things, then
they are hard to test. Which has given rise to many diverse ways of
addressing this via mocking, using interfaces, dependancy injection
and so forth.

Which reminds me, I have some tests that are doing this that I need to
fix.
Ruby is nice, because you can mess about with its innards, and thus
get around some of these difficulties. Although, with TDDing and
refactoring, you shouldn't paint yourself into corners in the first
place. But for legacy code, this approach has some merit, IMO.

AOP strategies for unit testing are nothing new:
http://blogs.codehaus.org/people/vmassol/archives/000138_aop_unit_testing_example.html

Another potential use of AOP with testing is in fault injection:

cut IMHacker < Kernel
def exec(command, *args)
raise SecurityError "Caught ya, you lazy good-fer-nuthing low-life"
...
end
end

LOL :)

IOn this case though Kernel is module, so you can't cut it (cause you
can't sublcass it) But of course you could cut Object or use a module
and preclude:

module IMHacker
def exec(command, *args)
raise SecurityError "Caught ya, you lazy good-fer-nuthing
low-life"
...
end
end
Kernel.preclude IMhacker
def test_catchem
assert_raise(SecurityError) { exec("cat /etc/passwd") }
end

.. where the exec call would really be buried in another class somewhere.

Any is there any prototypes of this available anywhere, or is it too
soon to ask that yet?

Yes, though it doesn't do everything mentioned in the RCR, but it does
the basics:

http://rubyforge.org/frs/?group_id=137
I'd vote for this, but RCRchive won't let me in.

Thanks. We've got a good favorable margin so it's okay, but I hope you
find out what's wrong.

T.
 
E

Ed Howland

IOn this case though Kernel is module, so you can't cut it (cause you
can't sublcass it) But of course you could cut Object or use a module
and preclude:

module IMHacker
def exec(command, *args)
raise SecurityError "Caught ya, you lazy good-fer-nuthing
low-life"
...
end
end
Kernel.preclude IMhacker

Definately have to find out more about precludes
Yes, though it doesn't do everything mentioned in the RCR, but it does
the basics:
Great! Is it downloadable? Where?
http://rubyforge.org/frs/?group_id=3D137


Thanks. We've got a good favorable margin so it's okay, but I hope you
find out what's wrong.

Thanks, dblack fixed my deficient brain. I strongly advocated, so you
are should over the top.

Ed
 
T

Trans

Great! Is it downloadable? Where?

http://rubyforge.org/frs/?group_id=137

under 'cut (transparent subclass)' Use 3.0. It's a patch against Ruby
1.8.3 so you have to download Ruby source, apply the patch and compile
to try it out.

Right now it uses '__cut__' in place of 'cut' just to prevent a name
clash with a Tk method so that the testcases pass (not a big deal,
but..) Peter will look at adding #preclude support in a week or two.

T.
 
K

Kero

Just had Ruby 1.8.3 installed on our HP-UX box, and it seems to be
really misbehaving... I'm trying to promote Ruby here but this is
giving it bad press.

For example, the following code

#!/usr/local/bin/ruby
p ARGV
ARGV.each do |fname |
puts "File: #{fname}"
loop do
break
end
end

gives .....
xdump param
["param"]
File: param
/home/fcux_dev/tadb/bin/xdump:6: [BUG] Bus Error
ruby 1.8.3 (2005-09-21) [hppa2.0w-hpux11.11]
Abort(coredump)And in fact, this error ([BUG] Bus Error - what is it ?) seems to pop up
at the slightest provocation, although some relatively complex
ruby code seems to run ok.
I didn't do the installation myself, but I suspect that the HP-UX
bundled C compiler was used to do the installation.
Could that be the problem ?

Hardly.
I compiled ruby 1.8.1 or so succesfully with cc, just tried ruby 1.8.4-preview1.
Both work fine with your code above.

NB: I'm not the sysadmin, so I have to use ./configure --prefix=$HOME
you can try the same and see if you have better luck than your sysadmin.
Does miniruby have the same problem?

$ ruby -v
ruby 1.8.4 (2005-10-29) [hppa20.w-hpux11.11]
$ make test
test succeeded
$ make test-all
[some wsdl/iconv problem that I'll report on elsewhere.]

I don't think I managed to compile 1.8.1 with gcc,
haven't tried for 1.8.4-preview1.

Hth,
Kero.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads

easy AOP right now using evil.rb 2
RCR 13 0
RCR for Range.rand 0
AOP bigger picture 3
The likes of AOP (1 of 2) 1
ideas for an RCR: variable locality 16
aop in ruby 2
No Thing Here vs Uninitialized and RCR 303 21

Members online

No members online now.

Forum statistics

Threads
473,770
Messages
2,569,584
Members
45,075
Latest member
MakersCBDBloodSupport

Latest Threads

Top