proxified 0.1.0 → 1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.dockerignore +1 -0
- data/.env.remote_dev +5 -0
- data/.rubocop.yml +8 -0
- data/.travis.yml +2 -2
- data/Dockerfile +24 -4
- data/Gemfile.lock +64 -59
- data/Guardfile +3 -1
- data/README.md +119 -75
- data/bin/compose_up +4 -0
- data/bin/console +1 -0
- data/docker-compose.yml +1 -3
- data/lib/proxified/version.rb +1 -1
- data/lib/proxified.rb +477 -69
- data/proxified.gemspec +13 -9
- metadata +17 -21
data/lib/proxified.rb
CHANGED
@@ -3,39 +3,46 @@
|
|
3
3
|
require 'active_support'
|
4
4
|
require 'active_support/core_ext'
|
5
5
|
|
6
|
-
#
|
6
|
+
# Allows to _proxify_ and _unproxify_ any instance method of a class with
|
7
|
+
# custom code and to inherit and change the behaviour down the class hierarchy.
|
8
|
+
#
|
9
|
+
# The global methods allow to dinamically _proxify_ and _unproxify_ a class or
|
10
|
+
# an object injecting Proxified in the class or the object's singleton class.
|
11
|
+
#
|
12
|
+
# This makes possible to dinamically wrap a proxy around any class with no need
|
13
|
+
# for the class to know it, and to change the behaviour of one or more objects
|
14
|
+
# without side effects on other objects of the same class.
|
7
15
|
module Proxified
|
8
16
|
extend ::ActiveSupport::Concern
|
9
17
|
|
10
18
|
included do
|
11
|
-
# Stores the methods to
|
19
|
+
# Stores the methods to _proxify_ allowing descendants to override them
|
12
20
|
# without affecting the parent.
|
13
21
|
class_attribute :proxified_methods, default: {}, instance_accessor: false
|
14
22
|
end
|
15
23
|
|
16
24
|
class_methods do
|
17
|
-
# For each +method+ in +methods+, defines a
|
18
|
-
# the given +block+ when +method+ is called, or raises ArgumentError
|
19
|
-
# block or no
|
25
|
+
# For each +method+ in +methods+, defines a _proxified_ _method_ that
|
26
|
+
# runs the given +block+ when +method+ is called, or raises ArgumentError
|
27
|
+
# if no +block+ or no +methods+ are given.
|
20
28
|
#
|
21
|
-
# In order to
|
29
|
+
# In order not to change the class interface, a method is only _proxified_
|
22
30
|
# when the corresponding instance method is defined (before or after the
|
23
|
-
# proxy definition), while a
|
31
|
+
# proxy definition), while a _proxified_ _method_ is removed whenever the
|
24
32
|
# corresponding instance method is removed from the class. Moreover, the
|
25
|
-
#
|
26
|
-
# +block+ should take the same arguments as the original +methods
|
27
|
-
#
|
28
|
-
#
|
33
|
+
# _proxified_ _methods_ take the arguments specified by the +block+, so the
|
34
|
+
# +block+ should take the same arguments as the original +methods+.
|
35
|
+
# Finally, it's possible to call the original +methods+ invoking +super+
|
36
|
+
# inside the +block+.
|
29
37
|
#
|
30
|
-
# The
|
31
|
-
# automatically to the class only the first time a
|
32
|
-
# defined within that class
|
33
|
-
#
|
34
|
-
#
|
35
|
-
# +proxified_method+ get the parent's proxy module.
|
38
|
+
# The _proxified_ _methods_ are defined in a proxy module that is
|
39
|
+
# automatically prepended to the class only the first time a _proxified_
|
40
|
+
# _method_ is defined within that class. In this way, descendants who
|
41
|
+
# redefine a _proxified_ _method_ get their own proxy module, while those
|
42
|
+
# who do not redefine a _proxified_ _method_ get the parent's proxy module.
|
36
43
|
#
|
37
|
-
# Beware: if a child redefines a
|
38
|
-
# parent's
|
44
|
+
# Beware: if a child redefines a _proxified_ _method_ to call +super+, the
|
45
|
+
# parent's _proxified_ _method_ will be called.
|
39
46
|
#
|
40
47
|
# ======Examples
|
41
48
|
#
|
@@ -53,7 +60,7 @@ module Proxified
|
|
53
60
|
# end
|
54
61
|
#
|
55
62
|
# def welcome(name)
|
56
|
-
# puts "
|
63
|
+
# puts "welcome #{name}!"
|
57
64
|
# end
|
58
65
|
#
|
59
66
|
# def goodbye(name)
|
@@ -61,50 +68,54 @@ module Proxified
|
|
61
68
|
# end
|
62
69
|
# end
|
63
70
|
#
|
64
|
-
# A.ancestors => [A::Proxy, A, Proxified, ...]
|
71
|
+
# A.ancestors # => [A::Proxy, A, Proxified, ...]
|
65
72
|
#
|
66
73
|
# a = A.new
|
67
|
-
# a.welcome('jack') => 'checking jack'; 'welcome jack!';
|
68
|
-
# a.goodbye('jack') => 'checking jack'; 'goodbye jack!';
|
69
|
-
# a.welcome => raises ArgumentError
|
70
|
-
# a.check('jack') => 'checking jack'
|
74
|
+
# a.welcome('jack') # => 'checking jack'; 'welcome jack!';
|
75
|
+
# a.goodbye('jack') # => 'checking jack'; 'goodbye jack!';
|
76
|
+
# a.welcome # => raises ArgumentError
|
77
|
+
# a.check('jack') # => 'checking jack' (not proxified)
|
78
|
+
#
|
71
79
|
#
|
72
80
|
# Just inheriting:
|
73
81
|
# class B < A; end
|
74
82
|
#
|
75
|
-
# B.ancestors => [B, A::Proxy, A, Proxified, ...]
|
83
|
+
# B.ancestors # => [B, A::Proxy, A, Proxified, ...]
|
76
84
|
#
|
77
85
|
# b = B.new
|
78
|
-
# b.welcome('jack') => 'checking jack'; 'welcome jack!';
|
79
|
-
# b.goodbye('jack') => 'checking jack'; 'goodbye jack!';
|
86
|
+
# b.welcome('jack') # => 'checking jack'; 'welcome jack!';
|
87
|
+
# b.goodbye('jack') # => 'checking jack'; 'goodbye jack!';
|
80
88
|
#
|
81
|
-
#
|
89
|
+
#
|
90
|
+
# Inheriting and redefining a _proxified_ _method_:
|
82
91
|
# class C < A
|
83
92
|
# def welcome(name)
|
84
93
|
# puts "welcome #{name.upcase}!"
|
85
94
|
# end
|
86
95
|
# end
|
87
96
|
#
|
88
|
-
# C.ancestors => [C::Proxy, C, A::Proxy, A, Proxified, ...]
|
97
|
+
# C.ancestors # => [C::Proxy, C, A::Proxy, A, Proxified, ...]
|
89
98
|
#
|
90
99
|
# c = C.new
|
91
|
-
# c.welcome('jack') => 'checking jack'; 'welcome JACK!';
|
92
|
-
# c.goodbye('jack') => 'checking jack'; 'goodbye jack!';
|
100
|
+
# c.welcome('jack') # => 'checking jack'; 'welcome JACK!';
|
101
|
+
# c.goodbye('jack') # => 'checking jack'; 'goodbye jack!';
|
102
|
+
#
|
93
103
|
#
|
94
|
-
#
|
104
|
+
# Inheriting and _reproxifing_ a _proxified_ _method_:
|
95
105
|
# class D < A
|
96
106
|
# proxify :welcome do |name|
|
97
107
|
# super(name.upcase)
|
98
108
|
# end
|
99
109
|
# end
|
100
110
|
#
|
101
|
-
# D.ancestors => [D::Proxy, D, A::Proxy, A, Proxified, ...]
|
111
|
+
# D.ancestors # => [D::Proxy, D, A::Proxy, A, Proxified, ...]
|
102
112
|
#
|
103
113
|
# d = D.new
|
104
|
-
# d.welcome('jack') => 'checking JACK'; 'welcome JACK!';
|
105
|
-
# d.goodbye('jack') => 'checking jack'; 'goodbye jack!';
|
114
|
+
# d.welcome('jack') # => 'checking JACK'; 'welcome JACK!';
|
115
|
+
# d.goodbye('jack') # => 'checking jack'; 'goodbye jack!';
|
116
|
+
#
|
106
117
|
#
|
107
|
-
#
|
118
|
+
# Inheriting, _reproxifing_ and redefining a _proxified_ _method_:
|
108
119
|
# class E < A
|
109
120
|
# proxify :welcome do |name|
|
110
121
|
# super(name.upcase)
|
@@ -115,13 +126,14 @@ module Proxified
|
|
115
126
|
# end
|
116
127
|
# end
|
117
128
|
#
|
118
|
-
# E.ancestors => [E::Proxy, E, A::Proxy, A, Proxified, ...]
|
129
|
+
# E.ancestors # => [E::Proxy, E, A::Proxy, A, Proxified, ...]
|
119
130
|
#
|
120
131
|
# e = E.new
|
121
|
-
# e.welcome('jack') => 'hello JACK!';
|
122
|
-
# e.goodbye('jack') => 'checking jack'; 'goodbye jack!';
|
132
|
+
# e.welcome('jack') # => 'hello JACK!';
|
133
|
+
# e.goodbye('jack') # => 'checking jack'; 'goodbye jack!';
|
123
134
|
#
|
124
|
-
#
|
135
|
+
#
|
136
|
+
# Inheriting and redefining a _proxified_ _method_ to call +super+:
|
125
137
|
# class F < A
|
126
138
|
# def welcome(name)
|
127
139
|
# super(name)
|
@@ -129,11 +141,11 @@ module Proxified
|
|
129
141
|
# end
|
130
142
|
# end
|
131
143
|
#
|
132
|
-
# F.ancestors => [F::Proxy, F, A::Proxy, A, Proxified, ...]
|
144
|
+
# F.ancestors # => [F::Proxy, F, A::Proxy, A, Proxified, ...]
|
133
145
|
#
|
134
146
|
# f = F.new
|
135
|
-
# f.welcome('
|
136
|
-
# f.goodbye('jack') => 'checking jack'; 'goodbye jack!';
|
147
|
+
# f.welcome('jack') # => 'checking jack'; 'checking jack'; 'welcome jack!'; 'hi';
|
148
|
+
# f.goodbye('jack') # => 'checking jack'; 'goodbye jack!';
|
137
149
|
def proxify(*methods, &block)
|
138
150
|
raise ArgumentError, 'no block given' unless block_given?
|
139
151
|
raise ArgumentError, 'no methods given' if methods.empty?
|
@@ -144,54 +156,97 @@ module Proxified
|
|
144
156
|
end
|
145
157
|
end
|
146
158
|
|
147
|
-
#
|
159
|
+
# Unproxifies the given +methods+ removing them from the proxy module. If no
|
160
|
+
# +methods+ are given, all the _proxified_ _methods_ are removed.
|
148
161
|
#
|
149
162
|
# ======Examples
|
150
163
|
#
|
151
164
|
# class A
|
152
165
|
# include Proxified
|
153
166
|
#
|
154
|
-
# proxify :
|
155
|
-
#
|
156
|
-
# super(name)
|
167
|
+
# proxify :foo, :bar, :biz do
|
168
|
+
# super().upcase
|
157
169
|
# end
|
158
170
|
#
|
159
|
-
# def
|
160
|
-
#
|
171
|
+
# def foo
|
172
|
+
# 'foo'
|
161
173
|
# end
|
162
174
|
#
|
163
|
-
# def
|
164
|
-
#
|
175
|
+
# def bar
|
176
|
+
# 'bar'
|
165
177
|
# end
|
166
178
|
#
|
167
|
-
# def
|
168
|
-
#
|
179
|
+
# def biz
|
180
|
+
# 'biz'
|
169
181
|
# end
|
170
182
|
# end
|
171
183
|
#
|
172
|
-
#
|
173
|
-
# a.
|
174
|
-
# a.
|
184
|
+
# A.unproxify(:foo)
|
185
|
+
# a.foo # => 'foo;
|
186
|
+
# a.bar # => 'BAR'
|
187
|
+
# a.biz # => 'BIZ'
|
175
188
|
#
|
176
|
-
#
|
177
|
-
#
|
178
|
-
# a.
|
179
|
-
# a.
|
189
|
+
# A.unproxify
|
190
|
+
# a.foo # => 'foo;
|
191
|
+
# a.bar # => 'bar'
|
192
|
+
# a.biz # => 'biz'
|
180
193
|
def unproxify(*methods)
|
194
|
+
methods = proxified_methods.keys if methods.empty?
|
195
|
+
|
181
196
|
self.proxified_methods = proxified_methods.except(*methods)
|
182
197
|
|
183
198
|
methods.each { |method| remove_proxy_method(method) }
|
184
199
|
end
|
185
200
|
|
186
|
-
#
|
187
|
-
|
188
|
-
|
201
|
+
# If given no +method+, checks whether any instance method is _proxified_,
|
202
|
+
# otherwise it checks for the given +method+.
|
203
|
+
#
|
204
|
+
# ======Examples
|
205
|
+
#
|
206
|
+
# class A
|
207
|
+
# include Proxified
|
208
|
+
#
|
209
|
+
# proxify :foo, :bar do |name|
|
210
|
+
# super().upcase
|
211
|
+
# end
|
212
|
+
#
|
213
|
+
# def foo
|
214
|
+
# 'foo'
|
215
|
+
# end
|
216
|
+
#
|
217
|
+
# def bar
|
218
|
+
# 'bar'
|
219
|
+
# end
|
220
|
+
#
|
221
|
+
# def biz
|
222
|
+
# 'biz'
|
223
|
+
# end
|
224
|
+
# end
|
225
|
+
#
|
226
|
+
# A.proxified? # => true
|
227
|
+
# A.proxified?(:foo) # => true
|
228
|
+
# A.proxified?(:bar) # => true
|
229
|
+
# A.proxified?(:biz) # => false
|
230
|
+
#
|
231
|
+
# A.unproxify(:foo)
|
232
|
+
# A.proxified? # => true
|
233
|
+
# A.proxified?(:foo) # => false
|
234
|
+
# A.proxified?(:bar) # => true
|
235
|
+
# A.proxified?(:biz) # => false
|
236
|
+
#
|
237
|
+
# A.unproxify(:bar)
|
238
|
+
# A.proxified? # => false
|
239
|
+
# A.proxified?(:foo) # => false
|
240
|
+
# A.proxified?(:bar) # => false
|
241
|
+
# A.proxified?(:biz) # => false
|
242
|
+
def proxified?(method = nil)
|
243
|
+
method.nil? ? proxified_methods.any? : method.in?(proxified_methods)
|
189
244
|
end
|
190
245
|
|
191
246
|
private
|
192
247
|
|
193
248
|
# Adds the +method+ to the proxy only if it has been proxified.
|
194
|
-
def method_added(method)
|
249
|
+
def method_added(method) # :nodoc:
|
195
250
|
# Don't do nothing if the attribute is not defined and initialized yet
|
196
251
|
return unless respond_to?(:proxified_methods) && proxified_methods?
|
197
252
|
|
@@ -199,7 +254,7 @@ module Proxified
|
|
199
254
|
end
|
200
255
|
|
201
256
|
# Unproxifies the +method+ only if it has been proxified.
|
202
|
-
def method_removed(method)
|
257
|
+
def method_removed(method) # :nodoc:
|
203
258
|
# Don't do nothing if the attribute is not defined and initialized yet
|
204
259
|
return unless respond_to?(:proxified_methods) && proxified_methods?
|
205
260
|
|
@@ -207,22 +262,375 @@ module Proxified
|
|
207
262
|
end
|
208
263
|
|
209
264
|
# Defines the +method+ in the proxy module.
|
210
|
-
def add_proxy_method(method)
|
265
|
+
def add_proxy_method(method) # :nodoc:
|
211
266
|
# Redefine to avoid warnings if the method has already been defined
|
212
267
|
proxy.redefine_method(method, &proxified_methods[method])
|
213
268
|
end
|
214
269
|
|
215
270
|
# Removes the +method+ from the proxy module.
|
216
|
-
def remove_proxy_method(method)
|
271
|
+
def remove_proxy_method(method) # :nodoc:
|
217
272
|
proxy.remove_method(method) if proxy.method_defined?(method)
|
218
273
|
end
|
219
274
|
|
220
275
|
# Returns the proxy module prepending it only if it's not already present
|
221
276
|
# in this class.
|
222
|
-
def proxy
|
277
|
+
def proxy # :nodoc:
|
223
278
|
return const_get('Proxy', false) if const_defined?('Proxy', false)
|
224
279
|
|
225
280
|
const_set('Proxy', Module.new).tap { |proxy| prepend proxy }
|
226
281
|
end
|
227
282
|
end
|
228
283
|
end
|
284
|
+
|
285
|
+
# Injects Proxified in the +receiver+ and _proxifies_ the given +methods+, or
|
286
|
+
# raises ArgumentError if no +block+ or no +methods+ are given.
|
287
|
+
#
|
288
|
+
# +receiver+ can be a class or an ordinary object.
|
289
|
+
#
|
290
|
+
# If +receiver+ is a class, it is equivalent to including Proxified and calling
|
291
|
+
# .proxify.
|
292
|
+
#
|
293
|
+
# If +receiver+ is an object, Proxified is injected in its singleton class and
|
294
|
+
# other objects of the same class will not be affected.
|
295
|
+
#
|
296
|
+
# If +receiver+ is an object of a _proxified_ class, the class' proxy is
|
297
|
+
# overridden but other objects of the class will not be affected.
|
298
|
+
#
|
299
|
+
# See Proxified.proxify for further details.
|
300
|
+
#
|
301
|
+
# ======Examples
|
302
|
+
#
|
303
|
+
# _Proxifying_ a class:
|
304
|
+
# class A
|
305
|
+
# def foo
|
306
|
+
# 'foo'
|
307
|
+
# end
|
308
|
+
#
|
309
|
+
# def bar
|
310
|
+
# 'bar'
|
311
|
+
# end
|
312
|
+
# end
|
313
|
+
#
|
314
|
+
# a1, a2 = A.new, A.new
|
315
|
+
#
|
316
|
+
# Proxify(A, :foo) { super().upcase }
|
317
|
+
# a1.foo # => 'FOO'
|
318
|
+
# a2.foo # => 'FOO'
|
319
|
+
# a1.bar # => 'bar'
|
320
|
+
# a2.bar # => 'bar'
|
321
|
+
#
|
322
|
+
#
|
323
|
+
# _Proxifying_ an object:
|
324
|
+
# class B
|
325
|
+
# def foo
|
326
|
+
# 'foo'
|
327
|
+
# end
|
328
|
+
#
|
329
|
+
# def bar
|
330
|
+
# 'bar'
|
331
|
+
# end
|
332
|
+
# end
|
333
|
+
#
|
334
|
+
# b1, b2 = B.new, B.new
|
335
|
+
#
|
336
|
+
# Proxify(b1, :foo) { super().upcase }
|
337
|
+
# b1.foo # => 'FOO'
|
338
|
+
# b2.foo # => 'foo'
|
339
|
+
# b1.bar # => 'bar'
|
340
|
+
# b2.bar # => 'bar'
|
341
|
+
#
|
342
|
+
#
|
343
|
+
# _Reproxifying_ an object of a _proxified_ class:
|
344
|
+
# class C
|
345
|
+
# def foo
|
346
|
+
# 'foo'
|
347
|
+
# end
|
348
|
+
#
|
349
|
+
# def bar
|
350
|
+
# 'bar'
|
351
|
+
# end
|
352
|
+
# end
|
353
|
+
#
|
354
|
+
# c1, c2 = C.new, C.new
|
355
|
+
#
|
356
|
+
# Proxify(C, :foo, :bar) { super().upcase }
|
357
|
+
#
|
358
|
+
# # the class proxy is overridden
|
359
|
+
# Proxify(c1, :foo) { 'proxified' }
|
360
|
+
# c1.foo # => 'proxified'
|
361
|
+
# c2.foo # => 'FOO'
|
362
|
+
# c1.bar # => 'BAR'
|
363
|
+
# c2.bar # => 'BAR'
|
364
|
+
#
|
365
|
+
# # if super is called the class' proxy will also be called
|
366
|
+
# Proxify(c1, :foo) { "i am a proxified #{super()}"}
|
367
|
+
# c1.foo # => 'i am a proxified FOO'
|
368
|
+
# c2.foo # => 'FOO'
|
369
|
+
# c1.bar # => 'BAR'
|
370
|
+
# c2.bar # => 'BAR'
|
371
|
+
def Proxify(receiver, *methods, &block)
|
372
|
+
raise ArgumentError, 'no block given' unless block_given?
|
373
|
+
raise ArgumentError, 'no methods given' if methods.empty?
|
374
|
+
|
375
|
+
target = receiver.is_a?(Class) ? receiver : receiver.singleton_class
|
376
|
+
|
377
|
+
target.include(Proxified).proxify(*methods, &block)
|
378
|
+
end
|
379
|
+
|
380
|
+
# If the +receiver+ is _proxified_ unproxifies the given +methods+, or all the
|
381
|
+
# _proxified_ _methods_ if no +methods+ are given.
|
382
|
+
#
|
383
|
+
# +receiver+ can be a class or an ordinary object.
|
384
|
+
#
|
385
|
+
# If +receiver+ is an object of a _proxified_ class only its (eventual) proxy
|
386
|
+
# methods will be removed and the proxy of the class will not be affected.
|
387
|
+
#
|
388
|
+
# See Proxified.unproxify for further details.
|
389
|
+
#
|
390
|
+
# ======Examples
|
391
|
+
#
|
392
|
+
# _Unproxifying_ a _proxified_ class:
|
393
|
+
# class A
|
394
|
+
# def foo
|
395
|
+
# 'foo'
|
396
|
+
# end
|
397
|
+
#
|
398
|
+
# def bar
|
399
|
+
# 'bar'
|
400
|
+
# end
|
401
|
+
#
|
402
|
+
# def biz
|
403
|
+
# 'biz'
|
404
|
+
# end
|
405
|
+
# end
|
406
|
+
#
|
407
|
+
# a1, a2 = A.new, A.new
|
408
|
+
#
|
409
|
+
# Proxify(A, :foo, :bar, :biz) { super().upcase }
|
410
|
+
#
|
411
|
+
# Unproxify(A, :foo)
|
412
|
+
# a1.foo # => 'foo'
|
413
|
+
# a2.foo # => 'foo'
|
414
|
+
# a1.bar # => 'BAR'
|
415
|
+
# a2.bar # => 'BAR'
|
416
|
+
# a1.biz # => 'BIZ'
|
417
|
+
# a2.biz # => 'BIZ'
|
418
|
+
#
|
419
|
+
# Unproxify(A)
|
420
|
+
# a1.foo # => 'foo'
|
421
|
+
# a2.foo # => 'foo'
|
422
|
+
# a1.bar # => 'bar'
|
423
|
+
# a2.bar # => 'bar'
|
424
|
+
# a1.biz # => 'biz'
|
425
|
+
# a2.biz # => 'biz'
|
426
|
+
#
|
427
|
+
#
|
428
|
+
# _Unproxifying_ a _proxified_ object:
|
429
|
+
# class B
|
430
|
+
# def foo
|
431
|
+
# 'foo'
|
432
|
+
# end
|
433
|
+
#
|
434
|
+
# def bar
|
435
|
+
# 'bar'
|
436
|
+
# end
|
437
|
+
#
|
438
|
+
# def biz
|
439
|
+
# 'biz'
|
440
|
+
# end
|
441
|
+
# end
|
442
|
+
#
|
443
|
+
# b1, b2 = B.new, B.new
|
444
|
+
#
|
445
|
+
# Proxify(b1, :foo, :bar, :biz) { super().upcase }
|
446
|
+
#
|
447
|
+
# Unproxify(b1, :foo)
|
448
|
+
# b1.foo # => 'foo'
|
449
|
+
# b2.foo # => 'foo'
|
450
|
+
# b1.bar # => 'BAR'
|
451
|
+
# b2.bar # => 'BAR'
|
452
|
+
# b1.biz # => 'BIZ'
|
453
|
+
# b2.biz # => 'BIZ'
|
454
|
+
#
|
455
|
+
# Unproxify(b1)
|
456
|
+
# b1.foo # => 'foo'
|
457
|
+
# b2.foo # => 'foo'
|
458
|
+
# b1.bar # => 'bar'
|
459
|
+
# b2.bar # => 'bar'
|
460
|
+
# b1.biz # => 'biz'
|
461
|
+
# b2.biz # => 'biz'
|
462
|
+
#
|
463
|
+
#
|
464
|
+
# Trying to _unproxify_ an object of a _proxified_ class:
|
465
|
+
# class C
|
466
|
+
# def foo
|
467
|
+
# 'foo'
|
468
|
+
# end
|
469
|
+
# end
|
470
|
+
#
|
471
|
+
# c1, c2 = C.new, C.new
|
472
|
+
#
|
473
|
+
# Proxify(C, :foo) { super().upcase }
|
474
|
+
#
|
475
|
+
# Unproxify(c1)
|
476
|
+
# c1.foo # => 'FOO' (does not work because an object cannot affect its class)
|
477
|
+
# c2.foo # => 'FOO'
|
478
|
+
#
|
479
|
+
#
|
480
|
+
# _Unproxifying_ a _reproxified_ object of a _proxified_ class:
|
481
|
+
# class D
|
482
|
+
# def foo
|
483
|
+
# 'foo'
|
484
|
+
# end
|
485
|
+
# end
|
486
|
+
#
|
487
|
+
# d1, d2 = D.new, D.new
|
488
|
+
#
|
489
|
+
# Proxify(D, :foo) { super().upcase }
|
490
|
+
#
|
491
|
+
# Proxify(d1, :foo) { 'proxified'}
|
492
|
+
#
|
493
|
+
# Unproxify(d1)
|
494
|
+
# d1.foo # => 'FOO' (the class proxy is restored)
|
495
|
+
# d2.foo # => 'FOO'
|
496
|
+
def Unproxify(receiver, *methods)
|
497
|
+
target = receiver.is_a?(Class) ? receiver : receiver.singleton_class
|
498
|
+
|
499
|
+
Proxified?(target) ? target.unproxify(*methods) : methods
|
500
|
+
end
|
501
|
+
|
502
|
+
# If given no +method+, checks whether any of the +receiver+'s instance
|
503
|
+
# methods is _proxified_, otherwise it checks for the given +method+.
|
504
|
+
#
|
505
|
+
# +receiver+ can be a class or an ordinary object.
|
506
|
+
#
|
507
|
+
# If +receiver+ is an object of a _proxified_ class and the class has at least a
|
508
|
+
# _proxified_ method, will return true even when the +receiver+ has no
|
509
|
+
# _proxified_ methods.
|
510
|
+
#
|
511
|
+
# See Proxified.proxified? for further details.
|
512
|
+
#
|
513
|
+
# ======Examples
|
514
|
+
#
|
515
|
+
# Checking if a class is _proxified_:
|
516
|
+
# class A
|
517
|
+
# def foo
|
518
|
+
# 'foo'
|
519
|
+
# end
|
520
|
+
#
|
521
|
+
# def bar
|
522
|
+
# 'bar'
|
523
|
+
# end
|
524
|
+
# end
|
525
|
+
#
|
526
|
+
# Proxified?(A) # => false
|
527
|
+
# Proxified?(A, :foo) # => false
|
528
|
+
# Proxified?(A, :bar) # => false
|
529
|
+
#
|
530
|
+
# Proxify(A, :foo, :bar) { 'proxified' }
|
531
|
+
# Proxified?(A) # => true
|
532
|
+
# Proxified?(A, :foo) # => true
|
533
|
+
# Proxified?(A, :bar) # => true
|
534
|
+
#
|
535
|
+
# Unproxify(A, :foo)
|
536
|
+
# Proxified?(A) # => true
|
537
|
+
# Proxified?(A, :foo) # => false
|
538
|
+
# Proxified?(A, :bar) # => true
|
539
|
+
#
|
540
|
+
# Unproxify(A, :bar)
|
541
|
+
# Proxified?(A) # => false
|
542
|
+
# Proxified?(A, :foo) # => false
|
543
|
+
# Proxified?(A, :bar) # => false
|
544
|
+
#
|
545
|
+
#
|
546
|
+
# Checking if an object is _proxified_:
|
547
|
+
# class B
|
548
|
+
# def foo
|
549
|
+
# 'foo'
|
550
|
+
# end
|
551
|
+
#
|
552
|
+
# def bar
|
553
|
+
# 'bar'
|
554
|
+
# end
|
555
|
+
# end
|
556
|
+
#
|
557
|
+
# b1, b2 = B.new, B.new
|
558
|
+
#
|
559
|
+
# Proxified?(b1) # => false
|
560
|
+
# Proxified?(b1, :foo) # => false
|
561
|
+
# Proxified?(b1, :bar) # => false
|
562
|
+
# Proxified?(b2) # => false
|
563
|
+
# Proxified?(b2, :foo) # => false
|
564
|
+
# Proxified?(b2, :bar) # => false
|
565
|
+
#
|
566
|
+
# Proxify(b1, :foo) { 'proxified' }
|
567
|
+
# Proxified?(b1) # => true
|
568
|
+
# Proxified?(b1, :foo) # => true
|
569
|
+
# Proxified?(b1, :bar) # => false
|
570
|
+
# Proxified?(b2) # => false
|
571
|
+
# Proxified?(b2, :foo) # => false
|
572
|
+
# Proxified?(b2, :bar) # => false
|
573
|
+
#
|
574
|
+
# Unproxify(b1)
|
575
|
+
# Proxified?(b1) # => false
|
576
|
+
# Proxified?(b1, :foo) # => false
|
577
|
+
# Proxified?(b1, :bar) # => false
|
578
|
+
# Proxified?(b2) # => false
|
579
|
+
# Proxified?(b2, :foo) # => false
|
580
|
+
# Proxified?(b2, :bar) # => false
|
581
|
+
#
|
582
|
+
#
|
583
|
+
# Checking if an object of a _proxified_ class is _proxified_:
|
584
|
+
# class C
|
585
|
+
# def foo
|
586
|
+
# 'foo'
|
587
|
+
# end
|
588
|
+
#
|
589
|
+
# def bar
|
590
|
+
# 'bar'
|
591
|
+
# end
|
592
|
+
# end
|
593
|
+
#
|
594
|
+
# c1, c2 = C.new, C.new
|
595
|
+
#
|
596
|
+
# Proxify(C, :foo) { 'proxified' }
|
597
|
+
#
|
598
|
+
# Proxified?(c1) # => true
|
599
|
+
# Proxified?(c1, :foo) # => true
|
600
|
+
# Proxified?(c1, :bar) # => false
|
601
|
+
# Proxified?(c2) # => true
|
602
|
+
# Proxified?(c2, :foo) # => true
|
603
|
+
# Proxified?(c2, :bar) # => false
|
604
|
+
#
|
605
|
+
# Unproxify(c1)
|
606
|
+
# Proxified?(c1) # => true (the class is not affected)
|
607
|
+
# Proxified?(c1, :foo) # => true
|
608
|
+
# Proxified?(c1, :bar) # => false
|
609
|
+
# Proxified?(c2) # => true
|
610
|
+
# Proxified?(c2, :foo) # => true
|
611
|
+
# Proxified?(c2, :bar) # => false
|
612
|
+
#
|
613
|
+
# Unproxify(C)
|
614
|
+
# Proxified?(c1) # => false
|
615
|
+
# Proxified?(c1, :foo) # => false
|
616
|
+
# Proxified?(c1, :bar) # => false
|
617
|
+
# Proxified?(c2) # => false
|
618
|
+
# Proxified?(c2, :foo) # => false
|
619
|
+
# Proxified?(c2, :bar) # => false
|
620
|
+
#
|
621
|
+
# Proxify(c1, :foo) { 'proxified' }
|
622
|
+
# Unproxify(C)
|
623
|
+
# Proxified?(c1) # => true (is not affected by the class)
|
624
|
+
# Proxified?(c1, :foo) # => true
|
625
|
+
# Proxified?(c1, :bar) # => false
|
626
|
+
# Proxified?(c2) # => false
|
627
|
+
# Proxified?(c2, :foo) # => false
|
628
|
+
# Proxified?(c2, :bar) # => false
|
629
|
+
def Proxified?(receiver, method = nil)
|
630
|
+
if receiver.is_a?(Class)
|
631
|
+
receiver.include?(Proxified) && receiver.proxified?(method)
|
632
|
+
else
|
633
|
+
Proxified?(receiver.singleton_class, method) ||
|
634
|
+
Proxified?(receiver.class, method)
|
635
|
+
end
|
636
|
+
end
|