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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bd5b3ded355bfb619efec1c6a3314498662945cd1ca2e36d2b38ae71823a0bb6
4
- data.tar.gz: e16834d5a79ab0cd7d5b38b40ed7e7f7af2203c37b84c569e90f33a57ebd6c18
3
+ metadata.gz: 32993e659cfcc2aa53356778623ee52326882a72b27532690c47e64aff86b4db
4
+ data.tar.gz: bee698f6c58a298229cdac6ef91dd404ef77e0e56342197ff39bbf0d96f2479d
5
5
  SHA512:
6
- metadata.gz: 56ba529f8c836164dd010395d7311511bcce0123dd482574585e3327bc66060f1a512984379397f148f73cbcc0d66efae98d3ff1cf54133eb0d269ef1c93ec41
7
- data.tar.gz: c7553667d0ff27a830d315a33c44d7a5b257451a7d53201e0dadb13507a419cc4e0e331e1667977503b3032ba0391e614b92f97b63f66d877c605f6798640324
6
+ metadata.gz: 69c8f491db5b66212e13f64705329a14426883c797669a34a0ed00ad995ce3ba3a8b236c134b7fbdfb6c04c073bfb250b506475111b72d4404f4602355aaed71
7
+ data.tar.gz: 6a137b59ef2dbf4e821bb0794369304764bf64160fe35b1be83ee2a8aa70dd7c4de688a46b76730494a1c61caf778f056621a61f20cb2bdd2ff961578fa2ab5a
@@ -1,5 +1,13 @@
1
+ AllCops:
2
+ TargetRubyVersion: '2.6'
3
+
1
4
  Metrics/BlockLength:
2
5
  Exclude:
6
+ - lib/proxified.rb
3
7
  - spec/**/*
4
8
  - Guardfile
5
9
  - proxified.gemspec
10
+
11
+ Naming/MethodName:
12
+ Exclude:
13
+ - lib/proxified.rb
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- proxified (0.1.0)
4
+ proxified (1.0.0)
5
5
  activesupport (~> 5.2, >= 5.2.2)
6
6
 
7
7
  GEM
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
- Proxify any object with a few lines of code.
5
+ A simple way to put a proxy in front of any object, at any time.
4
6
 
5
- A simple way to add (and remove) a proxy to any object's instance methods and to inherit and change the behaviour down the class hierarchy.
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
- Just `include Proxified` in your class and call `proxify` with the method(s) you want to proxify and the code you want to run.
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
- If you want to remove a proxy, just call `unproxify` with the method(s) you want to unproxify.
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
- In order to not change the class interface, a method is only `proxified` when the corresponding instance method is defined (before or after the proxy definition).
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
- Moreover, the `proxified methods` take the arguments specified by the `block`, so it should take the same arguments as the original `methods`.
33
- Finally, it's possible to call the actual `methods` invoking `super` inside the `block`.
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
- # Basic usage:
48
+ # Static proxy:
49
+
40
50
  class A
41
51
  include Proxified
42
52
 
43
- proxify :welcome, :goodbye do |name|
44
- check(name)
45
- super(name)
53
+ proxify :foo, :bar, :biz do
54
+ "proxified #{super()}"
46
55
  end
47
56
 
48
- def check(name)
49
- puts "checking #{name}"
50
- end
57
+ def foo; 'foo'; end
51
58
 
52
- def welcome(name)
53
- puts "hello #{name}!"
54
- end
59
+ def bar; 'bar'; end
55
60
 
56
- def goodbye(name)
57
- puts "goodbye #{name}!"
58
- end
61
+ def biz; 'biz'; end
62
+
63
+ def baz; 'baz'; end
59
64
  end
60
65
 
61
- a = A.new
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
- # Unproxifing a proxified method:
68
- class B < A
69
- unproxify :welcome
70
- end
68
+ a1, a2 = A.new, A.new
71
69
 
72
- b = B.new
73
- b.welcome('jack') => 'welcome jack!';
74
- b.goodbye('jack') => 'checking jack'; 'goodbye jack!';
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
- # Redefining a proxified method:
78
- class C < A
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
- c = C.new
85
- c.welcome('jack') => 'checking jack'; 'welcome JACK!';
86
- c.goodbye('jack') => 'checking jack'; 'goodbye jack!';
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
- d = D.new
97
- d.welcome('jack') => 'checking JACK'; 'welcome JACK!';
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
- # Reproxifing and redefining a proxified method:
102
- class E < A
103
- proxify :welcome do |name|
104
- super(name.upcase)
105
- end
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
- e = E.new
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
- # Redefining a proxified method to call super:
118
- class F < A
119
- def welcome(name)
120
- # Will call F's proxy, then A's proxy and finally A's method
121
- super(name)
122
- puts 'hi'
123
- end
124
- end
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 something to the community.
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
 
