glue 0.15.0 → 0.16.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +66 -0
- data/README +1 -1
- data/Rakefile +148 -5
- data/doc/RELEASES +32 -1
- data/install.rb +1 -1
- data/lib/glue.rb +6 -6
- data/lib/glue/array.rb +2 -2
- data/lib/glue/aspects.rb +237 -0
- data/lib/glue/attribute.rb +1 -10
- data/lib/glue/cache.rb +2 -2
- data/lib/glue/dynamic_include.rb +5 -2
- data/lib/glue/flexob.rb +8 -1
- data/lib/glue/hash.rb +2 -2
- data/lib/glue/inflector.rb +1 -1
- data/lib/glue/logger.rb +2 -2
- data/lib/glue/misc.rb +1 -15
- data/lib/glue/mixins.rb +2 -2
- data/lib/glue/number.rb +2 -2
- data/lib/glue/object.rb +1 -1
- data/lib/glue/pool.rb +2 -2
- data/lib/glue/property.rb +21 -20
- data/lib/glue/string.rb +3 -3
- data/lib/glue/time.rb +2 -2
- data/lib/glue/validation.rb +20 -20
- data/test/glue/tc_aspects.rb +101 -0
- data/test/glue/tc_cache.rb +6 -6
- data/test/glue/tc_hash.rb +3 -5
- data/test/glue/tc_numbers.rb +6 -8
- data/test/glue/tc_property.rb +1 -3
- data/test/glue/tc_property_mixins.rb +4 -9
- data/test/glue/tc_property_type_checking.rb +1 -1
- data/test/glue/tc_strings.rb +35 -36
- data/test/glue/tc_validation.rb +4 -3
- data/vendor/breakpoint.rb +1 -1
- data/vendor/breakpoint_client.rb +1 -1
- metadata +37 -55
data/CHANGELOG
CHANGED
@@ -1,5 +1,71 @@
|
|
1
|
+
15-04-2005 George Moschovitis <gm@navel.gr>
|
2
|
+
|
3
|
+
* lib/glue/aspects.rb (#append_features): fixed stupid include bug!
|
4
|
+
improved inherited code,
|
5
|
+
fix: use __meta to keep the advices.
|
6
|
+
|
7
|
+
* lib/glue/property.rb: include Aspects if calling property.
|
8
|
+
|
9
|
+
14-04-2005 George Moschovitis <gm@navel.gr>
|
10
|
+
|
11
|
+
* lib/glue/aspects.rb: fixed proc aspect,
|
12
|
+
handle Module inclusion.
|
13
|
+
|
14
|
+
13-04-2005 George Moschovitis <gm@navel.gr>
|
15
|
+
|
16
|
+
* lib/glue/aspects.rb (#include_advice_modules): iplemented.
|
17
|
+
cooler, added support for Aspects as modules,
|
18
|
+
added some aliases.
|
19
|
+
|
20
|
+
12-04-2005 George Moschovitis <gm@navel.gr>
|
21
|
+
|
22
|
+
* Rakefile: updated to support autoupload to Rubyforge. [flgr]
|
23
|
+
|
24
|
+
11-04-2005 George Moschovitis <gm@navel.gr>
|
25
|
+
|
26
|
+
* test/glue/tc_aspects.rb: introduced and implemented tests.
|
27
|
+
|
28
|
+
* lib/glue/aspects.rb: introduced,
|
29
|
+
copied code from /lib/nitro/filters.rb
|
30
|
+
(Aspect): introduced.
|
31
|
+
(Advice): introduced,
|
32
|
+
it works :)
|
33
|
+
(#wrap): handle methods with any arity.
|
34
|
+
use join instead of when.
|
35
|
+
(##wrap): recoded implementation.
|
36
|
+
allow for instance and class aspects,
|
37
|
+
many small fixes.
|
38
|
+
|
39
|
+
* created new public SVN repository, to allow for easier
|
40
|
+
patching by the community.
|
41
|
+
|
42
|
+
09-04-2005 George Moschovitis <gm@navel.gr>
|
43
|
+
|
44
|
+
* test/*: fixes to pass again.
|
45
|
+
|
46
|
+
* lib/glue/flexob.rb (#update): added.
|
47
|
+
|
48
|
+
08-04-2005 George Moschovitis <gm@navel.gr>
|
49
|
+
|
50
|
+
* Rakefile: removed flexob, extensions, ruby-breakpointer dependencies [james_b],
|
51
|
+
bumped required Ruby version.
|
52
|
+
|
53
|
+
* test/*: many small fixes.
|
54
|
+
|
55
|
+
* Rakefile: fixed to run tests.
|
56
|
+
|
57
|
+
* lib/glue.rb: include in TOPLEVEL binding for easy access.
|
58
|
+
|
59
|
+
* lib/glue/dynamic_include.rb: added alias.
|
60
|
+
|
61
|
+
* lib/glue/attribute.rb: removed call_xx method.
|
62
|
+
|
63
|
+
* MAJOR: changed the namespace from N to Glue.
|
64
|
+
|
1
65
|
01-04-2005 George Moschovitis <gm@navel.gr>
|
2
66
|
|
67
|
+
* --- VERSION 0.15.0 ---
|
68
|
+
|
3
69
|
* doc/RELEASES: updated.
|
4
70
|
|
5
71
|
* README: updated.
|
data/README
CHANGED
data/Rakefile
CHANGED
@@ -6,11 +6,34 @@ require 'rake/rdoctask'
|
|
6
6
|
require 'rake/testtask'
|
7
7
|
require 'rake/gempackagetask'
|
8
8
|
|
9
|
+
# Initialize some variables.
|
10
|
+
|
11
|
+
readme = File.read('README')
|
12
|
+
Release = (readme[/^= (.+) README$/, 1] || 'unknown').downcase.tr(" ", "-")
|
13
|
+
Name = Release[/\D+/].sub(/\-+$/, '') || 'unknown'
|
14
|
+
Version = Release[/[\d.]+/] || 'unknown'
|
15
|
+
|
16
|
+
AuthorName, AuthorMail = 'George Moschovitis', 'gm@navel.gr'
|
17
|
+
RubyVersion = '1.8.2'
|
18
|
+
|
19
|
+
# Description = (readme[/README\s+(.+?)\n\n/m, 1] || "unknown").gsub(/\s+/, " ")
|
20
|
+
# Summary = Description[/^.+?>/] || "unknown"
|
21
|
+
|
22
|
+
# DocFiles = %w(README NEWS TODO COPYING GPL)
|
23
|
+
# RDocFiles = DocFiles - %w(GPL)
|
24
|
+
RDocOpts = ["--inline-source", "--line-numbers","--title", Name ]
|
25
|
+
# AdditionalFiles = DocFiles + %w(setup.rb)
|
26
|
+
VersionFile = MainFile = File.join("lib", Name + '.rb')
|
27
|
+
|
28
|
+
RubyForgeProject = 'nitro'
|
29
|
+
RubyForgeUser = 'gmosx'
|
30
|
+
Homepage = "http://#{RubyForgeProject}.rubyforge.org/"
|
31
|
+
|
9
32
|
task :default => :package
|
10
33
|
|
11
34
|
# Run all tests.
|
12
35
|
|
13
|
-
Rake::TestTask.new
|
36
|
+
Rake::TestTask.new do |t|
|
14
37
|
t.libs << 'test'
|
15
38
|
t.test_files = FileList['test/**/*.rb']
|
16
39
|
t.verbose = true
|
@@ -20,7 +43,7 @@ end
|
|
20
43
|
|
21
44
|
Rake::RDocTask.new do |rd|
|
22
45
|
rd.main = 'README'
|
23
|
-
rd.rdoc_dir = '
|
46
|
+
rd.rdoc_dir = 'rdoc'
|
24
47
|
rd.rdoc_files.include('README', 'INSTALL', 'lib/**/*.rb')
|
25
48
|
rd.options << '--all --inline-source'
|
26
49
|
end
|
@@ -36,10 +59,10 @@ spec = Gem::Specification.new do |s|
|
|
36
59
|
end
|
37
60
|
s.summary = 'Glue utilities'
|
38
61
|
s.description = 'A collection of utilities and useful classes'
|
39
|
-
s.add_dependency 'extensions', '>= 0.5'
|
40
|
-
s.add_dependency 'flexmock', '>= 0.0.3'
|
62
|
+
# s.add_dependency 'extensions', '>= 0.5'
|
63
|
+
# s.add_dependency 'flexmock', '>= 0.0.3'
|
41
64
|
|
42
|
-
s.required_ruby_version = '>= 1.8.
|
65
|
+
s.required_ruby_version = '>= 1.8.2'
|
43
66
|
|
44
67
|
s.files = FileList[
|
45
68
|
'[A-Z]*', 'install.rb', '{doc,lib,test,vendor}/**/*'
|
@@ -75,3 +98,123 @@ task :install do
|
|
75
98
|
ruby 'install.rb'
|
76
99
|
end
|
77
100
|
|
101
|
+
# Release files to Rubyforge.
|
102
|
+
# The code for this task provided by Florian Gross.
|
103
|
+
|
104
|
+
desc "Publish the release files to RubyForge."
|
105
|
+
task :publish => [:package] do
|
106
|
+
files = ['gem', 'tgz', 'zip'].map { |ext| "dist/#{Release}.#{ext}" }
|
107
|
+
|
108
|
+
if RubyForgeProject then
|
109
|
+
require 'net/http'
|
110
|
+
require 'open-uri'
|
111
|
+
|
112
|
+
changes = ''
|
113
|
+
if File.exist?('doc/RELEASES') then
|
114
|
+
changes_re = /^== \s+ Version \s+ #{Regexp.quote(Version)} \s*
|
115
|
+
(.+?) (?:==|\Z)/mx
|
116
|
+
changes = File.read('doc/RELEASES')[changes_re, 1] || ''
|
117
|
+
end
|
118
|
+
|
119
|
+
project_uri = "http://rubyforge.org/projects/#{RubyForgeProject}/"
|
120
|
+
project_data = open(project_uri) { |data| data.read }
|
121
|
+
group_id = project_data[/[?&]group_id=(\d+)/, 1]
|
122
|
+
raise "Couldn't get group id" unless group_id
|
123
|
+
|
124
|
+
print "#{RubyForgeUser}@rubyforge.org's password: "
|
125
|
+
password = STDIN.gets.chomp
|
126
|
+
|
127
|
+
login_response = Net::HTTP.start('rubyforge.org', 80) do |http|
|
128
|
+
data = [
|
129
|
+
"login=1",
|
130
|
+
"form_loginname=#{RubyForgeUser}",
|
131
|
+
"form_pw=#{password}"
|
132
|
+
].join("&")
|
133
|
+
http.post('/account/login.php', data)
|
134
|
+
end
|
135
|
+
|
136
|
+
cookie = login_response['set-cookie']
|
137
|
+
raise 'Login failed' unless cookie
|
138
|
+
headers = { 'Cookie' => cookie }
|
139
|
+
|
140
|
+
release_uri = "http://rubyforge.org/frs/admin/?group_id=#{group_id}"
|
141
|
+
release_data = open(release_uri, headers) { |data| data.read }
|
142
|
+
package_id = release_data[/[?&]package_id=(\d+)/, 1]
|
143
|
+
raise "Couldn't get package id" unless package_id
|
144
|
+
|
145
|
+
first_file = true
|
146
|
+
release_id = ""
|
147
|
+
|
148
|
+
files.each do |filename|
|
149
|
+
basename = File.basename(filename)
|
150
|
+
file_ext = File.extname(filename)
|
151
|
+
file_data = File.open(filename, "rb") { |file| file.read }
|
152
|
+
|
153
|
+
puts "Releasing #{basename}..."
|
154
|
+
|
155
|
+
release_response = Net::HTTP.start('rubyforge.org', 80) do |http|
|
156
|
+
release_date = Time.now.strftime('%Y-%m-%d %H:%M')
|
157
|
+
type_map = {
|
158
|
+
'.zip' => '3000',
|
159
|
+
'.tgz' => '3110',
|
160
|
+
'.gz' => '3110',
|
161
|
+
'.gem' => '1400',
|
162
|
+
'.md5sum' => '8100'
|
163
|
+
}; type_map.default = '9999'
|
164
|
+
type = type_map[file_ext]
|
165
|
+
boundary = 'rubyqMY6QN9bp6e4kS21H4y0zxcvoor'
|
166
|
+
|
167
|
+
query_hash = if first_file then
|
168
|
+
{
|
169
|
+
'group_id' => group_id,
|
170
|
+
'package_id' => package_id,
|
171
|
+
'release_name' => Release,
|
172
|
+
'release_date' => release_date,
|
173
|
+
'type_id' => type,
|
174
|
+
'processor_id' => '8000', # Any
|
175
|
+
'release_notes' => '',
|
176
|
+
'release_changes' => changes,
|
177
|
+
'preformatted' => '1',
|
178
|
+
'submit' => '1'
|
179
|
+
}
|
180
|
+
else
|
181
|
+
{
|
182
|
+
'group_id' => group_id,
|
183
|
+
'release_id' => release_id,
|
184
|
+
'package_id' => package_id,
|
185
|
+
'step2' => '1',
|
186
|
+
'type_id' => type,
|
187
|
+
'processor_id' => '8000', # Any
|
188
|
+
'submit' => 'Add This File'
|
189
|
+
}
|
190
|
+
end
|
191
|
+
|
192
|
+
query = '?' + query_hash.map do |(name, value)|
|
193
|
+
[name, URI.encode(value)].join('=')
|
194
|
+
end.join('&')
|
195
|
+
|
196
|
+
data = [
|
197
|
+
"--" + boundary,
|
198
|
+
"Content-Disposition: form-data; name=\"userfile\"; filename=\"#{basename}\"",
|
199
|
+
"Content-Type: application/octet-stream",
|
200
|
+
"Content-Transfer-Encoding: binary",
|
201
|
+
"", file_data, ""
|
202
|
+
].join("\x0D\x0A")
|
203
|
+
|
204
|
+
release_headers = headers.merge(
|
205
|
+
'Content-Type' => "multipart/form-data; boundary=#{boundary}"
|
206
|
+
)
|
207
|
+
|
208
|
+
target = first_file ? '/frs/admin/qrs.php' : '/frs/admin/editrelease.php'
|
209
|
+
http.post(target + query, data, release_headers)
|
210
|
+
end
|
211
|
+
|
212
|
+
if first_file then
|
213
|
+
release_id = release_response.body[/release_id=(\d+)/, 1]
|
214
|
+
raise("Couldn't get release id") unless release_id
|
215
|
+
end
|
216
|
+
|
217
|
+
first_file = false
|
218
|
+
end
|
219
|
+
end
|
220
|
+
end
|
data/doc/RELEASES
CHANGED
@@ -1,11 +1,42 @@
|
|
1
|
-
== Version 0.
|
1
|
+
== Version 0.16.0
|
2
|
+
|
3
|
+
A snapshot of the latest developments. Many, many subtle improvements,
|
4
|
+
new features and a major cleanup of the source code.
|
5
|
+
|
6
|
+
Most notable attitions:
|
7
|
+
|
8
|
+
* Aspect Oriented Programming support. This new system
|
9
|
+
is used to reimplement features such as Controller filters,
|
10
|
+
Og callbacks and Og observers. By using this unified
|
11
|
+
system you can now add Observers to controllers and use
|
12
|
+
a metalanguage for wraping Og object callbacks:
|
13
|
+
|
14
|
+
class Controller
|
15
|
+
pre :force_login, :where => :prepend
|
16
|
+
wrap Benchmark, :on => :index
|
17
|
+
post :taraa, :on => login
|
18
|
+
end
|
19
|
+
|
20
|
+
module Timestamped
|
21
|
+
pre :on => :og_insert { |this| this.create_time = Time.now }
|
22
|
+
pre :on => :og_update { |this| this.update_time = Time.now }
|
23
|
+
pre :on => [:og_insert, :og_update] { |this| this.create_time = Time.now }
|
24
|
+
end
|
25
|
+
|
26
|
+
This feature will be used extensivelly in future versions
|
27
|
+
to improve logging, the shaders and more.
|
28
|
+
|
29
|
+
|
30
|
+
== Version 0.15.0 was released on 04/04/2005.
|
2
31
|
|
3
32
|
* Dynamic include.
|
4
33
|
|
34
|
+
|
5
35
|
== Version 0.14.0 was released on 28/03/2005.
|
6
36
|
|
7
37
|
* Fixes nasty property inheritance bug.
|
8
38
|
|
39
|
+
|
9
40
|
== Version 0.13.0 was released on 17/03/2005.
|
10
41
|
|
11
42
|
The first release as a standalone gem.
|
data/install.rb
CHANGED
data/lib/glue.rb
CHANGED
@@ -4,7 +4,7 @@
|
|
4
4
|
#
|
5
5
|
# George Moschovitis <gm@navel.gr>
|
6
6
|
# (c) 2004-2005 Navel, all rights reserved.
|
7
|
-
# $Id: glue.rb
|
7
|
+
# $Id: glue.rb 1 2005-04-11 11:04:30Z gmosx $
|
8
8
|
|
9
9
|
require 'English'
|
10
10
|
require 'pp'
|
@@ -12,10 +12,6 @@ require 'pp'
|
|
12
12
|
require 'glue/property'
|
13
13
|
require 'glue/attribute'
|
14
14
|
|
15
|
-
# The standard namespace module.
|
16
|
-
|
17
|
-
module N; end
|
18
|
-
|
19
15
|
class NilClass
|
20
16
|
|
21
17
|
# quite usefull for error tolerant apps.
|
@@ -57,10 +53,14 @@ module Glue
|
|
57
53
|
|
58
54
|
# The version.
|
59
55
|
|
60
|
-
Version = '0.
|
56
|
+
Version = '0.16.0'
|
61
57
|
|
62
58
|
# Library path.
|
63
59
|
|
64
60
|
LibPath = File.dirname(__FILE__)
|
65
61
|
|
66
62
|
end
|
63
|
+
|
64
|
+
# Include in the top level binding for easy access.
|
65
|
+
|
66
|
+
include Glue
|
data/lib/glue/array.rb
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
# * George Moschovitis <gm@navel.gr>
|
2
2
|
# (c) 2002-2005 Navel, all rights reserved.
|
3
|
-
# $Id: array.rb
|
3
|
+
# $Id: array.rb 1 2005-04-11 11:04:30Z gmosx $
|
4
4
|
|
5
5
|
require 'sync'
|
6
6
|
|
7
|
-
module
|
7
|
+
module Glue
|
8
8
|
|
9
9
|
# A thread-safe array. We use a sync object instead of a
|
10
10
|
# mutex, because it is re-entrant. An exclusive lock is
|
data/lib/glue/aspects.rb
ADDED
@@ -0,0 +1,237 @@
|
|
1
|
+
# * George Moschovitis <gm@navel.gr>
|
2
|
+
# (c) 2005 Navel, all rights reserved.
|
3
|
+
# $Id: aspects.rb 20 2005-04-15 15:18:36Z gmosx $
|
4
|
+
|
5
|
+
require 'glue/property'
|
6
|
+
|
7
|
+
module Glue
|
8
|
+
|
9
|
+
# An Aspect is a class that defines advices.
|
10
|
+
|
11
|
+
class Aspect
|
12
|
+
class << self
|
13
|
+
def wrap(target, methods = target.instance_methods, pre = :pre, post = :post)
|
14
|
+
target.send(:include, Aspects) unless target.ancestors.include?(Aspects)
|
15
|
+
target.wrap(self, :pre => pre, :post => post)
|
16
|
+
end
|
17
|
+
|
18
|
+
alias_method :observe, :wrap
|
19
|
+
end
|
20
|
+
|
21
|
+
def wrap(target, methods = target.instance_methods, pre = :pre, post = :post)
|
22
|
+
target.send(:include, Aspects) unless target.ancestors.include?(Aspects)
|
23
|
+
target.wrap(self, :pre => pre, :post => post)
|
24
|
+
end
|
25
|
+
alias_method :observe, :wrap
|
26
|
+
end
|
27
|
+
|
28
|
+
# Add support for Aspect Oriented Programming (AOP).
|
29
|
+
#
|
30
|
+
# === Examples
|
31
|
+
#
|
32
|
+
# class Controller
|
33
|
+
# pre :force_login, :where => :prepend
|
34
|
+
# wrap Benchmark, :on => :index
|
35
|
+
# post :taraa, :on => login
|
36
|
+
# end
|
37
|
+
#
|
38
|
+
# module Timestamped
|
39
|
+
# pre :on => :og_insert { |this| this.create_time = Time.now }
|
40
|
+
# pre :on => :og_update { |this| this.update_time = Time.now }
|
41
|
+
# pre :on => [:og_insert, :og_update] { |this| this.create_time = Time.now }
|
42
|
+
# end
|
43
|
+
|
44
|
+
module Aspects
|
45
|
+
|
46
|
+
# Store the code and the metadata (options) for
|
47
|
+
# an Advice.
|
48
|
+
|
49
|
+
Advice = Struct.new(:code, :options)
|
50
|
+
|
51
|
+
# Apply the advices to the target class.
|
52
|
+
|
53
|
+
def self.wrap(target, methods = target.instance_methods)
|
54
|
+
include_advice_modules(target)
|
55
|
+
|
56
|
+
for m in [methods].flatten
|
57
|
+
args = []
|
58
|
+
target.instance_method(m).arity.times { |i| args << "a#{i}" }
|
59
|
+
args = args.join(',')
|
60
|
+
|
61
|
+
target.module_eval <<-end_eval, __FILE__, __LINE__
|
62
|
+
alias_method :__unwrapped_#{m}, :#{m}
|
63
|
+
def #{m}(#{args})
|
64
|
+
#{gen_advice_code(m, target.advices, :pre)}
|
65
|
+
__unwrapped_#{m}(#{args})
|
66
|
+
#{gen_advice_code(m, target.advices, :post)}
|
67
|
+
end
|
68
|
+
end_eval
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
# Include Modules that define advices.
|
73
|
+
|
74
|
+
def self.include_advice_modules(target)
|
75
|
+
for a in target.advices
|
76
|
+
if a.code.is_a?(Module) and (!a.code.class.ancestors.include?(Class))
|
77
|
+
target.module_eval %{ include #{a.code} }
|
78
|
+
|
79
|
+
options = a.options.reject { |k,v| k == :pre || k == :post }
|
80
|
+
|
81
|
+
method = (a.options[:pre] || 'pre').to_s
|
82
|
+
if a.code.instance_methods.include?(method)
|
83
|
+
options.update(:where => :prepend, :join => :pre)
|
84
|
+
target.advices << Advice.new(method, options)
|
85
|
+
end
|
86
|
+
|
87
|
+
method = (a.options[:post] || 'post').to_s
|
88
|
+
if a.code.instance_methods.include?(method)
|
89
|
+
options.update(:where => :append, :join => :post)
|
90
|
+
target.advices << Advice.new(method, options)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
# Remove the original advice.
|
96
|
+
|
97
|
+
target.advices.delete_if do |a|
|
98
|
+
a.code.is_a?(Module) and (!a.code.class.ancestors.include?(Class))
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
# Generates the code to call the aspects.
|
103
|
+
|
104
|
+
def self.gen_advice_code(method, advices, join = :pre) # :nodoc:
|
105
|
+
code = ''
|
106
|
+
|
107
|
+
advices.each_with_index do |advice, idx|
|
108
|
+
o = options = advice.options
|
109
|
+
|
110
|
+
if only = options[:only] || options[:on]
|
111
|
+
next unless [only].flatten.include?(method.to_sym)
|
112
|
+
elsif except = options[:except]
|
113
|
+
next if [except].flatten.include?(method.to_sym)
|
114
|
+
end
|
115
|
+
|
116
|
+
advice = advice.code
|
117
|
+
|
118
|
+
if advice.is_a?(Symbol) or advice.is_a?(String)
|
119
|
+
next if o[:join] != join
|
120
|
+
code << "#{advice}; "
|
121
|
+
elsif advice.respond_to?('call')
|
122
|
+
next if o[:join] != join
|
123
|
+
code << "self.class.advices[#{idx}].code.call(self); "
|
124
|
+
elsif advice.is_a?(Class)
|
125
|
+
if advice.class.ancestors.include?(Class)
|
126
|
+
if m = o[join] and advice.methods.include?(m.to_s)
|
127
|
+
code << "#{advice}.#{m}(self); "
|
128
|
+
end
|
129
|
+
else
|
130
|
+
# Module, allready handled.
|
131
|
+
end
|
132
|
+
else
|
133
|
+
if m = o[join] and advice.methods.include?(m.to_s)
|
134
|
+
code << "self.class.advices[#{idx}].code.#{m}(self); "
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
return code
|
140
|
+
end
|
141
|
+
|
142
|
+
def self.append_features(base)
|
143
|
+
super
|
144
|
+
base.extend(ClassMethods)
|
145
|
+
base.module_eval %{
|
146
|
+
Glue::PropertyUtils.enchant(self)
|
147
|
+
|
148
|
+
def self.advices
|
149
|
+
__meta[:advices] || []
|
150
|
+
end
|
151
|
+
|
152
|
+
def self.advices=(advices)
|
153
|
+
__meta[:advices] = advices
|
154
|
+
end
|
155
|
+
|
156
|
+
# def self.inherited(child)
|
157
|
+
# super
|
158
|
+
# child.send(:include, Aspects)
|
159
|
+
# end
|
160
|
+
#
|
161
|
+
# def self.append_features(base)
|
162
|
+
# super
|
163
|
+
# base.send(:include, Aspects)
|
164
|
+
# end
|
165
|
+
}
|
166
|
+
end
|
167
|
+
|
168
|
+
module ClassMethods
|
169
|
+
|
170
|
+
# Add a pre (before) advice.
|
171
|
+
|
172
|
+
def pre(*args, &block)
|
173
|
+
o = options = {
|
174
|
+
:join => :pre,
|
175
|
+
:where => :prepend,
|
176
|
+
}
|
177
|
+
options.update(args.pop) if args.last.is_a?(Hash)
|
178
|
+
|
179
|
+
if block_given?
|
180
|
+
advices = [ Advice.new(block, options) ]
|
181
|
+
else
|
182
|
+
advices = args.collect { |a| Advice.new(a, options) }
|
183
|
+
end
|
184
|
+
|
185
|
+
if options[:where] == :prepend
|
186
|
+
self.advices = advices + self.advices
|
187
|
+
else
|
188
|
+
self.advices = self.advices + advices
|
189
|
+
end
|
190
|
+
end
|
191
|
+
alias_method :before, :pre
|
192
|
+
|
193
|
+
# Add a post (after) advice.
|
194
|
+
|
195
|
+
def post(*args, &block)
|
196
|
+
o = options = {
|
197
|
+
:join => :post,
|
198
|
+
:where => :append,
|
199
|
+
}
|
200
|
+
options.update(args.pop) if args.last.is_a?(Hash)
|
201
|
+
|
202
|
+
if block_given?
|
203
|
+
advices = [ Advice.new(block, options) ]
|
204
|
+
else
|
205
|
+
advices = args.collect { |a| Advice.new(a, options) }
|
206
|
+
end
|
207
|
+
|
208
|
+
if options[:where] == :prepend
|
209
|
+
self.advices = advices + self.advices
|
210
|
+
else
|
211
|
+
self.advices = self.advices + advices
|
212
|
+
end
|
213
|
+
end
|
214
|
+
alias_method :after, :post
|
215
|
+
|
216
|
+
# Add a wrap (arround) aspect. An aspect is a class that
|
217
|
+
# responds to the before and after advices.
|
218
|
+
|
219
|
+
def wrap(*args)
|
220
|
+
o = options = {
|
221
|
+
:pre => :pre,
|
222
|
+
:post => :post
|
223
|
+
}
|
224
|
+
options.update(args.pop) if args.last.is_a?(Hash)
|
225
|
+
|
226
|
+
for aspect in args
|
227
|
+
self.advices << Advice.new(aspect, options)
|
228
|
+
end
|
229
|
+
end
|
230
|
+
alias_method :around, :wrap
|
231
|
+
alias_method :observer, :wrap
|
232
|
+
|
233
|
+
end
|
234
|
+
|
235
|
+
end
|
236
|
+
|
237
|
+
end
|