private_please 0.0.2 → 0.0.3
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.
- data/.ruby-version +1 -0
- data/CHANGELOG +6 -0
- data/README.md +51 -7
- data/TODO +11 -13
- data/lib/private_please/candidate.rb +41 -0
- data/lib/private_please/report/reporter.rb +52 -0
- data/lib/private_please/report/templates/simple.txt.erb +61 -0
- data/lib/private_please/ruby_backports.rb +22 -0
- data/lib/private_please/storage/calls_store.rb +41 -0
- data/lib/private_please/storage/candidates_store.rb +48 -0
- data/lib/private_please/storage/methods_names.rb +9 -0
- data/lib/private_please/storage/methods_names_bucket.rb +69 -0
- data/lib/private_please/tracking/extension.rb +19 -0
- data/lib/private_please/tracking/instrumentor.rb +71 -0
- data/lib/private_please/tracking/instruments_all_below.rb +41 -0
- data/lib/private_please/tracking/line_change_tracker.rb +36 -0
- data/lib/private_please/version.rb +1 -1
- data/lib/private_please.rb +33 -50
- data/private_please.gemspec +1 -0
- data/sample.rb +68 -0
- data/spec/01_marking_candidate_methods_to_observe_spec.rb +153 -0
- data/spec/02_logging_calls_on_candidate_methods_spec.rb +39 -0
- data/spec/04_instrumented_program_activity_observation_result_spec.rb +89 -0
- data/spec/fixtures/sample_class_for_report.rb +54 -0
- data/spec/fixtures/sample_class_with_all_calls_combinations.rb +69 -0
- data/spec/spec_helper.rb +52 -1
- data/spec/units/calls_store_spec.rb +15 -0
- data/spec/units/candidates_store_spec.rb +55 -0
- metadata +58 -28
- data/lib/private_please/candidates.rb +0 -37
- data/lib/private_please/configuration.rb +0 -21
- data/lib/private_please/line_change_tracker.rb +0 -19
- data/lib/private_please/recorder.rb +0 -34
- data/lib/private_please/report/template.txt.erb +0 -15
- data/lib/private_please/report.rb +0 -47
- data/spec/01_marking_methods_spec.rb +0 -30
- data/spec/02_calling_methods_spec.rb +0 -58
- data/spec/03_configuration_spec.rb +0 -52
- data/spec/04_at_exit_report_printing_spec.rb +0 -47
data/lib/private_please.rb
CHANGED
@@ -1,83 +1,66 @@
|
|
1
1
|
require 'private_please/version'
|
2
|
-
require 'private_please/
|
3
|
-
require 'private_please/
|
4
|
-
require 'private_please/
|
5
|
-
require 'private_please/
|
6
|
-
require 'private_please/
|
2
|
+
require 'private_please/ruby_backports'
|
3
|
+
require 'private_please/candidate'
|
4
|
+
require 'private_please/storage/calls_store'
|
5
|
+
require 'private_please/storage/candidates_store'
|
6
|
+
require 'private_please/storage/methods_names'
|
7
|
+
require 'private_please/storage/methods_names_bucket'
|
8
|
+
require 'private_please/report/reporter'
|
9
|
+
require 'private_please/tracking/line_change_tracker'
|
10
|
+
require 'private_please/tracking/extension'
|
11
|
+
require 'private_please/tracking/instrumentor'
|
12
|
+
require 'private_please/tracking/instruments_all_below'
|
7
13
|
|
8
14
|
module PrivatePlease
|
9
15
|
|
10
|
-
def
|
11
|
-
|
12
|
-
args.reject!{|m| !klass.instance_methods.include?(m.to_s)}
|
13
|
-
storage.candidates[klass.to_s] += args
|
14
|
-
args.each do |m|
|
15
|
-
mark_method(m)
|
16
|
-
end
|
16
|
+
def self.install
|
17
|
+
Module.send :include, PrivatePlease::Tracking::Extension
|
17
18
|
end
|
18
19
|
|
19
20
|
#--------------
|
20
21
|
# config
|
21
22
|
#--------------
|
22
|
-
|
23
|
-
|
23
|
+
|
24
|
+
def self.after_method_call(candidate, outside_call)
|
25
|
+
outside_call ?
|
26
|
+
calls_store.store_outside_call(candidate) :
|
27
|
+
calls_store.store_inside_call(candidate)
|
24
28
|
end
|
25
29
|
|
26
|
-
def
|
27
|
-
|
30
|
+
def self.remember_candidate(candidate)
|
31
|
+
candidates_store.store(candidate)
|
28
32
|
end
|
29
33
|
|
34
|
+
|
30
35
|
#--------------
|
31
|
-
#
|
36
|
+
# data & config containers :
|
32
37
|
#--------------
|
33
|
-
def recorder ; Recorder .instance end
|
34
|
-
def storage ; Candidates .instance end
|
35
|
-
def config ; Configuration.instance end
|
36
38
|
|
37
39
|
def self.reset_before_new_test
|
38
|
-
|
39
|
-
Candidates .reset_before_new_test
|
40
|
-
Configuration .reset_before_new_test
|
40
|
+
@@_calls_store = @@_candidates_store = nil
|
41
41
|
end
|
42
42
|
|
43
43
|
#--------------
|
44
44
|
# report
|
45
45
|
#--------------
|
46
|
-
|
47
|
-
|
46
|
+
|
47
|
+
def self.report
|
48
|
+
Report::Reporter.new(candidates_store, calls_store)
|
48
49
|
end
|
49
50
|
|
50
51
|
private
|
51
52
|
|
52
|
-
def
|
53
|
-
|
54
|
-
PrivatePlease.recorder.record_candidate(self_class, name)
|
55
|
-
orig_method = instance_method(name)
|
56
|
-
define_method(name) do |*args, &blk|
|
57
|
-
set_trace_func(nil) #don't track activity while here
|
58
|
-
|
59
|
-
self_class = self.class
|
60
|
-
if PrivatePlease.active?
|
61
|
-
call_initiator = LineChangeTracker.prev_self
|
62
|
-
is_outside_call = call_initiator.class != self_class
|
63
|
-
is_outside_call ?
|
64
|
-
PrivatePlease.recorder.record_outside_call(self_class, name) :
|
65
|
-
PrivatePlease.recorder.record_inside_call( self_class, name)
|
66
|
-
end
|
67
|
-
|
68
|
-
# make the call :
|
69
|
-
set_trace_func(LineChangeTracker::MY_TRACE_FUN)
|
70
|
-
orig_method.bind(self).call(*args, &blk)
|
71
|
-
end
|
53
|
+
def self.calls_store
|
54
|
+
@@_calls_store ||= Storage::CallsStore.new
|
72
55
|
end
|
73
56
|
|
57
|
+
def self.candidates_store
|
58
|
+
@@_candidates_store ||= Storage::CandidatesStore.new
|
59
|
+
end
|
74
60
|
end
|
75
61
|
|
76
|
-
Module.send :include, PrivatePlease
|
77
62
|
|
63
|
+
PrivatePlease.install
|
78
64
|
at_exit {
|
79
|
-
|
80
|
-
puts '-'*888
|
81
|
-
puts PrivatePlease.report.to_s
|
82
|
-
end
|
65
|
+
puts PrivatePlease.report.to_s
|
83
66
|
}
|
data/private_please.gemspec
CHANGED
data/sample.rb
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
# require 'private_please'
|
2
|
+
require 'lib/private_please' # use the latest version
|
3
|
+
|
4
|
+
module ReportSample
|
5
|
+
###########################################
|
6
|
+
class Simple # Internal calls : #
|
7
|
+
# -> called methods are _GOOD CANDIDATES_ #
|
8
|
+
def make_internal_calls ###########################################
|
9
|
+
instance_m_1 # i -> i
|
10
|
+
instance_m_3 # i -> i
|
11
|
+
self.class.class_m_1 # i -> C
|
12
|
+
self.class.class_m_2 # i -> C
|
13
|
+
self.class.c_make_internal_method_calls # i -> C --> C
|
14
|
+
end # +-> i
|
15
|
+
|
16
|
+
def self.c_make_internal_method_calls #
|
17
|
+
class_m_1 # C -> C
|
18
|
+
new.instance_m_2 # C -> i
|
19
|
+
end #
|
20
|
+
end
|
21
|
+
|
22
|
+
#######################################################
|
23
|
+
class AnotherClass # External calls (would fail if methods were private) #
|
24
|
+
private_please # -> called methods are _BAD CANDIDATES_ #
|
25
|
+
def make_external_calls #######################################################
|
26
|
+
Simple.new.instance_m_1 # i -> i
|
27
|
+
Simple .class_m_1 # i -> C
|
28
|
+
self.class.c_make_external_calls # i -> C -> i
|
29
|
+
end # -> C
|
30
|
+
def self.c_make_external_calls #
|
31
|
+
Simple.new.instance_m_1 # C -> i
|
32
|
+
Simple .class_m_1 # C -> C
|
33
|
+
Simple .class_m_2 # C -> C
|
34
|
+
end #
|
35
|
+
def call_the_candidate_from_inside_and_outside
|
36
|
+
make_external_calls
|
37
|
+
Simple.new.make_internal_calls
|
38
|
+
end
|
39
|
+
def never_called; end
|
40
|
+
def self.never_called_c; end
|
41
|
+
end
|
42
|
+
|
43
|
+
#-----------------------------------------------------------------------------------------------------------------------
|
44
|
+
class Simple
|
45
|
+
def self.not_a_candidate_c1;
|
46
|
+
class_m_2
|
47
|
+
end
|
48
|
+
|
49
|
+
private_please
|
50
|
+
def instance_m_1; end
|
51
|
+
def instance_m_2; end
|
52
|
+
def instance_m_3; end
|
53
|
+
|
54
|
+
def self.class_m_1;
|
55
|
+
class_m_2
|
56
|
+
end
|
57
|
+
def self.class_m_2; end
|
58
|
+
|
59
|
+
def never_called_1; end
|
60
|
+
def self.class_never_called_1; end
|
61
|
+
end
|
62
|
+
end unless defined?(ReportSample::Simple)
|
63
|
+
#-----------------------------------------------------------------------------------------------------------------------
|
64
|
+
|
65
|
+
ReportSample::Simple.new.make_internal_calls
|
66
|
+
ReportSample::AnotherClass.new.make_external_calls
|
67
|
+
ReportSample::AnotherClass.c_make_external_calls
|
68
|
+
|
@@ -0,0 +1,153 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe PrivatePlease, 'collecting the details of candidate-methods to observe' do
|
4
|
+
module MarkingTest; end
|
5
|
+
|
6
|
+
let(:candidates_store) { PrivatePlease.storage }
|
7
|
+
|
8
|
+
# ----------------
|
9
|
+
context 'observing with `private_please(<method names>)`' do
|
10
|
+
# ----------------
|
11
|
+
|
12
|
+
it('stores the instance methods names in the candidates list, indexed by their owning class') do
|
13
|
+
class MarkingTest::Simple1
|
14
|
+
def foo ; 'foo' end
|
15
|
+
def bar ; 'bar' end
|
16
|
+
def buz ; 'bar' end
|
17
|
+
private_please :bar, 'buz' # <<-- what we test
|
18
|
+
end
|
19
|
+
|
20
|
+
assert_instance_methods_candidates 'MarkingTest::Simple1' =>[:bar, :buz]
|
21
|
+
end
|
22
|
+
|
23
|
+
|
24
|
+
it('does not work with class methods') do
|
25
|
+
class MarkingTest::Simple1b
|
26
|
+
def self.found ; 'I am a class method' end
|
27
|
+
private_please :found # <<-- class method => not observed
|
28
|
+
end
|
29
|
+
|
30
|
+
assert_instance_methods_candidates ({})
|
31
|
+
assert_class_methods_candidates ({})
|
32
|
+
end
|
33
|
+
|
34
|
+
it('ignores invalid candidates (method not found in the class)') do
|
35
|
+
class MarkingTest::Simple2
|
36
|
+
def found ; 'foo' end
|
37
|
+
private_please :found # <<-- valid
|
38
|
+
private_please :not_found_method # <<-- not found => INvalid
|
39
|
+
end
|
40
|
+
|
41
|
+
assert_instance_methods_candidates 'MarkingTest::Simple2' =>[:found]
|
42
|
+
end
|
43
|
+
|
44
|
+
it('ignores duplicates') do
|
45
|
+
class MarkingTest::Simple3
|
46
|
+
def found ; 'foo' end
|
47
|
+
private_please :found #
|
48
|
+
private_please :found # duplicate -> ignore
|
49
|
+
end
|
50
|
+
|
51
|
+
assert_instance_methods_candidates 'MarkingTest::Simple3' =>[:found]
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
|
56
|
+
# ----------------
|
57
|
+
context 'observing with `private_please()`' do
|
58
|
+
# ----------------
|
59
|
+
|
60
|
+
example 'all the instance methods defined after `private_please` are stored as candidates' do
|
61
|
+
|
62
|
+
class MarkingTest::Automatic1
|
63
|
+
def foo ; end # NO (too early)
|
64
|
+
private_please # ---> # <start observing>
|
65
|
+
def baz ; end # *
|
66
|
+
public # *
|
67
|
+
def qux ; end # *
|
68
|
+
def included ; end # * special name, but valid candidate (in classes).
|
69
|
+
end
|
70
|
+
assert_instance_methods_candidates 'MarkingTest::Automatic1' =>[:baz, :qux, :included]
|
71
|
+
assert_class_methods_candidates ({})
|
72
|
+
end
|
73
|
+
|
74
|
+
|
75
|
+
example 'all the class methods defined after `private_please` are stored as candidates' do
|
76
|
+
class MarkingTest::Automatic1b
|
77
|
+
def self.foo ; end # NO (too early)
|
78
|
+
private_please # ---> # <start observing>
|
79
|
+
def self.baz ; end # YES
|
80
|
+
public # *
|
81
|
+
def self.qux ; end # YES
|
82
|
+
def self.included ; end # * special name, but valid candidate (in classes).
|
83
|
+
end
|
84
|
+
|
85
|
+
assert_instance_methods_candidates ({})
|
86
|
+
assert_class_methods_candidates 'MarkingTest::Automatic1b' =>[:baz, :qux, :included]
|
87
|
+
end
|
88
|
+
|
89
|
+
example ('already private methods are ignored/not observed') do
|
90
|
+
class MarkingTest::Automatic1c
|
91
|
+
private_please # ---> # <start observing>
|
92
|
+
def self.baz ; end # YES
|
93
|
+
public # *
|
94
|
+
def qux ; end # YES
|
95
|
+
private #
|
96
|
+
def already_private ; end # NO
|
97
|
+
class << self
|
98
|
+
private
|
99
|
+
def class_already_private ; end # NO
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
assert_instance_methods_candidates 'MarkingTest::Automatic1c' =>[:qux]
|
104
|
+
assert_class_methods_candidates 'MarkingTest::Automatic1c' =>[:baz]
|
105
|
+
end
|
106
|
+
|
107
|
+
|
108
|
+
example 'method coming from an included module are observed too' do
|
109
|
+
#TODO : find a better way to instrument modules
|
110
|
+
#TODO : find a way to instrument modules automatically (? possible)
|
111
|
+
|
112
|
+
module Extra002 ; private_please end # <<=== Pre-instrument.
|
113
|
+
module Extra002::ClassMethods ; private_please end # <<=== Pre-instrument.
|
114
|
+
|
115
|
+
module Extra002 # Reopen the pre-instrumented
|
116
|
+
def im_from_module ; end # module.
|
117
|
+
def self.included(base) #
|
118
|
+
base.extend ClassMethods #
|
119
|
+
end #
|
120
|
+
module ClassMethods #
|
121
|
+
def cm_from_modulex ; end #
|
122
|
+
end #
|
123
|
+
end #
|
124
|
+
assert_instance_methods_candidates 'Extra002' =>[:im_from_module],
|
125
|
+
'Extra002::ClassMethods' =>[:cm_from_module]
|
126
|
+
assert_class_methods_candidates ({})
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
|
131
|
+
# ----------------
|
132
|
+
context 'observing with `include PrivatePlease::Tracking::InstrumentsAllBelow`' do
|
133
|
+
# ----------------
|
134
|
+
|
135
|
+
example 'all the methods defined subsequently are stored as candidates' do
|
136
|
+
|
137
|
+
class MarkingTest::Automatic2
|
138
|
+
def foo ; end
|
139
|
+
def bar ; end
|
140
|
+
include PrivatePlease::Tracking::InstrumentsAllBelow # ---> # <start observing>
|
141
|
+
def baz ; end # YES
|
142
|
+
def self.class_m1; end # YES
|
143
|
+
protected #
|
144
|
+
def qux ; end # YES
|
145
|
+
end
|
146
|
+
|
147
|
+
assert_instance_methods_candidates 'MarkingTest::Automatic2' =>[:baz, :qux]
|
148
|
+
assert_class_methods_candidates 'MarkingTest::Automatic2' =>[:class_m1]
|
149
|
+
end
|
150
|
+
|
151
|
+
end
|
152
|
+
|
153
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe PrivatePlease, 'calling observed methods and logging calls in 2 categories : internal or external' do
|
4
|
+
|
5
|
+
before do
|
6
|
+
#-----------------------------------------------------------------------------------------------------------------------
|
7
|
+
require File.dirname(__FILE__) + '/fixtures/sample_class_with_all_calls_combinations'
|
8
|
+
#-----------------------------------------------------------------------------------------------------------------------
|
9
|
+
end
|
10
|
+
|
11
|
+
|
12
|
+
NO_CALLS_OBSERVED = {}
|
13
|
+
|
14
|
+
example ('pure internal calls are categorized correctly') do
|
15
|
+
CallsSample::Simple.new.make_internal_calls
|
16
|
+
assert_calls_detected :inside => {'CallsSample::Simple' => mnames_for([:instance_m_1, :instance_m_2])},
|
17
|
+
:outside => NO_CALLS_OBSERVED,
|
18
|
+
:inside_c => {'CallsSample::Simple' => mnames_for([:class_m_1, :class_m_2])},
|
19
|
+
:outside_c => NO_CALLS_OBSERVED
|
20
|
+
end
|
21
|
+
|
22
|
+
example ('pure external calls are categorized correctly') do
|
23
|
+
CallsSample::AnotherClass.new.make_external_calls
|
24
|
+
assert_calls_detected :inside => NO_CALLS_OBSERVED,
|
25
|
+
:outside => {'CallsSample::Simple' => mnames_for([:instance_m_1])},
|
26
|
+
:inside_c => {'CallsSample::Simple' => mnames_for([:class_m_2])},
|
27
|
+
:outside_c => {'CallsSample::Simple' => mnames_for([:class_m_1])}
|
28
|
+
end
|
29
|
+
|
30
|
+
example('when a method is called both from inside and from outside its class, it is recorded is both categories') do
|
31
|
+
CallsSample::AnotherClass.new.call_the_candidate_from_inside_and_outside
|
32
|
+
assert_calls_detected :inside => {'CallsSample::Simple' => mnames_for([:instance_m_1, :instance_m_2])},
|
33
|
+
:outside => {'CallsSample::Simple' => mnames_for([:instance_m_1])},
|
34
|
+
:inside_c => {'CallsSample::Simple' => mnames_for([:class_m_2, :class_m_1])},
|
35
|
+
:outside_c => {'CallsSample::Simple' => mnames_for([:class_m_1])}
|
36
|
+
end
|
37
|
+
|
38
|
+
#-----------------------------------------------------------------------------------------------------------------------
|
39
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'PrivatePlease.report', 'observing an instrumented program activity' do
|
4
|
+
|
5
|
+
def run_the_instrumented_program
|
6
|
+
ActivityTest::Simple.new.tap do |o|
|
7
|
+
o.not_a_candidate_1
|
8
|
+
o.not_a_candidate_2
|
9
|
+
o.class.not_a_candidate_c1
|
10
|
+
o.bad_candidate_3
|
11
|
+
o.bad_candidate_6
|
12
|
+
o.class.bad_candidate_c3
|
13
|
+
end
|
14
|
+
ActivityTest::Simple2.new.bad_candidate_too
|
15
|
+
ActivityTest::Simple2 .bad_candidate_c_too
|
16
|
+
end
|
17
|
+
|
18
|
+
before do
|
19
|
+
|
20
|
+
module ActivityTest
|
21
|
+
class Simple
|
22
|
+
def not_a_candidate_1; bad_candidate_3 end
|
23
|
+
def not_a_candidate_2; good_candidate_7 end
|
24
|
+
def self.not_a_candidate_c1;
|
25
|
+
good_candidate_c2
|
26
|
+
end
|
27
|
+
private_please
|
28
|
+
def bad_candidate_3; good_candidate_4 end
|
29
|
+
def good_candidate_4; good_candidate_5 end
|
30
|
+
def good_candidate_5; bad_candidate_6 end
|
31
|
+
def bad_candidate_6; good_candidate_7 end
|
32
|
+
def good_candidate_7; end
|
33
|
+
def ignored_8 ; 'never called' end
|
34
|
+
def self.ignored_c9 ; 'never called' end
|
35
|
+
def self.good_candidate_c2; end
|
36
|
+
def self.bad_candidate_c3; end
|
37
|
+
end
|
38
|
+
|
39
|
+
class Simple2
|
40
|
+
private_please
|
41
|
+
def bad_candidate_too; end
|
42
|
+
def ignored_2; 'never called' end
|
43
|
+
def self.ignored_c3; 'never called' end
|
44
|
+
def self.bad_candidate_c_too; end
|
45
|
+
end
|
46
|
+
end unless defined?(ActivityTest::Simple)
|
47
|
+
end
|
48
|
+
|
49
|
+
# Note: test all in 1 go because testing in bits would fail, and it differs from real usage.
|
50
|
+
it 'obtains the right info by observing the program activity' do
|
51
|
+
run_the_instrumented_program
|
52
|
+
the_report = PrivatePlease.report
|
53
|
+
{
|
54
|
+
:good_candidates => the_report.good_candidates,
|
55
|
+
:good_candidates_c => the_report.good_candidates_c,
|
56
|
+
:bad_candidates => the_report.bad_candidates,
|
57
|
+
:bad_candidates_c => the_report.bad_candidates_c,
|
58
|
+
:ignored => the_report.never_called_candidates,
|
59
|
+
:ignored_c => the_report.never_called_candidates_c
|
60
|
+
}.should == {
|
61
|
+
:good_candidates => {
|
62
|
+
'ActivityTest::Simple' => mnames_for([:good_candidate_4, :good_candidate_5, :good_candidate_7])
|
63
|
+
},
|
64
|
+
:good_candidates_c => {
|
65
|
+
'ActivityTest::Simple' => mnames_for([:good_candidate_c2])
|
66
|
+
},
|
67
|
+
:bad_candidates => {
|
68
|
+
'ActivityTest::Simple' => mnames_for([:bad_candidate_3, :bad_candidate_6]),
|
69
|
+
'ActivityTest::Simple2' => mnames_for([:bad_candidate_too])
|
70
|
+
},
|
71
|
+
:bad_candidates_c => {
|
72
|
+
'ActivityTest::Simple' => mnames_for([:bad_candidate_c3]),
|
73
|
+
'ActivityTest::Simple2' => mnames_for([:bad_candidate_c_too])
|
74
|
+
},
|
75
|
+
:ignored => {
|
76
|
+
'ActivityTest::Simple' => mnames_for([:ignored_8]),
|
77
|
+
'ActivityTest::Simple2' => mnames_for([:ignored_2])
|
78
|
+
},
|
79
|
+
:ignored_c => {
|
80
|
+
'ActivityTest::Simple' => mnames_for([:ignored_c9]),
|
81
|
+
'ActivityTest::Simple2' => mnames_for([:ignored_c3])
|
82
|
+
}
|
83
|
+
}
|
84
|
+
puts the_report.to_s
|
85
|
+
puts "\n***report building time : #{the_report.building_time} sec."
|
86
|
+
|
87
|
+
end
|
88
|
+
|
89
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module ReportSample
|
2
|
+
###########################################
|
3
|
+
class Simple # Internal calls : #
|
4
|
+
# -> called methods are _GOOD CANDIDATES_ #
|
5
|
+
def make_internal_calls ###########################################
|
6
|
+
instance_m_1 # i -> i
|
7
|
+
self.class.class_m_1 # i -> C
|
8
|
+
self.class.c_make_internal_method_calls # i -> C --> C
|
9
|
+
end # +-> i
|
10
|
+
|
11
|
+
def self.c_make_internal_method_calls #
|
12
|
+
class_m_1 # C -> C
|
13
|
+
new.instance_m_2 # C -> i
|
14
|
+
end #
|
15
|
+
end
|
16
|
+
|
17
|
+
#######################################################
|
18
|
+
class AnotherClass # External calls (would fail if methods were private) #
|
19
|
+
# -> called methods are _BAD CANDIDATES_ #
|
20
|
+
def make_external_calls #######################################################
|
21
|
+
Simple.new.instance_m_1 # i -> i
|
22
|
+
Simple .class_m_1 # i -> C
|
23
|
+
self.class.c_make_external_calls # i -> C -> i
|
24
|
+
end # -> C
|
25
|
+
def self.c_make_external_calls #
|
26
|
+
Simple.new.instance_m_1 # C -> i
|
27
|
+
Simple .class_m_1 # C -> C
|
28
|
+
end #
|
29
|
+
def call_the_candidate_from_inside_and_outside
|
30
|
+
make_external_calls
|
31
|
+
Simple.new.make_internal_calls
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
#-----------------------------------------------------------------------------------------------------------------------
|
36
|
+
class Simple
|
37
|
+
def self.not_a_candidate_c1;
|
38
|
+
class_m_2
|
39
|
+
end
|
40
|
+
|
41
|
+
private_please
|
42
|
+
def instance_m_1; end
|
43
|
+
def instance_m_2; end
|
44
|
+
|
45
|
+
def self.class_m_1;
|
46
|
+
class_m_2
|
47
|
+
end
|
48
|
+
def self.class_m_2; end
|
49
|
+
|
50
|
+
def never_called_1; end
|
51
|
+
def self.class_never_called_1; end
|
52
|
+
end
|
53
|
+
end unless defined?(ReportSample::Simple)
|
54
|
+
#-----------------------------------------------------------------------------------------------------------------------
|
@@ -0,0 +1,69 @@
|
|
1
|
+
module CallsSample
|
2
|
+
###########################################
|
3
|
+
class Simple # Internal calls : #
|
4
|
+
# -> called methods are _GOOD CANDIDATES_ #
|
5
|
+
def make_internal_calls ###########################################
|
6
|
+
instance_m_1 # i -> i
|
7
|
+
self.class.class_m_1 # i -> C
|
8
|
+
self.class.c_make_internal_method_calls # i -> C --> C
|
9
|
+
end # +-> i
|
10
|
+
|
11
|
+
def self.c_make_internal_method_calls #
|
12
|
+
class_m_1 # C -> C
|
13
|
+
new.instance_m_2 # C -> i
|
14
|
+
end #
|
15
|
+
end
|
16
|
+
|
17
|
+
#######################################################
|
18
|
+
class AnotherClass # External calls (would fail if methods were private) #
|
19
|
+
# -> called methods are _BAD CANDIDATES_ #
|
20
|
+
def make_external_calls #######################################################
|
21
|
+
Simple.new.instance_m_1 # i -> i
|
22
|
+
Simple .class_m_1 # i -> C
|
23
|
+
self.class.c_make_external_calls # i -> C -> i
|
24
|
+
end # -> C
|
25
|
+
def self.c_make_external_calls #
|
26
|
+
Simple.new.instance_m_1 # C -> i
|
27
|
+
Simple .class_m_1 # C -> C
|
28
|
+
end #
|
29
|
+
def call_the_candidate_from_inside_and_outside
|
30
|
+
make_external_calls
|
31
|
+
CallsSample::Simple.new.make_internal_calls
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
#-----------------------------------------------------------------------------------------------------------------------
|
36
|
+
module Extra ; private_please end # <<=== Pre-instrument.
|
37
|
+
module Extra::ClassMethods ; private_please end # <<=== Pre-instrument.
|
38
|
+
|
39
|
+
module Extra
|
40
|
+
def self.included(base)
|
41
|
+
base.extend(ClassMethods)
|
42
|
+
end
|
43
|
+
def an_instance_method ; end
|
44
|
+
module ClassMethods
|
45
|
+
def a_class_method_via_module_Extra ; end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
|
50
|
+
class Simple
|
51
|
+
def self.not_a_candidate_c1;
|
52
|
+
class_m_2
|
53
|
+
end
|
54
|
+
|
55
|
+
private_please
|
56
|
+
include Extra
|
57
|
+
def instance_m_1; end
|
58
|
+
def instance_m_2; end
|
59
|
+
|
60
|
+
def self.class_m_1;
|
61
|
+
class_m_2
|
62
|
+
end
|
63
|
+
def self.class_m_2; end
|
64
|
+
|
65
|
+
def never_called_1; end
|
66
|
+
def self.class_never_called_1; end
|
67
|
+
end
|
68
|
+
#-----------------------------------------------------------------------------------------------------------------------
|
69
|
+
end unless defined?(CallsSample::Simple)
|
data/spec/spec_helper.rb
CHANGED
@@ -1,9 +1,60 @@
|
|
1
|
-
# This file was generated by the `rspec --init` command. Conventionally, all
|
1
|
+
# This file was (originally) generated by the `rspec --init` command. Conventionally, all
|
2
2
|
# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
|
3
3
|
# Require this file using `require "spec_helper"` to ensure that it is only
|
4
4
|
# loaded once.
|
5
5
|
#
|
6
6
|
# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
|
7
|
+
|
8
|
+
module PrivatePlease
|
9
|
+
def self.reset_before_new_test
|
10
|
+
PrivatePlease .reset_before_new_test
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
class Hash
|
15
|
+
def to_methods_names_bucket
|
16
|
+
PrivatePlease::Storage::MethodsNamesBucket.new.tap do |bucket|
|
17
|
+
each_pair do |class_name, method_names_as_a|
|
18
|
+
method_names_as_a.each do |method_name|
|
19
|
+
bucket.add_method_name(class_name, method_name)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def assert_instance_methods_candidates(raw_expected)
|
27
|
+
expected = raw_expected.to_methods_names_bucket if raw_expected.is_a?(Hash)
|
28
|
+
PrivatePlease.candidates_store.instance_methods.should == expected
|
29
|
+
end
|
30
|
+
|
31
|
+
def assert_class_methods_candidates(raw_expected)
|
32
|
+
expected = raw_expected.to_methods_names_bucket if raw_expected.is_a?(Hash)
|
33
|
+
PrivatePlease.candidates_store.class_methods.should == expected
|
34
|
+
end
|
35
|
+
|
36
|
+
|
37
|
+
|
38
|
+
def assert_calls_detected(expected)
|
39
|
+
calls_db = PrivatePlease.calls_store
|
40
|
+
{ :inside => calls_db.internal_calls,
|
41
|
+
:inside_c => calls_db.class_internal_calls,
|
42
|
+
:outside => calls_db.external_calls,
|
43
|
+
:outside_c => calls_db.class_external_calls
|
44
|
+
}.should == expected
|
45
|
+
end
|
46
|
+
|
47
|
+
NO_CALLS_OBSERVED = {}
|
48
|
+
|
49
|
+
def assert_no_calls_detected
|
50
|
+
assert_calls_detected :inside => NO_CALLS_OBSERVED, :outside => NO_CALLS_OBSERVED,
|
51
|
+
:inside_c => NO_CALLS_OBSERVED, :outside_c => NO_CALLS_OBSERVED
|
52
|
+
end
|
53
|
+
|
54
|
+
def mnames_for(args)
|
55
|
+
PrivatePlease::Storage::MethodsNames.new(Array(args))
|
56
|
+
end
|
57
|
+
|
7
58
|
RSpec.configure do |config|
|
8
59
|
config.treat_symbols_as_metadata_keys_with_true_values = true
|
9
60
|
config.run_all_when_everything_filtered = true
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
|
4
|
+
describe PrivatePlease::Storage::CallsStore do
|
5
|
+
|
6
|
+
let(:calls_store ) { PrivatePlease::Storage::CallsStore.new }
|
7
|
+
|
8
|
+
context 'when fresh' do
|
9
|
+
it 'is empty (has no calls)' do
|
10
|
+
calls_store.internal_calls .should be_empty
|
11
|
+
calls_store.external_calls .should be_empty
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|