hometown 0.2.1 → 0.2.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +11 -3
- data/Rakefile +13 -0
- data/examples/dispose.rb +8 -4
- data/lib/hometown.rb +13 -7
- data/lib/hometown/disposal_tracer.rb +57 -3
- data/lib/hometown/version.rb +1 -1
- data/test/hometown/disposal_tracer_test.rb +90 -0
- data/test/hometown_test.rb +15 -0
- metadata +4 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ef3bf9cd07fd65698dbf269368f59acf0e8af42c
|
4
|
+
data.tar.gz: 4e911e6a515e81f1009bf40afd6673dceb00fde9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2c0c696f52311f61a9d46ca615014f7d1c748bf33670aca6575e17e8ad96f26543c2504be435ab118476044f414d7fbca0a93f5c1a481ddda0067cc7c65a83fd
|
7
|
+
data.tar.gz: b9d13e4fffd22bac7677d67cdce2ae4c6b28540430047970cef33fb87d7fdf639c8b33a91fe90163d83fc5a2e821fefe41698fb169d163db4feb88a566762c17
|
data/README.md
CHANGED
@@ -56,6 +56,8 @@ Hometown can help track down these leaks. To watch a class of objects to ensure
|
|
56
56
|
created instances are disposed, call `Hometown.watch_for_disposal` on the
|
57
57
|
class. `Hometown.undisposed` returns you objects indicating--with stack traces
|
58
58
|
--all the locations where an object was created but not released.
|
59
|
+
`Hometown.undisposed_report` will give a formatted output of the undisposed
|
60
|
+
objects.
|
59
61
|
|
60
62
|
```
|
61
63
|
# dispose.rb
|
@@ -73,12 +75,13 @@ Hometown.watch_for_disposal(Disposable, :dispose)
|
|
73
75
|
# Creating initial object
|
74
76
|
disposable = Disposable.new
|
75
77
|
puts "Still there!"
|
76
|
-
p Hometown.undisposed
|
78
|
+
p Hometown.undisposed
|
79
|
+
puts
|
77
80
|
|
78
81
|
# All done!
|
79
82
|
disposable.dispose
|
80
83
|
puts "Properly disposed"
|
81
|
-
|
84
|
+
puts Hometown.undisposed_report
|
82
85
|
|
83
86
|
|
84
87
|
$ ruby examples/dispose.rb
|
@@ -87,7 +90,12 @@ Still there!
|
|
87
90
|
{ #<Hometown::Trace:0x007f9aa516ec88 ...> => 1 }
|
88
91
|
|
89
92
|
Properly disposed!
|
90
|
-
|
93
|
+
Undisposed Resources:
|
94
|
+
[Disposable] => 0
|
95
|
+
examples/dispose.rb:13:in `<main>'
|
96
|
+
|
97
|
+
Undiposed Totals:
|
98
|
+
[Disposable] => 0
|
91
99
|
```
|
92
100
|
|
93
101
|
## Contributing
|
data/Rakefile
CHANGED
@@ -11,3 +11,16 @@ Rake::TestTask.new do |test|
|
|
11
11
|
test.test_files = FileList['test/**/*_test.rb']
|
12
12
|
end
|
13
13
|
|
14
|
+
if Rake::Task.task_defined?("release:source_control_push")
|
15
|
+
puts "Found release:source_control_push task... overwriting to support push.default=nothing"
|
16
|
+
|
17
|
+
Rake::Task['release:source_control_push'].clear
|
18
|
+
task 'release:source_control_push' do
|
19
|
+
`git push origin master`
|
20
|
+
|
21
|
+
version = Bundler::GemHelper.gemspec.version
|
22
|
+
version_tag = "v#{version}"
|
23
|
+
`git tag -a -m \"Version #{version}\" #{version_tag}`
|
24
|
+
`git push --tags`
|
25
|
+
end
|
26
|
+
end
|
data/examples/dispose.rb
CHANGED
@@ -8,13 +8,17 @@ end
|
|
8
8
|
|
9
9
|
# Watch Disposable and track calls to dispose
|
10
10
|
Hometown.watch_for_disposal(Disposable, :dispose)
|
11
|
+
Hometown.undisposed_report_at_exit
|
11
12
|
|
12
13
|
# Creating initial object
|
13
14
|
disposable = Disposable.new
|
15
|
+
Disposable.new
|
14
16
|
puts "Still there!"
|
15
|
-
|
17
|
+
puts "*" * 30
|
18
|
+
puts Hometown.undisposed_report
|
19
|
+
puts
|
16
20
|
|
17
|
-
#
|
21
|
+
# Dispose of one, and at_exit hook will show the results!
|
18
22
|
disposable.dispose
|
19
|
-
puts "
|
20
|
-
|
23
|
+
puts "Final undisposed report!"
|
24
|
+
puts "*" * 30
|
data/lib/hometown.rb
CHANGED
@@ -7,12 +7,8 @@ module Hometown
|
|
7
7
|
@creation_tracer = Hometown::CreationTracer.new
|
8
8
|
@disposal_tracer = Hometown::DisposalTracer.new
|
9
9
|
|
10
|
-
|
11
|
-
|
12
|
-
end
|
13
|
-
|
14
|
-
def self.disposal_tracer
|
15
|
-
@disposal_tracer
|
10
|
+
class << self
|
11
|
+
attr_accessor :creation_tracer, :disposal_tracer
|
16
12
|
end
|
17
13
|
|
18
14
|
def self.watch(clazz)
|
@@ -28,6 +24,16 @@ module Hometown
|
|
28
24
|
end
|
29
25
|
|
30
26
|
def self.undisposed
|
31
|
-
@disposal_tracer.undisposed
|
27
|
+
@disposal_tracer.undisposed
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.undisposed_report
|
31
|
+
@disposal_tracer.undisposed_report
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.undisposed_report_at_exit
|
35
|
+
at_exit do
|
36
|
+
puts Hometown.undisposed_report
|
37
|
+
end
|
32
38
|
end
|
33
39
|
end
|
@@ -1,10 +1,12 @@
|
|
1
1
|
module Hometown
|
2
2
|
class DisposalTracer
|
3
|
-
attr_reader :undisposed
|
3
|
+
attr_reader :undisposed, :untraced_disposals
|
4
4
|
|
5
5
|
def initialize
|
6
|
-
@undisposed = Hash.new(0)
|
7
6
|
@tracing_classes = {}
|
7
|
+
|
8
|
+
@undisposed = Hash.new(0)
|
9
|
+
@untraced_disposals = Hash.new(0)
|
8
10
|
end
|
9
11
|
|
10
12
|
def patch(clazz, disposal_method)
|
@@ -41,7 +43,59 @@ module Hometown
|
|
41
43
|
|
42
44
|
def notice_disposed(instance)
|
43
45
|
trace = Hometown.for(instance)
|
44
|
-
|
46
|
+
if trace
|
47
|
+
@undisposed[trace] -= 1
|
48
|
+
else
|
49
|
+
trace = Trace.new(instance.class, caller)
|
50
|
+
@untraced_disposals[trace] += 1
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
UNDISPOSED_HEADING = "Undisposed Resources"
|
55
|
+
UNTRACED_HEADING = "Untraced Disposals"
|
56
|
+
UNDISPOSED_TOTALS_HEADING = "Undisposed Totals"
|
57
|
+
UNTRACED_TOTALS_HEADING = "Untraced Disposals Totals"
|
58
|
+
|
59
|
+
def undisposed_report
|
60
|
+
result = format_trace_hash(UNDISPOSED_HEADING, @undisposed)
|
61
|
+
result += format_trace_hash(UNTRACED_HEADING, @untraced_disposals)
|
62
|
+
|
63
|
+
result += format_totals(UNDISPOSED_TOTALS_HEADING, @undisposed)
|
64
|
+
result += format_totals(UNTRACED_TOTALS_HEADING, @untraced_disposals)
|
65
|
+
|
66
|
+
result
|
67
|
+
end
|
68
|
+
|
69
|
+
def format_trace_hash(heading, hash)
|
70
|
+
result = ""
|
71
|
+
hash.each do |trace, count|
|
72
|
+
if count > 0
|
73
|
+
result += "[#{trace.traced_class}] => #{count}\n"
|
74
|
+
result += "\t#{trace.backtrace.join("\n\t")}\n\n"
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
add_heading_if_needed(heading, result)
|
79
|
+
end
|
80
|
+
|
81
|
+
def format_totals(heading, hash)
|
82
|
+
result = ""
|
83
|
+
hash.group_by { |trace, _| trace.traced_class }.each do |clazz, counts|
|
84
|
+
count = counts.map { |count| count.last }.inject(0, &:+)
|
85
|
+
if count > 0
|
86
|
+
result += "[#{clazz}] => #{count}"
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
add_heading_if_needed(heading, result)
|
91
|
+
end
|
92
|
+
|
93
|
+
def add_heading_if_needed(heading, result)
|
94
|
+
if result.empty?
|
95
|
+
""
|
96
|
+
else
|
97
|
+
"#{heading}:\n#{result}"
|
98
|
+
end
|
45
99
|
end
|
46
100
|
end
|
47
101
|
end
|
data/lib/hometown/version.rb
CHANGED
@@ -0,0 +1,90 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), "..", "test_helper"))
|
2
|
+
require 'hometown'
|
3
|
+
require 'hometown/disposal_tracer'
|
4
|
+
|
5
|
+
module Hometown
|
6
|
+
class DisposalTracerTest < Minitest::Test
|
7
|
+
def setup
|
8
|
+
@tracer = DisposalTracer.new
|
9
|
+
@original_tracer = Hometown.disposal_tracer
|
10
|
+
Hometown.disposal_tracer = @tracer
|
11
|
+
end
|
12
|
+
|
13
|
+
def teardown
|
14
|
+
Hometown.disposal_tracer = @original_tracer
|
15
|
+
end
|
16
|
+
|
17
|
+
def test_empty_report
|
18
|
+
assert_empty @tracer.undisposed_report
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_traces_disposal
|
22
|
+
clazz = new_class
|
23
|
+
@tracer.patch(clazz, :dispose)
|
24
|
+
|
25
|
+
instance = clazz.new
|
26
|
+
trace = Hometown.for(instance)
|
27
|
+
assert_equal 1, @tracer.undisposed[trace]
|
28
|
+
|
29
|
+
instance.dispose
|
30
|
+
assert_equal 0, @tracer.undisposed[trace]
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_undisposed_report
|
34
|
+
clazz = new_class
|
35
|
+
@tracer.patch(clazz, :dispose)
|
36
|
+
|
37
|
+
instance = clazz.new
|
38
|
+
report = @tracer.undisposed_report
|
39
|
+
|
40
|
+
assert_match DisposalTracer::UNDISPOSED_HEADING, report
|
41
|
+
assert_match DisposalTracer::UNDISPOSED_TOTALS_HEADING, report
|
42
|
+
assert_match clazz.to_s, report
|
43
|
+
assert_match __FILE__, report
|
44
|
+
assert_match /#{clazz.to_s}.*1/, report
|
45
|
+
end
|
46
|
+
|
47
|
+
def test_empty_report_if_all_disposed
|
48
|
+
clazz = new_class
|
49
|
+
@tracer.patch(clazz, :dispose)
|
50
|
+
|
51
|
+
instance = clazz.new
|
52
|
+
instance.dispose
|
53
|
+
|
54
|
+
assert_empty @tracer.undisposed_report
|
55
|
+
end
|
56
|
+
|
57
|
+
def test_safely_disposes_already_created_objects
|
58
|
+
clazz = new_class
|
59
|
+
instance = clazz.new
|
60
|
+
@tracer.patch(clazz, :dispose)
|
61
|
+
|
62
|
+
instance.dispose
|
63
|
+
|
64
|
+
assert_empty @tracer.undisposed
|
65
|
+
assert_equal 1, @tracer.untraced_disposals.count
|
66
|
+
end
|
67
|
+
|
68
|
+
def test_untraced_disposals_show_up_in_report
|
69
|
+
clazz = new_class
|
70
|
+
instance = clazz.new
|
71
|
+
@tracer.patch(clazz, :dispose)
|
72
|
+
|
73
|
+
instance.dispose
|
74
|
+
report = @tracer.undisposed_report
|
75
|
+
|
76
|
+
assert_match DisposalTracer::UNTRACED_HEADING, report
|
77
|
+
assert_match DisposalTracer::UNTRACED_TOTALS_HEADING, report
|
78
|
+
assert_match clazz.to_s, report
|
79
|
+
assert_match __FILE__, report
|
80
|
+
assert_match /#{clazz.to_s}.*1/, report
|
81
|
+
end
|
82
|
+
|
83
|
+
def new_class
|
84
|
+
Class.new do
|
85
|
+
define_method(:dispose) do
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
data/test/hometown_test.rb
CHANGED
@@ -158,4 +158,19 @@ class HometownTest < Minitest::Test
|
|
158
158
|
result = Hometown.undisposed
|
159
159
|
assert_equal 1, result[trace]
|
160
160
|
end
|
161
|
+
|
162
|
+
def test_undisposed_report
|
163
|
+
clazz = Class.new do
|
164
|
+
define_method(:dispose) do
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
Hometown.watch_for_disposal(clazz, :dispose)
|
169
|
+
instance = clazz.new
|
170
|
+
|
171
|
+
report = Hometown.undisposed_report
|
172
|
+
assert_kind_of String, report
|
173
|
+
assert_includes report, clazz.to_s
|
174
|
+
assert_includes report, __FILE__
|
175
|
+
end
|
161
176
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hometown
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jason R. Clark
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-06-
|
11
|
+
date: 2014-06-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -144,6 +144,7 @@ files:
|
|
144
144
|
- lib/hometown/disposal_tracer.rb
|
145
145
|
- lib/hometown/trace.rb
|
146
146
|
- lib/hometown/version.rb
|
147
|
+
- test/hometown/disposal_tracer_test.rb
|
147
148
|
- test/hometown/trace_test.rb
|
148
149
|
- test/hometown_test.rb
|
149
150
|
- test/test_helper.rb
|
@@ -172,7 +173,7 @@ signing_key:
|
|
172
173
|
specification_version: 4
|
173
174
|
summary: Track object creation
|
174
175
|
test_files:
|
176
|
+
- test/hometown/disposal_tracer_test.rb
|
175
177
|
- test/hometown/trace_test.rb
|
176
178
|
- test/hometown_test.rb
|
177
179
|
- test/test_helper.rb
|
178
|
-
has_rdoc:
|