proxified 0.1.0 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
[![Gem Version](https://badge.fury.io/rb/proxified.svg)](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
|
- - ">="
|