private_please 0.0.4 → 0.0.5

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/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