memtf 0.0.1 → 0.0.2
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/.travis.yml +5 -0
- data/CHANGELOG.md +11 -0
- data/Guardfile +5 -0
- data/README.md +17 -5
- data/Rakefile +6 -1
- data/lib/memtf/analyzer.rb +90 -29
- data/lib/memtf/persistance.rb +8 -0
- data/lib/memtf/reporter.rb +6 -3
- data/lib/memtf/runner.rb +9 -3
- data/lib/memtf/utilities/array.rb +2 -1
- data/lib/memtf/version.rb +1 -1
- data/lib/memtf.rb +13 -6
- data/memtf.gemspec +2 -0
- data/spec/integration/memtf_spec.rb +58 -0
- data/spec/lib/memtf_spec.rb +61 -0
- data/spec/spec_helper.rb +2 -0
- metadata +61 -23
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f77e6fb9813978dda4987dc20dddb424c4a1c1b5
|
4
|
+
data.tar.gz: 6f5b28f54b82938efadaa508f09e5d550a1a2978
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: df1fe991d654a1c019e72121bd4c4fa38fbc8564727dc29ce0e6faa8dc2684c735e440b96758aca6bc50dd462fdeb3176aa8513978e14ffc73ce6a94d69af660
|
7
|
+
data.tar.gz: 9abcd938d071c1728be1e6609f89747492d80df7b9087d510e50266a9b5a304b2aab4e418e8f0c438d0e666269fbf949d9fd2bf767223ae96280a4ee5fbe110b
|
data/.travis.yml
ADDED
data/CHANGELOG.md
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
Unreleased ([changes](https://github.com/dresselm/memtf/compare/v0.0.2...master))
|
2
|
+
====================
|
3
|
+
|
4
|
+
v0.0.2
|
5
|
+
=====================
|
6
|
+
* Changed 'Memtf.finish' to 'Memtf.stop'
|
7
|
+
* Added support for a row in the report that consolidates the memory heap sizes of
|
8
|
+
all classes that do not meet the threshold. This is labeled as 'Others*'.
|
9
|
+
* Updated documentation and specs
|
10
|
+
* Hooked into Travis
|
11
|
+
* Added development support for guard-rspec
|
data/Guardfile
ADDED
data/README.md
CHANGED
@@ -1,7 +1,11 @@
|
|
1
|
+
[](http://travis-ci.org/dresselm/memtf)
|
2
|
+
|
1
3
|
# Memtf
|
2
4
|
|
3
5
|
A simple utility to help isolate memory leaks in your ruby applications.
|
4
6
|
|
7
|
+
## Why do we need another 'memory profiler'?
|
8
|
+
|
5
9
|
## Installation
|
6
10
|
|
7
11
|
Add this line to your application's Gemfile:
|
@@ -16,25 +20,32 @@ Or install it yourself as:
|
|
16
20
|
|
17
21
|
$ gem install memtf
|
18
22
|
|
23
|
+
## Prerequisites
|
24
|
+
|
25
|
+
The APIs used by the gem require ruby 1.9.3+.
|
26
|
+
|
19
27
|
## Usage
|
20
|
-
|
28
|
+
|
21
29
|
$ bundle exec irb
|
30
|
+
|
22
31
|
> require 'memtf'
|
32
|
+
|
23
33
|
> Memtf.start
|
24
34
|
> # ... do some stuff ...
|
25
|
-
> Memtf.
|
35
|
+
> Memtf.stop
|
36
|
+
|
26
37
|
> # or, wrap around a block
|
27
38
|
> Memtf.around { ... }
|
28
39
|
|
29
40
|
## Example
|
30
|
-
|
41
|
+
|
31
42
|
> require 'memtf'
|
32
|
-
>
|
43
|
+
>
|
33
44
|
> leaky_array = []
|
34
45
|
> Memtf.around do
|
35
46
|
> 500000.times { |i| leaky_array << "#{i % 2}-#{Time.now.to_i}" }
|
36
47
|
> end
|
37
|
-
|
48
|
+
|
38
49
|
+-----------------------------+---------+---------+--------+
|
39
50
|
| Class | Objects | Leakage | Impact |
|
40
51
|
+-----------------------------+---------+---------+--------+
|
@@ -48,6 +59,7 @@ Or install it yourself as:
|
|
48
59
|
| Thread | 0 | 0.000MB | 0.00% |
|
49
60
|
+-----------------------------+---------+---------+--------+
|
50
61
|
|
62
|
+
## What should I do with these results?
|
51
63
|
|
52
64
|
## Contributing
|
53
65
|
|
data/Rakefile
CHANGED
data/lib/memtf/analyzer.rb
CHANGED
@@ -1,35 +1,44 @@
|
|
1
1
|
require 'objspace'
|
2
2
|
|
3
3
|
class Memtf::Analyzer
|
4
|
+
|
5
|
+
attr_reader :threshold, :filter
|
6
|
+
|
7
|
+
DEFAULT_THRESHOLD = 0.005
|
4
8
|
MB = 1024.0**2
|
5
9
|
|
10
|
+
# @param [Hash] options
|
6
11
|
def self.analyze(options={})
|
7
12
|
new(options).analyze
|
8
13
|
end
|
9
14
|
|
15
|
+
# @param [String] group
|
16
|
+
# @return [Hash]
|
10
17
|
def self.analyze_group(group)
|
11
|
-
start_analysis = Memtf::Persistance.load(Memtf::
|
12
|
-
end_analysis = Memtf::Persistance.load(Memtf::
|
18
|
+
start_analysis = Memtf::Persistance.load(Memtf::START, group)
|
19
|
+
end_analysis = Memtf::Persistance.load(Memtf::STOP, group)
|
13
20
|
|
14
|
-
comparison
|
21
|
+
comparison = {}
|
15
22
|
total_memsize = 0
|
16
23
|
|
17
24
|
end_analysis.each do |clazz,end_stats|
|
18
|
-
start_stats
|
25
|
+
start_stats = start_analysis[clazz]
|
19
26
|
comparison[clazz] = {}
|
20
27
|
|
21
28
|
end_stats.each do |stat_key, stat_values|
|
22
29
|
start_val = start_stats.nil? ? 0 : start_stats[stat_key]
|
23
|
-
end_val
|
24
|
-
delta
|
25
|
-
total_memsize += delta if stat_key == 'size'
|
30
|
+
end_val = end_stats[stat_key]
|
31
|
+
delta = end_val - start_val
|
26
32
|
comparison[clazz][stat_key] = delta
|
33
|
+
|
34
|
+
# Perhaps just compare this
|
35
|
+
total_memsize += delta if stat_key == 'size'
|
27
36
|
end
|
28
37
|
end
|
29
38
|
|
30
|
-
# Determine relative impact of each class
|
39
|
+
# Determine the relative memory impact of each class
|
31
40
|
comparison.keys.each do |klazz|
|
32
|
-
stats
|
41
|
+
stats = comparison[klazz]
|
33
42
|
stats['impact'] = stats['size'] / total_memsize
|
34
43
|
end
|
35
44
|
|
@@ -37,40 +46,92 @@ class Memtf::Analyzer
|
|
37
46
|
end
|
38
47
|
|
39
48
|
def initialize(options={})
|
40
|
-
@
|
41
|
-
@threshold = options.fetch(:threshold,
|
49
|
+
@filter = options[:filter]
|
50
|
+
@threshold = options.fetch(:threshold, DEFAULT_THRESHOLD)
|
42
51
|
end
|
43
52
|
|
53
|
+
# @return [Hash]
|
44
54
|
def analyze
|
45
55
|
GC.start
|
46
56
|
|
47
|
-
|
57
|
+
classes_stats = {}
|
48
58
|
total_memsize = 0
|
49
59
|
|
50
|
-
|
60
|
+
# Track the memory footprint of each class
|
61
|
+
# and calculate the cumulative footprint.
|
62
|
+
#
|
63
|
+
# Output:
|
64
|
+
#
|
65
|
+
# {
|
66
|
+
# 'Hash' => [10, 15],
|
67
|
+
# 'Fixnum' => [1],
|
68
|
+
# 'Array' => [20, 30, 40],
|
69
|
+
# 'String' => [2,1]
|
70
|
+
# }
|
71
|
+
#
|
72
|
+
ObjectSpace.each_object do |obj|
|
51
73
|
if (clazz = obj.class).respond_to?(:name)
|
52
|
-
class_name
|
53
|
-
|
54
|
-
|
55
|
-
|
74
|
+
class_name = clazz.name
|
75
|
+
class_stats = (classes_stats[class_name] ||= [])
|
76
|
+
|
77
|
+
obj_memsize = ObjectSpace.memsize_of(obj)
|
78
|
+
class_stats << obj_memsize
|
56
79
|
total_memsize += obj_memsize
|
57
80
|
end
|
58
81
|
end
|
59
82
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
ObjectSpace.each_object(@class_or_module_filter,&obj_space_routine)
|
64
|
-
end
|
83
|
+
sorted_mem_hogs = identify_hogs(classes_stats, total_memsize)
|
84
|
+
translate_hogs(sorted_mem_hogs)
|
85
|
+
end
|
65
86
|
|
66
|
-
|
67
|
-
|
68
|
-
|
87
|
+
private
|
88
|
+
|
89
|
+
# Identify the most meaningful memory hogs, rollup the non-meaningful
|
90
|
+
# classes into a single slot called 'Other*' and sort the results.
|
91
|
+
#
|
92
|
+
# Output:
|
93
|
+
#
|
94
|
+
# {
|
95
|
+
# 'Array' => [20, 30, 40],
|
96
|
+
# 'Hash' => [10, 15],
|
97
|
+
# 'Others*' => [1,2,1]
|
98
|
+
# }
|
99
|
+
#
|
100
|
+
# TODO Ensure threshold is easily configurable
|
101
|
+
#
|
102
|
+
# @param [Hash] memory_by_class
|
103
|
+
# @param [Fixnum] total_memory_size
|
104
|
+
# @return [Hash]
|
105
|
+
def identify_hogs(memory_by_class, total_memory_size)
|
106
|
+
mem_threshold = threshold * total_memory_size
|
107
|
+
mem_hogs, others = {}, []
|
108
|
+
memory_by_class.each_pair do |k,v|
|
109
|
+
if v.sum >= mem_threshold
|
110
|
+
mem_hogs[k] = v
|
111
|
+
else
|
112
|
+
others += v
|
113
|
+
end
|
69
114
|
end
|
70
|
-
sorted_mem_hogs = Hash[mem_hogs.sort_by {|k,v| -v.sum }]
|
71
115
|
|
116
|
+
mem_hogs.merge!({'Others*' => others})
|
117
|
+
Hash[mem_hogs.sort_by {|k,v| -v.sum }]
|
118
|
+
end
|
119
|
+
|
120
|
+
# Translate hogs into a suitable format
|
121
|
+
#
|
122
|
+
# Output:
|
123
|
+
#
|
124
|
+
# {
|
125
|
+
# 'Array' => {:count => 3, :size => 90},
|
126
|
+
# 'Hash' => {:count => 2, :size => 25},
|
127
|
+
# 'Others*' => {:count => 3, :size => 4}
|
128
|
+
# }
|
129
|
+
#
|
130
|
+
# @param [Hash] memory_hogs
|
131
|
+
# @return [Hash]
|
132
|
+
def translate_hogs(memory_hogs)
|
72
133
|
smh_hash = {}
|
73
|
-
|
134
|
+
memory_hogs.each do |k,v|
|
74
135
|
count = v.size
|
75
136
|
size = v.sum / MB
|
76
137
|
|
@@ -78,8 +139,8 @@ class Memtf::Analyzer
|
|
78
139
|
count: count,
|
79
140
|
size: size
|
80
141
|
}
|
81
|
-
end
|
82
|
-
|
142
|
+
end
|
83
143
|
smh_hash
|
84
144
|
end
|
145
|
+
|
85
146
|
end
|
data/lib/memtf/persistance.rb
CHANGED
@@ -5,6 +5,9 @@ class Memtf::Persistance
|
|
5
5
|
OUTPUT_DIR = "tmp/memtf"
|
6
6
|
|
7
7
|
class << self
|
8
|
+
# @param [String] name
|
9
|
+
# @param [String] group
|
10
|
+
# @param [Object] payload
|
8
11
|
def save(name, group, payload)
|
9
12
|
group_directory = group_dir(group)
|
10
13
|
FileUtils.mkdir_p("#{group_directory}")
|
@@ -15,6 +18,9 @@ class Memtf::Persistance
|
|
15
18
|
end
|
16
19
|
end
|
17
20
|
|
21
|
+
# @param [String] name
|
22
|
+
# @param [String] group
|
23
|
+
# @return [Object]
|
18
24
|
def load(name, group)
|
19
25
|
load_file = "#{group_dir(group)}/#{name}.json"
|
20
26
|
::MultiJson.decode File.read(load_file)
|
@@ -22,6 +28,8 @@ class Memtf::Persistance
|
|
22
28
|
|
23
29
|
private
|
24
30
|
|
31
|
+
# @param [String] group
|
32
|
+
# @return [String] the group dir
|
25
33
|
def group_dir(group)
|
26
34
|
"#{OUTPUT_DIR}/#{group}"
|
27
35
|
end
|
data/lib/memtf/reporter.rb
CHANGED
@@ -4,31 +4,34 @@ class Memtf::Reporter
|
|
4
4
|
|
5
5
|
attr_reader :group, :options
|
6
6
|
|
7
|
+
# @param [String] group
|
7
8
|
def self.report(group)
|
8
9
|
new(group).report
|
9
10
|
end
|
10
11
|
|
11
12
|
def initialize(group, options={})
|
12
|
-
@group
|
13
|
+
@group = group
|
13
14
|
@options = options
|
14
15
|
end
|
15
16
|
|
17
|
+
# @return [Terminal::Table]
|
16
18
|
def report
|
17
|
-
|
19
|
+
Terminal::Table.new(:headings => ['Class', 'Objects', 'Leakage', 'Impact']) do |t|
|
18
20
|
group_analysis = Memtf::Analyzer.analyze_group(group)
|
19
21
|
group_analysis.sort_by { |k,v| -v['impact'] }.each do |k,v|
|
20
22
|
t << [k,v['count'],to_MB(v['size']),to_pct(v['impact'])]
|
21
23
|
end
|
22
24
|
end
|
23
|
-
puts table
|
24
25
|
end
|
25
26
|
|
26
27
|
private
|
27
28
|
|
29
|
+
# @param [Number] bytes
|
28
30
|
def to_MB(bytes)
|
29
31
|
"%.3fMB" % [bytes]
|
30
32
|
end
|
31
33
|
|
34
|
+
# @param [Number] num
|
32
35
|
def to_pct(num)
|
33
36
|
"%.2f%" % [num * 100]
|
34
37
|
end
|
data/lib/memtf/runner.rb
CHANGED
@@ -1,21 +1,27 @@
|
|
1
1
|
class Memtf::Runner
|
2
|
-
attr_reader :group, :options
|
2
|
+
attr_reader :group, :options, :report
|
3
3
|
|
4
|
+
# @param [String] stage
|
5
|
+
# @param [Hash] options
|
4
6
|
def self.run(stage, options={})
|
5
7
|
new(options).run(stage)
|
6
8
|
end
|
7
9
|
|
8
10
|
def initialize(options={})
|
9
|
-
@group
|
11
|
+
@group = options.delete(:group) || Time.now.to_i
|
10
12
|
@options = options
|
11
13
|
end
|
12
14
|
|
15
|
+
# @param [String] stage
|
13
16
|
def run(stage)
|
14
17
|
analysis = Memtf::Analyzer.analyze(options)
|
15
18
|
Memtf::Persistance.save(stage, group, analysis)
|
16
19
|
analysis = nil
|
17
20
|
|
18
|
-
|
21
|
+
if stage == Memtf::STOP
|
22
|
+
@report = Memtf::Reporter.report(group)
|
23
|
+
puts @report
|
24
|
+
end
|
19
25
|
|
20
26
|
self
|
21
27
|
end
|
data/lib/memtf/version.rb
CHANGED
data/lib/memtf.rb
CHANGED
@@ -1,24 +1,31 @@
|
|
1
1
|
module Memtf
|
2
|
-
|
3
|
-
|
2
|
+
# Represents the starting
|
3
|
+
START = :start
|
4
|
+
# Represents the end of a run
|
5
|
+
STOP = :stop
|
4
6
|
|
5
7
|
class << self
|
6
8
|
attr_accessor :runner
|
7
9
|
|
10
|
+
# @param [Hash] options
|
11
|
+
# @return [Runner]
|
8
12
|
def start(options={})
|
9
|
-
self.runner = Runner.run(
|
13
|
+
self.runner = Runner.run(START, options)
|
10
14
|
end
|
11
15
|
|
12
|
-
|
13
|
-
|
16
|
+
# @param [Hash] options
|
17
|
+
def stop(options={})
|
18
|
+
default_group = self.runner.group
|
19
|
+
Runner.run(STOP, {:group => default_group}.merge(options))
|
14
20
|
ensure
|
15
21
|
self.runner = nil
|
16
22
|
end
|
17
23
|
|
24
|
+
# @param [Hash] options
|
18
25
|
def around(options={}, &block)
|
19
26
|
start(options)
|
20
27
|
block.call if block_given?
|
21
|
-
|
28
|
+
stop(options)
|
22
29
|
end
|
23
30
|
end
|
24
31
|
end
|
data/memtf.gemspec
CHANGED
@@ -25,5 +25,7 @@ Gem::Specification.new do |spec|
|
|
25
25
|
spec.add_development_dependency "pry"
|
26
26
|
spec.add_development_dependency "rake"
|
27
27
|
spec.add_development_dependency "rspec"
|
28
|
+
spec.add_development_dependency "guard-rspec"
|
28
29
|
spec.add_development_dependency "simplecov"
|
30
|
+
spec.add_development_dependency "yard"
|
29
31
|
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'Integration tests' do
|
4
|
+
class Leak < Struct.new(:id, :name); end
|
5
|
+
class LeakyHarness < Struct.new(:leaker)
|
6
|
+
def leak
|
7
|
+
25000.times do |index|
|
8
|
+
leaker << Leak.new(index, "Name: #{index}")
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
# This is janky, but works for now as a simplistic check.
|
14
|
+
# Since we are at the mercy of the GC, these specs are
|
15
|
+
# generally going to lack any consistent output.
|
16
|
+
def leaker_class_names(runner)
|
17
|
+
report = runner.report
|
18
|
+
rows = report.rows
|
19
|
+
rows.map { |row| row.cells.first.value }
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'should expose the memory leak' do
|
23
|
+
arr = []
|
24
|
+
harness = LeakyHarness.new(arr)
|
25
|
+
runner = Memtf.around do
|
26
|
+
harness.leak
|
27
|
+
end
|
28
|
+
|
29
|
+
leaker_class_names(runner).should include('Array')
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'should rollup minor leaks into Other*' do
|
33
|
+
arr = []
|
34
|
+
harness = LeakyHarness.new(arr)
|
35
|
+
runner = Memtf.around do
|
36
|
+
harness.leak
|
37
|
+
end
|
38
|
+
|
39
|
+
leaker_class_names(runner).should include('Others*')
|
40
|
+
end
|
41
|
+
|
42
|
+
context 'when the memory leak is fixed' do
|
43
|
+
it 'should not expose a memory leak' do
|
44
|
+
runner = Memtf.around do
|
45
|
+
arr = []
|
46
|
+
harness = LeakyHarness.new(arr)
|
47
|
+
harness.leak
|
48
|
+
|
49
|
+
harness.leaker.each { |leak| leak = nil}
|
50
|
+
harness.leaker = nil
|
51
|
+
harness = nil
|
52
|
+
arr = nil
|
53
|
+
end
|
54
|
+
|
55
|
+
leaker_class_names(runner).should_not include('Array')
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Memtf do
|
4
|
+
let(:options) { {} }
|
5
|
+
|
6
|
+
describe '.start' do
|
7
|
+
it 'should delegate to Memtf::Runner' do
|
8
|
+
Memtf::Runner.should_receive(:run).with(Memtf::START, options)
|
9
|
+
|
10
|
+
Memtf.start(options)
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'should set the runner variable' do
|
14
|
+
Memtf.runner.should be_nil
|
15
|
+
|
16
|
+
expected_runner = Memtf.start(options)
|
17
|
+
|
18
|
+
Memtf.runner.should_not be_nil
|
19
|
+
Memtf.runner.should == expected_runner
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
describe '.stop' do
|
24
|
+
it 'should delegate to Memtf::Runner' do
|
25
|
+
Memtf::Runner.should_receive(:run).with(Memtf::STOP, hash_including(:group))
|
26
|
+
|
27
|
+
Memtf.stop(options)
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'should clear the runner variable' do
|
31
|
+
runner = Memtf.start(options)
|
32
|
+
Memtf.runner.should_not be_nil
|
33
|
+
|
34
|
+
Memtf.stop(options)
|
35
|
+
Memtf.runner.should be_nil
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
describe '.around' do
|
40
|
+
it 'should delegate to start' do
|
41
|
+
Memtf.should_receive(:start).with(options)
|
42
|
+
Memtf.stub(:stop)
|
43
|
+
|
44
|
+
Memtf.around(options) { a = 1 + 2 }
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'should delegate to finish' do
|
48
|
+
Memtf.should_receive(:stop).with(options)
|
49
|
+
|
50
|
+
Memtf.around(options) { a = 1 + 2 }
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'should call the given block' do
|
54
|
+
Memtf.stub(:stop)
|
55
|
+
lambda = lambda { a = 1 + 2 }
|
56
|
+
lambda.should_receive(:call)
|
57
|
+
|
58
|
+
Memtf.around(options,&lambda)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
CHANGED
@@ -1,111 +1,139 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: memtf
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Matthew Dressel
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-12-
|
11
|
+
date: 2013-12-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: multi_json
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- -
|
17
|
+
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: '0'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- -
|
24
|
+
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '0'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: terminal-table
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- -
|
31
|
+
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
33
|
version: '0'
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- -
|
38
|
+
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: bundler
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- - ~>
|
45
|
+
- - "~>"
|
46
46
|
- !ruby/object:Gem::Version
|
47
47
|
version: '1.3'
|
48
48
|
type: :development
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- - ~>
|
52
|
+
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '1.3'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: pry
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
|
-
- -
|
59
|
+
- - ">="
|
60
60
|
- !ruby/object:Gem::Version
|
61
61
|
version: '0'
|
62
62
|
type: :development
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
|
-
- -
|
66
|
+
- - ">="
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '0'
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: rake
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
72
72
|
requirements:
|
73
|
-
- -
|
73
|
+
- - ">="
|
74
74
|
- !ruby/object:Gem::Version
|
75
75
|
version: '0'
|
76
76
|
type: :development
|
77
77
|
prerelease: false
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
79
79
|
requirements:
|
80
|
-
- -
|
80
|
+
- - ">="
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: '0'
|
83
83
|
- !ruby/object:Gem::Dependency
|
84
84
|
name: rspec
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|
86
86
|
requirements:
|
87
|
-
- -
|
87
|
+
- - ">="
|
88
88
|
- !ruby/object:Gem::Version
|
89
89
|
version: '0'
|
90
90
|
type: :development
|
91
91
|
prerelease: false
|
92
92
|
version_requirements: !ruby/object:Gem::Requirement
|
93
93
|
requirements:
|
94
|
-
- -
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: guard-rspec
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
95
109
|
- !ruby/object:Gem::Version
|
96
110
|
version: '0'
|
97
111
|
- !ruby/object:Gem::Dependency
|
98
112
|
name: simplecov
|
99
113
|
requirement: !ruby/object:Gem::Requirement
|
100
114
|
requirements:
|
101
|
-
- -
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: yard
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - ">="
|
102
130
|
- !ruby/object:Gem::Version
|
103
131
|
version: '0'
|
104
132
|
type: :development
|
105
133
|
prerelease: false
|
106
134
|
version_requirements: !ruby/object:Gem::Requirement
|
107
135
|
requirements:
|
108
|
-
- -
|
136
|
+
- - ">="
|
109
137
|
- !ruby/object:Gem::Version
|
110
138
|
version: '0'
|
111
139
|
description: A simple utility to help you isolate the little bastards that are stealing
|
@@ -116,10 +144,13 @@ executables: []
|
|
116
144
|
extensions: []
|
117
145
|
extra_rdoc_files: []
|
118
146
|
files:
|
119
|
-
- .gitignore
|
120
|
-
- .ruby-gemset
|
121
|
-
- .ruby-version
|
147
|
+
- ".gitignore"
|
148
|
+
- ".ruby-gemset"
|
149
|
+
- ".ruby-version"
|
150
|
+
- ".travis.yml"
|
151
|
+
- CHANGELOG.md
|
122
152
|
- Gemfile
|
153
|
+
- Guardfile
|
123
154
|
- LICENSE.txt
|
124
155
|
- README.md
|
125
156
|
- Rakefile
|
@@ -132,6 +163,9 @@ files:
|
|
132
163
|
- lib/memtf/utilities/array.rb
|
133
164
|
- lib/memtf/version.rb
|
134
165
|
- memtf.gemspec
|
166
|
+
- spec/integration/memtf_spec.rb
|
167
|
+
- spec/lib/memtf_spec.rb
|
168
|
+
- spec/spec_helper.rb
|
135
169
|
homepage: http://github.com/dresselm/memtf
|
136
170
|
licenses:
|
137
171
|
- MIT
|
@@ -142,18 +176,22 @@ require_paths:
|
|
142
176
|
- lib
|
143
177
|
required_ruby_version: !ruby/object:Gem::Requirement
|
144
178
|
requirements:
|
145
|
-
- -
|
179
|
+
- - ">="
|
146
180
|
- !ruby/object:Gem::Version
|
147
181
|
version: '0'
|
148
182
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
149
183
|
requirements:
|
150
|
-
- -
|
184
|
+
- - ">="
|
151
185
|
- !ruby/object:Gem::Version
|
152
186
|
version: '0'
|
153
187
|
requirements: []
|
154
188
|
rubyforge_project:
|
155
|
-
rubygems_version: 2.0
|
189
|
+
rubygems_version: 2.2.0
|
156
190
|
signing_key:
|
157
191
|
specification_version: 4
|
158
192
|
summary: Leaking memory like a sieve? Cursing? Memtf is here to help.
|
159
|
-
test_files:
|
193
|
+
test_files:
|
194
|
+
- spec/integration/memtf_spec.rb
|
195
|
+
- spec/lib/memtf_spec.rb
|
196
|
+
- spec/spec_helper.rb
|
197
|
+
has_rdoc:
|