proxified 0.1.0 → 1.0.1
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.
- 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
|