@@ -1,4 +1,5 @@
1
1
  #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
2
3
 
3
4
  require 'bundler/setup'
4
5
  require 'proxified'
@@ -3,39 +3,46 @@
3
3
  require 'active_support'
4
4
  require 'active_support/core_ext'
5
5
 
6
- # =====Allows to "proxify" and "unproxify" any instance method with custom code and to inherit and change the behaviour down the class hierarchy.
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 proxify allowing descendants to override them
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 +proxified_method+ that runs
18
- # the given +block+ when +method+ is called, or raises ArgumentError if no
19
- # block or no method is given.
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 not change the class interface, a method is only +proxified+
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 +proxified_method+ is removed whenever the
31
+ # proxy definition), while a _proxified_ _method_ is removed whenever the
24
32
  # corresponding instance method is removed from the class. Moreover, the
25
- # +proxified_methods+ take the arguments specified by the +block+, so the
26
- # +block+ should take the same arguments as the original +methods+
27
- # (although it can take any number of arguments). Finally, it's possible
28
- # to call the actual +methods+ invoking +super+ inside the +block+.
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 +proxified_methods+ are defined in a proxy module that is prepended
31
- # automatically to the class only the first time a +proxified_method+ is
32
- # defined within that class and the proxy module's name is prefixed with the
33
- # class name. In this way, descendants who redefine a +proxified_method+
34
- # get their own proxy module, while those who do not redefine a
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 +proxified_method+ to call +super+, the
38
- # parent's +proxified_method+ will be called.
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 "hello #{name}!"
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' # not proxified
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
- # Redefining a +proxified_method+:
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
- # Reproxifing a +proxified_method+:
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
- # Reproxifing and redefining a +proxified_method+:
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
- # Redefining a +proxified_method+ to call +super+:
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('tom') => 'checking tom'; 'checking tom'; 'welcome tom!'; 'hi';
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
- # Removes +methods+ from the proxy.
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 :welcome, :goodbye do |name|
155
- # check(name)
156
- # super(name)
167
+ # proxify :foo, :bar, :biz do
168
+ # super().upcase
157
169
  # end
158
170
  #
159
- # def check(name)
160
- # puts "checking #{name}"
171
+ # def foo
172
+ # 'foo'
161
173
  # end
162
174
  #
163
- # def welcome(name)
164
- # puts "welcome #{name}!"
175
+ # def bar
176
+ # 'bar'
165
177
  # end
166
178
  #
167
- # def goodbye(name)
168
- # puts "goodbye #{name}!"
179
+ # def biz
180
+ # 'biz'
169
181
  # end
170
182
  # end
171
183
  #
172
- # a = A.new
173
- # a.welcome('jack') => 'checking jack'; 'welcome jack!';
174
- # a.goodbye('jack') => 'checking jack'; 'goodbye jack!';
184
+ # A.unproxify(:foo)
185
+ # a.foo # => 'foo;
186
+ # a.bar # => 'BAR'
187
+ # a.biz # => 'BIZ'
175
188
  #
176
- # a.class.unproxify(:welcome)
177
- #
178
- # a.welcome('jack') => 'welcome jack!';
179
- # a.goodbye('jack') => 'checking jack'; 'goodbye jack!';
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
- # Checks whether +method+ has been proxified.
187
- def proxified?(method)
188
- method.in?(proxified_methods)
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Proxified
4
- VERSION = '0.1.0'.freeze
4
+ VERSION = '1.0.0'
5
5
  end
@@ -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 = 'A simple way to put a proxy in front of any object.'
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
- # # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
19
- # # to allow pushing to a single host or delete this section to allow pushing to any host.
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"] = "TODO: Set to 'http://mygemserver.com'"
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"] = "TODO: Put your gem's public repo URL here."
25
- # spec.metadata["changelog_uri"] = "TODO: Put your gem's CHANGELOG.md URL here."
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: 0.1.0
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-01-31 00:00:00.000000000 Z
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: '0'
181
+ version: '2.6'
182
182
  required_rubygems_version: !ruby/object:Gem::Requirement
183
183
  requirements:
184
184
  - - ">="