proxeze 0.5.0 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +24 -1
- data/VERSION +1 -1
- data/lib/proxeze.rb +34 -11
- data/proxeze.gemspec +2 -2
- data/spec/definitions.rb +9 -0
- data/spec/proxeze_spec.rb +14 -1
- metadata +3 -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, 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.
|
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
|
|
@@ -95,6 +95,29 @@ Of course, you can proxy the class and all subsequent instances even after you'v
|
|
95
95
|
a.class # => Proxeze::A
|
96
96
|
a.__getobj__.class # => A
|
97
97
|
|
98
|
+
== Proxying Classes
|
99
|
+
As we said before when you proxy a class, generally speaking, the #new method will be aliased so that all subsequent instances of the class will be proxied instances. What is the #new method? It's just an instance method of your class. What about all of the other instance methods of the class? In large part, they are available also, though there are mechanisms for making them unavailable. Consider this scenario:
|
100
|
+
|
101
|
+
class A
|
102
|
+
def self.foo; 1; end
|
103
|
+
def self.bar; 1; end
|
104
|
+
end
|
105
|
+
|
106
|
+
I can tell Proxeze to allow for the invocation of the #foo method, but not the #bar method like this:
|
107
|
+
|
108
|
+
Proxeze.proxy A, :exclude_class_methods => [:bar]
|
109
|
+
|
110
|
+
If you don't specify the :exclude_class_methods option, all class methods defined in your class will be available.
|
111
|
+
|
112
|
+
The special case to this is that class methods defined in Object are not proxied, and there are a few class methods in the Delegate framework that are excluded. What if you've overridden a class method that is already defined in Object, like #hash? Well you can *include* that by sending the :include_class_methods option:
|
113
|
+
|
114
|
+
class A
|
115
|
+
def self.hash; 17; end
|
116
|
+
end
|
117
|
+
Proxeze.proxy A, :include_class_methods => [:hash]
|
118
|
+
|
119
|
+
Note: I don't recommend overriding the #hash method on your class, this serves only as an example.
|
120
|
+
|
98
121
|
== Supported Ruby versions
|
99
122
|
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.
|
100
123
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
1.0.0
|
data/lib/proxeze.rb
CHANGED
@@ -5,15 +5,31 @@ module Proxeze
|
|
5
5
|
def self.class_defined? name
|
6
6
|
const_defined? name, false
|
7
7
|
end
|
8
|
+
|
9
|
+
def self.object_methods
|
10
|
+
Object.methods
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.class_methods_from target_class
|
14
|
+
target_class.methods
|
15
|
+
end
|
8
16
|
else
|
9
17
|
def self.class_defined? name
|
10
18
|
const_defined? name
|
11
19
|
end
|
20
|
+
|
21
|
+
def self.object_methods
|
22
|
+
Object.methods.collect{|e| e.to_sym}
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.class_methods_from target_class
|
26
|
+
target_class.methods.collect{|e| e.to_sym}
|
27
|
+
end
|
12
28
|
end
|
13
29
|
|
14
30
|
# Create a proxy class for the given target class.
|
15
|
-
# If redefine_new_method is false, the
|
16
|
-
# method will not be reimplemented.
|
31
|
+
# If the :redefine_new_method option is false, the
|
32
|
+
# target class' #new method will not be reimplemented.
|
17
33
|
#
|
18
34
|
# When the target class' #new method is reimplemented,
|
19
35
|
# all subsequent calls to #new on that class will return
|
@@ -23,25 +39,28 @@ module Proxeze
|
|
23
39
|
#
|
24
40
|
# Typically, only the Proxeze.for method should pass in
|
25
41
|
# redefine_new_method=false here.
|
26
|
-
def self.proxy target_class,
|
42
|
+
def self.proxy target_class, opts = {}
|
43
|
+
options = default_proxy_options.merge opts
|
27
44
|
cls_name = target_class.name.gsub( '::', '' )
|
28
45
|
unless self.class_defined? cls_name
|
29
46
|
cls = DelegateClass target_class
|
30
47
|
cls.send :include, self
|
31
48
|
self.const_set cls_name, cls
|
49
|
+
|
50
|
+
excluded_class_methods = object_methods + [:new, :public_api, :delegating_block] + options[:exclude_class_methods]
|
51
|
+
(class_methods_from(target_class) - excluded_class_methods + options[:include_class_methods]).each do |method|
|
52
|
+
blk = class_delegating_block(method, target_class)
|
53
|
+
(class << cls; self; end).instance_eval do
|
54
|
+
define_method(method, &blk)
|
55
|
+
end
|
56
|
+
end
|
32
57
|
end
|
33
58
|
|
34
59
|
cls = self.const_get cls_name
|
35
|
-
(target_class.methods - Object.methods - [:new, :public_api, :delegating_block]).each do |method|
|
36
|
-
blk = class_delegating_block(method, target_class)
|
37
|
-
(class << cls; self; end).instance_eval do
|
38
|
-
define_method(method, &blk)
|
39
|
-
end
|
40
|
-
end
|
41
60
|
|
42
61
|
# we have to collect the methods as Strings here because
|
43
62
|
# 1.9 changed the implementation to return Symbols instead of Strings
|
44
|
-
if redefine_new_method && !target_class.methods.collect{|e| e.to_s}.include?('new_with_extra_behavior')
|
63
|
+
if options[:redefine_new_method] && !target_class.methods.collect{|e| e.to_s}.include?('new_with_extra_behavior')
|
45
64
|
meta = class << target_class; self; end
|
46
65
|
meta.class_eval %Q{
|
47
66
|
def new_with_extra_behavior *args, &blk
|
@@ -55,6 +74,10 @@ module Proxeze
|
|
55
74
|
self.const_get cls_name
|
56
75
|
end
|
57
76
|
|
77
|
+
def self.default_proxy_options
|
78
|
+
{:redefine_new_method => true, :exclude_class_methods => [], :include_class_methods => []}
|
79
|
+
end
|
80
|
+
|
58
81
|
def self.class_delegating_block mid, target
|
59
82
|
lambda do |*args, &block|
|
60
83
|
begin
|
@@ -67,7 +90,7 @@ module Proxeze
|
|
67
90
|
|
68
91
|
# create a proxy object for the given object
|
69
92
|
def self.for object
|
70
|
-
self.proxy( object.class, false ).new( object )
|
93
|
+
self.proxy( object.class, :redefine_new_method => false ).new( object )
|
71
94
|
end
|
72
95
|
|
73
96
|
# create a new proxy around a clone of my delegate object
|
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 = "0.
|
8
|
+
s.version = "1.0.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-05}
|
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 = [
|
data/spec/definitions.rb
CHANGED
@@ -43,6 +43,15 @@ class ClassWithClassMethods
|
|
43
43
|
def self.foo; 1; end
|
44
44
|
end
|
45
45
|
|
46
|
+
class ClassWithClassMethods_SomeOfWhichWillBeExcluded
|
47
|
+
def self.foo; 1; end
|
48
|
+
def self.bar; 2; end
|
49
|
+
end
|
50
|
+
|
51
|
+
class ClassWithOverriddenObjectMethod
|
52
|
+
def self.hash; 17; end
|
53
|
+
end
|
54
|
+
|
46
55
|
class Category
|
47
56
|
attr_accessor :categories
|
48
57
|
attr_reader :name
|
data/spec/proxeze_spec.rb
CHANGED
@@ -150,8 +150,21 @@ describe Proxeze do
|
|
150
150
|
end
|
151
151
|
|
152
152
|
it "should proxy class methods also" do
|
153
|
-
|
153
|
+
Proxeze.proxy ClassWithClassMethods
|
154
154
|
Proxeze::ClassWithClassMethods.should respond_to(:foo)
|
155
155
|
Proxeze::ClassWithClassMethods.foo.should == ClassWithClassMethods.foo
|
156
156
|
end
|
157
|
+
|
158
|
+
it "should not proxy class methods that are marked as excluded" do
|
159
|
+
Proxeze.proxy ClassWithClassMethods_SomeOfWhichWillBeExcluded, :exclude_class_methods => [:foo]
|
160
|
+
Proxeze::ClassWithClassMethods_SomeOfWhichWillBeExcluded.should_not respond_to(:foo)
|
161
|
+
Proxeze::ClassWithClassMethods_SomeOfWhichWillBeExcluded.should respond_to(:bar)
|
162
|
+
Proxeze::ClassWithClassMethods_SomeOfWhichWillBeExcluded.bar.should == ClassWithClassMethods_SomeOfWhichWillBeExcluded.bar
|
163
|
+
end
|
164
|
+
|
165
|
+
it "should proxy class methods also" do
|
166
|
+
Proxeze.proxy ClassWithOverriddenObjectMethod, :include_class_methods => [:hash]
|
167
|
+
Proxeze::ClassWithOverriddenObjectMethod.should respond_to(:hash)
|
168
|
+
Proxeze::ClassWithOverriddenObjectMethod.hash.should == 17
|
169
|
+
end
|
157
170
|
end
|
metadata
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
name: proxeze
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease:
|
5
|
-
version: 0.
|
5
|
+
version: 1.0.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-05 00:00:00 -05:00
|
14
14
|
default_executable:
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
@@ -188,7 +188,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
188
188
|
requirements:
|
189
189
|
- - ">="
|
190
190
|
- !ruby/object:Gem::Version
|
191
|
-
hash: -
|
191
|
+
hash: -4275161442413397534
|
192
192
|
segments:
|
193
193
|
- 0
|
194
194
|
version: "0"
|