proxeze 1.0.0 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +36 -31
- data/VERSION +1 -1
- data/lib/proxeze.rb +35 -33
- data/lib/proxeze/class_methods.rb +47 -0
- data/lib/proxeze/delegator_blocks.rb +89 -0
- data/lib/proxeze/instance_methods.rb +89 -0
- data/proxeze.gemspec +6 -2
- data/run-rvm-specs +2 -0
- data/spec/definitions.rb +8 -0
- data/spec/proxeze_spec.rb +112 -0
- metadata +7 -3
data/README.rdoc
CHANGED
@@ -4,7 +4,7 @@ A basic proxy/delegate framework for Ruby that will allow you to wrap any object
|
|
4
4
|
|
5
5
|
== Details
|
6
6
|
|
7
|
-
When Proxeze proxies an object
|
7
|
+
When Proxeze proxies an object it creates a delegate class under its namespace (using Ruby's built-in Delegate class) that mirrors your class. It overrides your class' #new method so that when you create instances of your class you get back the proxy object instead. In this way, you don't have to change the way you instantiate your objects, but you get the benefit of the proxy pattern. When proxying a class Proxeze will also proxy most class methods (see Proxying Classes below).
|
8
8
|
|
9
9
|
== How does that help me?
|
10
10
|
|
@@ -13,60 +13,62 @@ Examples tell it best... In this example we have a tree structure of Categories.
|
|
13
13
|
class Category
|
14
14
|
attr_accessor :categories
|
15
15
|
attr_reader :name
|
16
|
-
|
17
16
|
def initialize name
|
18
17
|
@name = name
|
19
18
|
@categories = []
|
20
19
|
end
|
21
20
|
end
|
22
|
-
|
23
|
-
# now every time we instantiate Category, we
|
21
|
+
|
22
|
+
# now every time we instantiate Category, we
|
23
|
+
# will get back a Proxeze::Category instance
|
24
24
|
Proxeze.proxy Category
|
25
|
-
|
26
|
-
c1, c2, c3 = Category.new('1'), Category.new('2'), Category.new('3')
|
27
|
-
c1.categories = [c2, c3]
|
28
|
-
c2.categories << Category.new('4')
|
29
|
-
c2.categories << Category.new('5')
|
30
|
-
c6 = Category.new('6')
|
31
|
-
c2.categories << c6
|
32
|
-
c6.categories << Category.new('7')
|
33
|
-
c6.categories << Category.new('8')
|
34
|
-
|
35
|
-
# now we have a tree like this:
|
36
|
-
# c1
|
37
|
-
# ___||___
|
38
|
-
# || ||
|
39
|
-
# c2 c3
|
40
|
-
# ____||____
|
41
|
-
# || || ||
|
42
|
-
# c4 c5 c6
|
43
|
-
# ___||___
|
44
|
-
# || ||
|
45
|
-
# c7 c8
|
46
|
-
|
47
|
-
Let's say we need to be able to hide c6 and its children at some point, to do that we can run the following code:
|
48
25
|
|
26
|
+
# Controls the visibility of the categories
|
49
27
|
module Visibility
|
50
28
|
def visible?
|
51
29
|
@visible = true if @visible.nil?
|
52
30
|
@visible
|
53
31
|
end
|
54
|
-
|
32
|
+
|
55
33
|
def be_invisible!
|
56
34
|
@visible = false
|
57
35
|
categories.each {|e| e.be_invisible!}
|
58
36
|
self
|
59
37
|
end
|
60
|
-
|
38
|
+
|
61
39
|
def be_visible!
|
62
40
|
@visible = true
|
63
41
|
categories.each {|e| e.be_visible!}
|
64
42
|
self
|
65
43
|
end
|
44
|
+
|
45
|
+
Proxeze::Category.send :include, self
|
66
46
|
end
|
67
|
-
|
68
|
-
|
47
|
+
|
48
|
+
# instantiate Category objects as we normally would
|
49
|
+
c1 = Category.new('1')
|
50
|
+
c1.categories = [Category.new('2'), Category.new('3')]
|
51
|
+
c2 = c1.categories.first
|
52
|
+
c2.categories = [Category.new('4'), Category.new('5'), Category.new('6')]
|
53
|
+
c6 = c2.categories.last
|
54
|
+
c6.categories = [Category.new('7'), Category.new('8')]
|
55
|
+
|
69
56
|
c6.be_invisible!
|
57
|
+
|
58
|
+
# before we hide c6 and its children | after hiding c6
|
59
|
+
# we have a tree like this: | our tree becomes:
|
60
|
+
# ------------------------------------ + --------------------
|
61
|
+
# c1 + c1
|
62
|
+
# ___||___ + ___||___
|
63
|
+
# || || + || ||
|
64
|
+
# c2 c3 + c2 c3
|
65
|
+
# ____||____ + ____||____
|
66
|
+
# || || || + || ||
|
67
|
+
# c4 c5 c6 + c4 c5
|
68
|
+
# ___||__ +
|
69
|
+
# || | +
|
70
|
+
# c7 c8 +
|
71
|
+
# |
|
70
72
|
|
71
73
|
So, we've added behavior to the proxied objects, but not the Category objects themselves.
|
72
74
|
|
@@ -118,6 +120,9 @@ The special case to this is that class methods defined in Object are not proxied
|
|
118
120
|
|
119
121
|
Note: I don't recommend overriding the #hash method on your class, this serves only as an example.
|
120
122
|
|
123
|
+
== Method Interceptions
|
124
|
+
Proxeze has the ability to surround instance method calls with _before_ and _after_ callbacks. This support was lifted straight from proxy_machine (https://github.com/tulios/proxy_machine).
|
125
|
+
|
121
126
|
== Supported Ruby versions
|
122
127
|
This code has been tested on 1.8.7, 1.9.2, and JRuby 1.5.6. I haven't bothered to test it on anything else, but I strongly suspect it will work just fine on any Ruby implementation greater than 1.8.6.
|
123
128
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.
|
1
|
+
1.1.0
|
data/lib/proxeze.rb
CHANGED
@@ -1,4 +1,6 @@
|
|
1
|
-
require '
|
1
|
+
require 'proxeze/delegator_blocks'
|
2
|
+
require 'proxeze/instance_methods'
|
3
|
+
require 'proxeze/class_methods'
|
2
4
|
|
3
5
|
module Proxeze
|
4
6
|
if RUBY_VERSION =~ /1\.9/
|
@@ -35,28 +37,28 @@ module Proxeze
|
|
35
37
|
# all subsequent calls to #new on that class will return
|
36
38
|
# an instance of a proxied class (in the Proxeze namespace),
|
37
39
|
# thereby allowing seemless integration with existing
|
38
|
-
# classes.
|
40
|
+
# classes and object creation.
|
39
41
|
#
|
40
|
-
# Typically, only the Proxeze
|
41
|
-
# redefine_new_method
|
42
|
-
def self.proxy target_class, opts = {}
|
42
|
+
# Typically, only the Proxeze>>#for method should pass in
|
43
|
+
# :redefine_new_method => false here.
|
44
|
+
def self.proxy target_class, opts = {}, &callback_blk
|
43
45
|
options = default_proxy_options.merge opts
|
44
|
-
cls_name = target_class
|
46
|
+
cls_name = class_name_for(target_class)
|
45
47
|
unless self.class_defined? cls_name
|
46
48
|
cls = DelegateClass target_class
|
47
|
-
cls.send :include,
|
49
|
+
cls.send :include, Copying
|
50
|
+
cls.send :include, Hooks
|
51
|
+
cls.send :extend, ClassHooks
|
48
52
|
self.const_set cls_name, cls
|
49
|
-
|
53
|
+
|
50
54
|
excluded_class_methods = object_methods + [:new, :public_api, :delegating_block] + options[:exclude_class_methods]
|
51
55
|
(class_methods_from(target_class) - excluded_class_methods + options[:include_class_methods]).each do |method|
|
52
|
-
blk =
|
56
|
+
blk = Delegator.delegating_block_for_method_and_target(method, target_class)
|
53
57
|
(class << cls; self; end).instance_eval do
|
54
58
|
define_method(method, &blk)
|
55
59
|
end
|
56
60
|
end
|
57
61
|
end
|
58
|
-
|
59
|
-
cls = self.const_get cls_name
|
60
62
|
|
61
63
|
# we have to collect the methods as Strings here because
|
62
64
|
# 1.9 changed the implementation to return Symbols instead of Strings
|
@@ -71,35 +73,35 @@ module Proxeze
|
|
71
73
|
}, __FILE__, __LINE__
|
72
74
|
end
|
73
75
|
|
74
|
-
self.const_get cls_name
|
76
|
+
cls = self.const_get cls_name
|
77
|
+
unless callback_blk.nil?
|
78
|
+
# (class << cls; self; end).instance_eval &callback_blk
|
79
|
+
cls.instance_eval &callback_blk
|
80
|
+
end
|
81
|
+
cls
|
75
82
|
end
|
76
83
|
|
77
84
|
def self.default_proxy_options
|
78
85
|
{:redefine_new_method => true, :exclude_class_methods => [], :include_class_methods => []}
|
79
86
|
end
|
80
87
|
|
81
|
-
def self.class_delegating_block mid, target
|
82
|
-
lambda do |*args, &block|
|
83
|
-
begin
|
84
|
-
target.__send__(mid, *args, &block)
|
85
|
-
ensure
|
86
|
-
$@.delete_if {|t| /\A#{Regexp.quote(__FILE__)}:#{__LINE__-2}:/o =~ t} if $@
|
87
|
-
end
|
88
|
-
end
|
89
|
-
end
|
90
|
-
|
91
88
|
# create a proxy object for the given object
|
92
|
-
def self.for object
|
93
|
-
self.proxy( object.class, :redefine_new_method => false ).new( object )
|
89
|
+
def self.for object, &callback_blk
|
90
|
+
proxy = self.proxy( object.class, :redefine_new_method => false ).new( object )
|
91
|
+
proxy.class.hooks.clear
|
92
|
+
cls = (class << proxy; self; end)
|
93
|
+
cls.send :include, Copying unless cls.ancestors.include?(Copying)
|
94
|
+
cls.send :include, Hooks unless cls.ancestors.include?(Hooks)
|
95
|
+
cls.send :extend, ClassHooks unless cls.ancestors.include?(ClassHooks)
|
96
|
+
unless callback_blk.nil?
|
97
|
+
proxy.instance_eval &callback_blk
|
98
|
+
end
|
99
|
+
proxy
|
94
100
|
end
|
95
101
|
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
# create a new proxy object for my delegate
|
102
|
-
def new_proxy
|
103
|
-
Proxeze.for __getobj__
|
104
|
-
end
|
102
|
+
private
|
103
|
+
def self.class_name_for target_class
|
104
|
+
name = target_class.name ? target_class.name : "#{target_class}"
|
105
|
+
name.gsub( 'Class:', '' ).gsub( /[:<>#]/, '' )
|
106
|
+
end
|
105
107
|
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module Proxeze
|
2
|
+
module ClassHooks
|
3
|
+
def hooks
|
4
|
+
@hooks ||= {:after => {}, :after_all => {}, :before => {}, :before_all => {}}
|
5
|
+
end
|
6
|
+
|
7
|
+
# The after hook will receive 3 arguments:
|
8
|
+
# target, result, and any arguments to the
|
9
|
+
# method that was called.
|
10
|
+
def after mid, *args, &blk
|
11
|
+
insert_into_callback_chain :hook => :after, :mid => mid, :args => args, :blk => blk
|
12
|
+
end
|
13
|
+
|
14
|
+
# The after_all hook will receive 4 arguments:
|
15
|
+
# target, result, method id, and any arguments
|
16
|
+
# to the method that was called.
|
17
|
+
def after_all &blk
|
18
|
+
insert_into_callback_chain :hook => :after_all, :blk => blk
|
19
|
+
end
|
20
|
+
|
21
|
+
# The before hook will receive 2 arguments:
|
22
|
+
# target and any arguments to the method that
|
23
|
+
# is being called.
|
24
|
+
def before mid, *args, &blk
|
25
|
+
insert_into_callback_chain :hook => :before, :mid => mid, :args => args, :blk => blk
|
26
|
+
end
|
27
|
+
|
28
|
+
# The before_all hook will receive 3 arguments:
|
29
|
+
# target, method id, and any arguments to the
|
30
|
+
# method that is being called.
|
31
|
+
def before_all &blk
|
32
|
+
insert_into_callback_chain :hook => :before_all, :blk => blk
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
def insert_into_callback_chain options={}
|
37
|
+
hook, mid, args, blk = options[:hook], options[:mid], options[:args], options[:blk]
|
38
|
+
callback = blk.nil? ? args : blk
|
39
|
+
if mid
|
40
|
+
self.hooks[hook] ||= {}
|
41
|
+
self.hooks[hook][mid] = callback
|
42
|
+
else
|
43
|
+
self.hooks[hook] = callback
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
require 'delegate'
|
2
|
+
|
3
|
+
def Delegator.delegating_block mid
|
4
|
+
lambda do |*args, &block|
|
5
|
+
target = self.__getobj__
|
6
|
+
begin
|
7
|
+
mid = mid.to_sym
|
8
|
+
method = mid.to_s
|
9
|
+
|
10
|
+
after_all = self.class.hooks[:after_all]
|
11
|
+
after = self.class.hooks[:after] ? self.class.hooks[:after][mid] : nil
|
12
|
+
before_all = self.class.hooks[:before_all]
|
13
|
+
before = self.class.hooks[:before] ? self.class.hooks[:before][mid] : nil
|
14
|
+
|
15
|
+
execute_call(before_all, target, mid, args)
|
16
|
+
execute_call(before, target, args)
|
17
|
+
|
18
|
+
result = target.__send__(mid, *args, &block)
|
19
|
+
result_after = execute_call(after, target, result, args)
|
20
|
+
result_after_all = execute_call(after_all, target, result, mid, args)
|
21
|
+
return result_after_all if result_after_all
|
22
|
+
return result_after if result_after
|
23
|
+
result
|
24
|
+
ensure
|
25
|
+
$@.delete_if {|t| /\A#{Regexp.quote(__FILE__)}:#{__LINE__-2}:/o =~ t} if $@
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def Delegator.delegating_block_for_method_and_target mid, target
|
31
|
+
lambda do |*args, &block|
|
32
|
+
begin
|
33
|
+
target.__send__(mid, *args, &block)
|
34
|
+
ensure
|
35
|
+
$@.delete_if {|t| /\A#{Regexp.quote(__FILE__)}:#{__LINE__-2}:/o =~ t} if $@
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
unless RUBY_VERSION =~ /1\.9/
|
41
|
+
def DelegateClass(superclass)
|
42
|
+
klass = Class.new
|
43
|
+
methods = superclass.public_instance_methods(true)
|
44
|
+
methods -= ::Kernel.public_instance_methods(false)
|
45
|
+
methods |= ["to_s","to_a","inspect","==","=~","==="]
|
46
|
+
klass.module_eval {
|
47
|
+
def initialize(obj) # :nodoc:
|
48
|
+
@_dc_obj = obj
|
49
|
+
end
|
50
|
+
def method_missing(m, *args, &block) # :nodoc:
|
51
|
+
unless @_dc_obj.respond_to?(m)
|
52
|
+
super(m, *args, &block)
|
53
|
+
end
|
54
|
+
@_dc_obj.__send__(m, *args, &block)
|
55
|
+
end
|
56
|
+
def respond_to?(m, include_private = false) # :nodoc:
|
57
|
+
return true if super
|
58
|
+
return @_dc_obj.respond_to?(m, include_private)
|
59
|
+
end
|
60
|
+
def __getobj__ # :nodoc:
|
61
|
+
@_dc_obj
|
62
|
+
end
|
63
|
+
def __setobj__(obj) # :nodoc:
|
64
|
+
raise ArgumentError, "cannot delegate to self" if self.equal?(obj)
|
65
|
+
@_dc_obj = obj
|
66
|
+
end
|
67
|
+
def clone # :nodoc:
|
68
|
+
new = super
|
69
|
+
new.__setobj__(__getobj__.clone)
|
70
|
+
new
|
71
|
+
end
|
72
|
+
def dup # :nodoc:
|
73
|
+
new = super
|
74
|
+
new.__setobj__(__getobj__.clone)
|
75
|
+
new
|
76
|
+
end
|
77
|
+
}
|
78
|
+
for method in methods
|
79
|
+
begin
|
80
|
+
klass.module_eval do
|
81
|
+
define_method method, Delegator.delegating_block(method)
|
82
|
+
end
|
83
|
+
rescue SyntaxError
|
84
|
+
raise NameError, "invalid identifier %s" % method, caller(3)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
return klass
|
88
|
+
end
|
89
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
module Proxeze
|
2
|
+
module Copying
|
3
|
+
# create a new proxy around a clone of my delegate object
|
4
|
+
def clone
|
5
|
+
hooks = self.class.hooks
|
6
|
+
clone = Proxeze.for __getobj__.clone
|
7
|
+
clone.class.hooks.merge hooks
|
8
|
+
clone
|
9
|
+
end
|
10
|
+
|
11
|
+
# create a new proxy object for my delegate
|
12
|
+
def new_proxy
|
13
|
+
Proxeze.for __getobj__
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
module Hooks
|
18
|
+
def after mid, *args, &blk
|
19
|
+
self.class.after mid, *args, &blk
|
20
|
+
end
|
21
|
+
|
22
|
+
def after_all &blk
|
23
|
+
self.class.after_all &blk
|
24
|
+
end
|
25
|
+
|
26
|
+
def before mid, *args, &blk
|
27
|
+
self.class.before mid, *args, &blk
|
28
|
+
end
|
29
|
+
|
30
|
+
def before_all &blk
|
31
|
+
self.class.before_all &blk
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
def execute_call container, *args
|
36
|
+
executor = get_executor(container)
|
37
|
+
result = nil
|
38
|
+
if executor.respond_to? :each
|
39
|
+
executor.each do |e|
|
40
|
+
result = e.send :call, *args if proc?(e)
|
41
|
+
result = e.send(:new, *args).call if class?(e)
|
42
|
+
end
|
43
|
+
return result
|
44
|
+
end
|
45
|
+
|
46
|
+
return executor.send :call, *args if proc?(executor)
|
47
|
+
return executor.send(:new, *args).call if class?(executor)
|
48
|
+
end
|
49
|
+
|
50
|
+
def get_executor container
|
51
|
+
return nil unless container
|
52
|
+
|
53
|
+
# The content is a proc or a class
|
54
|
+
return container if proc?(container) or class?(container)
|
55
|
+
|
56
|
+
# The content is an array with an array filled with a regex and a proc or a class
|
57
|
+
if array?(container) and regexp?(container)
|
58
|
+
matched = regexp_elements(container).select {|array| get_regexp(array) =~ @method}
|
59
|
+
return matched.collect {|array| get_proc_or_class(array)} unless matched.empty?
|
60
|
+
end
|
61
|
+
|
62
|
+
hash?(container) ? container[@method_symbol] : container
|
63
|
+
end
|
64
|
+
|
65
|
+
def regexp_elements array
|
66
|
+
elements = array.collect {|sub_array| array_with_regex?(sub_array) ? sub_array : nil}
|
67
|
+
compacted_array = elements.compact
|
68
|
+
compacted_array.nil? ? [] : compacted_array
|
69
|
+
end
|
70
|
+
|
71
|
+
def get_regexp array
|
72
|
+
array.detect {|element| element.class == Regexp}
|
73
|
+
end
|
74
|
+
|
75
|
+
def get_proc_or_class array
|
76
|
+
array.detect {|element| proc?(element) or class?(element)}
|
77
|
+
end
|
78
|
+
|
79
|
+
def array_with_regex? array
|
80
|
+
array.class == Array and array.size == 2 and not get_regexp(array).nil?
|
81
|
+
end
|
82
|
+
|
83
|
+
def proc? block; block and block.class == Proc end
|
84
|
+
def class? param; param and param.class == Class end
|
85
|
+
def array? param; param and param.class == Array end
|
86
|
+
def hash? param; param and param.class == Hash end
|
87
|
+
def regexp? array; array and not regexp_elements(array).empty? end
|
88
|
+
end
|
89
|
+
end
|
data/proxeze.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{proxeze}
|
8
|
-
s.version = "1.
|
8
|
+
s.version = "1.1.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Jason Rogers"]
|
12
|
-
s.date = %q{2011-02-
|
12
|
+
s.date = %q{2011-02-19}
|
13
13
|
s.description = %q{A basic proxy/delegate framework for Ruby that will allow you to wrap any object with a proxy instance. For more information about the Proxy and Delegate patterns, check out http://en.wikipedia.org/wiki/Proxy_pattern and http://en.wikipedia.org/wiki/Delegation_pattern respectively.}
|
14
14
|
s.email = %q{jacaetevha@gmail.com}
|
15
15
|
s.extra_rdoc_files = [
|
@@ -32,7 +32,11 @@ Gem::Specification.new do |s|
|
|
32
32
|
"examples/sinatra/views/index.haml",
|
33
33
|
"examples/sinatra/views/layout.haml",
|
34
34
|
"lib/proxeze.rb",
|
35
|
+
"lib/proxeze/class_methods.rb",
|
36
|
+
"lib/proxeze/delegator_blocks.rb",
|
37
|
+
"lib/proxeze/instance_methods.rb",
|
35
38
|
"proxeze.gemspec",
|
39
|
+
"run-rvm-specs",
|
36
40
|
"spec/definitions.rb",
|
37
41
|
"spec/proxeze_spec.rb",
|
38
42
|
"spec/spec_helper.rb"
|
data/run-rvm-specs
ADDED
data/spec/definitions.rb
CHANGED
@@ -52,6 +52,14 @@ class ClassWithOverriddenObjectMethod
|
|
52
52
|
def self.hash; 17; end
|
53
53
|
end
|
54
54
|
|
55
|
+
class ClassWhereinWeMeetBeforeBlocks
|
56
|
+
def foo; 1; end
|
57
|
+
def bar; 2.0; end
|
58
|
+
def baz arg
|
59
|
+
(arg.to_f / foo) * bar
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
55
63
|
class Category
|
56
64
|
attr_accessor :categories
|
57
65
|
attr_reader :name
|
data/spec/proxeze_spec.rb
CHANGED
@@ -1,6 +1,12 @@
|
|
1
1
|
require File.dirname(__FILE__) + '/spec_helper'
|
2
2
|
require 'definitions'
|
3
3
|
|
4
|
+
class Symbol
|
5
|
+
def <=> other
|
6
|
+
self.to_s <=> other.to_s
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
4
10
|
shared_examples_for "all wrapped classes" do
|
5
11
|
it "should wrap the class>>#new method so we get an instance of the proxy instead" do
|
6
12
|
Proxeze.proxy Testing::NestedClass
|
@@ -167,4 +173,110 @@ describe Proxeze do
|
|
167
173
|
Proxeze::ClassWithOverriddenObjectMethod.should respond_to(:hash)
|
168
174
|
Proxeze::ClassWithOverriddenObjectMethod.hash.should == 17
|
169
175
|
end
|
176
|
+
|
177
|
+
it "should run 'before' callbacks" do
|
178
|
+
baz_method_args = nil
|
179
|
+
Proxeze.proxy( ClassWhereinWeMeetBeforeBlocks ) do
|
180
|
+
before :baz do |*args|
|
181
|
+
baz_method_args = args.last
|
182
|
+
end
|
183
|
+
end
|
184
|
+
instance = ClassWhereinWeMeetBeforeBlocks.new
|
185
|
+
instance.foo.should == 1
|
186
|
+
instance.bar.should == 2.0
|
187
|
+
instance.baz(2).should == 4.0
|
188
|
+
baz_method_args.should == [2]
|
189
|
+
end
|
190
|
+
|
191
|
+
it "should run 'before_all' callbacks" do
|
192
|
+
callbacks = {}
|
193
|
+
Proxeze.proxy( ClassWhereinWeMeetBeforeBlocks ) do
|
194
|
+
before_all do |*args|
|
195
|
+
target, mid, arguments = *args
|
196
|
+
callbacks[mid] = arguments
|
197
|
+
end
|
198
|
+
end
|
199
|
+
instance = ClassWhereinWeMeetBeforeBlocks.new
|
200
|
+
instance.foo.should == 1
|
201
|
+
instance.bar.should == 2.0
|
202
|
+
instance.baz(2).should == 4.0
|
203
|
+
|
204
|
+
callbacks.keys.sort.should == [:bar, :baz, :foo]
|
205
|
+
callbacks[:foo].should == []
|
206
|
+
callbacks[:bar].should == []
|
207
|
+
callbacks[:baz].should == [2]
|
208
|
+
end
|
209
|
+
|
210
|
+
it "should run 'after' callbacks" do
|
211
|
+
callbacks = {}
|
212
|
+
Proxeze.proxy( ClassWhereinWeMeetBeforeBlocks ) do
|
213
|
+
after :foo do |*args|
|
214
|
+
callbacks[:foo] = args.last
|
215
|
+
args[-2]
|
216
|
+
end
|
217
|
+
end
|
218
|
+
instance = ClassWhereinWeMeetBeforeBlocks.new
|
219
|
+
instance.foo.should == 1
|
220
|
+
instance.bar.should == 2.0
|
221
|
+
instance.baz(2).should == 4.0
|
222
|
+
|
223
|
+
callbacks.keys.sort.should == [:foo]
|
224
|
+
callbacks[:foo].should == []
|
225
|
+
end
|
226
|
+
|
227
|
+
it "should run 'after_all' callbacks" do
|
228
|
+
callbacks = {}
|
229
|
+
Proxeze.proxy( ClassWhereinWeMeetBeforeBlocks ) do
|
230
|
+
after_all do |*args|
|
231
|
+
target, result, mid, arguments = *args
|
232
|
+
callbacks[mid] = result
|
233
|
+
result * 2
|
234
|
+
end
|
235
|
+
end
|
236
|
+
instance = ClassWhereinWeMeetBeforeBlocks.new
|
237
|
+
instance.foo.should == 2
|
238
|
+
instance.bar.should == 4.0
|
239
|
+
instance.baz(2).should == 8.0
|
240
|
+
|
241
|
+
callbacks.keys.sort.should == [:bar, :baz, :foo]
|
242
|
+
callbacks[:foo].should == 1
|
243
|
+
callbacks[:bar].should == 2.0
|
244
|
+
callbacks[:baz].should == 4.0
|
245
|
+
end
|
246
|
+
|
247
|
+
it "should be able to add hooks to a proxied instance" do
|
248
|
+
a = Proxeze.for [0, 1, 3, 2, 5, 4] do
|
249
|
+
before :reverse do |*args|
|
250
|
+
target, mid, arguments = *args
|
251
|
+
target << target.length
|
252
|
+
end
|
253
|
+
end
|
254
|
+
a.reverse.should == [6, 4, 5, 2, 3, 1, 0]
|
255
|
+
|
256
|
+
a.after :sort do |*args|
|
257
|
+
target, result, arguments = *args
|
258
|
+
result << result.length
|
259
|
+
end
|
260
|
+
a.sort.should == [0, 1, 2, 3, 4, 5, 6, 7]
|
261
|
+
|
262
|
+
# make sure that other instances of Arrays don't get the
|
263
|
+
# behavior added to the proxied instances above
|
264
|
+
[0, 1, 3, 2, 5, 4].sort.reverse.should == [5, 4, 3, 2, 1, 0]
|
265
|
+
[1, 3, 2].reverse.should == [2, 3, 1]
|
266
|
+
Proxeze.for([1, 3, 2]).reverse.should == [2, 3, 1]
|
267
|
+
end
|
268
|
+
|
269
|
+
it "should accept a class for the callbacks" do
|
270
|
+
class SortPerformer
|
271
|
+
def initialize object, result = nil, method = nil, args = nil
|
272
|
+
@object = object; @result = result; @method = method, @args = args
|
273
|
+
end
|
274
|
+
|
275
|
+
def call; @object.sort! end
|
276
|
+
end
|
277
|
+
p = Proxeze.for [1, 2, 3] do
|
278
|
+
after :reverse, SortPerformer
|
279
|
+
end
|
280
|
+
p.reverse.should == [1, 2, 3]
|
281
|
+
end
|
170
282
|
end
|
metadata
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
name: proxeze
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease:
|
5
|
-
version: 1.
|
5
|
+
version: 1.1.0
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Jason Rogers
|
@@ -10,7 +10,7 @@ autorequire:
|
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
12
|
|
13
|
-
date: 2011-02-
|
13
|
+
date: 2011-02-19 00:00:00 -05:00
|
14
14
|
default_executable:
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
@@ -170,7 +170,11 @@ files:
|
|
170
170
|
- examples/sinatra/views/index.haml
|
171
171
|
- examples/sinatra/views/layout.haml
|
172
172
|
- lib/proxeze.rb
|
173
|
+
- lib/proxeze/class_methods.rb
|
174
|
+
- lib/proxeze/delegator_blocks.rb
|
175
|
+
- lib/proxeze/instance_methods.rb
|
173
176
|
- proxeze.gemspec
|
177
|
+
- run-rvm-specs
|
174
178
|
- spec/definitions.rb
|
175
179
|
- spec/proxeze_spec.rb
|
176
180
|
- spec/spec_helper.rb
|
@@ -188,7 +192,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
188
192
|
requirements:
|
189
193
|
- - ">="
|
190
194
|
- !ruby/object:Gem::Version
|
191
|
-
hash:
|
195
|
+
hash: 1558564409570473253
|
192
196
|
segments:
|
193
197
|
- 0
|
194
198
|
version: "0"
|