memtf 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: aa14c68446bef3d1c846cbe75a96e1745e3be6ff
4
- data.tar.gz: bc1961d37230b93cbf5f01b1f81ffe578874dab3
3
+ metadata.gz: f77e6fb9813978dda4987dc20dddb424c4a1c1b5
4
+ data.tar.gz: 6f5b28f54b82938efadaa508f09e5d550a1a2978
5
5
  SHA512:
6
- metadata.gz: c08147b6310efb17f3cb25e5a57bbd58c595e6126157ab881472eaf2dc5d842a330a05ec19e2caddd76f9473cea71822d68334d0f80c8f8459ab6b85409347cb
7
- data.tar.gz: f8a4922b9475ab2cfcb21a4daf21fa42a1d5d9dfc66193140c0539a1b2399333ae24d0022112586b47c26a28d05b3338d718847344a7e6c24cc88f6c303c2caf
6
+ metadata.gz: df1fe991d654a1c019e72121bd4c4fa38fbc8564727dc29ce0e6faa8dc2684c735e440b96758aca6bc50dd462fdeb3176aa8513978e14ffc73ce6a94d69af660
7
+ data.tar.gz: 9abcd938d071c1728be1e6609f89747492d80df7b9087d510e50266a9b5a304b2aab4e418e8f0c438d0e666269fbf949d9fd2bf767223ae96280a4ee5fbe110b
data/.travis.yml ADDED
@@ -0,0 +1,5 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.1.0-preview2
4
+ - 2.0.0
5
+ - 1.9.3
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
@@ -0,0 +1,5 @@
1
+ guard :rspec do
2
+ watch(%r{^spec/.+_spec\.rb$})
3
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
4
+ watch('spec/spec_helper.rb') { "spec" }
5
+ end
data/README.md CHANGED
@@ -1,7 +1,11 @@
1
+ [![Build Status](https://secure.travis-ci.org/dresselm/memtf.png)](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.finish
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
@@ -1 +1,6 @@
1
- require "bundler/gem_tasks"
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
@@ -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::START_STAGE, group)
12
- end_analysis = Memtf::Persistance.load(Memtf::FINISH_STAGE, group)
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 = start_analysis[clazz]
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 = end_stats[stat_key]
24
- delta = end_val - start_val
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 = comparison[klazz]
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
- @class_or_module_filter = options[:class_or_module_filter]
41
- @threshold = options.fetch(:threshold, 0.005)
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
- class_stats = {}
57
+ classes_stats = {}
48
58
  total_memsize = 0
49
59
 
50
- obj_space_routine = lambda do |obj|
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 = clazz.name
53
- class_stat = (class_stats[class_name] ||= [])
54
- obj_memsize = ObjectSpace.memsize_of(obj)
55
- class_stat << obj_memsize
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
- if @class_or_module_filter.nil?
61
- ObjectSpace.each_object(&obj_space_routine)
62
- else
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
- threshold = @threshold * total_memsize
67
- mem_hogs = class_stats.select do |k,v|
68
- v.sum >= threshold
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
- sorted_mem_hogs.each do |k,v|
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; nil
82
-
142
+ end
83
143
  smh_hash
84
144
  end
145
+
85
146
  end
@@ -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
@@ -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 = group
13
+ @group = group
13
14
  @options = options
14
15
  end
15
16
 
17
+ # @return [Terminal::Table]
16
18
  def report
17
- table = Terminal::Table.new(:headings => ['Class', 'Objects', 'Leakage', 'Impact']) do |t|
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 = options.delete(:group) || Time.now.to_i
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
- Memtf::Reporter.report(group) if stage == Memtf::FINISH_STAGE
21
+ if stage == Memtf::STOP
22
+ @report = Memtf::Reporter.report(group)
23
+ puts @report
24
+ end
19
25
 
20
26
  self
21
27
  end
@@ -1,5 +1,6 @@
1
1
  module Memtf::Utilities::Array
2
- def sum
2
+ # @return [Number]
3
+ def sum
3
4
  inject(0) { |sum, elem| sum + elem }
4
5
  end
5
6
  end
data/lib/memtf/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Memtf
2
- VERSION = "0.0.1"
2
+ VERSION = "0.0.2"
3
3
  end
data/lib/memtf.rb CHANGED
@@ -1,24 +1,31 @@
1
1
  module Memtf
2
- START_STAGE = :start
3
- FINISH_STAGE = :finish
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(START_STAGE, options)
13
+ self.runner = Runner.run(START, options)
10
14
  end
11
15
 
12
- def finish(options={})
13
- Runner.run(FINISH_STAGE, options.merge(:group => self.runner.group))
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
- finish(options)
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
@@ -0,0 +1,2 @@
1
+ require 'simplecov'
2
+ require 'memtf'
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.1
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-22 00:00:00.000000000 Z
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.14
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: