private_please 0.0.4 → 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG CHANGED
@@ -1,3 +1,6 @@
1
+ v0.0.5
2
+ - required gems/standard libraries are no longer tracked.
3
+
1
4
  v0.0.4
2
5
  - `private_please :foo, :bar` syntax is removed.
3
6
  - auto-mode via `$ pp_ruby`
@@ -18,7 +18,9 @@ module PrivatePlease
18
18
  end
19
19
 
20
20
  def self.pp_automatic_mode_enabled? ; !!$pp_automatic_mode_enabled end
21
- def self.pp_automatic_mode_enable ; $pp_automatic_mode_enabled = true end
21
+ def self.pp_automatic_mode_enable(value=true)
22
+ $pp_automatic_mode_enabled = value
23
+ end
22
24
  def self.pp_automatic_mode_disable ; $pp_automatic_mode_enabled = false end
23
25
 
24
26
  # TODO : replace class methods by PP instance + instance methods
@@ -1,28 +1,14 @@
1
+ require File.dirname(__FILE__) + '/data_compiler'
1
2
  module PrivatePlease ; module Reporter
2
3
 
3
4
  class Base
4
5
 
5
- attr_reader :candidates_store, :calls_store,
6
- :good_candidates, :bad_candidates,
7
- :good_candidates_c, :bad_candidates_c,
8
- :never_called_candidates, :never_called_candidates_c,
9
- :building_time
10
-
6
+ attr_reader :data
11
7
 
12
8
  def initialize(candidates_store, calls_store)
13
- @candidates_store = candidates_store
14
- @calls_store = calls_store
15
-
16
- start_time = Time.now
17
- prepare_report_data
18
- @building_time = Time.now - start_time
9
+ @data = DataCompiler.new(candidates_store, calls_store).compile_data
19
10
  end
20
11
 
21
- private
22
-
23
- def prepare_report_data
24
- raise "prepare_report_data() ot implemented in the child class"
25
- end
26
12
  end
27
13
 
28
14
  end end
@@ -0,0 +1,82 @@
1
+ module PrivatePlease ; module Reporter
2
+
3
+ class Data < Struct.new(
4
+ :candidates_classes_names,
5
+ :good_candidates, :bad_candidates, :never_called_candidates,
6
+ :good_candidates_c, :bad_candidates_c, :never_called_candidates_c,
7
+ :building_time
8
+ )
9
+ end
10
+
11
+ class DataCompiler
12
+
13
+ def initialize(candidates_store, calls_store)
14
+ @candidates_store = candidates_store
15
+ @calls_store = calls_store
16
+ end
17
+
18
+ # TODO : optimize (with Hamster?)
19
+ def compile_data
20
+ start_time = Time.now
21
+
22
+ bad_candidates,
23
+ bad_candidates_c = read_bad_candidates
24
+ candidates_classes_names = read_candidates_classes_names
25
+
26
+ good_candidates,
27
+ good_candidates_c = compute_good_candidates(bad_candidates, bad_candidates_c)
28
+
29
+ never_called_candidates,
30
+ never_called_candidates_c = compute_never_called_candidates(good_candidates, bad_candidates,
31
+ good_candidates_c, bad_candidates_c)
32
+
33
+ remove_candidates_with_no_methods!(bad_candidates, good_candidates, never_called_candidates,
34
+ bad_candidates_c, good_candidates_c, never_called_candidates_c)
35
+ building_time = Time.now - start_time
36
+
37
+ Data.new(
38
+ candidates_classes_names,
39
+ good_candidates, bad_candidates, never_called_candidates,
40
+ good_candidates_c, bad_candidates_c, never_called_candidates_c,
41
+ building_time
42
+ )
43
+ end
44
+
45
+ private
46
+
47
+ def read_candidates_classes_names
48
+ @candidates_store.classes_names.sort
49
+ end
50
+
51
+ def read_bad_candidates
52
+ [ bad_candidates = @calls_store.external_calls,
53
+ bad_candidates_c = @calls_store.class_external_calls
54
+ ]
55
+ end
56
+
57
+ def compute_good_candidates(bad_candidates, bad_candidates_c)
58
+ [ good_candidates = @calls_store.internal_calls .clone.remove(bad_candidates),
59
+ good_candidates_c = @calls_store.class_internal_calls.clone.remove(bad_candidates_c)
60
+ ]
61
+ end
62
+
63
+ def compute_never_called_candidates(good_candidates, bad_candidates, good_candidates_c, bad_candidates_c)
64
+ never_called_candidates = @candidates_store.instance_methods.clone.
65
+ remove(good_candidates).
66
+ remove(bad_candidates)
67
+
68
+ never_called_candidates_c = @candidates_store.class_methods.clone.
69
+ remove(good_candidates_c).
70
+ remove(bad_candidates_c)
71
+ [never_called_candidates, never_called_candidates_c]
72
+ end
73
+
74
+ def remove_candidates_with_no_methods!(bad_candidates, good_candidates, never_called_candidates, bad_candidates_c, good_candidates_c, never_called_candidates_c)
75
+ [
76
+ bad_candidates, bad_candidates_c, good_candidates, good_candidates_c, never_called_candidates, never_called_candidates_c
77
+ ].each { |arr| arr.reject! { |k, v| v.empty? } }
78
+ end
79
+
80
+ end
81
+
82
+ end end
@@ -1,12 +1,37 @@
1
1
 
