busy-administrator 1.0.0
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 +7 -0
- data/lib/busy-administrator/display.rb +41 -0
- data/lib/busy-administrator/example_generator.rb +13 -0
- data/lib/busy-administrator/memory_size.rb +143 -0
- data/lib/busy-administrator/memory_utils.rb +201 -0
- data/lib/busy-administrator/process_utils.rb +30 -0
- data/lib/busy-administrator/version.rb +3 -0
- data/lib/busy-administrator.rb +55 -0
- metadata +80 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 883afd8faafc52f568eea6a1393d2a945654bcf7
|
4
|
+
data.tar.gz: a08973fcbc8caddb7db15d787751ebdc5a151235
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 5ad360f51265c9d1a901327d1a2577ea6ae44504f0a5647b7deeba2753112bbfd093723cbbe1f38ee45cca743cddf35df1ef7a1b7e56e756a278a67f51bd40f4
|
7
|
+
data.tar.gz: a4ea6628c47693c4b551a4e58cea763de0ba9a7ca1897237222e5e491440b7be64ddaa04249e5df9a12985a149de0e050e00bf1fff89ebb83f61fbbee3e35a75
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module BusyAdministrator
|
2
|
+
module Display
|
3
|
+
def self.debug(target, indent: 0)
|
4
|
+
if target.is_a?(Hash)
|
5
|
+
indent_space = " " * (indent * 4)
|
6
|
+
puts indent_space + "{"
|
7
|
+
|
8
|
+
indent += 1
|
9
|
+
|
10
|
+
target.each do |key, value|
|
11
|
+
if value.is_a?(Hash) || value.is_a?(Array)
|
12
|
+
indent_space = " " * (indent * 4)
|
13
|
+
puts indent_space + "#{ key }:"
|
14
|
+
|
15
|
+
self.debug(value, indent: indent + 1)
|
16
|
+
else
|
17
|
+
indent_space = " " * (indent * 4)
|
18
|
+
puts indent_space + "#{ key }: #{ value }"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
indent -= 1
|
23
|
+
indent_space = " " * (indent * 4)
|
24
|
+
puts indent_space + "}"
|
25
|
+
elsif target.is_a?(Array)
|
26
|
+
indent_space = " " * (indent * 4)
|
27
|
+
puts indent_space + "["
|
28
|
+
|
29
|
+
target.each do |element|
|
30
|
+
self.debug(element, indent: indent + 1)
|
31
|
+
end
|
32
|
+
|
33
|
+
indent_space = " " * (indent * 4)
|
34
|
+
puts indent_space + "]"
|
35
|
+
else
|
36
|
+
indent_space = " " * (indent * 4)
|
37
|
+
puts indent_space + "#{ target }"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'securerandom'
|
2
|
+
|
3
|
+
module BusyAdministrator
|
4
|
+
module ExampleGenerator
|
5
|
+
class << self
|
6
|
+
def generate_string_with_specified_memory_size(memory_size)
|
7
|
+
raise Exception unless memory_size.respond_to?(:mebibytes)
|
8
|
+
|
9
|
+
SecureRandom.random_bytes(memory_size.bytes)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,143 @@
|
|
1
|
+
class Numeric
|
2
|
+
[:mebibytes, :megabytes, :kibibytes, :kilobytes].each do |method|
|
3
|
+
define_method(method) do
|
4
|
+
BusyAdministrator::MemorySize.send(method, self)
|
5
|
+
end
|
6
|
+
end
|
7
|
+
|
8
|
+
alias_method :mebibyte, :mebibytes
|
9
|
+
alias_method :megabyte, :megabytes
|
10
|
+
alias_method :kibibyte, :kibibytes
|
11
|
+
alias_method :kilobyte, :kilobytes
|
12
|
+
end
|
13
|
+
|
14
|
+
module BusyAdministrator
|
15
|
+
class MemorySize
|
16
|
+
def initialize(bytes:)
|
17
|
+
@bytes = bytes
|
18
|
+
end
|
19
|
+
|
20
|
+
def bytes
|
21
|
+
@bytes
|
22
|
+
end
|
23
|
+
|
24
|
+
def kibibytes
|
25
|
+
@bytes / 1024
|
26
|
+
end
|
27
|
+
|
28
|
+
def kilobytes
|
29
|
+
@bytes / 1000
|
30
|
+
end
|
31
|
+
|
32
|
+
def mebibytes
|
33
|
+
@bytes / 1024 / 1024
|
34
|
+
end
|
35
|
+
|
36
|
+
def megabytes
|
37
|
+
@bytes / 1000 / 1000
|
38
|
+
end
|
39
|
+
|
40
|
+
def +(other)
|
41
|
+
self.class.new(bytes: @bytes + other.bytes)
|
42
|
+
end
|
43
|
+
|
44
|
+
def -(other)
|
45
|
+
self.class.new(bytes: @bytes - other.bytes)
|
46
|
+
end
|
47
|
+
|
48
|
+
def *(number)
|
49
|
+
self.class.new(bytes: @bytes * number)
|
50
|
+
end
|
51
|
+
|
52
|
+
def /(number)
|
53
|
+
self.class.new(bytes: @bytes / number)
|
54
|
+
end
|
55
|
+
|
56
|
+
def ==(other_object)
|
57
|
+
self.bytes == other_object.bytes
|
58
|
+
end
|
59
|
+
|
60
|
+
def >(other_object)
|
61
|
+
self.bytes > other_object.bytes
|
62
|
+
end
|
63
|
+
|
64
|
+
def >=(other_object)
|
65
|
+
self.bytes >= other_object.bytes
|
66
|
+
end
|
67
|
+
|
68
|
+
def <(other_object)
|
69
|
+
self.bytes < other_object.bytes
|
70
|
+
end
|
71
|
+
|
72
|
+
def <=(other_object)
|
73
|
+
self.bytes <= other_object.bytes
|
74
|
+
end
|
75
|
+
|
76
|
+
def to_s
|
77
|
+
if @bytes < 1024
|
78
|
+
"#{ bytes } Bytes"
|
79
|
+
elsif @bytes < 1024 * 1024
|
80
|
+
"#{ kibibytes } KiB"
|
81
|
+
else
|
82
|
+
"#{ mebibytes } MiB"
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def inspect
|
87
|
+
to_s
|
88
|
+
end
|
89
|
+
|
90
|
+
class << self
|
91
|
+
def kibibytes(num)
|
92
|
+
new(bytes: num * 1024)
|
93
|
+
end
|
94
|
+
|
95
|
+
def kilobytes(num)
|
96
|
+
new(bytes: num * 1000)
|
97
|
+
end
|
98
|
+
|
99
|
+
def mebibytes(num)
|
100
|
+
new(bytes: num * 1024 * 1024)
|
101
|
+
end
|
102
|
+
|
103
|
+
def megabytes(num)
|
104
|
+
new(bytes: num * 1000 * 1000)
|
105
|
+
end
|
106
|
+
|
107
|
+
def of(target, checked_objects: [])
|
108
|
+
total_size = 0
|
109
|
+
|
110
|
+
unless checked_objects.include?(target.object_id)
|
111
|
+
total_size += ObjectSpace.memsize_of(target)
|
112
|
+
|
113
|
+
checked_objects << target.object_id
|
114
|
+
|
115
|
+
(ObjectSpace.reachable_objects_from(target) || []).each do |reachable_object|
|
116
|
+
return new(bytes: 0) if reachable_object.is_a?(ObjectSpace::InternalObjectWrapper)
|
117
|
+
|
118
|
+
total_size += self.of(reachable_object, checked_objects: checked_objects).bytes
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
new(bytes: total_size)
|
123
|
+
end
|
124
|
+
|
125
|
+
def of_all_objects_from(target)
|
126
|
+
total_memory_size = 0
|
127
|
+
|
128
|
+
# ensure that we don't double count duplicates
|
129
|
+
checked_objects = []
|
130
|
+
|
131
|
+
if target.is_a?(Class) || target.is_a?(Module)
|
132
|
+
ObjectSpace.each_object(target).each do |instance|
|
133
|
+
total_memory_size += self.of(instance, checked_objects: checked_objects).bytes
|
134
|
+
end
|
135
|
+
else
|
136
|
+
raise Exception, "target should be a Class or Module"
|
137
|
+
end
|
138
|
+
|
139
|
+
new(bytes: total_memory_size)
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
@@ -0,0 +1,201 @@
|
|
1
|
+
module BusyAdministrator
|
2
|
+
module MemoryUtils
|
3
|
+
class MemoryAnalyzer
|
4
|
+
attr_reader :pairs
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
@pairs = []
|
8
|
+
end
|
9
|
+
|
10
|
+
def include(key:, value:)
|
11
|
+
@pairs << [key, value.object_id]
|
12
|
+
end
|
13
|
+
|
14
|
+
def analyze(verbose: false)
|
15
|
+
output = {}
|
16
|
+
|
17
|
+
@pairs.each do |pair|
|
18
|
+
key, value = pair
|
19
|
+
|
20
|
+
target = ObjectSpace._id2ref(value)
|
21
|
+
|
22
|
+
if target.is_a?(Class) || target.is_a?(Module)
|
23
|
+
output[key.to_sym] = MemorySize.of_all_objects_from(target)
|
24
|
+
else
|
25
|
+
output[key.to_sym] = MemorySize.of(target)
|
26
|
+
end
|
27
|
+
|
28
|
+
log("#{ key } = #{ output[key.to_sym] } { #{ target.class } }", verbose: verbose)
|
29
|
+
end
|
30
|
+
|
31
|
+
output
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def log(message, verbose: false)
|
37
|
+
if verbose
|
38
|
+
puts "[BusyAdministrator::MemoryUtils::Analyzer.analyze] #{ message }"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
class << self
|
44
|
+
def trigger_gc
|
45
|
+
GC.start(full_mark:true, immediate_sweep: true, immediate_mark: false)
|
46
|
+
end
|
47
|
+
|
48
|
+
def get_created_object_classes
|
49
|
+
ObjectSpace.each_object.to_a.map(&:class).uniq.select do |target|
|
50
|
+
target.is_a?(Class) || target.is_a?(Module)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def profile(gc_enabled: true, verbose: false)
|
55
|
+
analyzer = MemoryAnalyzer.new
|
56
|
+
excluded_object_id_storage = []
|
57
|
+
all_object_ids_after_execution = []
|
58
|
+
gc_count_before = 0
|
59
|
+
|
60
|
+
output_container = {
|
61
|
+
memory_usage: {},
|
62
|
+
total_time: 0.0,
|
63
|
+
gc: {
|
64
|
+
count: 0,
|
65
|
+
enabled: false
|
66
|
+
}
|
67
|
+
}
|
68
|
+
|
69
|
+
action("GC Settings") do
|
70
|
+
output_container[:gc][:enabled] = gc_enabled
|
71
|
+
|
72
|
+
if gc_enabled
|
73
|
+
GC.enable
|
74
|
+
log("[Before] Enable GC", verbose: verbose)
|
75
|
+
else
|
76
|
+
GC.disable
|
77
|
+
log("[Before] Disable GC", verbose: verbose)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
action("Prepare Object ID Storage Before Execution") do
|
82
|
+
excluded_object_id_storage = get_created_object_ids
|
83
|
+
log("[Before] Object Count: #{ excluded_object_id_storage.size }", verbose: verbose)
|
84
|
+
end
|
85
|
+
|
86
|
+
action("Get Memory Usage Before Execution") do
|
87
|
+
memory_usage_before = ProcessUtils.get_memory_usage(:rss)
|
88
|
+
output_container[:memory_usage][:before] = memory_usage_before
|
89
|
+
|
90
|
+
log("[Before] Memory Usage: #{ memory_usage_before }", verbose: verbose)
|
91
|
+
end
|
92
|
+
|
93
|
+
action("Execute Main Action") do
|
94
|
+
gc_count_before = GC.stat[:count]
|
95
|
+
log("[Before] GC Count: #{ gc_count_before }", verbose: verbose)
|
96
|
+
|
97
|
+
log("[Before] Block Start", verbose: verbose)
|
98
|
+
|
99
|
+
total_time = Benchmark.realtime do
|
100
|
+
yield(analyzer) if block_given?
|
101
|
+
end
|
102
|
+
|
103
|
+
output_container[:total_time] = total_time.round(6)
|
104
|
+
|
105
|
+
log("[After] Block End", verbose: verbose)
|
106
|
+
log("[After] Total Time: #{ total_time } seconds", verbose: verbose)
|
107
|
+
end
|
108
|
+
|
109
|
+
action("Compute Specific Stats") do
|
110
|
+
output_container[:specific] = analyzer.analyze(verbose: verbose)
|
111
|
+
end
|
112
|
+
|
113
|
+
action("Run GC if enabled") do
|
114
|
+
if gc_enabled
|
115
|
+
self.trigger_gc
|
116
|
+
log("[After] Run GC", verbose: verbose)
|
117
|
+
end
|
118
|
+
|
119
|
+
gc_count_after = GC.stat[:count]
|
120
|
+
log("[After] GC Count: #{ gc_count_after }", verbose: verbose)
|
121
|
+
|
122
|
+
gc_count_diff = gc_count_after - gc_count_before
|
123
|
+
output_container[:gc][:count] = gc_count_diff
|
124
|
+
|
125
|
+
log("[Diff] GC Count: #{ gc_count_diff }", verbose: verbose)
|
126
|
+
end
|
127
|
+
|
128
|
+
action("Get Memory Usage After Execution") do
|
129
|
+
memory_usage_after = ProcessUtils.get_memory_usage(:rss)
|
130
|
+
log("[After] Memory Usage: #{ memory_usage_after }", verbose: verbose)
|
131
|
+
|
132
|
+
output_container[:memory_usage][:after] = memory_usage_after
|
133
|
+
output_container[:memory_usage][:diff] = output_container[:memory_usage][:after] - output_container[:memory_usage][:before]
|
134
|
+
log("[Diff] Memory Usage: #{ output_container[:memory_usage] }", verbose: verbose)
|
135
|
+
end
|
136
|
+
|
137
|
+
action("Get Object Count After Execution") do
|
138
|
+
all_object_ids_after_execution = get_created_object_ids
|
139
|
+
log("[After] Object Count: #{ all_object_ids_after_execution.size }", verbose: verbose)
|
140
|
+
|
141
|
+
all_object_ids_after_execution -= excluded_object_id_storage
|
142
|
+
log("[Diff] Object Count: #{ all_object_ids_after_execution.size }", verbose: verbose)
|
143
|
+
output_container[:object_count] = all_object_ids_after_execution.size
|
144
|
+
end
|
145
|
+
|
146
|
+
action("Compute General Stats") do
|
147
|
+
general = {}
|
148
|
+
|
149
|
+
all_object_ids_after_execution.each do |object_id|
|
150
|
+
target = ObjectSpace._id2ref(object_id)
|
151
|
+
target_class = target.class.name
|
152
|
+
|
153
|
+
general[target_class.to_sym] ||= 0
|
154
|
+
general[target_class.to_sym] += ObjectSpace.memsize_of(target)
|
155
|
+
end
|
156
|
+
|
157
|
+
general.each do |key, value|
|
158
|
+
general[key] = MemorySize.new(bytes: value)
|
159
|
+
log("[Diff] Class #{ key }: #{ general[key] } ")
|
160
|
+
end
|
161
|
+
|
162
|
+
output_container[:general] = general
|
163
|
+
end
|
164
|
+
|
165
|
+
action("Run GC") do
|
166
|
+
GC.enable
|
167
|
+
self.trigger_gc
|
168
|
+
end
|
169
|
+
|
170
|
+
output_container
|
171
|
+
end
|
172
|
+
|
173
|
+
private
|
174
|
+
|
175
|
+
def action(label)
|
176
|
+
log("Action: #{ label }")
|
177
|
+
|
178
|
+
yield if block_given?
|
179
|
+
end
|
180
|
+
|
181
|
+
def log(message, verbose: false)
|
182
|
+
if verbose
|
183
|
+
puts "[BusyAdministrator::MemoryUtils.profile] #{ message }"
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
def get_created_object_ids
|
188
|
+
output = ObjectSpace.each_object.to_a.map(&:object_id)
|
189
|
+
output << output.object_id
|
190
|
+
|
191
|
+
output
|
192
|
+
end
|
193
|
+
|
194
|
+
def get_unique_classes_from_object_ids(object_ids_array)
|
195
|
+
object_ids_array.map { |object_id| ObjectSpace._id2ref(object_id) }.map(&:class).uniq.select do |target|
|
196
|
+
target.is_a?(Class) || target.is_a?(Module)
|
197
|
+
end
|
198
|
+
end
|
199
|
+
end
|
200
|
+
end
|
201
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module BusyAdministrator
|
2
|
+
module ProcessUtils
|
3
|
+
class << self
|
4
|
+
# http://stackoverflow.com/questions/7880784/what-is-rss-and-vsz-in-linux-memory-management
|
5
|
+
def get_memory_usage(metric = :rss)
|
6
|
+
available_options = [:rss, :vsz]
|
7
|
+
|
8
|
+
if available_options.include?(metric)
|
9
|
+
bytes = `ps -o #{ metric.to_s }= -p #{ Process.pid }`.to_i * 1024
|
10
|
+
|
11
|
+
MemorySize.new(bytes: bytes)
|
12
|
+
else
|
13
|
+
raise Exception, "available_options: #{ available_options.inspect }"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
# Does not work in OSX
|
18
|
+
# Will raise NoMemoryError: failed to allocate memory
|
19
|
+
def set_max_memory_usage(mebibytes:)
|
20
|
+
Process.setrlimit(Process::RLIMIT_AS, mebibytes * 1024 * 1024)
|
21
|
+
end
|
22
|
+
|
23
|
+
def get_max_memory_usage
|
24
|
+
bytes = Process.getrlimit(Process::RLIMIT_AS)[1]
|
25
|
+
|
26
|
+
MemorySize.new(bytes: bytes)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'objspace'
|
2
|
+
require 'benchmark'
|
3
|
+
require 'busy-administrator/display'
|
4
|
+
require 'busy-administrator/example_generator'
|
5
|
+
require 'busy-administrator/memory_size'
|
6
|
+
require 'busy-administrator/memory_utils'
|
7
|
+
require 'busy-administrator/process_utils'
|
8
|
+
require 'busy-administrator/version'
|
9
|
+
|
10
|
+
"""
|
11
|
+
require 'busy-administrator'
|
12
|
+
|
13
|
+
BusyAdministrator::MemoryUtils.get_created_object_classes
|
14
|
+
BusyAdministrator::MemoryUtils.profile(verbose: true) do
|
15
|
+
puts 'something'
|
16
|
+
end
|
17
|
+
|
18
|
+
class Testing
|
19
|
+
attr_accessor :large_value
|
20
|
+
end
|
21
|
+
|
22
|
+
BusyAdministrator::MemoryUtils.profile(verbose: true, gc_enabled: false) do |analyzer|
|
23
|
+
data = BusyAdministrator::ExampleGenerator.generate_string_with_specified_memory_size(10.mebibytes)
|
24
|
+
|
25
|
+
testing_a = Testing.new
|
26
|
+
testing_a.large_value = BusyAdministrator::ExampleGenerator.generate_string_with_specified_memory_size(5.mebibytes)
|
27
|
+
|
28
|
+
testing_b = Testing.new
|
29
|
+
testing_b.large_value = BusyAdministrator::ExampleGenerator.generate_string_with_specified_memory_size(10.mebibytes)
|
30
|
+
|
31
|
+
analyzer.include(key: 'data', value: data)
|
32
|
+
analyzer.include(key: 'testing_a', value: testing_a)
|
33
|
+
analyzer.include(key: 'testing_b', value: testing_b)
|
34
|
+
analyzer.include(key: 'Testing', value: Testing)
|
35
|
+
end
|
36
|
+
|
37
|
+
data = BusyAdministrator::ExampleGenerator.generate_string_with_specified_memory_size(10.mebibytes)
|
38
|
+
BusyAdministrator::MemorySize.of(data).mebibytes
|
39
|
+
BusyAdministrator::MemorySize.of_all_objects_from(SampleClass).mebibytes
|
40
|
+
|
41
|
+
BusyAdministrator::ProcessUtils.get_memory_usage(:rss).mebibytes
|
42
|
+
BusyAdministrator::ProcessUtils.get_memory_usage(:vsz).mebibytes
|
43
|
+
|
44
|
+
# set max memory usage will check vsz
|
45
|
+
BusyAdministrator::ProcessUtils.set_max_memory_usage(100.mebibytes)
|
46
|
+
BusyAdministrator::ProcessUtils.get_max_memory_usage.mebibytes
|
47
|
+
|
48
|
+
TODO:
|
49
|
+
Create gem and add tests and documentation
|
50
|
+
Add option to set recursion level for MemorySize
|
51
|
+
Add advanced analyzer for objects with references to other objects
|
52
|
+
"""
|
53
|
+
|
54
|
+
module BusyAdministrator
|
55
|
+
end
|
metadata
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: busy-administrator
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Joshua Arvin Lat
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-09-25 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.5'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.5'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
description: Handy Ruby Dev Tools for the Busy Administrator
|
42
|
+
email:
|
43
|
+
- joshua.arvin.lat@gmail.com
|
44
|
+
executables: []
|
45
|
+
extensions: []
|
46
|
+
extra_rdoc_files: []
|
47
|
+
files:
|
48
|
+
- lib/busy-administrator.rb
|
49
|
+
- lib/busy-administrator/display.rb
|
50
|
+
- lib/busy-administrator/example_generator.rb
|
51
|
+
- lib/busy-administrator/memory_size.rb
|
52
|
+
- lib/busy-administrator/memory_utils.rb
|
53
|
+
- lib/busy-administrator/process_utils.rb
|
54
|
+
- lib/busy-administrator/version.rb
|
55
|
+
homepage: ''
|
56
|
+
licenses:
|
57
|
+
- MIT
|
58
|
+
metadata: {}
|
59
|
+
post_install_message:
|
60
|
+
rdoc_options: []
|
61
|
+
require_paths:
|
62
|
+
- lib
|
63
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
64
|
+
requirements:
|
65
|
+
- - ">="
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: '0'
|
68
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
69
|
+
requirements:
|
70
|
+
- - ">="
|
71
|
+
- !ruby/object:Gem::Version
|
72
|
+
version: '0'
|
73
|
+
requirements: []
|
74
|
+
rubyforge_project:
|
75
|
+
rubygems_version: 2.4.8
|
76
|
+
signing_key:
|
77
|
+
specification_version: 4
|
78
|
+
summary: Handy Ruby Dev Tools for the Busy Administrator
|
79
|
+
test_files: []
|
80
|
+
has_rdoc:
|