stub_a 0.0.1 → 0.0.2
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/lib/stub_a.rb +231 -56
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: c5c160196910a2a2749394b33cf6f8bab32c513b
|
|
4
|
+
data.tar.gz: 761a09839f11949d5bcafe88cea8828537e7dbf2
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 8c1f8f4a27b708b5e80a087e3c911c6380aadfd275453fd24cfc7550a7edadee9625d9a8f09158a1a974448073d689de715db7c54796882ad0feb757f14c1711
|
|
7
|
+
data.tar.gz: cf1754d3a5414126cacdac2485279405bfcbab2fa8377dbfcaa0be446bcc2a36d3f4dbd6fdf420ce4562676341f65507e7f8b3bb364d6f475429d316b5bd86ae
|
data/lib/stub_a.rb
CHANGED
|
@@ -1,35 +1,220 @@
|
|
|
1
|
+
# coding: utf-8
|
|
2
|
+
|
|
1
3
|
class StubA
|
|
4
|
+
# コンストラクタ
|
|
5
|
+
#
|
|
6
|
+
# ==詳細
|
|
7
|
+
# 操作対象のクラスまたはインスタンスを渡し、
|
|
8
|
+
# 操作用オブジェクトを作成します。
|
|
9
|
+
#
|
|
10
|
+
# インスタンスが渡された場合、インスタンス
|
|
11
|
+
# メソッドに対するフックは特異メソッドとして
|
|
12
|
+
# 作成されます。
|
|
13
|
+
#
|
|
14
|
+
# クラスメソッドは、もともと特異メソッドの
|
|
15
|
+
# ようなものなので、クラスメソッドに対する操作は
|
|
16
|
+
# インスタンスを渡してもクラスを渡しても
|
|
17
|
+
# 変わりません。
|
|
18
|
+
#
|
|
19
|
+
# ==引数
|
|
20
|
+
# - ++object+: クラスまたはインスタンス
|
|
2
21
|
def initialize(object)
|
|
3
|
-
|
|
4
|
-
|
|
22
|
+
if object.is_a? Class
|
|
23
|
+
@target = object
|
|
24
|
+
@target_class = class << object; self; end
|
|
25
|
+
else
|
|
26
|
+
@target = class << object; self; end
|
|
27
|
+
@target_class = class << object.class; self; end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# インスタンスメソッドに対する before フックを作成
|
|
32
|
+
#
|
|
33
|
+
# ==詳細
|
|
34
|
+
# 引数で指定したインスタンスメソッドが実行される
|
|
35
|
+
# 直前に呼ばれるフックメソッドを作成します。
|
|
36
|
+
#
|
|
37
|
+
# 対象のメソッドはメソッド名で指定します。
|
|
38
|
+
#
|
|
39
|
+
# ==引数
|
|
40
|
+
# - ++method_name++: メソッド名
|
|
41
|
+
#
|
|
42
|
+
def before(method_name, &block)
|
|
43
|
+
make_hook(:before, @target, method_name, &block)
|
|
5
44
|
end
|
|
6
45
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
46
|
+
# クラスメソッドに対する before フックを作成
|
|
47
|
+
#
|
|
48
|
+
# ==詳細
|
|
49
|
+
# 引数で指定したクラスメソッドが実行される直前に
|
|
50
|
+
# 呼ばれるフックメソッドを作成します。
|
|
51
|
+
#
|
|
52
|
+
# 対象のメソッドはメソッド名で指定します。
|
|
53
|
+
#
|
|
54
|
+
# ==引数
|
|
55
|
+
# - ++method_name++: メソッド名
|
|
56
|
+
#
|
|
57
|
+
def cbefore(method_name, &block)
|
|
58
|
+
make_hook(:before, @target_class, method_name, &block)
|
|
59
|
+
end
|
|
12
60
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
61
|
+
# インスタンスメソッドに対する after フックを作成
|
|
62
|
+
#
|
|
63
|
+
# ==詳細
|
|
64
|
+
# 引数で指定したインスタンスメソッドが実行される
|
|
65
|
+
# 直後に呼ばれるフックメソッドを作成します。
|
|
66
|
+
#
|
|
67
|
+
# 対象のメソッドはメソッド名で指定します。
|
|
68
|
+
#
|
|
69
|
+
# ==引数
|
|
70
|
+
# - ++method_name++: メソッド名
|
|
71
|
+
#
|
|
72
|
+
def after(method_name, &block)
|
|
73
|
+
make_hook(:after, @target, method_name, &block)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# クラスメソッドに対する after フックを作成
|
|
77
|
+
#
|
|
78
|
+
# ==詳細
|
|
79
|
+
# 引数で指定したクラスメソッドが実行される直後に
|
|
80
|
+
# 呼ばれるフックメソッドを作成します。
|
|
81
|
+
#
|
|
82
|
+
# 対象のメソッドはメソッド名で指定します。
|
|
83
|
+
#
|
|
84
|
+
# ==引数
|
|
85
|
+
# - ++method_name++: メソッド名
|
|
86
|
+
#
|
|
87
|
+
def cafter(method_name, &block)
|
|
88
|
+
make_hook(:after, @target_class, method_name, &block)
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
# インスタンスメソッドに対するスタブメソッドを作成
|
|
92
|
+
#
|
|
93
|
+
# ==詳細
|
|
94
|
+
# 引数で指定したインスタンスメソッドの代わりに呼ばれる
|
|
95
|
+
# 代替メソッドを作成します。
|
|
96
|
+
#
|
|
97
|
+
# 対象のメソッドはメソッド名で指定します。
|
|
98
|
+
#
|
|
99
|
+
# ==引数
|
|
100
|
+
# - ++method_name++: メソッド名
|
|
101
|
+
#
|
|
102
|
+
def stub(method_name, &block)
|
|
103
|
+
make_stub(@target, method_name, &block)
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
# クラスメソッドに対するスタブを作成
|
|
107
|
+
#
|
|
108
|
+
# ==詳細
|
|
109
|
+
# 引数で指定したクラスメソッドの代わりに呼ばれる代替
|
|
110
|
+
# メソッドを作成します。
|
|
111
|
+
#
|
|
112
|
+
# 対象のメソッドはメソッド名で指定します。
|
|
113
|
+
#
|
|
114
|
+
# ==引数
|
|
115
|
+
# - ++method_name++: メソッド名
|
|
116
|
+
#
|
|
117
|
+
def cstub(method_name, &block)
|
|
118
|
+
make_stub(@target_class, method_name, &block)
|
|
19
119
|
end
|
|
20
120
|
|
|
21
|
-
|
|
121
|
+
# インスタンスメソッドを書き戻す
|
|
122
|
+
#
|
|
123
|
+
# ==詳細
|
|
124
|
+
# 引数で指定したメソッドに対して行った操作を元に戻します。
|
|
125
|
+
#
|
|
126
|
+
# 基本的に、第一引数にメソッド名、第二引数に戻したい操作の
|
|
127
|
+
# 種類を指定します。
|
|
128
|
+
#
|
|
129
|
+
# たとえば、++foo++ というメソッドに対して ++before++
|
|
130
|
+
# フックを作成した、という操作を戻したい場合は、
|
|
131
|
+
#
|
|
132
|
+
# stub_a.restore(:foo, :before)
|
|
133
|
+
#
|
|
134
|
+
# のように指定します。
|
|
135
|
+
# 第一引数のメソッドに対して、戻したい操作の種類が複数ある
|
|
136
|
+
# 場合は、
|
|
137
|
+
#
|
|
138
|
+
# stub_a.restore(:foo, :before, :after)
|
|
139
|
+
#
|
|
140
|
+
# のように続けて指定することもできます。
|
|
141
|
+
#
|
|
142
|
+
# 逆に第二引数を省略した場合は、第一引数で指定したメソッドに
|
|
143
|
+
# 対して行ったすべての種類の操作を戻します。
|
|
144
|
+
#
|
|
145
|
+
# 操作したメソッドがひとつだけの場合で、かつ操作をすべて
|
|
146
|
+
# 戻して構わない場合は、引数を省略することもできます。
|
|
147
|
+
#
|
|
148
|
+
# ==引数
|
|
149
|
+
# - ++method_name++: メソッド名
|
|
150
|
+
# - ++types++: 操作の種類
|
|
151
|
+
#
|
|
152
|
+
def restore(method_name=nil, *types)
|
|
153
|
+
restore_hooks(@target, method_name, *types)
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
# クラスメソッドを書き戻す
|
|
157
|
+
#
|
|
158
|
+
# ==詳細
|
|
159
|
+
# ++restore++ がインスタンスメソッドに対する操作であるのに
|
|
160
|
+
# 対し、++crestore++ はクラスメソッドを操作の対象にします。
|
|
161
|
+
#
|
|
162
|
+
# 詳細については、++restore++ の説明を参照してください。
|
|
163
|
+
#
|
|
164
|
+
def crestore(method_name=nil, *types)
|
|
165
|
+
restore_hooks(@target_class, method_name, *types)
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
# すべてのインスタンスメソッドを書き戻す
|
|
169
|
+
#
|
|
170
|
+
# ==詳細
|
|
171
|
+
# インスタンスメソッドに対するすべての操作を書き戻します。
|
|
172
|
+
#
|
|
173
|
+
def restore_all
|
|
174
|
+
restore_all_hooks(@target)
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
# すべてのクラスメソッドを書き戻す
|
|
178
|
+
#
|
|
179
|
+
# ==詳細
|
|
180
|
+
# クラスメソッドに対するすべての操作を書き戻します。
|
|
181
|
+
#
|
|
182
|
+
def crestore_all
|
|
183
|
+
restore_all_hooks(@target_class)
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
private
|
|
188
|
+
METHOD_TYPES = [
|
|
189
|
+
:before,
|
|
190
|
+
:after,
|
|
191
|
+
:stub,
|
|
192
|
+
:origin,
|
|
193
|
+
]
|
|
194
|
+
private_constant :METHOD_TYPES
|
|
195
|
+
|
|
196
|
+
def make_hook(hook_type, target, method, &block)
|
|
197
|
+
make_hook_points(target, method)
|
|
198
|
+
|
|
199
|
+
method_name = hook_method_name(method, hook_type)
|
|
200
|
+
hook = block if block
|
|
201
|
+
hook ||= default_hook(method, hook_type)
|
|
202
|
+
target.__send__ :define_method, method_name, hook
|
|
203
|
+
self
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
def make_stub(target, method, &block)
|
|
22
207
|
raise ArgumentError, "No block" unless block
|
|
23
|
-
make_hook_points(method)
|
|
208
|
+
make_hook_points(target, method)
|
|
24
209
|
|
|
25
210
|
method_name = hook_method_name(method, :stub)
|
|
26
|
-
|
|
211
|
+
target.__send__ :define_method, method_name, block
|
|
27
212
|
self
|
|
28
213
|
end
|
|
29
214
|
|
|
30
|
-
def
|
|
215
|
+
def restore_hooks(target, method=nil, *types)
|
|
31
216
|
if method.nil?
|
|
32
|
-
hooks = defined_hooks
|
|
217
|
+
hooks = defined_hooks(target)
|
|
33
218
|
method = hooks.keys.first if hooks.keys.size == 1
|
|
34
219
|
end
|
|
35
220
|
raise "Method name to be restored is required." if method.nil?
|
|
@@ -41,38 +226,29 @@ class StubA
|
|
|
41
226
|
|
|
42
227
|
types.each do |type|
|
|
43
228
|
method_name = hook_method_name(method, type)
|
|
44
|
-
next unless
|
|
45
|
-
|
|
229
|
+
next unless target.method_defined? method_name
|
|
230
|
+
target.__send__ :remove_method, method_name
|
|
46
231
|
end
|
|
47
232
|
|
|
48
|
-
hooks = defined_hooks
|
|
233
|
+
hooks = defined_hooks(target)
|
|
49
234
|
if hooks[method.to_s].size == 1 and
|
|
50
235
|
hooks[method.to_s].first == 'origin'
|
|
51
236
|
origin = hook_method_name(method, :origin)
|
|
52
|
-
|
|
53
|
-
|
|
237
|
+
target.__send__ :alias_method, method, origin
|
|
238
|
+
target.__send__ :remove_method, origin
|
|
54
239
|
end
|
|
55
240
|
end
|
|
56
241
|
|
|
57
|
-
def
|
|
58
|
-
defined_hooks.each do |method, types|
|
|
242
|
+
def restore_all_hooks(target)
|
|
243
|
+
defined_hooks(target).each do |method, types|
|
|
59
244
|
types.each do |type|
|
|
60
245
|
name = hook_method_name(method, type)
|
|
61
|
-
next unless
|
|
62
|
-
|
|
63
|
-
|
|
246
|
+
next unless target.method_defined? name
|
|
247
|
+
target.__send__ :alias_method, method, name if type == 'origin'
|
|
248
|
+
target.__send__ :remove_method, name
|
|
64
249
|
end
|
|
65
250
|
end
|
|
66
251
|
end
|
|
67
|
-
|
|
68
|
-
private
|
|
69
|
-
METHOD_TYPES = [
|
|
70
|
-
:before,
|
|
71
|
-
:after,
|
|
72
|
-
:stub,
|
|
73
|
-
:origin,
|
|
74
|
-
]
|
|
75
|
-
private_constant :METHOD_TYPES
|
|
76
252
|
|
|
77
253
|
def hook_method_name(method, type)
|
|
78
254
|
"===>(stub_a) #{type}-#{method}"
|
|
@@ -84,12 +260,12 @@ class StubA
|
|
|
84
260
|
end
|
|
85
261
|
end
|
|
86
262
|
|
|
87
|
-
def make_hook_points(method_name)
|
|
263
|
+
def make_hook_points(target, method_name)
|
|
88
264
|
methods = hook_method_names(method_name)
|
|
89
|
-
return if
|
|
265
|
+
return if target.method_defined? methods[:origin]
|
|
90
266
|
|
|
91
|
-
|
|
92
|
-
|
|
267
|
+
target.__send__ :alias_method, methods[:origin], method_name
|
|
268
|
+
target.__send__ :define_method, method_name, ->(*args, &block) {
|
|
93
269
|
if respond_to? methods[:before]
|
|
94
270
|
__send__ methods[:before], ARGS[:before].new(method_name, args), &block
|
|
95
271
|
end
|
|
@@ -102,20 +278,19 @@ class StubA
|
|
|
102
278
|
end
|
|
103
279
|
|
|
104
280
|
if respond_to? methods[:after]
|
|
105
|
-
__send__ methods[:after], ARGS[:after].new(method_name, val)
|
|
281
|
+
__send__ methods[:after], ARGS[:after].new(method_name, args, val)
|
|
106
282
|
end
|
|
107
283
|
|
|
108
284
|
val
|
|
109
285
|
}
|
|
110
286
|
end
|
|
111
287
|
|
|
112
|
-
def defined_hooks
|
|
113
|
-
re = /\A===>\(stub_a\) (
|
|
114
|
-
|
|
115
|
-
if name.to_s
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
end
|
|
288
|
+
def defined_hooks(target)
|
|
289
|
+
re = /\A===>\(stub_a\) (#{METHOD_TYPES.join('|')})-(.+)\z/
|
|
290
|
+
target.instance_methods.each_with_object({}) {|name, h|
|
|
291
|
+
next if name.to_s !~ re
|
|
292
|
+
h[$2] ||= []
|
|
293
|
+
h[$2] << $1
|
|
119
294
|
}
|
|
120
295
|
end
|
|
121
296
|
|
|
@@ -129,26 +304,26 @@ class StubA
|
|
|
129
304
|
end
|
|
130
305
|
|
|
131
306
|
def default_before_hook(method)
|
|
132
|
-
->(
|
|
133
|
-
puts "[#{Time.now}] call `#{
|
|
134
|
-
puts "args: #{args.inspect}" if args.size > 0
|
|
307
|
+
->(arg, &block) {
|
|
308
|
+
puts "[#{Time.now}] call `#{arg.method_name}' (#{self.inspect})"
|
|
309
|
+
puts "args: #{arg.args.inspect}" if arg.args.size > 0
|
|
135
310
|
}
|
|
136
311
|
end
|
|
137
312
|
|
|
138
313
|
def default_after_hook(method)
|
|
139
314
|
before_method = hook_method_name(method, :before)
|
|
140
|
-
->(
|
|
315
|
+
->(arg) {
|
|
141
316
|
unless respond_to? before_method
|
|
142
|
-
puts "[#{Time.now}] call `#{
|
|
317
|
+
puts "[#{Time.now}] call `#{arg.method_name}' (#{self.inspect})"
|
|
143
318
|
end
|
|
144
|
-
puts "return: #{
|
|
319
|
+
puts "return: #{arg.return_value.inspect}"
|
|
145
320
|
}
|
|
146
321
|
end
|
|
147
322
|
|
|
148
323
|
ARGS = {
|
|
149
324
|
before: Struct.new(:method_name, :args),
|
|
150
325
|
stub: Struct.new(:method, :args),
|
|
151
|
-
after: Struct.new(:method_name, :return_value),
|
|
326
|
+
after: Struct.new(:method_name, :args, :return_value),
|
|
152
327
|
}
|
|
153
328
|
private_constant :ARGS
|
|
154
329
|
end
|