2
- def show_never_called_candidates_section?
3
- ENV['PP_OPTIONS'] =~ /--show-never-called/
4
- end
2
+ DEFAULT_REPORT_OPTIONS = {
3
+ :show_never_called_candidates_section? => false,
4
+ :show_bad_candidates_section? => false,
5
+ :show_empty_classes? => false
6
+ }
5
7
 
6
- def show_bad_candidates_section?
7
- ENV['PP_OPTIONS'] =~ /--show-bad-candidates/
8
- end
8
+ def options
9
+ Object.new.tap do |o|
10
+ def o.show_never_called_candidates_section?
11
+ (ENV['PP_OPTIONS'] =~ /--show-never-called/) || DEFAULT_REPORT_OPTIONS[:show_never_called_candidates_section?]
12
+ end
9
13
 
10
- def show_empty_classes?
11
- ENV['PP_OPTIONS'] =~ /--show-empty-classes/
14
+ def o.show_bad_candidates_section?
15
+ (ENV['PP_OPTIONS'] =~ /--show-bad-candidates/) || DEFAULT_REPORT_OPTIONS[:show_bad_candidates_section?]
16
+ end
17
+
18
+ def o.show_empty_classes?
19
+ (ENV['PP_OPTIONS'] =~ /--show-empty-classes/) || DEFAULT_REPORT_OPTIONS[:show_empty_classes?]
20
+ end
21
+ end
12
22
  end
23
+
24
+ def options_footer_parts
25
+ parts = []
26
+ DEFAULT_REPORT_OPTIONS.keys.each do |key|
27
+ display = "--#{key}".gsub('_', '-')
28
+ current_value = options.send(key)
29
+ is_default = DEFAULT_REPORT_OPTIONS[key] == current_value
30
+ parts << [display, (is_default ? '*' : ' '), current_value]
31
+ end
32
+ longest_value_length = parts.map(&:first).map(&:length).max || 0
33
+ parts.each do |p|
34
+ p[0] = p[0].ljust(longest_value_length)
35
+ end
36
+ parts
37
+ end
@@ -13,34 +13,6 @@ module PrivatePlease ; module Reporter
13
13
  erb.result(binding)
14
14
  end
15
15
 
16
- private
17
-
18
- def prepare_report_data
19
- start_time = Time.now
20
- @bad_candidates = calls_store.external_calls .clone
21
- @bad_candidates_c = calls_store.class_external_calls.clone
22
- # TODO : optimize (with Hamster?)
23
- @good_candidates = calls_store.internal_calls .clone.remove(@bad_candidates)
24
- @good_candidates_c= calls_store.class_internal_calls.clone.remove(@bad_candidates_c)
25
-
26
- @never_called_candidates = candidates_store.instance_methods.clone.
27
- remove(@good_candidates).
28
- remove(@bad_candidates )
29
-
30
- @never_called_candidates_c = candidates_store.class_methods.clone.
31
- remove(@good_candidates_c).
32
- remove(@bad_candidates_c )
33
- [
34
- @bad_candidates, @bad_candidates_c, @good_candidates, @good_candidates_c, @never_called_candidates, @never_called_candidates_c
35
- ].each {|arr| arr.reject!{|k, v| v.empty?}}
36
- @building_time = Time.now - start_time
37
-
38
- @candidates_classes_names = (candidates_store.instance_methods.classes_names +
39
- candidates_store.class_methods .classes_names ).uniq.sort
40
- @good_candidates_classes_names = (@good_candidates_c.classes_names + @good_candidates.classes_names).uniq.sort
41
- @bad_candidates_classes_names = (@bad_candidates_c .classes_names + @bad_candidates .classes_names).uniq.sort
42
- @never_called_candidates_classes_names = (@never_called_candidates_c .classes_names + @never_called_candidates.classes_names).uniq.sort
43
- end
44
16
  end
45
17
 
46
18
  end end
@@ -1,26 +1,26 @@
1
1
  ====================================================================================
2
2
  = PrivatePlease report : =
3
3
  ====================================================================================
4
- % @candidates_classes_names .sort.each do |class_name|
4
+ % data.candidates_classes_names .sort.each do |class_name|
5
5
  %
6
6
  % show_good_candidates_section = true
7
- % show_bad_candidates_section = show_bad_candidates_section?
8
- % show_never_candidates_section = show_never_called_candidates_section?
7
+ % show_bad_candidates_section = options.show_bad_candidates_section?
8
+ % show_never_candidates_section = options.show_never_called_candidates_section?
9
9
  %
10
10
  % if show_good_candidates_section
11
11
  % good_candidates_table = table_for(
12
- % names_from(class_name, good_candidates , prefix = "#"),
13
- % names_from(class_name, good_candidates_c, prefix = "."))
12
+ % names_from(class_name, data.good_candidates , prefix = "#"),
13
+ % names_from(class_name, data.good_candidates_c, prefix = "."))
14
14
  % end
15
15
  % if show_bad_candidates_section
16
16
  % bad_candidates_table = table_for(
17
- % names_from(class_name, bad_candidates , prefix = "#"),
18
- % names_from(class_name, bad_candidates_c, prefix = "."))
17
+ % names_from(class_name, data.bad_candidates , prefix = "#"),
18
+ % names_from(class_name, data.bad_candidates_c, prefix = "."))
19
19
  % end
20
20
  % if show_never_candidates_section
21
21
  % never_called_candidates_table = table_for(
22
- % names_from(class_name, never_called_candidates , prefix = "#"),
23
- % names_from(class_name, never_called_candidates_c, prefix = "."))
22
+ % names_from(class_name, data.never_called_candidates , prefix = "#"),
23
+ % names_from(class_name, data.never_called_candidates_c, prefix = "."))
24
24
  % end
25
25
  %
26
26
  % # Always hide empty tables :
@@ -30,8 +30,9 @@
30
30
  % show_never_candidates_section &&= !never_called_candidates_table.empty?
31
31
  %
32
32
  % nothing_to_show = !(show_good_candidates_section || show_bad_candidates_section || show_never_candidates_section)
33
- % next if nothing_to_show && !show_empty_classes?
33
+ % next if nothing_to_show && !options.show_empty_classes?
34
34
  %
35
+
35
36
  <%= class_name
36
37
  %>
37
38
  %
@@ -71,7 +72,9 @@
71
72
  % end
72
73
 
73
74
  ====================================================================================
74
- % if ENV['PP_OPTIONS']
75
- Default display overriden :
76
- $PP_OPTIONS = <%= ENV['PP_OPTIONS'].inspect %>
77
- % end
75
+
76
+ Report options :
77
+ % options_footer_parts.each do |o|
78
+ <%= (value = o[2]) ? "V" : 'x' %> <%= is_default = o[1] %> <%= display = o[0] %>
79
+ % end
80
+ (PP_OPTIONS = <%= ENV['PP_OPTIONS'] %>)
@@ -28,6 +28,10 @@ module PrivatePlease
28
28
  bucket_for(candidate).get_methods_names(candidate.klass_name).include?(candidate.method_name)
29
29
  end
30
30
 
31
+ def classes_names
32
+ (instance_methods.classes_names + class_methods .classes_names).uniq
33
+ end
34
+
31
35
  #--------------------------------------------------------------------------
32
36
  # COMMANDS:
33
37
  #--------------------------------------------------------------------------
@@ -42,6 +42,7 @@ module PrivatePlease
42
42
  end
43
43
 
44
44
  require 'private_please/tracking/utils'
45
+ require 'private_please/tracking/load_utils'
45
46
  require 'private_please/tracking/instrumentor'
46
47
  require 'private_please/tracking/extension'
47
48
  require 'private_please/tracking/instruments_all_methods_below'
@@ -1,3 +1,19 @@
1
+ module Kernel
2
+
3
+ alias_method :_orig_require, :require
4
+
5
+ def require string
6
+ prev_val = PrivatePlease.pp_automatic_mode_enabled?
7
+ if PrivatePlease::Tracking::LoadUtils.standard_lib_or_gem?(string)
8
+ PrivatePlease.pp_automatic_mode_disable
9
+ end
10
+
11
+ send :_orig_require, string
12
+
13
+ PrivatePlease.pp_automatic_mode_enable(prev_val)
14
+ end
15
+
16
+ end
1
17
 
2
18
  class Class
3
19
 
@@ -0,0 +1,32 @@
1
+ module PrivatePlease::Tracking
2
+
3
+ module LoadUtils
4
+ require File.dirname(__FILE__) + '/load_utils/gem_utils'
5
+ require File.dirname(__FILE__) + '/load_utils/standard_lib_utils'
6
+
7
+ class << self
8
+
9
+ def standard_lib_or_gem?(requiree)
10
+ (@@_standard_lib_or_gem ||= {})[requiree] ||= begin
11
+ standard_lib?(requiree) || gem?(requiree)
12
+ end
13
+ end
14
+
15
+ def standard_lib?(requiree)
16
+ (@@_standard_lib ||= {})[requiree] ||= StandardLibUtils.standard_lib?(requiree)
17
+ end
18
+
19
+ def gem?(requiree)
20
+ (@@_gems ||= {})[requiree] ||= begin
21
+ base_name = requiree.include?('/') ?
22
+ requiree.split('/').first : # ex: require 'rspec/autorun'
23
+ requiree # ex: require 'rspec'
24
+ GemUtils.gems_names.include?(base_name)
25
+ end
26
+
27
+ end
28
+
29
+ end
30
+ end
31
+
32
+ end
@@ -0,0 +1,49 @@
1
+ # OPTIMISATION :
2
+ # Calls to `$ gem ..` are slow (esp. on jruby!)
3
+ # => we 1/ pre-perform them asynchronously (Threads) when this file is loaded,
4
+ # 2/ cache the obtained value in a variable,
5
+ # 3/ rewrite the slow method as a noop version that simply returns the cached value.
6
+
7
+ module PrivatePlease::Tracking::LoadUtils
8
+
9
+ module GemUtils
10
+
11
+ class << self
12
+
13
+ # performs `$ gem env`
14
+ #
15
+ def gem_env
16
+ GEM_ENV_PRELOADER.join
17
+ gem_env # call the fast/just rewritten version
18
+ end
19
+
20
+ # performs `$ gem list` + extracts the names
21
+ #
22
+ def gems_names
23
+ GEMS_NAMES_PRELOADER.join
24
+ gems_names
25
+ end
26
+
27
+ #-------------------------------------------------------------------------------------------------------------------
28
+ private
29
+
30
+ GEM_ENV_PRELOADER = Thread.new do
31
+ @@_cached_gem_env = `gem env`
32
+ def GemUtils.gem_env
33
+ @@_cached_gem_env
34
+ end
35
+ end
36
+
37
+ GEMS_NAMES_PRELOADER = Thread.new do
38
+ @@_cached_gems_names = `gem list`. # very slow on jruby
39
+ split("\n").
40
+ map { |l| l.match(/(\S+)\s+.*/)[1]} # ["bundle", "bundler", "rspec", ..]
41
+ def GemUtils.gems_names
42
+ @@_cached_gems_names
43
+ end
44
+ end
45
+
46
+ end
47
+ end
48
+
49
+ end
@@ -0,0 +1,38 @@
1
+ module PrivatePlease::Tracking::LoadUtils
2
+
3
+ module StandardLibUtils
4
+
5
+ class << self
6
+
7
+ def standard_lib?(requiree)
8
+ path_base = "#{std_lib_home}/#{requiree}"
9
+ if File.exists?(path_base)
10
+ path_base
11
+ elsif File.exists?("#{path_base}.rb")
12
+ "#{path_base}.rb"
13
+ end
14
+ end
15
+
16
+ #-------------------------------------------------------------------------------------------------------------------
17
+ private
18
+
19
+ # Ex: "/Users/ara/.rbenv/versions/jruby-1.7.3/bin/jruby"
20
+ def ruby_executable
21
+ @@_ruby_executable ||= GemUtils.gem_env.match(/RUBY EXECUTABLE:\s*(.*)/)[1]
22
+ end
23
+
24
+ # Ex: "/Users/ara/.rbenv/versions/jruby-1.7.3/lib/ruby/1.9"
25
+ def std_lib_home
26
+ @@_std_lib_home ||= begin
27
+ basedir = ruby_executable.gsub(/bin\/[j]?ruby/, 'lib/ruby') # => "/Users/ara/.rbenv/versions/jruby-1.7.3/lib/ruby"
28
+ # jruby has 2+ directories of std. libs under the basedir : 1.8 and 1.9
29
+ $:.detect {|path| # We choose the one that is also in the load path.
30
+ path =~ /#{basedir}\/[12][^\/]+$/ #
31
+ } # => "/Users/ara/.rbenv/versions/jruby-1.7.3/lib/ruby/1.9"
32
+ end # ^^^ == the mode
33
+ end
34
+
35
+ end
36
+ end
37
+
38
+ end
@@ -1,3 +1,3 @@
1
1
  module PrivatePlease
2
- VERSION = "0.0.4"
2
+ VERSION = "0.0.5"
3
3
  end
@@ -0,0 +1,31 @@
1
+ require 'spec_helper'
2
+
3
+ describe "acceptance : standard libs are not tracked" do
4
+
5
+ before { PrivatePlease.pp_automatic_mode_enable }
6
+ after { PrivatePlease.pp_automatic_mode_disable}
7
+
8
+ module RequireTest; end
9
+ #-----------------
10
+
11
+ example "the csv **standard library** is required but not tracked" do
12
+
13
+ class RequireTest::Case1
14
+ require 'csv'
15
+ def foo ; end
16
+ end
17
+
18
+ assert_classes_names ['RequireTest::Case1']
19
+ end
20
+
21
+ example "the rspec **gem** is required but not tracked" do
22
+
23
+ class RequireTest::Case2
24
+ require 'rspec/autorun'
25
+ def foo ; end
26
+ end
27
+
28
+ assert_classes_names ['RequireTest::Case2']
29
+ end
30
+
31
+ end
@@ -0,0 +1,40 @@
1
+ require 'spec_helper'
2
+
3
+ describe PrivatePlease::Tracking::LoadUtils do
4
+
5
+ def std_lib?(requiree)
6
+ PrivatePlease::Tracking::LoadUtils.standard_lib?(requiree)
7
+ end
8
+
9
+ def gem?(requiree)
10
+ PrivatePlease::Tracking::LoadUtils.gem?(requiree)
11
+ end
12
+
13
+
14
+ example '.standard_lib? detects if a string matches a standard library' do
15
+ std_lib?('csv' ).should be_true
16
+ std_lib?('csv.rb' ).should be_true
17
+ std_lib?('bigdecimal' ).should be_true
18
+ std_lib?('bigdecimal/util' ).should be_true
19
+ std_lib?('bigdecimal/util.rb' ).should be_true
20
+
21
+ std_lib?('rspec' ).should be_false
22
+ std_lib?('private_please' ).should be_false
23
+ end
24
+
25
+ example '.gem? detects if a string matches a gem' do
26
+ gem?('csv' ).should be_false
27
+ gem?('csv.rb' ).should be_false
28
+ gem?('bigdecimal' ).should be_false
29
+ gem?('bigdecimal/util' ).should be_false
30
+ gem?('bigdecimal/util.rb' ).should be_false
31
+
32
+ gem?('rspec' ).should be_true
33
+ gem?('rspec/core/rake_task').should be_true
34
+ gem?('rspec/autorun' ).should be_true
35
+ gem?('coderay' ).should be_true
36
+ #gem?('private_please' ).should be_false
37
+ end
38
+
39
+
40
+ end
@@ -5,8 +5,6 @@ describe PrivatePlease, 'in $automatic mode, all the methods are tracked for obs
5
5
  before { PrivatePlease.pp_automatic_mode_enable }
