cuts 0.0.4 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (11) hide show
  1. data/COPYING +162 -669
  2. data/MANIFEST +12 -13
  3. data/README +13 -15
  4. data/RELEASE +24 -0
  5. data/VERSION +1 -1
  6. data/lib/cuts/aop.rb +32 -31
  7. data/lib/cuts/cut.rb +31 -100
  8. data/test/test_cut.rb +15 -137
  9. metadata +19 -35
  10. data/NOTES +0 -1
  11. data/meta/requires +0 -1
data/MANIFEST CHANGED
@@ -1,22 +1,21 @@
1
- Rakefile
1
+ lib
2
+ meta
2
3
  test
3
- test/test_cut.rb
4
- test/test_aop.rb
5
- NOTES
4
+ Rakefile
5
+ RELEASE
6
6
  README
7
7
  HISTORY
8
- meta
8
+ VERSION
9
+ COPYING
10
+ lib/cuts.rb
11
+ lib/cuts
12
+ lib/cuts/aop.rb
13
+ lib/cuts/cut.rb
9
14
  meta/created
10
15
  meta/homepage
11
16
  meta/summary
12
17
  meta/abstract
13
18
  meta/license
14
- meta/requires
15
19
  meta/contact
16
- lib
17
- lib/cuts.rb
18
- lib/cuts
19
- lib/cuts/aop.rb
20
- lib/cuts/cut.rb
21
- VERSION
22
- COPYING
20
+ test/test_cut.rb
21
+ test/test_aop.rb
data/README CHANGED
@@ -11,13 +11,9 @@ Cuts is an expiremental implementation of cut-based AOP for Ruby.
11
11
 
12
12
  == RELEASE NOTES
13
13
 
14
- Please see NOTES file.
14
+ Please see RELEASE file.
15
15
 
16
16
 
17
- == RECENT CHANGES
18
-
19
- Please see CHANGES file.
20
-
21
17
 
22
18
  == HOW TO INSTALL
23
19
 
@@ -27,25 +23,27 @@ To install with RubyGems simply open a console and type:
27
23
 
28
24
  gem install cuts
29
25
 
