glue 0.15.0 → 0.16.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.
- 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
|