hometown 0.2.1 → 0.2.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.
- 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:
|