6
6
  after { PrivatePlease.pp_automatic_mode_disable}
7
7
 
8
- let(:candidates_store) { PrivatePlease.storage }
9
-
10
8
  # ----------------
11
9
  context 'in a flat class,' do # simple class; no module nor inheritance
12
10
  # ----------------
@@ -29,7 +27,7 @@ describe PrivatePlease, 'in $automatic mode, all the methods are tracked for obs
29
27
  class AutFlatClass::Case2
30
28
  def foo ; end #
31
29
 
32
- def self.baz ; end #
30
+ def self.baz ; end #
33
31
  end
34
32
 
35
33
  assert_instance_methods_candidates 'AutFlatClass::Case2' => [:foo]
@@ -84,7 +82,7 @@ describe PrivatePlease, 'in $automatic mode, all the methods are tracked for obs
84
82
  def foo ; end #
85
83
  def included ; end # : not a special name in classes
86
84
 
87
- def self.baz ; end #
85
+ def self.baz ; end #
88
86
  def self.included ; end # : not a special name in classes
89
87
  end
90
88
 
@@ -125,7 +123,7 @@ describe PrivatePlease, 'in $automatic mode, all the methods are tracked for obs
125
123
  context '1 class including 1 module' do
126
124
  # ----------------
127
125
  module IncludedModule ; end
128
-
126
+
129
127
  example 'the tracked module methods are associated to the module, not the class(es) that includes the module' do
130
128
  module IncludedModule
131
129
  module Module1 #
@@ -138,10 +136,10 @@ describe PrivatePlease, 'in $automatic mode, all the methods are tracked for obs
138
136
  end #
139
137
  end #
140
138
  class Case1
141
- include Module1 # NO methods are associated to this class.
139
+ include Module1 # NO methods are associated to this class.
142
140
  end
143
141
  end
144
-
142
+
145
143
  assert_instance_methods_candidates 'IncludedModule::Module1' =>[:im_from_module],
146
144
  'IncludedModule::Module1::ClassMethods' =>[:cm_from_module]
147
145
  assert_singleton_methods_candidates ({})
@@ -154,10 +152,10 @@ describe PrivatePlease, 'in $automatic mode, all the methods are tracked for obs
154
152
  describe 'overridden methods are not tracked in classes' do
155
153
  # ----------------
156
154
  module ImplOverridingTest ; end
157
-
155
+
158
156
  example 'overridden methods are NOT marked as candidate' do
159
157
  module ImplOverridingTest
160
- class Base
158
+ class Base
161
159
  def base_t_foo ; end # is tracked
162
160
  def self.c_base_t_foo ; end # is tracked
163
161
  private
@@ -168,10 +166,10 @@ describe PrivatePlease, 'in $automatic mode, all the methods are tracked for obs
168
166
  def base_priv ; end # overriding a private method => not tracked
169
167
  def base_yes ; end # new -> tracked
170
168
  def self.c_base_yes ; end # new -> tracked
171
-
169
+
172
170
  def base_t_foo ; end # NOT tracked
173
171
  def self.c_base_t_foo ; end # NOT tracked
174
-
172
+
175
173
  def to_s ; end # NOT tracked
176
174
  end
177
175
  end
@@ -49,14 +49,14 @@ describe 'PrivatePlease.reporter', 'observing an instrumented program activity'
49
49
  # Note: test all in 1 go because testing in bits would fail, and it differs from real usage.
50
50
  it 'obtains the right info by observing the program activity' do
51
51
  run_the_instrumented_program