30
- To manually installation, download the tgz package and type:
26
+ To manually installation, you will need the Ruby Setup package
27
+ (http://setup.rubyforge.org). Then download the tgz package
28
+ and type:
29
+
30
+ $ tar -xvzf cuts-x.y.z.tgz
31
+ $ cd cuts-x.y.z.tgz
32
+ $ sudo setup.rb
31
33
 
32
- tar -xvzf cuts-x.y.z.tgz
33
- cd cuts-x.y.z.tgz
34
- rake config
35
- rake setup
36
- rake install
37
34
 
38
35
 
39
36
  == USAGE
40
37
 
41
- Describe how to use your library or application here.
38
+ Please see RDoc API documentation.
39
+
42
40
 
43
41
 
44
42
  == LICENSE
45
43
 
46
- Copyright (c) 2008
44
+ Copyright (c) 2008 TigerOps
47
45
 
48
- This program is ditributed unser the terms of the MIT license.
46
+ This program is ditributed unser the terms of the LGPL license.
49
47
 
50
- Please see COPYING file.
48
+ Please see COPYING file.
51
49
 
data/RELEASE ADDED
@@ -0,0 +1,24 @@
1
+ This release completel overhauls how cuts are
2
+ implemented.
3
+
4
+ Before, cuts where overriding the constant of the
5
+ original class and redirecting class changes
6
+ (define_method, alias_method, etc.) to the original
7
+ class. This works, and is technically more true to
8
+ the core idea of Cuts, but it is rather fragile --
9
+ getting a handle on the Cut vs. the Cut Class b/c
10
+ tricky.
11
+
12
+ The new implementation simply creates a module for
13
+ a cut instead, and then used #extend on objects
14
+ upon instantiation. The end result is less dynamic
15
+ (cuts need to be defined up front), but it is more
16
+ stable. As long as #new, when overriden, is done so
17
+ properly (ie. use super or copy the cut extension
18
+ logic) everthing will work as expected.
19
+
20
+
21
+ ### 0.1.0 / 2008-11-24
22
+
23
+ * Overhauled underlying implementation.
24
+
data/VERSION CHANGED
@@ -1 +1 @@
1
- cuts 0.0.4 alpha (2008-09-18)
1
+ cuts 0.1.0 beta (2008-11-24)
@@ -13,8 +13,6 @@
13
13
  #
14
14
  # - Can JointPoint and Target be the same class?
15
15
 
16
- #require 'facets/kernel/object'
17
- #require 'facets/module/methods'
18
16
  require 'cuts/cut'
19
17
 
20
18
  #
@@ -38,7 +36,7 @@ class Aspect < Module
38
36
 
39
37
  end
40
38
 
41
- #
39
+ # TODO: pass actual method instead of using instace_method ?
42
40
 
43
41
  class Joinpoint
44
42
  def initialize(object, base, method, *args, &block)
@@ -109,49 +107,52 @@ def cross_cut(klass)
109
107
  Cut.new(klass) do
110
108
  define_method :__base__ do klass end
111
109
 
112
- methods = public_instance_methods + private_instance_methods + protected_instance_methods
113
- methods.each do |meth|
114
- undef_method(meth) unless meth.to_s =~ /(^__|initialize$|p$|class$|inspect$)/
115
- end
110
+ def advices; @advices ||= {}; end
116
111
 
117
- #def initialize(base, *args, &block)
118
- # @base = base
119
- # @delegate = base.__new(*args, &block)
120
- # @advices = {}
121
- #end
112
+ def self.extended(obj)
113
+ base = obj.class #__base__
122
114
 
123
- def method_missing(sym, *args, &blk)
124
- # p "METHOD MISSING: #{sym}" #if DEBUG
115
+ methods = obj.methods + obj.private_methods - ['advices']
125
116
 
126
- @advices ||= {}
117
+ methods.each do |sym|
127
118
 
128
- base = __base__
119
+ #meth = obj.method(sym)
129
120
 
130
- jp = Joinpoint.new(self, base, sym, *args, &blk)
121
+ define_method(sym) do |*args| #, &blk| # TODO imporove interface mirroring
122
+ jp = Joinpoint.new(self, base, sym, *args) #, &blk)
131
123
 
132
- # calculate advices on first use.
133
- unless @advices[sym]
134
- @advices[sym] = []
135
- base.aspects.each do |aspect|
136
- aspect.points.each do |advice, matches|
137
- matches.each do |match|
138
- if jp === match
139
- @advices[sym] << [aspect, advice]
124
+ # calculate advices on first use.
125
+ unless advices[sym]
126
+ advices[sym] = []
127
+ base.aspects.each do |aspect|
128
+ aspect.points.each do |advice, matches|
129
+ matches.each do |match|
130
+ if jp === match
131
+ advices[sym] << [aspect, advice]
132
+ end
133
+ end
140
134
  end
141
135
  end
142
136
  end
143
- end
144
- end
137
+
138
+ if advices[sym].empty?
139
+ super
140
+ else
141
+ target = jp #Target.new(self, sym, *args, &blk) # Target == JoinPoint ?
142
+ advices[sym].each do |(aspect, advice)|
143
+ target = Target.new(aspect, advice, target)
144
+ end
145
+ target.super
146
+ end
145
147
 
146
- target = jp #Target.new(self, sym, *args, &blk) # Target == JoinPoint ?
148
+ end
147
149
 
148
- @advices[sym].each do |(aspect, advice)|
149
- target = Target.new(aspect, advice, target)
150
150
  end
151
151
 
152
- target.super
153
152
  end
153
+
154
154
  end
155
+
155
156
  end
156
157
 
157
158
 
@@ -25,13 +25,13 @@
25
25
  # def x; "x"; end
26
26
  # end
27
27
  #
28
- # cut :C < X do
28
+ # cut :Z < X do
29
29
  # def x; '{' + super + '}'; end
30
30
  # end
31
31
  #
32
32
  # X.new.x #=> "{x}"
33
33
  #
34
- # To use this in an AOP fashion you can define an Aspect, as a class
34
+ # One way to use this in an AOP fashion is to define an aspect as a class
35
35
  # or function module, and tie it together with the Cut.
36
36
  #
37
37
  # module LogAspect
@@ -41,7 +41,7 @@
41
41
  # end
42
42
  # end
43
43
  #
44
- # cut :C < X do
44
+ # cut :Z < X do
45
45
  # def x
46
46
  # LogAspect.log(:x, r = super)
47
47
  # return r
@@ -57,7 +57,8 @@
57
57
  # Instantiating AClass effecively instantiates ACut instead,
58
58
  # but that action is effectively transparent.
59
59
  #
60
- # This is the basic model of this particluar implementation:
60
+ # This particular implementation create a module for each cut
61
+ # and extends objects as they are created. Given the following example:
61
62
  #
62
63
  # class Klass
63
64
  # def x; "x"; end
@@ -67,76 +68,50 @@
67
68
  # def x; '{' + super + '}'; end
68
69
  # end
69
70
  #
70
- # We cut it like so:
71
+ # The effect is essentially:
71
72
  #
72
- # Klass = KlassCut
73
+ # k = Klass.new
74
+ # k.extend KlassCut
73
75
  #
74
- # p Klass.new.x
76
+ # p k.x
75
77
  #
76
- # This is simple and relatvely robust, but not 100% transparent.
77
- # So we add some redirection methods to the cut to improve the
78
- # transparency.
79
- #
80
- # Due to limitation in meta-programming Ruby as this level, the
81
- # transparency isn't perfect, but it's fairly close.
82
-
83
- class Cut
84
-
85
- def self.new(klass, &block)
86
- cut = Class.new(klass, &block) # <-- This is the actual cut.
87
-
88
- #cut.class_eval(&block)
78
+ # The downside to this approach is a limitation in dynamicism.
89
79
 
90
- cut.send(:include, Transparency)
91
- cut.extend MetaTransparency
92
-
93
- v = $VERBOSE
94
- $VERBOSE = false
95
- klass.modspace::const_set(klass.basename, cut)
96
- $VERBOSE = v
80
+ class Cut < Module
81
+ def initialize(klass, &block)
82
+ klass.cuts.unshift(self)
83
+ module_eval(&block)
84
+ end
85
+ end
97
86
 
98
- return cut
87
+ class Class
88
+ def cuts
89
+ @cuts ||= []
99
90
  end
91
+ end
100
92
 
101
- # These methods are needed to emulate full transparancy as
102
- # closely as possible.
93
+ class Object
94
+ class << self
95
+ alias_method :_new, :new
103
96
 
104
- module Transparency
105
- def methods(all=true)
106
- self.class.superclass.instance_methods(all)
107
- end
108
- def public_methods(all=true)
109
- self.class.superclass.public_instance_methods(all)
97
+ def new(*a, &b)
98
+ o = _new(*a, &b)
99
+ if !cuts.empty?
100
+ o.extend *cuts
101
+ end
102
+ o
110
103
  end
111
- def private_methods(all=true)
112
- self.class.superclass.private_instance_methods(all)
113
- end
114
- def protected_methods(all=true)
115
- self.class.superclass.protected_instance_methods(all)
116
- end
117
- end
118
104
 
119
- # These methods are needed to emulate full transparancy as
120
- # closely as possible.
121
-
122
- module MetaTransparency
123
- #def instance_method(name) ; p "XXXX"; superclass.instance_method(name) ; end
124
- def define_method(*a,&b) ; superclass.define_method(*a,&b) ; end
125
- def module_eval(*a,&b) ; superclass.module_eval(*a,&b) ; end
126
- def class_eval(*a,&b) ; superclass.class_eval(*a,&b) ; end
127
105
  end
128
-
129
106
  end
130
107
 
131
-
132
108
  class Symbol
133
109
  #alias :_op_lt_without_cuts :<
134
110
 
135
111
  # A little tick to simulate subclassing literal syntax.
136
-
137
112
  def <(klass)
138
113
  if Class === klass
139
- [self,klass]
114
+ [self, klass]
140
115
  else
141
116
  raise NoMethodError, "undefined method `<' for :#{self}:Symbol"
142
117
  #_op_lt_without_cuts(cut_class)
@@ -144,10 +119,8 @@ class Symbol
144
119
  end
145
120
  end
146
121
 
147
-
148
122
  module Kernel
149
123
  # Cut convienence method.
150
-
151
124
  def cut(klass, &block)
152
125
  case klass
153
126
  when Array
@@ -161,52 +134,10 @@ module Kernel
161
134
  # How to handle main, but not other instance spaces?
162
135
  #klass.modspace::const_set(klass.basename, cut)
163
136
  mod = (Module === self ? self : Object)
164
- mod.const_set(cutname, cut) # <<- this is what we don't have in Cut.new
137
+ mod.const_set(name, cut) if name # <<- this is what we don't have in Cut.new
165
138
 
166
139
  return cut
167
140
  end
168
141
  end
169
142
 
170
- class Module
171
- # Returns the root name of the module/class.
172
- #
173
- # module Example
174
- # class Demo
175
- # end
176
- # end
177
- #
178
- # Demo.name #=> "Example::Demo"
179
- # Demo.basename #=> "Demo"
180
- #
181
- # For anonymous modules this will provide a basename
182
- # based on Module#inspect.
183
- #
184
- # m = Module.new
185
- # m.inspect #=> "#<Module:0xb7bb0434>"
186
- # m.basename #=> "Module_0xb7bb0434"
187
- #
188
- def basename
189
- if name and not name.empty?
190
- name.gsub(/^.*::/, '')
191
- else
192
- nil #inspect.gsub('#<','').gsub('>','').sub(':', '_')
193
- end
194
- end
195
-
196
- # Returns the module's container module.
197
- #
198
- # module Example
199
- # class Demo
200
- # end
201
- # end
202
- #
203
- # Example::Demo.modspace #=> Example
204
- #
205
- # See also Module#basename.
206
- #
207
- def modspace
208
- space = name[ 0...(name.rindex( '::' ) || 0)]
209
- space.empty? ? Object : eval(space)
210
- end
211
- end
212
143
 
@@ -18,12 +18,6 @@ class TestCut < Test::Unit::TestCase
18
18
 
19
19
  end
20
20
 
21
-
22
- =begin
23
- require 'facets/cut.rb'
24
-
25
- require 'test/unit'
26
-
27
21
  class TestCut1 < Test::Unit::TestCase
28
22
 
29
23
  class F
@@ -31,19 +25,18 @@ class TestCut1 < Test::Unit::TestCase
31
25
  end
32
26
 
33
27
  cut :G < F do
34
- join :f => :f
35
- def f(target); '<'+target.super+'>' ; end
28
+ #join :f => :f
29
+ def f; '<'+super+'>' ; end
36
30
  end
37
31
 
38
32
  def test_1_01
39
33
  f = F.new
40
34
  assert_equal( "<f>", f.f )
41
35
  assert_equal( F, f.class )
42
- assert_equal( F, f.object_class )
43
36
  end
44
37
 
45
38
  def test_1_02
46
- assert( G )
39
+ assert(G)
47
40
  assert_equal( "TestCut1::G", G.name )
48
41
  end
49
42
 
@@ -58,150 +51,35 @@ class TestCut2 < Test::Unit::TestCase
58
51
  end
59
52
 
60
53
  cut :G < F do
61
- join :f => :f
62
- def f(target); '<'+target.super+'>' ; end
54
+ #join :f => :f
55
+ def f; '<'+super+'>' ; end
63
56
  end
64
57
 
65
58
  cut :Q < F do
66
- join :f => :f
67
- def f(target); '['+target.super+']'; end
59
+ #join :f => :f
60
+ def f; '['+super+']'; end
68
61
  end
69
62
 
70
- def test_2_01
71
- assert_equal( [Q, G], F.cuts )
72
- assert_equal( [Q, G], F.predecessors )
73
- end
63
+ #def test_2_01
64
+ # assert_equal( [Q, G], F.cuts )
65
+ # assert_equal( [Q, G], F.predecessors )
66
+ #end
74
67
 
75
68
  def test_2_02
76
69
  f = F.new
77
70
  assert_equal( F, f.class )
78
- assert_equal( F, f.object_class )
79
71
  assert_equal( "[<f>]", f.f )
80
72
  end
81
73
 
82
74
  def test_2_03
83
- assert( G )
75
+ assert(G)
84
76
  assert_equal( "TestCut2::G", G.name )
85
- assert( Q )
86
- assert_equal( "TestCut2::Q", Q.name )
87
- end
88
-
89
- end
90
-
91
- #
92
-
93
- class TestCut3 < Test::Unit::TestCase
94
-
95
- class C
96
- def r1; "r1"; end
97
- end
98
-
99
- cut :A < C do
100
- def r1
101
- b1( target( :r1 ){ super } )
102
- end
103
- def b1( target )
104
- '(' + target.super + ')'
105
- end
106
- end
107
-
108
- def test_3_01
109
- c = C.new
110
- assert_equal( '(r1)', c.r1 )
111
77
  end
112
78
 
113
- end
114
-
115
- # Test the addition of new methods and module inclusions
116
- # after the cut is defined with dynamic joining.
117
-
118
- class TestCut4 < Test::Unit::TestCase
119
-
120
- class C
121
- def r1; "r1"; end
122
- def r2; "r2"; end
123
- def j1; "j1"; end
124
- def j2; "j2"; end
125
- end
126
-
127
- cut :A < C do
128
-
129
- join :wrappy => lambda { |jp| /^r/ =~ jp }
130
- join :square => :j1, :flare => :j2
131
-
132
- def wrappy( target )
133
- '{'+target.super+'}'
134
- end
135
-
136
- def square(target) '['+target.super+']' end
137
- def flare(target) '*'+target.super+'*' end
138
- end
139
-
140
- class C
141
- def r3; "r3"; end
142
- end
143
-
144
- module M
145
- def r4 ; "r4"; end
146
- end
147
-
148
- class C
149
- include M
150
- end
151
-
152
- def test_4_01
153
- c = C.new
154
- assert_equal( '{r1}', c.r1 )
155
- assert_equal( '{r2}', c.r2 )
156
- assert_equal( '{r3}', c.r3 )
157
- assert_equal( '{r4}', c.r4 )
158
- end
159
-
160
- def test_4_02
161
- c = C.new
162
- assert_equal( '[j1]', c.j1 )
163
- assert_equal( '*j2*', c.j2 )
79
+ def test_2_04
80
+ assert(Q)
81
+ assert_equal( "TestCut2::Q", Q.name )
164
82
  end
165
83
 
166
84
  end
167
85
 
168
- # Test subclassing.
169
-
170
- class TestCut5 < Test::Unit::TestCase
171
-
172
- class C
173
- def r1; "r1"; end
174
- def r2; "r2"; end
175
- end
176
-
177
- cut :C1 < C do
178
- join :wrap1 => [:r1, :r2]
179
-
180
- def wrap1( target )
181
- '{' + target.super + '}'
182
- end
183
- end
184
-
185
- cut :C2 < C do
186
- join :wrap2 => [:r1, :r2]
187
-
188
- def wrap2( target )
189
- '[' + target.super + ']'
190
- end
191
- end
192
-
193
- class D < C
194
- def r1; '<' + super + '>'; end
195
- end
196
-
197
- def test_5_01
198
- c = C.new
199
- assert_equal( '[{r1}]', c.r1 )
200
- assert_equal( '[{r2}]', c.r2 )
201
- d = D.new
202
- assert_equal( '<[{r1}]>', d.r1 )
203
- assert_equal( '[{r2}]', d.r2 )
204
- end
205
-
206
- end
207
- =end