aquarium 0.4.3 → 0.4.4
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGES +322 -247
- data/README +11 -9
- data/Rakefile +22 -12
- data/UPGRADE +49 -43
- data/examples/aspect_design_example.rb +17 -14
- data/examples/design_by_contract_example.rb +14 -10
- data/examples/exception_wrapping_example.rb +5 -3
- data/examples/introductions_example.rb +2 -1
- data/examples/method_missing_example.rb +14 -13
- data/examples/method_tracing_example.rb +20 -16
- data/examples/reusable_aspect_hack_example.rb +8 -5
- data/lib/aquarium/aspects/exclusion_handler.rb +3 -3
- data/lib/aquarium/version.rb +1 -1
- data/rake_tasks/verify_rcov.rake +1 -1
- data/spec/aquarium/aspects/concurrent_aspects_spec.rb +41 -41
- data/spec/aquarium/aspects/join_point_spec.rb +5 -5
- data/spec/aquarium/aspects/pointcut_spec.rb +4 -1
- data/spec/aquarium/finders/type_finder_with_descendents_and_ancestors_spec.rb +4 -1
- metadata +3 -9
- data/Aquarium-IDEA.ipr +0 -252
- data/Aquarium-IDEA.iws +0 -493
- data/Aquarium.ipr +0 -253
- data/Aquarium.iws +0 -624
- data/ParseTreePlay.rb +0 -25
- data/TODO.rb +0 -186
data/README
CHANGED
@@ -414,15 +414,18 @@ Aquarium::Extras provides add-ons for Aquarium, such as a Design by Contract imp
|
|
414
414
|
|
415
415
|
The simplest approach is to install the gem:
|
416
416
|
|
417
|
-
|
417
|
+
gem install -y aquarium # sudo may be required on non-Windows systems
|
418
418
|
|
419
419
|
== Building the Aquarium gem
|
420
420
|
|
421
|
-
If you prefer to build the gem locally,
|
422
|
-
do the following:
|
421
|
+
If you prefer to build the gem locally, clone from GitHub,
|
423
422
|
|
424
|
-
|
425
|
-
|
423
|
+
git clone git://github.com/deanwampler/Aquarium.git
|
424
|
+
|
425
|
+
Then do the following:
|
426
|
+
|
427
|
+
rake gem
|
428
|
+
gem install pkg/aquarium-x.y.z.gem # sudo may be required
|
426
429
|
|
427
430
|
== Running Aquarium's RSpec Specs
|
428
431
|
|
@@ -432,17 +435,16 @@ In order to run Aquarium's full suite of specs (rake pre_commit) you must instal
|
|
432
435
|
* rspec # Used instead of Test::Unit for TDD
|
433
436
|
* rcov # Verifies that the code is 100% covered by specs
|
434
437
|
* webgen # Generates the static HTML website
|
435
|
-
*
|
436
|
-
* syntax # Required by RSpec's custom webgen extension to highlight ruby code
|
438
|
+
* coderay # Required by webgen
|
437
439
|
* diff-lcs # Required if you use the --diff switch
|
438
440
|
* win32console # Required by the --colour switch if you're on Windows
|
439
441
|
* meta_project # Required in order to make releases at RubyForge
|
440
442
|
* heckle # Required if you use the --heckle switch
|
441
|
-
* jruby # Required if run the separate spec suite in the "jruby" directory
|
443
|
+
* jruby # Required if run the separate spec suite in the "jruby" directory (v1.3+)
|
442
444
|
|
443
445
|
Once those are all installed, you should be able to run the suite with the following steps:
|
444
446
|
|
445
|
-
*
|
447
|
+
* git clone git://github.com/deanwampler/Aquarium.git
|
446
448
|
* cd aquarium
|
447
449
|
* rake spec
|
448
450
|
or
|
data/Rakefile
CHANGED
@@ -11,6 +11,8 @@ require 'aquarium/version'
|
|
11
11
|
require 'spec/rake/spectask'
|
12
12
|
require 'spec/rake/verify_rcov'
|
13
13
|
|
14
|
+
# TODO: add ../README.markdown to archives.
|
15
|
+
|
14
16
|
# Some of the tasks are in separate files since they are also part of the website documentation
|
15
17
|
load File.dirname(__FILE__) + '/rake_tasks/examples.rake'
|
16
18
|
load File.dirname(__FILE__) + '/rake_tasks/verify_rcov.rake'
|
@@ -34,14 +36,14 @@ Spec::Rake::SpecTask.new do |t|
|
|
34
36
|
t.spec_files = FileList['spec/**/*_spec.rb', 'examples/**/*_spec.rb']
|
35
37
|
t.spec_opts = ['--options', 'spec.opts']
|
36
38
|
t.rcov = true
|
37
|
-
t.rcov_dir = '../doc/
|
39
|
+
t.rcov_dir = '../doc/aquarium/out/coverage'
|
38
40
|
t.rcov_opts = ['--exclude', 'examples']
|
39
41
|
end
|
40
42
|
|
41
|
-
desc "Run all specs and store html output in doc/
|
43
|
+
desc "Run all specs and store html output in doc/aquarium/out/report.html"
|
42
44
|
Spec::Rake::SpecTask.new('spec_html') do |t|
|
43
45
|
t.spec_files = FileList['spec/**/*_spec.rb', 'examples/**/*_spec.rb']
|
44
|
-
t.spec_opts = ['--format html:../doc/
|
46
|
+
t.spec_opts = ['--format html:../doc/aquarium/out/report.html','--backtrace']
|
45
47
|
end
|
46
48
|
|
47
49
|
desc "Run all specs without rcov"
|
@@ -52,7 +54,7 @@ end
|
|
52
54
|
|
53
55
|
desc 'Generate HTML documentation for website'
|
54
56
|
task :webgen do
|
55
|
-
Dir.chdir '../doc' do
|
57
|
+
Dir.chdir '../doc/aquarium' do
|
56
58
|
output = nil
|
57
59
|
IO.popen('webgen 2>&1') do |io|
|
58
60
|
output = io.read
|
@@ -63,7 +65,7 @@ end
|
|
63
65
|
|
64
66
|
desc 'Generate RDoc'
|
65
67
|
rd = Rake::RDocTask.new do |rdoc|
|
66
|
-
rdoc.rdoc_dir = '../doc/
|
68
|
+
rdoc.rdoc_dir = '../doc/aquarium/out/rdoc'
|
67
69
|
rdoc.options << '--title' << 'Aquarium' << '--line-numbers' << '--inline-source' << '--main' << 'README'
|
68
70
|
rdoc.rdoc_files.include('README', 'CHANGES', 'MIT_LICENSE', 'examples/**/*.rb', 'UPGRADE', 'lib/**/*.rb') # 'EXAMPLES.rd'
|
69
71
|
end
|
@@ -124,23 +126,29 @@ task :todo do
|
|
124
126
|
end
|
125
127
|
|
126
128
|
task :clobber do
|
127
|
-
rm_rf '../doc/
|
129
|
+
rm_rf '../doc/aquarium/out'
|
128
130
|
rm_rf 'translated_specs'
|
129
131
|
end
|
130
132
|
|
131
133
|
task :release => [:clobber, :verify_committed, :verify_user, :spec, :publish_packages, :tag, :publish_website, :publish_news]
|
132
134
|
|
135
|
+
# TODO!
|
133
136
|
desc "Verifies that there is no uncommitted code"
|
134
137
|
task :verify_committed do
|
135
|
-
IO.popen('
|
138
|
+
IO.popen('git status') do |io|
|
136
139
|
io.each_line do |line|
|
137
|
-
raise "\n!!! Do a
|
140
|
+
raise "\n!!! Do a git commit first !!!\n\n" if line =~ /^\s*M\s*/
|
138
141
|
end
|
139
142
|
end
|
140
143
|
end
|
141
144
|
|
142
|
-
|
145
|
+
# TODO!
|
146
|
+
desc "Creates a tag in git"
|
143
147
|
task :tag do
|
148
|
+
end
|
149
|
+
|
150
|
+
desc "Creates a tag in svn (obsolete)"
|
151
|
+
task :svntag do
|
144
152
|
from = `svn info #{File.dirname(__FILE__)}`.match(/URL: (.*)\/aquarium/n)[1]
|
145
153
|
to = from.gsub(/trunk/, "tags/#{Aquarium::VERSION::TAG}")
|
146
154
|
tag_cmd = "svn cp #{from} #{to} -m \"Tag release #{Aquarium::VERSION::FULL_VERSION}\""
|
@@ -182,14 +190,16 @@ task :verify_user do
|
|
182
190
|
end
|
183
191
|
|
184
192
|
desc "Upload Website to RubyForge"
|
185
|
-
task :publish_website => [:verify_user, :website]
|
193
|
+
task :publish_website => [:verify_user, :website, :do_publish_website]
|
194
|
+
|
195
|
+
task :do_publish_website do
|
186
196
|
unless Aquarium::VERSION::RELEASE_CANDIDATE
|
187
197
|
# host = "aquarium-website@rubyforge.org"
|
188
198
|
host = "#{ENV['RUBYFORGE_USER']}@rubyforge.org"
|
189
199
|
publisher = Rake::SshDirPublisher.new(
|
190
200
|
"#{host}",
|
191
201
|
"/var/www/gforge-projects/#{PKG_NAME}",
|
192
|
-
"../doc/
|
202
|
+
"../doc/aquarium/out"
|
193
203
|
)
|
194
204
|
publisher.upload
|
195
205
|
else
|
@@ -204,7 +214,7 @@ task :archive_website => [:verify_user, :website] do
|
|
204
214
|
publisher = Rake::SshDirPublisher.new(
|
205
215
|
"#{host}",
|
206
216
|
"/var/www/gforge-projects/#{PKG_NAME}/#{Spec::VERSION::TAG}",
|
207
|
-
"../doc/
|
217
|
+
"../doc/aquarium/out"
|
208
218
|
)
|
209
219
|
publisher.upload
|
210
220
|
end
|
data/UPGRADE
CHANGED
@@ -1,82 +1,88 @@
|
|
1
1
|
== Updating to Aquarium-0.4.0
|
2
2
|
|
3
|
-
This release is fully backwards-compatible with previous releases. It expands
|
4
|
-
internal improvements to better support JRuby. There
|
3
|
+
This release is fully backwards-compatible with previous releases. It expands
|
4
|
+
the API slightly and adds internal improvements to better support JRuby. There
|
5
|
+
should be no upgrade issues.
|
5
6
|
|
6
7
|
== Updating to Aquarium-0.3.1
|
7
8
|
|
8
|
-
There should be no upgrade issues with this release. However, the enhancement
|
9
|
-
JoinPoint is only specified with one type and a type
|
10
|
-
regex is used to specify the
|
9
|
+
There should be no upgrade issues with this release. However, the enhancement
|
10
|
+
#17565 now ensures that a JoinPoint is only specified with one type and a type
|
11
|
+
that actually exists, when a string, symbol, or regex is used to specify the
|
12
|
+
type.
|
11
13
|
|
12
14
|
== Updating to Aquarium-0.3.0
|
13
15
|
|
14
|
-
There are no known upgrade issues with this release. Although many new synonyms
|
15
|
-
parameters, all changes are backwards compatible.
|
16
|
+
There are no known upgrade issues with this release. Although many new synonyms
|
17
|
+
were added for API method parameters, all changes are backwards compatible.
|
16
18
|
|
17
19
|
== Updating to Aquarium-0.2.0
|
18
20
|
|
19
|
-
This release changes the expected advice parameter list from
|
20
|
-
|join_point,
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
21
|
+
This release changes the expected advice parameter list from
|
22
|
+
|join_point, *method_args|
|
23
|
+
to
|
24
|
+
|join_point, object, *method_args|
|
25
|
+
where "object" is the current object receiving the message corresponding to
|
26
|
+
the advised join point. Therefore, when you upgrade, you will need to modify
|
27
|
+
your advices to take this extra argument, even if you don't use it. Since an
|
28
|
+
advice of |jp, *args| would silently "absorb" the object into the beginning of
|
29
|
+
"*args", thereby potentially causing confusion, Aquarium will raise an exception
|
30
|
+
if the advice block or proc has this obsolete signature.
|
25
31
|
|
26
|
-
Note that "JoinPoint#Context.advised_object" is still supported, even if it is
|
32
|
+
Note that "JoinPoint#Context.advised_object" is still supported, even if it is
|
33
|
+
now less useful.
|
27
34
|
|
28
35
|
== Updating to Aquarium-0.1.8
|
29
36
|
|
30
|
-
V0.1.7 did not successfully "register" at rubyforge. This releases fixes that
|
31
|
-
several feature enhancements and refactorings. There are
|
37
|
+
V0.1.7 did not successfully "register" at rubyforge. This releases fixes that
|
38
|
+
problem and also adds several feature enhancements and refactorings. There are
|
39
|
+
no known upgrade issues.
|
32
40
|
|
33
41
|
== Updating to Aquarium-0.1.7
|
34
42
|
|
35
|
-
This is primarily a bug-fix release, so there should be no upgrading or
|
43
|
+
This is primarily a bug-fix release, so there should be no upgrading or
|
44
|
+
incompatibility issues.
|
36
45
|
|
37
46
|
== Updating to Aquarium-0.1.6
|
38
47
|
|
39
|
-
As described in the CHANGES, the JoinPoint#type, JoinPoint#type=,
|
40
|
-
are now deprecated. Client code that
|
41
|
-
|
48
|
+
As described in the CHANGES, the JoinPoint#type, JoinPoint#type=,
|
49
|
+
JoinPoint#object, and JoinPoint#object= are now deprecated. Client code that
|
50
|
+
uses these methods will still work, but warning messages will be written to
|
51
|
+
STDOUT. See CHANGES for more details.
|
42
52
|
|
43
53
|
== Updating to Aquarium-0.1.5
|
44
54
|
|
45
|
-
This is mostly a bug-fix release, but it did have to introduce one API change,
|
46
|
-
CHANGES. In particular, the aspect "DSL" methods are no
|
47
|
-
their names overlap with methods
|
55
|
+
This is mostly a bug-fix release, but it did have to introduce one API change,
|
56
|
+
as described in the CHANGES. In particular, the aspect "DSL" methods are no
|
57
|
+
longer automatically to Object, as some of their names overlap with methods
|
58
|
+
added by Rails.
|
48
59
|
|
49
60
|
Now, if you want these methods added to Object, you must require the new
|
50
61
|
lib/aquarium/aspects/dsl/object_dsl.rb explicitly.
|
51
62
|
|
52
|
-
As an alternative, if you just want these methods added selectively in certain
|
53
|
-
following:
|
63
|
+
As an alternative, if you just want these methods added selectively in certain
|
64
|
+
types, then do the following:
|
54
65
|
|
55
|
-
|
56
|
-
require 'aquarium/dsl/aspect_dsl'
|
66
|
+
require 'aquarium/dsl/aspect_dsl'
|
57
67
|
|
58
|
-
class MyClass # reopen "MyClass"
|
59
|
-
|
60
|
-
|
61
|
-
end
|
62
|
-
</ruby>
|
68
|
+
class MyClass # reopen "MyClass"
|
69
|
+
# Add the methods as _class_ methods
|
70
|
+
include Aquarium::DSL
|
71
|
+
end
|
63
72
|
|
64
73
|
or, use (class|module)_eval:
|
65
|
-
<ruby>
|
66
|
-
require 'aquarium/dsl/aspect_dsl'
|
67
74
|
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
75
|
+
require 'aquarium/dsl/aspect_dsl'
|
76
|
+
|
77
|
+
MyClass.class_eval do
|
78
|
+
# Add the methods as _class_ methods
|
79
|
+
include Aquarium::DSL
|
80
|
+
end
|
73
81
|
|
74
82
|
To add the methods as _instance_ methods on individual objects:
|
75
83
|
|
76
|
-
|
77
|
-
object
|
78
|
-
object.extend(Aquarium::DSL)
|
79
|
-
</ruby>
|
84
|
+
object = MyClass.new
|
85
|
+
object.extend(Aquarium::DSL)
|
80
86
|
|
81
87
|
See the CHANGES for more details.
|
82
88
|
|
@@ -1,11 +1,12 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
-
# Example demonstrating emerging ideas about good aspect-oriented design.
|
3
|
-
# example follows ideas of Jonathan Aldrich on
|
4
|
-
#
|
5
|
-
#
|
6
|
-
#
|
7
|
-
#
|
8
|
-
#
|
2
|
+
# Example demonstrating emerging ideas about good aspect-oriented design.
|
3
|
+
# Specifically, this example follows ideas of Jonathan Aldrich on
|
4
|
+
# "Open Modules", where a "module" (in the generic sense of the word...) is
|
5
|
+
# responsible for defining and maintaining the pointcuts that it is willing
|
6
|
+
# to expose to potential aspects. Aspects are only allowed to advise the
|
7
|
+
# module through the pointcut. (Enforcing this constraint is TBD.) Griswold,
|
8
|
+
# Sullivan, and collaborators have expanded on these ideas. See their IEEE
|
9
|
+
# Software, March 2006 paper.
|
9
10
|
|
10
11
|
$LOAD_PATH.unshift File.dirname(__FILE__) + '/../lib'
|
11
12
|
require 'aquarium'
|
@@ -23,10 +24,11 @@ module Aquarium
|
|
23
24
|
# STATE_CHANGE = pointcut :method => :state=
|
24
25
|
# STATE_CHANGE = pointcut :attribute => :state, :attribute_options => [:writers]
|
25
26
|
# Note that only matching on the attribute writers is important, especially
|
26
|
-
# given the advice block below, because if the reader is allowed to be
|
27
|
-
# we get an infinite recursion of advice invocation! The correct
|
28
|
-
# the planned extension of the pointcut language to support
|
29
|
-
# context. I.e., we don't want the advice applied when
|
27
|
+
# given the advice block below, because if the reader is allowed to be
|
28
|
+
# advised, we get an infinite recursion of advice invocation! The correct
|
29
|
+
# solution is the planned extension of the pointcut language to support
|
30
|
+
# condition tests for context. I.e., we don't want the advice applied when
|
31
|
+
# it's already inside advice.
|
30
32
|
STATE_CHANGE = pointcut :writing => :state
|
31
33
|
end
|
32
34
|
end
|
@@ -34,9 +36,10 @@ end
|
|
34
36
|
include Aquarium::Aspects
|
35
37
|
|
36
38
|
# Observe state changes in the class, using the class-defined pointcut.
|
37
|
-
# Two ways of referencing the pointcut are shown. The first assumes you know
|
38
|
-
# pointcuts you care about. The second is more general; it
|
39
|
-
# :named_pointcut feature to search for all
|
39
|
+
# Two ways of referencing the pointcut are shown. The first assumes you know
|
40
|
+
# the particular pointcuts you care about. The second is more general; it
|
41
|
+
# uses the recently-introduced :named_pointcut feature to search for all
|
42
|
+
# pointcuts matching a name in a set of types.
|
40
43
|
|
41
44
|
observer1 = Aspect.new :after,
|
42
45
|
:pointcut => Aquarium::ClassWithStateAndBehavior::STATE_CHANGE do |jp, obj, *args|
|
@@ -1,10 +1,11 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
-
# Example demonstrating "Design by Contract", Bertrand Meyer's idea for
|
3
|
-
# specifying the contract of use for a class or module and
|
4
|
-
# during the testing process)
|
5
|
-
#
|
6
|
-
# Note: the DesignByContract module adds the #precondition, #postcondition,
|
7
|
-
# methods shown below to Object and they use "self" as the
|
2
|
+
# Example demonstrating "Design by Contract", Bertrand Meyer's idea for
|
3
|
+
# programmatically-specifying the contract of use for a class or module and
|
4
|
+
# testing it at runtime (usually during the testing process). This example
|
5
|
+
# is adapted from spec/extras/design_by_contract_spec.rb.
|
6
|
+
# Note: the DesignByContract module adds the #precondition, #postcondition,
|
7
|
+
# and #invariant methods shown below to Object and they use "self" as the
|
8
|
+
# :object to advise.
|
8
9
|
|
9
10
|
$LOAD_PATH.unshift File.dirname(__FILE__) + '/../lib'
|
10
11
|
require 'aquarium/extras/design_by_contract'
|
@@ -15,7 +16,8 @@ module Aquarium
|
|
15
16
|
p "inside :action"
|
16
17
|
end
|
17
18
|
|
18
|
-
precondition :calls_to => :action,
|
19
|
+
precondition :calls_to => :action,
|
20
|
+
:message => "Must pass more than one argument." do |jp, obj, *args|
|
19
21
|
args.size > 0
|
20
22
|
end
|
21
23
|
end
|
@@ -37,8 +39,9 @@ module Aquarium
|
|
37
39
|
end
|
38
40
|
|
39
41
|
postcondition :calls_to => :action,
|
40
|
-
:message => "Must return
|
41
|
-
jp.context.returned_value.size == args.size + 1 &&
|
42
|
+
:message => "Must return new array, [:a] + args." do |jp, obj, *args|
|
43
|
+
jp.context.returned_value.size == args.size + 1 &&
|
44
|
+
jp.context.returned_value[-1] == :a
|
42
45
|
end
|
43
46
|
end
|
44
47
|
end
|
@@ -66,7 +69,8 @@ module Aquarium
|
|
66
69
|
@invar = 1
|
67
70
|
end
|
68
71
|
|
69
|
-
invariant :calls_to => /action$/,
|
72
|
+
invariant :calls_to => /action$/,
|
73
|
+
:message => "The @invar value must not change." do |jp, obj, *args|
|
70
74
|
obj.invar == 0
|
71
75
|
end
|
72
76
|
end
|
@@ -25,11 +25,12 @@ module Aquarium
|
|
25
25
|
end
|
26
26
|
|
27
27
|
Aquarium::Aspects::Aspect.new :around,
|
28
|
-
|
28
|
+
:calls_to => /^raise_exception/,
|
29
|
+
:in_type => Aquarium::Raiser do |jp, obj, *args|
|
29
30
|
begin
|
30
31
|
jp.proceed
|
31
32
|
rescue Aquarium::Exception1 => e
|
32
|
-
raise Aquarium::NewException.new("
|
33
|
+
raise Aquarium::NewException.new("Exception message was \"#{e.message}\"")
|
33
34
|
end
|
34
35
|
end
|
35
36
|
|
@@ -40,7 +41,8 @@ rescue Aquarium::Exception2 => e
|
|
40
41
|
p "Rescued exception: #{e.class} with message: #{e}"
|
41
42
|
end
|
42
43
|
|
43
|
-
p "The raised Aquarium::Exception1 raised here will be intercepted and
|
44
|
+
p "The raised Aquarium::Exception1 raised here will be intercepted and"
|
45
|
+
p " Aquarium::NewException will be raised:"
|
44
46
|
begin
|
45
47
|
Aquarium::Raiser.new.raise_exception1
|
46
48
|
rescue Aquarium::NewException => e
|
@@ -21,7 +21,8 @@ include Aquarium::Finders
|
|
21
21
|
|
22
22
|
found = TypeFinder.new.find :types => /Aquarium::TypeFinderIntroductionExampleTarget/
|
23
23
|
|
24
|
-
# Now, iterate through them and "extend" them with the module defining
|
24
|
+
# Now, iterate through them and "extend" them with the module defining
|
25
|
+
# the new behavior.
|
25
26
|
|
26
27
|
found.each {|t| t.extend Aquarium::TypeFinderIntroductionExampleModule }
|
27
28
|
|
@@ -1,15 +1,15 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
-
# Example demonstrating "around" advice for method_missing. This is a
|
3
|
-
# avoiding collisions when different toolkits want to override
|
4
|
-
# same classes, e.g., Object. Using around advice as
|
5
|
-
# custom behavior while invoking the "native"
|
6
|
-
# method calls.
|
7
|
-
# Note that it is essential to use around advice, not before or after advice,
|
8
|
-
# neither can prevent the call to the "wrapped" method_missing, which
|
9
|
-
# not what you want.
|
10
|
-
#
|
11
|
-
#
|
12
|
-
#
|
2
|
+
# Example demonstrating "around" advice for method_missing. This is a
|
3
|
+
# technique for avoiding collisions when different toolkits want to override
|
4
|
+
# method_missing in the same classes, e.g., Object. Using around advice as
|
5
|
+
# shown allows a toolkit to add custom behavior while invoking the "native"
|
6
|
+
# method_missing to handle unrecognized method calls.
|
7
|
+
# Note that it is essential to use around advice, not before or after advice,
|
8
|
+
# because neither can prevent the call to the "wrapped" method_missing, which
|
9
|
+
# is presumably not what you want. In this (contrived) example, an Echo class
|
10
|
+
# uses method_missing to simply echo the method name and arguments. An aspect
|
11
|
+
# is used to intercept any calls to a fictitious "log" method and handle those
|
12
|
+
# in a different way.
|
13
13
|
|
14
14
|
$LOAD_PATH.unshift File.dirname(__FILE__) + '/../lib'
|
15
15
|
require 'aquarium'
|
@@ -32,11 +32,12 @@ echo1.log "something", "interesting..."
|
|
32
32
|
echo1.shout "theater", "in", "a", "crowded", "firehouse!"
|
33
33
|
|
34
34
|
Aquarium::Aspects::Aspect.new :around,
|
35
|
-
|
35
|
+
:calls_to => :method_missing,
|
36
|
+
:for_type => Aquarium::Echo do |jp, obj, sym, *args|
|
36
37
|
if sym == :log
|
37
38
|
p "--- Sending to log: #{args.join(" ")}"
|
38
39
|
else
|
39
|
-
|
40
|
+
jp.proceed
|
40
41
|
end
|
41
42
|
end
|
42
43
|
|