rinterceptor 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.
- data/CHANGELOG +3 -0
- data/MIT-LICENSE +20 -0
- data/Rakefile +29 -0
- data/lib/example_rinterceptor.rb +80 -0
- data/lib/rinterceptor.rb +178 -0
- metadata +57 -0
data/CHANGELOG
ADDED
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2008 [name of plugin creator]
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake/gempackagetask'
|
3
|
+
PKG_NAME = "rinterceptor"
|
4
|
+
PKG_VERSION = "0.1.0"
|
5
|
+
PKG_FILE_NAME = "#{PKG_NAME}-#{PKG_VERSION}"
|
6
|
+
PKG_FILES = FileList[
|
7
|
+
'[A-Z]*',
|
8
|
+
'lib/**/*'
|
9
|
+
]
|
10
|
+
spec = Gem::Specification.new do |s|
|
11
|
+
s.platform = Gem::Platform::RUBY
|
12
|
+
s.summary = "it is a inheritable, reusable AOP framework"
|
13
|
+
s.name = PKG_NAME
|
14
|
+
s.version = PKG_VERSION
|
15
|
+
s.require_path = 'lib'
|
16
|
+
s.homepage = %q{http://rinter.rubyforge.org/}
|
17
|
+
s.rubyforge_project = 'Rinterceptor'
|
18
|
+
s.has_rdoc = false
|
19
|
+
s.authors = ["Leon Li"]
|
20
|
+
s.email = "scorpio_leon@hotmail.com"
|
21
|
+
s.files = PKG_FILES
|
22
|
+
s.description = <<-EOF
|
23
|
+
it is a inheritable, reusable AOP framework with regex rule support, let your interceptor simple, flexible and with high expandability
|
24
|
+
EOF
|
25
|
+
end
|
26
|
+
Rake::GemPackageTask.new(spec) do |pkg|
|
27
|
+
pkg.need_zip = true
|
28
|
+
pkg.need_tar = true
|
29
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'rinterceptor'
|
3
|
+
module ExampleRinterceptor
|
4
|
+
def rinter_before(method, *args)
|
5
|
+
p "instance before -- method: #{method}, args: #{args} in ExampleRinterceptor"
|
6
|
+
end
|
7
|
+
def rinter_after(method, result, e, *args)
|
8
|
+
p "instance after -- method: #{method}, result: #{result}, e: #{e}, args: #{args} in ExampleRinterceptor"
|
9
|
+
result
|
10
|
+
end
|
11
|
+
|
12
|
+
module ClassMethods
|
13
|
+
def rinter_before(method, *args)
|
14
|
+
p "singleton before -- method: #{method}, args: #{args} in ExampleRinterceptor"
|
15
|
+
end
|
16
|
+
def rinter_after(method, result, e, *args)
|
17
|
+
p "singleton after -- method: #{method}, result: #{result}, e: #{e}, args: #{args} in ExampleRinterceptor"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
include Rinterceptor
|
21
|
+
end
|
22
|
+
|
23
|
+
module SubExampleRinterceptor
|
24
|
+
def self.rinter_before_include_class(base)
|
25
|
+
p "before_include_class in SubExampleRinterceptor"
|
26
|
+
#set interceptor rules of instance methods, the variable can also be defined in class before include this module
|
27
|
+
base.instance_variable_set(:@include_i_methods, {nil => [/^i2_/, /^i3_/], :handler_it => /^i1_/})
|
28
|
+
end
|
29
|
+
def self.rinter_after_include_class(base)
|
30
|
+
p "after_include_class in SubExampleRinterceptor"
|
31
|
+
end
|
32
|
+
def rinter_handler_it_around(invocation)
|
33
|
+
p "instance handler_it around begin -- method: #{invocation.method}, args: #{invocation.args} in SubExampleRinterceptor"
|
34
|
+
result = invocation.invoke("inter", "ddddd")
|
35
|
+
p "instance handler_it around end -- method: #{invocation.method}, args: #{invocation.args} in SubExampleRinterceptor"
|
36
|
+
result
|
37
|
+
end
|
38
|
+
module ClassMethods
|
39
|
+
def rinter_before(method, *args)
|
40
|
+
p "singleton before -- method: #{method}, args: #{args} in SubExampleRinterceptor"
|
41
|
+
end
|
42
|
+
end
|
43
|
+
include ExampleRinterceptor
|
44
|
+
end
|
45
|
+
|
46
|
+
|
47
|
+
|
48
|
+
if __FILE__ == $0
|
49
|
+
|
50
|
+
class TestRinterceptor
|
51
|
+
def i1_test(x, y)
|
52
|
+
p "i1_test x:#{x} y:#{y}"
|
53
|
+
end
|
54
|
+
def i2_test(x, y)
|
55
|
+
p "i2_test x:#{x} y:#{y}"
|
56
|
+
end
|
57
|
+
def i3_test(x, y)
|
58
|
+
p "i3_test x:#{x} y:#{y}"
|
59
|
+
end
|
60
|
+
def self.s_test(x, y)
|
61
|
+
p "s_test x:#{x} y:#{y}"
|
62
|
+
end
|
63
|
+
#set interceptor rules of singleton methods, an alternative way is demonstrated in "self.rinter_before_include_class" of SubExampleRinterceptor
|
64
|
+
#@include_s_methods value example:
|
65
|
+
#String(for exactly match)
|
66
|
+
#Regexp
|
67
|
+
#[Regexp]
|
68
|
+
#{} (unless key.nil? use rinter_#{key}_around to handle it, otherwise same behavior as before)
|
69
|
+
#refor to SubExampleRinterceptor
|
70
|
+
@include_s_methods = [/^s_/]
|
71
|
+
include SubExampleRinterceptor
|
72
|
+
end
|
73
|
+
|
74
|
+
TestRinterceptor.new.i1_test("xxx", "yyy")
|
75
|
+
TestRinterceptor.new.i2_test("xxx", "yyy")
|
76
|
+
TestRinterceptor.new.i3_test("xxx", "yyy")
|
77
|
+
TestRinterceptor.s_test("xxx", "yyy")
|
78
|
+
end
|
79
|
+
|
80
|
+
|
data/lib/rinterceptor.rb
ADDED
@@ -0,0 +1,178 @@
|
|
1
|
+
=begin
|
2
|
+
|
3
|
+
For expandability, Class can not include me directly, only accept Module to include me
|
4
|
+
for example:
|
5
|
+
|
6
|
+
module MyRinterceptor
|
7
|
+
def instance_method
|
8
|
+
end
|
9
|
+
module ClassMethods #don't change this name if you need singleton method
|
10
|
+
def singleton_method
|
11
|
+
end
|
12
|
+
end
|
13
|
+
include Rinterceptor #should be placed at last line of this module
|
14
|
+
end
|
15
|
+
|
16
|
+
class YourClass
|
17
|
+
include MyRinterceptor
|
18
|
+
end
|
19
|
+
|
20
|
+
|
21
|
+
#you can refer to example_rinterceptor.rb
|
22
|
+
=end
|
23
|
+
#TODO nested interceptor
|
24
|
+
module Rinterceptor
|
25
|
+
def self.included(base)
|
26
|
+
raise 'Class can not include me directly, only accept Module to include me' if base.is_a?(Class)
|
27
|
+
base.extend(ClassMethods)
|
28
|
+
end
|
29
|
+
|
30
|
+
#overridable
|
31
|
+
def rinter_skip?
|
32
|
+
false
|
33
|
+
end
|
34
|
+
|
35
|
+
#overridable
|
36
|
+
def rinter_before(method, *args)
|
37
|
+
end
|
38
|
+
|
39
|
+
#overridable
|
40
|
+
def rinter_after(method, result, e, *args)
|
41
|
+
raise e unless e.nil?
|
42
|
+
result
|
43
|
+
end
|
44
|
+
|
45
|
+
#overridable
|
46
|
+
def rinter_around(invocation)
|
47
|
+
invocation.invoke
|
48
|
+
end
|
49
|
+
|
50
|
+
module ClassMethods
|
51
|
+
#for sub module
|
52
|
+
def included(base)
|
53
|
+
if base.is_a?(Class)
|
54
|
+
rinter_before_include_class(base) #only available in last module for preparing data of Class which will include it
|
55
|
+
base.extend(ClassMethods)
|
56
|
+
base.ancestors[1..-1].reverse.each {|p| base.extend(p::ClassMethods) if p.respond_to?(:rinter_here?)}
|
57
|
+
include_s_methods = base.include_s_methods || []
|
58
|
+
include_i_methods = base.include_i_methods || []
|
59
|
+
include_s_methods = RinterceptorUtil.process_include_methods(include_s_methods)
|
60
|
+
include_i_methods = RinterceptorUtil.process_include_methods(include_i_methods)
|
61
|
+
exclude_s_methods = (base.exclude_s_methods || []) + [/^rinter_/, /include_[is]_methods/, /exclude_[is]_methods/]
|
62
|
+
exclude_i_methods = (base.exclude_i_methods || []) + [/^rinter_/, /include_[is]_methods/, /exclude_[is]_methods/]
|
63
|
+
s_methods = (base.private_methods + base.singleton_methods).delete_if{|m| ! RinterceptorUtil.match_method?(m, include_s_methods, exclude_s_methods) }
|
64
|
+
i_methods = (base.private_instance_methods + base.instance_methods).delete_if{|m| ! RinterceptorUtil.match_method?(m, include_i_methods, exclude_i_methods) }
|
65
|
+
s_methods.each{|m| rinter_generate_proxy(base, m, include_s_methods.is_a?(Hash) ? include_s_methods : nil, true)}
|
66
|
+
i_methods.each{|m| rinter_generate_proxy(base, m, include_i_methods.is_a?(Hash) ? include_i_methods : nil)}
|
67
|
+
rinter_after_include_class(base) #only available in last module for preparing data of Class which will include it
|
68
|
+
else
|
69
|
+
base.extend(ClassMethods)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
def rinter_here?
|
73
|
+
true
|
74
|
+
end
|
75
|
+
|
76
|
+
#overridable only in last module
|
77
|
+
def rinter_before_include_class(base)
|
78
|
+
end
|
79
|
+
|
80
|
+
#overridable only in last module
|
81
|
+
def rinter_after_include_class(base)
|
82
|
+
end
|
83
|
+
|
84
|
+
def rinter_generate_proxy(obj, method, methods, singleton=false)
|
85
|
+
handler = nil
|
86
|
+
unless methods.nil?
|
87
|
+
methods.each{|k, v| v.each{|vv| if method =~ vv then handler = method; break end }; unless handler.nil? then handler = k.nil? ? nil : "#{k}_"; break end}
|
88
|
+
end
|
89
|
+
obj.class_eval %{
|
90
|
+
#{"class << self" if singleton}
|
91
|
+
alias_method :old4rinter_#{method}, :#{method} unless method_defined?(:old4rinter_#{method})
|
92
|
+
def #{method}(*args)
|
93
|
+
return old4rinter_#{method}(*args) if rinter_skip?
|
94
|
+
rinter_before("#{method}", *args)
|
95
|
+
result = nil
|
96
|
+
e = nil
|
97
|
+
invocation = RinterceptorInvocation.new(self, "#{method}", *args)
|
98
|
+
begin
|
99
|
+
result = rinter_#{handler}around(invocation)
|
100
|
+
rescue => e
|
101
|
+
end
|
102
|
+
rinter_after("#{method}", result, e, *args)
|
103
|
+
result
|
104
|
+
end
|
105
|
+
#{"end" if singleton}
|
106
|
+
}
|
107
|
+
end
|
108
|
+
|
109
|
+
#target class' methods
|
110
|
+
attr_accessor :include_i_methods
|
111
|
+
attr_accessor :include_s_methods
|
112
|
+
attr_accessor :exclude_i_methods
|
113
|
+
attr_accessor :exclude_s_methods
|
114
|
+
|
115
|
+
#overridable
|
116
|
+
def rinter_skip?
|
117
|
+
false
|
118
|
+
end
|
119
|
+
|
120
|
+
#overridable
|
121
|
+
def rinter_before(method, *args)
|
122
|
+
end
|
123
|
+
|
124
|
+
#overridable
|
125
|
+
def rinter_after(method, result, e, *args)
|
126
|
+
raise e unless e.nil?
|
127
|
+
result
|
128
|
+
end
|
129
|
+
|
130
|
+
#overridable
|
131
|
+
def rinter_around(invocation)
|
132
|
+
invocation.invoke
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
module RinterceptorUtil
|
138
|
+
def self.match_method?(method, includes, excludes)
|
139
|
+
excludes.each {|i| return false if method =~ i}
|
140
|
+
real_includes = includes.is_a?(Array) ? includes : []
|
141
|
+
if includes.is_a?(Hash)
|
142
|
+
includes.each{|k, v| real_includes += v}
|
143
|
+
end
|
144
|
+
real_includes.each {|i| return true if method =~ i}
|
145
|
+
false
|
146
|
+
end
|
147
|
+
def self.process_include_methods(methods)
|
148
|
+
if methods.is_a?(Hash)
|
149
|
+
methods.each do |k, v|
|
150
|
+
if v.is_a?(String) || v.is_a?(Symbol)
|
151
|
+
v = Regexp.new("^#{v}$")
|
152
|
+
elsif v.is_a?(Array)
|
153
|
+
v.each_index{|i| v[i] = Regexp.new("^#{v[i]}$") if v[i].is_a?(String) || v[i].is_a?(Symbol)}
|
154
|
+
end
|
155
|
+
v = [v] if v.is_a?(Regexp)
|
156
|
+
methods[k] = v
|
157
|
+
end
|
158
|
+
end
|
159
|
+
methods
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
class RinterceptorInvocation
|
164
|
+
attr_accessor :object, :method, :args, :options
|
165
|
+
def initialize(object, method, *args)
|
166
|
+
@object = object
|
167
|
+
@method = method
|
168
|
+
@args = args
|
169
|
+
@options = {}
|
170
|
+
end
|
171
|
+
def invoke(*args)
|
172
|
+
unless @options.nil? || @options.empty?
|
173
|
+
@args = @args + [@options]
|
174
|
+
@options = nil
|
175
|
+
end
|
176
|
+
@object.send("old4rinter_#{@method}".to_sym, *(args.empty? ? @args : args))
|
177
|
+
end
|
178
|
+
end
|
metadata
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rinterceptor
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Leon Li
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-03-09 00:00:00 +08:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description: it is a inheritable, reusable AOP framework with regex rule support, let your interceptor simple, flexible and with high expandability
|
17
|
+
email: scorpio_leon@hotmail.com
|
18
|
+
executables: []
|
19
|
+
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files: []
|
23
|
+
|
24
|
+
files:
|
25
|
+
- MIT-LICENSE
|
26
|
+
- Rakefile
|
27
|
+
- CHANGELOG
|
28
|
+
- lib/rinterceptor.rb
|
29
|
+
- lib/example_rinterceptor.rb
|
30
|
+
has_rdoc: false
|
31
|
+
homepage: http://rinter.rubyforge.org/
|
32
|
+
post_install_message:
|
33
|
+
rdoc_options: []
|
34
|
+
|
35
|
+
require_paths:
|
36
|
+
- lib
|
37
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- - ">="
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
version: "0"
|
42
|
+
version:
|
43
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: "0"
|
48
|
+
version:
|
49
|
+
requirements: []
|
50
|
+
|
51
|
+
rubyforge_project: Rinterceptor
|
52
|
+
rubygems_version: 1.3.1
|
53
|
+
signing_key:
|
54
|
+
specification_version: 2
|
55
|
+
summary: it is a inheritable, reusable AOP framework
|
56
|
+
test_files: []
|
57
|
+
|