52
- the_report = PrivatePlease::Reporter::SimpleText.new(PrivatePlease.candidates_store, PrivatePlease.calls_store)
52
+ the_report_data = PrivatePlease::Reporter::SimpleText.new(PrivatePlease.candidates_store, PrivatePlease.calls_store).data
53
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
54
+ :good_candidates => the_report_data.good_candidates,
55
+ :good_candidates_c => the_report_data.good_candidates_c,
56
+ :bad_candidates => the_report_data.bad_candidates,
57
+ :bad_candidates_c => the_report_data.bad_candidates_c,
58
+ :ignored => the_report_data.never_called_candidates,
59
+ :ignored_c => the_report_data.never_called_candidates_c
60
60
  }.should == {
61
61
  :good_candidates => {
62
62
  'ActivityTest::Simple' => mnames_for([:good_candidate_4, :good_candidate_5, :good_candidate_7])
@@ -0,0 +1,76 @@
1
+ #----------
2
+
3
+ def mnames_for(args)
4
+ PrivatePlease::Storage::MethodsNames.new(Array(args))
5
+ end
6
+
7
+ #----------
8
+
9
+ class Hash
10
+ def to_methods_names_bucket
11
+ PrivatePlease::Storage::MethodsNamesBucket.new.tap do |bucket|
12
+ each_pair do |class_name, method_names_as_a|
13
+ method_names_as_a.each do |method_name|
14
+ bucket.add_method_name(class_name, method_name)
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
20
+
21
+
22
+ def assert_classes_names(expected)
23
+ PrivatePlease.candidates_store.classes_names.should == expected
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
+ alias :assert_singleton_methods_candidates :assert_class_methods_candidates
36
+
37
+ #----------
38
+
39
+ def assert_calls_detected(expected)
40
+ calls_db = PrivatePlease.calls_store
41
+ { :inside => calls_db.internal_calls,
42
+ :inside_c => calls_db.class_internal_calls,
43
+ :outside => calls_db.external_calls,
44
+ :outside_c => calls_db.class_external_calls
45
+ }.should == expected
46
+ end
47
+
48
+ NO_CALLS_OBSERVED = {}
49
+
50
+ def assert_no_calls_detected
51
+ assert_calls_detected :inside => NO_CALLS_OBSERVED, :outside => NO_CALLS_OBSERVED,
52
+ :inside_c => NO_CALLS_OBSERVED, :outside_c => NO_CALLS_OBSERVED
53
+ end
54
+
55
+ #----------
56
+ # Reporter::DataCompiler :
57
+ #----------
58
+
59
+ def run_and_inspect(fixture_file, __file__)
60
+ PrivatePlease.pp_automatic_mode_enable
61
+ load File.expand_path(File.dirname(__file__) + "/fixtures/#{fixture_file}")
62
+ c = PrivatePlease::Reporter::DataCompiler.new(PrivatePlease.candidates_store, PrivatePlease.calls_store)
63
+ data = c.compile_data
64
+ end
65
+
66
+ def assert_report_data_matches(data, expected_results = $expected_results)
67
+ ['candidates_classes_names', data.candidates_classes_names ].should == ['candidates_classes_names', expected_results[:candidates_classes_names ]]
68
+ ['good_candidates', data.good_candidates ].should == ['good_candidates', expected_results[:good_candidates ]]
69
+ ['bad_candidates', data.bad_candidates ].should == ['bad_candidates', expected_results[:bad_candidates ]]
70
+ ['never_called_candidates', data.never_called_candidates ].should == ['never_called_candidates', expected_results[:never_called_candidates ]]
71
+ ['good_candidates_c', data.good_candidates_c ].should == ['good_candidates_c', expected_results[:good_candidates_c ]]
72
+ ['bad_candidates_c', data.bad_candidates_c ].should == ['bad_candidates_c', expected_results[:bad_candidates_c ]]
73
+ ['never_called_candidates_c', data.never_called_candidates_c].should == ['never_called_candidates_c', expected_results[:never_called_candidates_c]]
74
+ end
75
+
76
+ #----------
@@ -0,0 +1,6 @@
1
+ # Fails with 1.8.7, works with 1.9.3, 2.0.0
2
+ require 'private_please'
3
+ require 'rubygems'
4
+ require 'coderay'
5
+ print CodeRay.scan('puts "Hello, world!"', :ruby).inspect # OK
6
+ print CodeRay.scan('puts "Hello, world!"', :ruby).html # FAIL
@@ -0,0 +1,12 @@
1
+ require 'private_please'
2
+
3
+ require 'csv' ## <<==
4
+ CSV.generate("/tmp/#{Time.now}") { |_| } ## <<==
5
+
6
+ class Foo
7
+ def initialize; foo end
8
+ def foo ;end
9
+ end
10
+ Foo.new
11
+
12
+ puts PrivatePlease.candidates_store.classes_names
data/spec/spec_helper.rb CHANGED
@@ -11,50 +11,6 @@ module PrivatePlease
11
11
  end
12
12
  end
13
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
- alias :assert_singleton_methods_candidates :assert_class_methods_candidates
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
-
58
14
  RSpec.configure do |config|
59
15
  config.treat_symbols_as_metadata_keys_with_true_values = true
60
16
  config.run_all_when_everything_filtered = true
@@ -72,6 +28,10 @@ RSpec.configure do |config|
72
28
  end
73
29
  end
74
30
 
31
+ require '_helpers/assert_helpers'
32
+
33
+ #--------------------------------------------------------
34
+
75
35
  require File.dirname(__FILE__) + '/../lib/private_please'
76
36
  PrivatePlease.pp_automatic_mode_disable
77
37
 
@@ -0,0 +1,12 @@
1
+ require 'spec_helper'
2
+
3
+ describe PrivatePlease::Reporter::DataCompiler do
4
+
5
+ context 'report generation for different scenarios' do
6
+ after { $expected_results = nil }
7
+
8
+ example('simple_case_1') { assert_report_data_matches(run_and_inspect("simple_case_1.rb", __FILE__)) }
9
+ example('simple_case_2') { assert_report_data_matches(run_and_inspect("simple_case_2.rb", __FILE__)) }
10
+ end
11
+
12
+ end
@@ -0,0 +1,30 @@
1
+ #---------
2
+ # Setup
3
+ #---------
4
+
5
+ class SimpleCase1
6
+ def entry_point; baz ; end
7
+ def baz ; end
8
+ def never; end
9
+ def self.c_entry_point; c_baz ; end
10
+ def self.c_baz ; end
11
+ def self.c_never; end
12
+ end
13
+ SimpleCase1.new.entry_point
14
+ SimpleCase1.c_entry_point
15
+
16
+ #------------------
17
+ # Expected results
18
+ #------------------
19
+
20
+ $expected_results = {
21
+ :candidates_classes_names => ['SimpleCase1'],
22
+
23
+ :good_candidates => {'SimpleCase1' => mnames_for([:baz]) },
24
+ :bad_candidates => {'SimpleCase1' => mnames_for([:entry_point]) },
25
+ :never_called_candidates => {'SimpleCase1' => mnames_for([:never]) },
26
+
27
+ :good_candidates_c => {'SimpleCase1' => mnames_for([:c_baz]) },
28
+ :bad_candidates_c => {'SimpleCase1' => mnames_for([:c_entry_point])},
29
+ :never_called_candidates_c => {'SimpleCase1' => mnames_for([:c_never]) }
30
+ }
@@ -0,0 +1,55 @@
1
+ #---------
2
+ # Scenario
3
+ #---------
4
+ # - additional internal calls are made to bad candidates (**1 )
5
+ # - an empty class is defined (**2 )
6
+ # - an ignored class is defined (**3 )
7
+
8
+ class SimpleCase2
9
+ def initialize
10
+ entry_point # **1
11
+ end
12
+
13
+ def entry_point
14
+ baz
15
+ self.class.c_entry_point # **1
16
+ end
17
+ def baz ; end
18
+ def never; end
19
+ def self.c_entry_point
20
+ c_baz
21
+ end
22
+ def self.c_baz ; end
23
+ def self.c_never; end
24
+ end
25
+ SimpleCase2.new.entry_point
26
+ SimpleCase2.c_entry_point
27
+
28
+
29
+ class SimpleCase2
30
+ class Empty # **2
31
+ end
32
+ class NotEmptyButNeverCalled # **3
33
+ def initialize ; neverr ; end
34
+ def neverr ; end
35
+ end
36
+ end
37
+
38
+ #------------------
39
+ # Expected results
40
+ #------------------
41
+
42
+ $expected_results = {
43
+ :candidates_classes_names => ['SimpleCase2',
44
+ 'SimpleCase2::NotEmptyButNeverCalled' # will produce a (hidden) empty 3-section block
45
+ ], # TODO : filter it out in the DataCompiler
46
+
47
+ :good_candidates => {'SimpleCase2' => mnames_for([:baz]) },
48
+ :bad_candidates => {'SimpleCase2' => mnames_for([:entry_point]) },
49
+ :never_called_candidates => {'SimpleCase2' => mnames_for([:never]),
50
+ 'SimpleCase2::NotEmptyButNeverCalled' => mnames_for([:neverr])
51
+ },
52
+ :good_candidates_c => {'SimpleCase2' => mnames_for([:c_baz]) },
53
+ :bad_candidates_c => {'SimpleCase2' => mnames_for([:c_entry_point])},
54
+ :never_called_candidates_c => {'SimpleCase2' => mnames_for([:c_never]) }
55
+ }
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: private_please
3
3
  version: !ruby/object:Gem::Version
4
- hash: 23
4
+ hash: 21
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
8
  - 0
9
- - 4
10
- version: 0.0.4
9
+ - 5
10
+ version: 0.0.5
11
11
  platform: ruby
12
12
  authors:
13
13
  - Alain Ravet
@@ -15,10 +15,12 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2013-05-04 00:00:00 +02:00
18
+ date: 2013-05-06 00:00:00 +02:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
22
+ name: rake
23
+ prerelease: false
22
24
  requirement: &id001 !ruby/object:Gem::Requirement
23
25
  none: false
24
26
  requirements:
@@ -29,10 +31,10 @@ dependencies:
29
31
  - 0
30
32
  version: "0"
31
33
  type: :development
32
- name: rake
33
34
  version_requirements: *id001
34
- prerelease: false
35
35
  - !ruby/object:Gem::Dependency
36
+ name: rspec
37
+ prerelease: false
36
38
  requirement: &id002 !ruby/object:Gem::Requirement
37
39
  none: false
38
40
  requirements:
@@ -43,10 +45,10 @@ dependencies:
43
45
  - 0
44
46
  version: "0"
45
47
  type: :development
46
- name: rspec
47
48
  version_requirements: *id002
48
- prerelease: false
49
49
  - !ruby/object:Gem::Dependency
50
+ name: guard-rspec
51
+ prerelease: false
50
52
  requirement: &id003 !ruby/object:Gem::Requirement
51
53
  none: false
52
54
  requirements:
@@ -57,10 +59,10 @@ dependencies:
57
59
  - 0
58
60
  version: "0"
59
61
  type: :development
60
- name: guard-rspec
61
62
  version_requirements: *id003
62
- prerelease: false
63
63
  - !ruby/object:Gem::Dependency
64
+ name: rb-fsevent
65
+ prerelease: false
64
66
  requirement: &id004 !ruby/object:Gem::Requirement
65
67
  none: false
66
68
  requirements:
@@ -71,9 +73,7 @@ dependencies:
71
73
  - 0
72
74
  version: "0"
73
75
  type: :development
74
- name: rb-fsevent
75
76
  version_requirements: *id004
76
- prerelease: false
77
77
  description: Test if methods can be made private
78
78
  email:
79
79
  - alainravet@gmail.com
@@ -109,6 +109,7 @@ files:
109
109
  - lib/private_please/report/table.rb
110
110
  - lib/private_please/reporter.rb
111
111
  - lib/private_please/reporter/base.rb
112
+ - lib/private_please/reporter/data_compiler.rb
112
113
  - lib/private_please/reporter/helpers/options_helpers.rb
113
114
  - lib/private_please/reporter/helpers/text_table_helpers.rb
114
115
  - lib/private_please/reporter/simple_text.rb
@@ -125,17 +126,25 @@ files:
125
126
  - lib/private_please/tracking/instruments_all_methods_below.rb
126
127
  - lib/private_please/tracking/instruments_automatically_all_methods_in_all_classes.rb
127
128
  - lib/private_please/tracking/line_change_tracker.rb
129
+ - lib/private_please/tracking/load_utils.rb
130
+ - lib/private_please/tracking/load_utils/gem_utils.rb
131
+ - lib/private_please/tracking/load_utils/standard_lib_utils.rb
128
132
  - lib/private_please/tracking/utils.rb
129
133
  - lib/private_please/version.rb
130
134
  - private_please.gemspec
131
135
  - sample.rb
136
+ - spec/01_tracking_candidate_methods/excluding_gems_and_standard_libraries_spec.rb
132
137
  - spec/01_tracking_candidate_methods/explicitely_with_the_private_please_command_spec.rb
138
+ - spec/01_tracking_candidate_methods/load_utils_spec.rb
133
139
  - spec/01_tracking_candidate_methods/systematically_in_auto_mode_spec.rb
134
140
  - spec/03_logging_calls_on_candidate_methods_spec.rb
135
141
  - spec/04_instrumented_program_activity_observation_result_spec.rb
136
142
  - spec/05_reporting/report_table_spec.rb
137
143
  - spec/06_at_exit_spec.rb
144
+ - spec/_helpers/assert_helpers.rb
138
145
  - spec/fixtures/bug_22.rb
146
+ - spec/fixtures/bug_30.rb
147
+ - spec/fixtures/issue_25.rb
139
148
  - spec/fixtures/sample_class_for_report.rb
140
149
  - spec/fixtures/sample_class_with_all_calls_combinations.rb
141
150
  - spec/sandbox/Gemfile
@@ -146,6 +155,9 @@ files:
146
155
  - spec/spec_helper.rb
147
156
  - spec/units/calls_store_spec.rb
148
157
  - spec/units/candidates_store_spec.rb
158
+ - spec/units/reporter/data_compiler_spec.rb
159
+ - spec/units/reporter/fixtures/simple_case_1.rb
160
+ - spec/units/reporter/fixtures/simple_case_2.rb
149
161
  has_rdoc: true
150
162
  homepage: https://github.com/alainravet/private_please
151
163
  licenses: []
@@ -181,13 +193,18 @@ signing_key:
181
193
  specification_version: 3
182
194
  summary: Test if methods can be made private
183
195
  test_files:
196
+ - spec/01_tracking_candidate_methods/excluding_gems_and_standard_libraries_spec.rb
184
197
  - spec/01_tracking_candidate_methods/explicitely_with_the_private_please_command_spec.rb
198
+ - spec/01_tracking_candidate_methods/load_utils_spec.rb
185
199
  - spec/01_tracking_candidate_methods/systematically_in_auto_mode_spec.rb
186
200
  - spec/03_logging_calls_on_candidate_methods_spec.rb
187
201
  - spec/04_instrumented_program_activity_observation_result_spec.rb
188
202
  - spec/05_reporting/report_table_spec.rb
189
203
  - spec/06_at_exit_spec.rb
204
+ - spec/_helpers/assert_helpers.rb
190
205
  - spec/fixtures/bug_22.rb
206
+ - spec/fixtures/bug_30.rb
207
+ - spec/fixtures/issue_25.rb
191
208
  - spec/fixtures/sample_class_for_report.rb
192
209
  - spec/fixtures/sample_class_with_all_calls_combinations.rb
193
210
  - spec/sandbox/Gemfile
@@ -198,3 +215,6 @@ test_files:
198
215
  - spec/spec_helper.rb
199
216
  - spec/units/calls_store_spec.rb
200
217
  - spec/units/candidates_store_spec.rb
218
+ - spec/units/reporter/data_compiler_spec.rb
219
+ - spec/units/reporter/fixtures/simple_case_1.rb
220
+ - spec/units/reporter/fixtures/simple_case_2.rb