peeek 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/Gemfile +6 -0
- data/LICENSE.txt +22 -0
- data/README.md +127 -0
- data/Rakefile +1 -0
- data/bin/peeek +16 -0
- data/lib/peeek.rb +147 -0
- data/lib/peeek/call.rb +134 -0
- data/lib/peeek/calls.rb +43 -0
- data/lib/peeek/hook.rb +188 -0
- data/lib/peeek/hook/instance.rb +51 -0
- data/lib/peeek/hook/linker.rb +29 -0
- data/lib/peeek/hook/singleton.rb +52 -0
- data/lib/peeek/hooks.rb +46 -0
- data/lib/peeek/supervisor.rb +120 -0
- data/lib/peeek/version.rb +3 -0
- data/peeek.gemspec +25 -0
- data/spec/peeek/call_spec.rb +226 -0
- data/spec/peeek/calls_spec.rb +86 -0
- data/spec/peeek/hook/instance_spec.rb +87 -0
- data/spec/peeek/hook/linker_spec.rb +15 -0
- data/spec/peeek/hook/singleton_spec.rb +82 -0
- data/spec/peeek/hook_spec.rb +380 -0
- data/spec/peeek/hooks_spec.rb +92 -0
- data/spec/peeek/supervisor_spec.rb +129 -0
- data/spec/peeek_spec.rb +335 -0
- data/spec/spec_helper.rb +78 -0
- metadata +125 -0
data/peeek.gemspec
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'peeek/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = 'peeek'
|
8
|
+
spec.version = Peeek::VERSION
|
9
|
+
spec.authors = ['Takahiro Kondo']
|
10
|
+
spec.email = ['heartery@gmail.com']
|
11
|
+
spec.description = %q{Peek at calls of a method}
|
12
|
+
spec.summary = spec.description
|
13
|
+
spec.homepage = 'https://github.com/takkkun/peeek'
|
14
|
+
spec.license = 'MIT'
|
15
|
+
spec.required_ruby_version = '>= 1.8.7'
|
16
|
+
|
17
|
+
spec.files = `git ls-files`.split($/)
|
18
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
19
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
20
|
+
spec.require_paths = ['lib']
|
21
|
+
|
22
|
+
spec.add_development_dependency 'bundler', '~> 1.3'
|
23
|
+
spec.add_development_dependency 'rake'
|
24
|
+
spec.add_development_dependency 'rspec'
|
25
|
+
end
|
@@ -0,0 +1,226 @@
|
|
1
|
+
require 'peeek/call'
|
2
|
+
|
3
|
+
def sample_call(attrs = {})
|
4
|
+
hook = attrs[:hook] || stub('Peeek::Hook', :to_s => 'String#%')
|
5
|
+
args = attrs[:args] || ['Koyomi', 18]
|
6
|
+
result = attrs[:result] || Peeek::Call::ReturnValue.new('Koyomi (18)')
|
7
|
+
Peeek::Call.new(hook, sample_backtrace, '%s (%d)', args, result)
|
8
|
+
end
|
9
|
+
|
10
|
+
def sample_backtrace
|
11
|
+
["koyomi.rb:7:in `print'", "koyomi.rb:21:in `<main>'"]
|
12
|
+
end
|
13
|
+
|
14
|
+
def sample_return_value
|
15
|
+
Peeek::Call::ReturnValue.new(:return_value)
|
16
|
+
end
|
17
|
+
|
18
|
+
def sample_exception
|
19
|
+
Peeek::Call::Exception.new(:exception)
|
20
|
+
end
|
21
|
+
|
22
|
+
describe Peeek::Call, '#initialize' do
|
23
|
+
it 'raises ArgumentError if the result is invalid' do
|
24
|
+
lambda { sample_call(:result => :result) }.should raise_error(ArgumentError, 'invalid as result')
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
describe Peeek::Call, '#hook' do
|
29
|
+
it 'returns the value when constructed the call' do
|
30
|
+
hook = :hook
|
31
|
+
call = sample_call(:hook => hook)
|
32
|
+
call.hook.should == hook
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
describe Peeek::Call, '#backtrace' do
|
37
|
+
it 'returns the value when constructed the call' do
|
38
|
+
call = sample_call
|
39
|
+
call.backtrace.should == sample_backtrace
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
describe Peeek::Call, '#file' do
|
44
|
+
it 'returns name of top file on the backtrace' do
|
45
|
+
call = sample_call
|
46
|
+
call.file.should == 'koyomi.rb'
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
describe Peeek::Call, '#line' do
|
51
|
+
it 'returns top line number on the backtrace' do
|
52
|
+
call = sample_call
|
53
|
+
call.line.should == 7
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
describe Peeek::Call, '#receiver' do
|
58
|
+
it 'returns the value when constructed the call' do
|
59
|
+
call = sample_call
|
60
|
+
call.receiver.should == '%s (%d)'
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
describe Peeek::Call, '#arguments' do
|
65
|
+
it 'returns the value when constructed the call' do
|
66
|
+
call = sample_call
|
67
|
+
call.arguments.should == ['Koyomi', 18]
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
describe Peeek::Call, '#result' do
|
72
|
+
it 'returns the value when constructed the call' do
|
73
|
+
result = sample_return_value
|
74
|
+
call = sample_call(:result => result)
|
75
|
+
call.result.should == result
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
describe Peeek::Call, '#return_value' do
|
80
|
+
it 'returns value of the result' do
|
81
|
+
call = sample_call(:result => sample_return_value)
|
82
|
+
call.return_value.should == :return_value
|
83
|
+
end
|
84
|
+
|
85
|
+
it 'raises TypeError if the call is raised an exception' do
|
86
|
+
call = sample_call(:result => sample_exception)
|
87
|
+
lambda { call.return_value }.should raise_error(TypeError, "the call didn't return a value")
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
describe Peeek::Call, '#exception' do
|
92
|
+
it 'returns value of the result' do
|
93
|
+
call = sample_call(:result => sample_exception)
|
94
|
+
call.exception.should == :exception
|
95
|
+
end
|
96
|
+
|
97
|
+
it 'raises TypeError if the call returned a value' do
|
98
|
+
call = sample_call(:result => sample_return_value)
|
99
|
+
lambda { call.exception }.should raise_error(TypeError, "the call didn't raised an exception")
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
describe Peeek::Call, '#returned?' do
|
104
|
+
it 'is true if the call returned a value' do
|
105
|
+
call = sample_call(:result => sample_return_value)
|
106
|
+
call.should be_returned
|
107
|
+
end
|
108
|
+
|
109
|
+
it 'is false if the call is raised an exception' do
|
110
|
+
call = sample_call(:result => sample_exception)
|
111
|
+
call.should_not be_returned
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
describe Peeek::Call, '#raised?' do
|
116
|
+
it 'is true if the call is raised an exception' do
|
117
|
+
call = sample_call(:result => sample_exception)
|
118
|
+
call.should be_raised
|
119
|
+
end
|
120
|
+
|
121
|
+
it 'is false if the call returned a value' do
|
122
|
+
call = sample_call(:result => sample_return_value)
|
123
|
+
call.should_not be_raised
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
describe Peeek::Call, '#to_s' do
|
128
|
+
context 'with no arguments' do
|
129
|
+
it 'returns the stringified call' do
|
130
|
+
call = sample_call(:args => [])
|
131
|
+
call.to_s.should == 'String#% from "%s (%d)" returned "Koyomi (18)" in koyomi.rb at 7'
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
context 'with an argument' do
|
136
|
+
it 'returns the stringified call' do
|
137
|
+
call = sample_call(:args => [:arg])
|
138
|
+
call.to_s.should == 'String#% from "%s (%d)" with :arg returned "Koyomi (18)" in koyomi.rb at 7'
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
context 'with multiple arguments' do
|
143
|
+
it 'returns the stringified call' do
|
144
|
+
call = sample_call(:args => [:arg1, :arg2])
|
145
|
+
call.to_s.should == 'String#% from "%s (%d)" with (:arg1, :arg2) returned "Koyomi (18)" in koyomi.rb at 7'
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
context 'with a return value result' do
|
150
|
+
it 'returns the stringified call' do
|
151
|
+
call = sample_call(:result => sample_return_value)
|
152
|
+
call.to_s.should == 'String#% from "%s (%d)" with ("Koyomi", 18) returned :return_value in koyomi.rb at 7'
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
context 'with an exception result' do
|
157
|
+
it 'returns the stringified call' do
|
158
|
+
call = sample_call(:result => sample_exception)
|
159
|
+
call.to_s.should == 'String#% from "%s (%d)" with ("Koyomi", 18) raised :exception in koyomi.rb at 7'
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
describe Peeek::Call::ReturnValue do
|
165
|
+
it 'inhertis Peeek::Call::Result' do
|
166
|
+
result = described_class.allocate
|
167
|
+
result.should be_a(Peeek::Call::Result)
|
168
|
+
end
|
169
|
+
|
170
|
+
it 'identifies as key in a hash' do
|
171
|
+
hash = {sample_return_value => :return_value}
|
172
|
+
hash.should be_key(sample_return_value)
|
173
|
+
hash.should_not be_key(sample_exception)
|
174
|
+
hash.should_not be_key(described_class.new(:other_return_value))
|
175
|
+
hash.should_not be_key(Peeek::Call::Exception.new(:return_value))
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
describe Peeek::Call::ReturnValue, '#value' do
|
180
|
+
it 'returns the value when constructed the result' do
|
181
|
+
result = sample_return_value
|
182
|
+
result.value.should == :return_value
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
describe Peeek::Call::ReturnValue, '#==' do
|
187
|
+
it 'verifies equivalency' do
|
188
|
+
result = sample_return_value
|
189
|
+
result.should == sample_return_value
|
190
|
+
result.should_not == sample_exception
|
191
|
+
result.should_not == described_class.new(:other_return_value)
|
192
|
+
result.should_not == Peeek::Call::Exception.new(:return_value)
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
describe Peeek::Call::Exception do
|
197
|
+
it 'inhertis Peeek::Call::Result' do
|
198
|
+
result = described_class.allocate
|
199
|
+
result.should be_a(Peeek::Call::Result)
|
200
|
+
end
|
201
|
+
|
202
|
+
it 'identifies as key in a hash' do
|
203
|
+
hash = {sample_exception => :exception}
|
204
|
+
hash.should be_key(sample_exception)
|
205
|
+
hash.should_not be_key(sample_return_value)
|
206
|
+
hash.should_not be_key(described_class.new(:other_exception))
|
207
|
+
hash.should_not be_key(Peeek::Call::ReturnValue.new(:exception))
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
describe Peeek::Call::Exception, '#value' do
|
212
|
+
it 'returns the value when constructed the result' do
|
213
|
+
result = sample_exception
|
214
|
+
result.value.should == :exception
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
describe Peeek::Call::Exception, '#==' do
|
219
|
+
it 'verifies equivalency' do
|
220
|
+
result = sample_exception
|
221
|
+
result.should == sample_exception
|
222
|
+
result.should_not == sample_return_value
|
223
|
+
result.should_not == described_class.new(:other_exception)
|
224
|
+
result.should_not == Peeek::Call::ReturnValue.new(:exception)
|
225
|
+
end
|
226
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'peeek/calls'
|
3
|
+
|
4
|
+
def sample_calls
|
5
|
+
Peeek::Calls.new([
|
6
|
+
call_stub(:return_value, :file => 'koyomi.rb', :line => 5, :receiver => String),
|
7
|
+
call_stub(:exception, :file => 'koyomi.rb', :line => 7, :receiver => String),
|
8
|
+
call_stub(:return_value, :file => 'koyomi.rb', :line => 11, :receiver => Numeric),
|
9
|
+
call_stub(:return_value, :file => 'karen.rb', :line => 4, :receiver => String),
|
10
|
+
call_stub(:return_value, :file => 'karen.rb', :line => 7, :receiver => Numeric),
|
11
|
+
call_stub(:return_value, :file => 'karen.rb', :line => 12, :receiver => Numeric),
|
12
|
+
call_stub(:return_value, :file => 'tsukihi.rb', :line => 2, :receiver => Numeric),
|
13
|
+
call_stub(:return_value, :file => 'tsukihi.rb', :line => 3, :receiver => String),
|
14
|
+
call_stub(:return_value, :file => 'tsukihi.rb', :line => 12, :receiver => String)
|
15
|
+
])
|
16
|
+
end
|
17
|
+
|
18
|
+
describe Peeek::Calls, '#in' do
|
19
|
+
it "returns an instance of #{described_class}" do
|
20
|
+
filtered_calls = sample_calls.in('koyomi.rb')
|
21
|
+
filtered_calls.should be_a(described_class)
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'returns calls that corresponds to the name of the file' do
|
25
|
+
filtered_calls = sample_calls.in('koyomi.rb')
|
26
|
+
filtered_calls.should have(3).items
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'supports Regexp' do
|
30
|
+
filtered_calls = sample_calls.in(/^k/)
|
31
|
+
filtered_calls.should have(6).items
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
describe Peeek::Calls, '#at' do
|
36
|
+
it "returns an instance of #{described_class}" do
|
37
|
+
filtered_calls = sample_calls.at(7)
|
38
|
+
filtered_calls.should be_a(described_class)
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'returns calls that corresponds to the line number' do
|
42
|
+
filtered_calls = sample_calls.at(7)
|
43
|
+
filtered_calls.should have(2).items
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'supports Range' do
|
47
|
+
filtered_calls = sample_calls.at(1..10)
|
48
|
+
filtered_calls.should have(6).items
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
describe Peeek::Calls, '#from' do
|
53
|
+
it "returns an instance of #{described_class}" do
|
54
|
+
filtered_calls = sample_calls.from(String)
|
55
|
+
filtered_calls.should be_a(described_class)
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'returns calls that corresponds to the receiver' do
|
59
|
+
filtered_calls = sample_calls.from(String)
|
60
|
+
filtered_calls.should have(5).items
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
describe Peeek::Calls, '#return_values' do
|
65
|
+
it "returns an instance of #{described_class}" do
|
66
|
+
filtered_calls = sample_calls.return_values
|
67
|
+
filtered_calls.should be_a(described_class)
|
68
|
+
end
|
69
|
+
|
70
|
+
it 'returns calls that a value returned' do
|
71
|
+
filtered_calls = sample_calls.return_values
|
72
|
+
filtered_calls.should have(8).items
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
describe Peeek::Calls, '#exceptions' do
|
77
|
+
it "returns an instance of #{described_class}" do
|
78
|
+
filtered_calls = sample_calls.exceptions
|
79
|
+
filtered_calls.should be_a(described_class)
|
80
|
+
end
|
81
|
+
|
82
|
+
it 'returns calls that an exception raised' do
|
83
|
+
filtered_calls = sample_calls.exceptions
|
84
|
+
filtered_calls.should have(1).items
|
85
|
+
end
|
86
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
require 'peeek/hook/instance'
|
2
|
+
|
3
|
+
def sample_instance_linker(method_name = :%)
|
4
|
+
Peeek::Hook::Instance.new(String, method_name)
|
5
|
+
end
|
6
|
+
|
7
|
+
describe Peeek::Hook::Instance, '#method_prefix' do
|
8
|
+
it 'returns "#"' do
|
9
|
+
linker = sample_instance_linker
|
10
|
+
linker.method_prefix.should == '#'
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
describe Peeek::Hook::Instance, '#defined?' do
|
15
|
+
it 'is true if the method is defined in the object' do
|
16
|
+
linker = sample_instance_linker
|
17
|
+
linker.should be_defined
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'is true if the method is defined privately in the object' do
|
21
|
+
linker = sample_instance_linker(:binding)
|
22
|
+
linker.should be_defined
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'is false if the method is not defined in the object' do
|
26
|
+
linker = sample_instance_linker(:undefined_method)
|
27
|
+
linker.should_not be_defined
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
describe Peeek::Hook::Instance, '#link' do
|
32
|
+
before do
|
33
|
+
@original_method = String.instance_method(:%)
|
34
|
+
@linker = sample_instance_linker
|
35
|
+
end
|
36
|
+
|
37
|
+
after do
|
38
|
+
@linker.unlink(@original_method)
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'gives appropriate arguments to the block when calling the method' do
|
42
|
+
block_args = nil
|
43
|
+
@linker.link { |*args| block_args = args }
|
44
|
+
'%s (%d)' % ['Koyomi', 18]
|
45
|
+
block_args[0][0].should =~ %r(spec/peeek/hook/instance_spec\.rb)
|
46
|
+
block_args[1].should == '%s (%d)'
|
47
|
+
block_args[2].should == [['Koyomi', 18]]
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'is return value from the block as return value from the method' do
|
51
|
+
return_value = 'return_value'
|
52
|
+
@linker.link { |*args| return_value }
|
53
|
+
('%s (%d)' % ['Koyomi', 18]).should equal(return_value)
|
54
|
+
end
|
55
|
+
|
56
|
+
it 'is exception from the block as exception from the method' do
|
57
|
+
@linker.link { |*args| raise 'exception' }
|
58
|
+
lambda { '%s (%d)' % ['Koyomi', 18] }.should raise_error('exception')
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'returns the original method' do
|
62
|
+
@linker.link { }.should == @original_method
|
63
|
+
end
|
64
|
+
|
65
|
+
it 'raises ArgumentError if a block not given' do
|
66
|
+
lambda { @linker.link }.should raise_error(ArgumentError, 'block not supplied')
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
describe Peeek::Hook::Instance, '#unlink' do
|
71
|
+
before do
|
72
|
+
@original_method = String.instance_method(:%)
|
73
|
+
@linker = sample_instance_linker
|
74
|
+
@linker.link { fail }
|
75
|
+
end
|
76
|
+
|
77
|
+
it 'defines method with the original method' do
|
78
|
+
call = lambda { '%s (%d)' % ['Koyomi', 18] }
|
79
|
+
|
80
|
+
# assert
|
81
|
+
call.should raise_error
|
82
|
+
|
83
|
+
@linker.unlink(@original_method)
|
84
|
+
call.should_not raise_error
|
85
|
+
call[].should == 'Koyomi (18)'
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'peeek/hook/linker'
|
2
|
+
|
3
|
+
describe Peeek::Hook::Linker, '.classes' do
|
4
|
+
before do
|
5
|
+
@class = Class.new(described_class)
|
6
|
+
end
|
7
|
+
|
8
|
+
after do
|
9
|
+
described_class.classes.delete(@class)
|
10
|
+
end
|
11
|
+
|
12
|
+
it "returns classes that inherited #{described_class}" do
|
13
|
+
described_class.classes.should be_include(@class)
|
14
|
+
end
|
15
|
+
end
|