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 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.5.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 target class' #new
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, redefine_new_method = true
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.5.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-04}
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
- proxy_class = Proxeze.proxy ClassWithClassMethods
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.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-04 00:00:00 -05:00
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: -744132594254975345
191
+ hash: -4275161442413397534
192
192
  segments:
193
193
  - 0
194
194
  version: "0"