proxified 0.1.0 → 1.0.0
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/.rubocop.yml +8 -0
- data/Gemfile.lock +1 -1
- data/Guardfile +2 -0
- data/README.md +119 -75
- data/bin/console +1 -0
- data/lib/proxified.rb +477 -69
- data/lib/proxified/version.rb +1 -1
- data/proxified.gemspec +10 -6
- metadata +5 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 32993e659cfcc2aa53356778623ee52326882a72b27532690c47e64aff86b4db
|
4
|
+
data.tar.gz: bee698f6c58a298229cdac6ef91dd404ef77e0e56342197ff39bbf0d96f2479d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 69c8f491db5b66212e13f64705329a14426883c797669a34a0ed00ad995ce3ba3a8b236c134b7fbdfb6c04c073bfb250b506475111b72d4404f4602355aaed71
|
7
|
+
data.tar.gz: 6a137b59ef2dbf4e821bb0794369304764bf64160fe35b1be83ee2a8aa70dd7c4de688a46b76730494a1c61caf778f056621a61f20cb2bdd2ff961578fa2ab5a
|
data/.rubocop.yml
CHANGED
data/Gemfile.lock
CHANGED
data/Guardfile
CHANGED
@@ -48,6 +48,8 @@ group :red_green_refactor, halt_on_fail: true do
|
|
48
48
|
# Ruby files
|
49
49
|
ruby = dsl.ruby
|
50
50
|
dsl.watch_spec_files_for(ruby.lib_files)
|
51
|
+
|
52
|
+
watch(ruby.lib_files) { "#{rspec.spec_dir}/global_methods_spec.rb" }
|
51
53
|
end
|
52
54
|
|
53
55
|
guard :rubocop, all_on_start: true, cli: ['-a'] do
|
data/README.md
CHANGED
@@ -1,8 +1,10 @@
|
|
1
|
+
[](https://badge.fury.io/rb/proxified)
|
2
|
+
|
1
3
|
# Proxified
|
2
4
|
|
3
|
-
|
5
|
+
A simple way to put a proxy in front of any object, at any time.
|
4
6
|
|
5
|
-
|
7
|
+
You can add and remove a proxy to and from any object instance methods and inherit or change the behavior down the class hierarchy.
|
6
8
|
|
7
9
|
## Installation
|
8
10
|
|
@@ -22,114 +24,156 @@ Or install it yourself as:
|
|
22
24
|
|
23
25
|
## Usage
|
24
26
|
|
25
|
-
|
27
|
+
You have two options to *proxify* and *unproxify* objects:
|
28
|
+
|
29
|
+
* *statically*: if you want to put a proxy on a class while defining it, just `include Proxified` and call `proxify` with the method(s) you want to *proxify* and the code you want to run.
|
30
|
+
When you want to remove a proxy, just call `unproxify` with the method(s) you want to *unproxify*, or without methods if you want to *unproxify* all *proxified* methods.
|
31
|
+
To check if a given method is *proxified*, call `proxified?` with the method name, or without arguments to check if any instance method is *proxified*.
|
26
32
|
|
27
|
-
|
33
|
+
* *dynamically*: if you want to put a proxy on a class at runtime, or on a single object without affecting its class, call `Proxify` with the class/object and the method(s) you want to *proxify*.
|
34
|
+
Similarly, use `Unproxify` and `Proxified?` with the class/object and the method(s) you want to *unproxify*/*check*.
|
28
35
|
|
29
|
-
|
30
|
-
Similarly, a `proxified method` is removed whenever the corresponding instance method is removed from the class.
|
36
|
+
You can also mix the two approaches! (see the examples below)
|
31
37
|
|
32
|
-
|
33
|
-
|
38
|
+
In order not to change the class interface, a method is only *proxified* when the corresponding instance method is defined (before or after the proxy definition).
|
39
|
+
Similarly, a *proxified method* is removed whenever the corresponding instance method is removed from the class.
|
40
|
+
|
41
|
+
Moreover, the *proxified methods* take the arguments specified by the block, so it should take the same arguments as the original methods.
|
42
|
+
Finally, it's possible to call the actual methods invoking `super` inside the block.
|
34
43
|
|
35
44
|
```ruby
|
36
45
|
|
37
46
|
require 'proxified'
|
38
47
|
|
39
|
-
#
|
48
|
+
# Static proxy:
|
49
|
+
|
40
50
|
class A
|
41
51
|
include Proxified
|
42
52
|
|
43
|
-
proxify :
|
44
|
-
|
45
|
-
super(name)
|
53
|
+
proxify :foo, :bar, :biz do
|
54
|
+
"proxified #{super()}"
|
46
55
|
end
|
47
56
|
|
48
|
-
def
|
49
|
-
puts "checking #{name}"
|
50
|
-
end
|
57
|
+
def foo; 'foo'; end
|
51
58
|
|
52
|
-
def
|
53
|
-
puts "hello #{name}!"
|
54
|
-
end
|
59
|
+
def bar; 'bar'; end
|
55
60
|
|
56
|
-
def
|
57
|
-
|
58
|
-
end
|
61
|
+
def biz; 'biz'; end
|
62
|
+
|
63
|
+
def baz; 'baz'; end
|
59
64
|
end
|
60
65
|
|
61
|
-
|
62
|
-
a.welcome('jack') => 'checking jack'; 'welcome jack!';
|
63
|
-
a.goodbye('jack') => 'checking jack'; 'goodbye jack!';
|
64
|
-
a.welcome => raises ArgumentError
|
65
|
-
a.check('jack') => 'checking jack' # not proxified
|
66
|
+
A.ancestors # => [A::Proxy, A, Proxified, ...]
|
66
67
|
|
67
|
-
|
68
|
-
class B < A
|
69
|
-
unproxify :welcome
|
70
|
-
end
|
68
|
+
a1, a2 = A.new, A.new
|
71
69
|
|
72
|
-
|
73
|
-
|
74
|
-
|
70
|
+
a1.foo # => 'proxified foo'
|
71
|
+
a2.foo # => 'proxified foo'
|
72
|
+
a1.bar # => 'proxified bar'
|
73
|
+
a2.bar # => 'proxified bar'
|
74
|
+
a1.biz # => 'proxified biz'
|
75
|
+
a2.biz # => 'proxified biz'
|
76
|
+
a1.baz # => 'baz'
|
77
|
+
a2.baz # => 'baz'
|
75
78
|
|
76
79
|
|
77
|
-
#
|
78
|
-
|
79
|
-
def welcome(name)
|
80
|
-
puts "welcome #{name.upcase}!"
|
81
|
-
end
|
82
|
-
end
|
80
|
+
# unproxify the :foo method
|
81
|
+
A.unproxify(:foo) # => [:foo]
|
83
82
|
|
84
|
-
|
85
|
-
|
86
|
-
|
83
|
+
# the :foo method is not proxified anymore
|
84
|
+
A.proxified?(:foo) # => false
|
85
|
+
# A is still proxified, i.e. it has at least one proxified method
|
86
|
+
A.proxified? # => true
|
87
87
|
|
88
|
+
a1.foo # => 'foo'
|
89
|
+
a2.foo # => 'foo'
|
90
|
+
a1.bar # => 'proxified bar'
|
91
|
+
a2.bar # => 'proxified bar'
|
92
|
+
a1.biz # => 'proxified biz'
|
93
|
+
a2.biz # => 'proxified biz'
|
94
|
+
a1.baz # => 'baz'
|
95
|
+
a2.baz # => 'baz'
|
88
96
|
|
89
|
-
# Reproxifing a proxified method:
|
90
|
-
class D < A
|
91
|
-
proxify :welcome do |name|
|
92
|
-
super(name.upcase)
|
93
|
-
end
|
94
|
-
end
|
95
97
|
|
96
|
-
|
97
|
-
|
98
|
-
d.goodbye('jack') => 'checking jack'; 'goodbye jack!';
|
98
|
+
# unproxify all the methods
|
99
|
+
A.unproxify # => [:bar, :biz]
|
99
100
|
|
101
|
+
# A is not proxified anymore
|
102
|
+
A.proxified? # => false
|
100
103
|
|
101
|
-
#
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
104
|
+
a1.foo # => 'foo'
|
105
|
+
a2.foo # => 'foo'
|
106
|
+
a1.bar # => 'bar'
|
107
|
+
a2.bar # => 'bar'
|
108
|
+
a1.biz # => 'biz'
|
109
|
+
a2.biz # => 'biz'
|
110
|
+
a1.baz # => 'baz'
|
111
|
+
a2.baz # => 'baz'
|
106
112
|
|
107
|
-
def welcome(name)
|
108
|
-
puts "hello #{name}!"
|
109
|
-
end
|
110
|
-
end
|
111
113
|
|
112
|
-
|
113
|
-
e.welcome('jack') => 'hello JACK!';
|
114
|
-
e.goodbye('jack') => 'checking jack'; 'goodbye jack!';
|
114
|
+
# Dynamic proxy:
|
115
115
|
|
116
|
+
# on a class
|
117
|
+
Proxify(A, :foo, :bar) { 'proxified again' } # => [:foo, :bar]
|
116
118
|
|
117
|
-
#
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
119
|
+
a1.foo # => 'proxified again'
|
120
|
+
a2.foo # => 'proxified again'
|
121
|
+
a1.bar # => 'proxified again'
|
122
|
+
a2.bar # => 'proxified again'
|
123
|
+
a1.biz # => 'biz'
|
124
|
+
a2.biz # => 'biz'
|
125
|
+
a1.baz # => 'baz'
|
126
|
+
a2.baz # => 'baz'
|
127
|
+
|
128
|
+
|
129
|
+
# on a single object
|
130
|
+
Proxify(a1, :bar, :biz) { 'singleton proxy' } # => [:bar, :biz]
|
131
|
+
|
132
|
+
a1.foo # => 'proxified again'
|
133
|
+
a2.foo # => 'proxified again'
|
134
|
+
a1.bar # => 'singleton proxy'
|
135
|
+
a2.bar # => 'proxified again'
|
136
|
+
a1.biz # => 'singleton proxy'
|
137
|
+
a2.biz # => 'biz'
|
138
|
+
a1.baz # => 'baz'
|
139
|
+
a2.baz # => 'baz'
|
140
|
+
|
141
|
+
|
142
|
+
# unproxify all the methods of a1
|
143
|
+
Unproxify(a1) # => [:foo, :bar, :biz]
|
144
|
+
|
145
|
+
# still proxified because of the class' proxy
|
146
|
+
Proxified?(a1) # => true
|
147
|
+
|
148
|
+
a1.foo # => 'proxified again'
|
149
|
+
a2.foo # => 'proxified again'
|
150
|
+
a1.bar # => 'proxified again'
|
151
|
+
a2.bar # => 'proxified again'
|
152
|
+
a1.biz # => 'biz'
|
153
|
+
a2.biz # => 'biz'
|
154
|
+
a1.baz # => 'baz'
|
155
|
+
a2.baz # => 'baz'
|
156
|
+
|
157
|
+
|
158
|
+
# unproxify all the methods of A
|
159
|
+
Unproxify(A, :foo, :bar) # => [:foo, :bar]
|
160
|
+
|
161
|
+
a1.foo # => 'foo'
|
162
|
+
a2.foo # => 'foo'
|
163
|
+
a1.bar # => 'bar'
|
164
|
+
a2.bar # => 'bar'
|
165
|
+
a1.biz # => 'biz'
|
166
|
+
a2.biz # => 'biz'
|
167
|
+
a1.baz # => 'baz'
|
168
|
+
a2.baz # => 'baz'
|
125
169
|
|
126
|
-
f = F.new
|
127
|
-
f.welcome('jack') => 'checking jack'; 'checking jack'; 'welcome jack!'; 'hi';
|
128
|
-
f.goodbye('jack') => 'checking jack'; 'goodbye jack!';
|
129
170
|
```
|
171
|
+
|
172
|
+
Just look at the code documentation to see more examples of what you can/cannot do.
|
173
|
+
|
130
174
|
## Notes
|
131
175
|
|
132
|
-
This is my first gem, something I extracted from a bigger project and a first attempt to give back
|
176
|
+
This is my first gem, something I extracted from a bigger project and a first attempt to give something back to the community.
|
133
177
|
|
134
178
|
Any constructive feedback is welcome and appreciated, thank you!
|
135
179
|
|
data/bin/console
CHANGED
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
|
data/lib/proxified/version.rb
CHANGED
data/proxified.gemspec
CHANGED
@@ -11,18 +11,20 @@ Gem::Specification.new do |spec|
|
|
11
11
|
spec.email = ['valerio.licata.dev@gmail.com']
|
12
12
|
|
13
13
|
spec.summary = 'Proxify any object with a few lines of code.'
|
14
|
-
spec.description =
|
14
|
+
spec.description =
|
15
|
+
'A simple way to put a proxy in front of any object, at any time.'
|
15
16
|
spec.homepage = 'https://github.com/vtsl01/proxified'
|
16
17
|
spec.license = 'MIT'
|
17
18
|
|
18
|
-
#
|
19
|
-
#
|
19
|
+
# Prevent pushing this gem to RubyGems.org. To allow pushes either set the
|
20
|
+
# 'allowed_push_host' to allow pushing to a single host or delete this
|
21
|
+
# section to allow pushing to any host.
|
20
22
|
# if spec.respond_to?(:metadata)
|
21
|
-
# spec.metadata["allowed_push_host"] = "
|
23
|
+
# spec.metadata["allowed_push_host"] = "Set to 'http://mygemserver.com'"
|
22
24
|
#
|
23
25
|
# spec.metadata["homepage_uri"] = spec.homepage
|
24
|
-
# spec.metadata["source_code_uri"] = "
|
25
|
-
# spec.metadata["changelog_uri"] = "
|
26
|
+
# spec.metadata["source_code_uri"] = "Put your gem's public repo URL here."
|
27
|
+
# spec.metadata["changelog_uri"] = "Put your gem's CHANGELOG.md URL here."
|
26
28
|
# else
|
27
29
|
# raise "RubyGems 2.0 or newer is required to protect against " \
|
28
30
|
# "public gem pushes."
|
@@ -40,6 +42,8 @@ Gem::Specification.new do |spec|
|
|
40
42
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
41
43
|
spec.require_paths = ['lib']
|
42
44
|
|
45
|
+
spec.required_ruby_version = '~> 2.6'
|
46
|
+
|
43
47
|
spec.add_development_dependency 'bundler', '~> 1.17'
|
44
48
|
spec.add_development_dependency 'guard', '~> 2.15'
|
45
49
|
spec.add_development_dependency 'guard-bundler', '~> 2.2', '>= 2.2.1'
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: proxified
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Valerio Licata
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-
|
11
|
+
date: 2019-03-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -140,7 +140,7 @@ dependencies:
|
|
140
140
|
- - ">="
|
141
141
|
- !ruby/object:Gem::Version
|
142
142
|
version: 5.2.2
|
143
|
-
description: A simple way to put a proxy in front of any object.
|
143
|
+
description: A simple way to put a proxy in front of any object, at any time.
|
144
144
|
email:
|
145
145
|
- valerio.licata.dev@gmail.com
|
146
146
|
executables: []
|
@@ -176,9 +176,9 @@ require_paths:
|
|
176
176
|
- lib
|
177
177
|
required_ruby_version: !ruby/object:Gem::Requirement
|
178
178
|
requirements:
|
179
|
-
- - "
|
179
|
+
- - "~>"
|
180
180
|
- !ruby/object:Gem::Version
|
181
|
-
version: '
|
181
|
+
version: '2.6'
|
182
182
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
183
183
|
requirements:
|
184
184
|
- - ">="
|