neutrino_client 0.0.3 → 0.0.5
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.
- data/lib/neutrino/metric.rb +7 -4
- data/lib/neutrino/munin_metric.rb +21 -5
- data/lib/neutrino/reporter.rb +12 -30
- data/lib/neutrino/shell_metric.rb +14 -6
- data/lib/neutrino/version.rb +1 -1
- data/test/cli_test.rb +1 -1
- data/test/config_test.rb +1 -1
- data/test/metric_test.rb +42 -15
- data/test/munin_metric_test.rb +41 -4
- data/test/reporter_test.rb +5 -10
- data/test/shell_metric_test.rb +29 -8
- metadata +4 -4
data/lib/neutrino/metric.rb
CHANGED
@@ -10,11 +10,10 @@ module Neutrino
|
|
10
10
|
property :group
|
11
11
|
property :type
|
12
12
|
property :name
|
13
|
-
property :
|
13
|
+
property :values
|
14
14
|
property :display_options
|
15
15
|
|
16
16
|
def metric_id
|
17
|
-
raise StandardError.new("Requires name and hostname") unless name && hostname
|
18
17
|
Digest::MD5.hexdigest("#{name}#{hostname}")
|
19
18
|
end
|
20
19
|
|
@@ -23,15 +22,19 @@ module Neutrino
|
|
23
22
|
end
|
24
23
|
|
25
24
|
def to_h
|
25
|
+
raise StandardError.new("Requires name") unless name
|
26
|
+
raise StandardError.new("Requires values") unless values
|
27
|
+
raise StandardError.new("Requires hostname") unless hostname
|
26
28
|
{
|
27
29
|
:metadata => (base_metadata || {}).merge({
|
28
30
|
:name => self.name,
|
29
31
|
:group => self.group,
|
30
|
-
:type => self.type
|
32
|
+
:type => self.type,
|
33
|
+
:hostname => self.hostname
|
31
34
|
}),
|
32
35
|
:display_options => self.display_options,
|
33
36
|
:name => self.metric_id,
|
34
|
-
:
|
37
|
+
:values => self.values || {}
|
35
38
|
}
|
36
39
|
end
|
37
40
|
end
|
@@ -8,7 +8,7 @@ module Neutrino
|
|
8
8
|
def initialize(opts={})
|
9
9
|
super(opts)
|
10
10
|
configure
|
11
|
-
|
11
|
+
query
|
12
12
|
end
|
13
13
|
|
14
14
|
def self.execute_and_parse(command)
|
@@ -16,9 +16,16 @@ module Neutrino
|
|
16
16
|
stdout.read.strip
|
17
17
|
end
|
18
18
|
result = {}
|
19
|
-
|
19
|
+
Log.debug("#{command} outputs #{output}")
|
20
|
+
output.to_s.split("\n").each do |line|
|
20
21
|
whole_line, key, value = line.match(/(\S*) (.*)/).to_a
|
21
|
-
|
22
|
+
key = line.strip if key.nil? # Can be nil if no value is specified
|
23
|
+
key_parts = nil
|
24
|
+
if key.match("graph_")
|
25
|
+
key_parts = key.split(/_/)
|
26
|
+
else
|
27
|
+
key_parts = key.split(/\./)
|
28
|
+
end
|
22
29
|
if key_parts.length == 2
|
23
30
|
result[key_parts.first] ||= {}
|
24
31
|
result[key_parts.first][key_parts.last] = value
|
@@ -26,6 +33,7 @@ module Neutrino
|
|
26
33
|
result[key_parts.first] = value
|
27
34
|
end
|
28
35
|
end
|
36
|
+
Log.debug("#{command} output is parsed as #{result.inspect}")
|
29
37
|
result
|
30
38
|
end
|
31
39
|
|
@@ -44,14 +52,22 @@ module Neutrino
|
|
44
52
|
self.base_metadata["group"] = plugin_configuration["graph"]["category"]
|
45
53
|
self.base_metadata["type"] = plugin_configuration["graph"]["vlabel"]
|
46
54
|
self.base_metadata["name"] = plugin_configuration["graph"]["title"]
|
55
|
+
self.name = plugin_configuration["graph"]["title"]
|
47
56
|
end
|
48
57
|
end
|
49
58
|
|
50
59
|
def query
|
51
60
|
plugin_query = MuninMetric.query_plugin(self.munin_plugin_path)
|
52
61
|
begin
|
53
|
-
|
54
|
-
|
62
|
+
values_hash = {}
|
63
|
+
plugin_query.to_a.each do |metric|
|
64
|
+
name = metric[0]
|
65
|
+
val = metric[1]["value"]
|
66
|
+
values_hash[name] = val.nil? ? nil : val.to_f
|
67
|
+
end
|
68
|
+
self.values = values_hash
|
69
|
+
rescue => e
|
70
|
+
Log.debug("Error querying munin: #{e}")
|
55
71
|
end
|
56
72
|
end
|
57
73
|
|
data/lib/neutrino/reporter.rb
CHANGED
@@ -6,60 +6,46 @@ module Neutrino
|
|
6
6
|
|
7
7
|
def self.record(metric)
|
8
8
|
Log.info("Recording: #{metric.to_json}")
|
9
|
-
HTTParty.post('http://neutrino2.heroku.com/record', :body => metric.
|
10
|
-
|
9
|
+
response = HTTParty.post('http://neutrino2.heroku.com/record', :body => metric.to_h)
|
10
|
+
Log.debug "Response: body=#{response.body} code=#{response.code} message=#{response.message} headers=#{response.headers.inspect}"
|
11
11
|
end
|
12
12
|
|
13
13
|
def self.get_metrics
|
14
14
|
ms = [
|
15
|
-
ShellMetric.new({
|
16
|
-
:name => "CPU Steal",
|
17
|
-
:command => "iostat | grep -A1 avg-cpu | tail -1 | awk '{print $5}'",
|
18
|
-
:group => "system",
|
19
|
-
:type => "CPU"
|
20
|
-
}),
|
21
15
|
ShellMetric.new({
|
22
16
|
:name => "User CPU",
|
23
|
-
:
|
17
|
+
:commands => {:user => "iostat | grep -A1 avg-cpu | tail -1 | awk '{print $1}'"},
|
24
18
|
:group => "system",
|
25
19
|
:type => "CPU",
|
26
20
|
:display_options => {:min => 0, :max => 1}
|
27
21
|
}),
|
28
22
|
ShellMetric.new({
|
29
23
|
:name => "Idle CPU",
|
30
|
-
:
|
24
|
+
:commands => {:idle => "iostat | grep -A1 avg-cpu | tail -1 | awk '{print $6}'"},
|
31
25
|
:group => "system",
|
32
26
|
:type => "CPU",
|
33
27
|
:display_options => {:min => 0, :max => 100}
|
34
28
|
}),
|
35
29
|
ShellMetric.new({
|
36
30
|
:name => "Free Memory",
|
37
|
-
:
|
31
|
+
:commands => {:free => "cat /proc/meminfo | grep 'MemFree' | awk '{print $2}'"},
|
38
32
|
:group => "system",
|
39
33
|
:type => 'memory'
|
40
34
|
# :display_options => {:min => 0, :max => ShellMetric.execute("cat /proc/meminfo | grep 'MemTotal' | awk '{print $2}'")}
|
41
35
|
}),
|
42
|
-
ShellMetric.new({
|
43
|
-
:name => "Load Avg (1m)",
|
44
|
-
:command => "cat /proc/loadavg | awk '{print $1}'",
|
45
|
-
:group => "system",
|
46
|
-
:type => 'load'
|
47
|
-
}),
|
48
|
-
ShellMetric.new({
|
49
|
-
:name => "Load Avg (5m)",
|
50
|
-
:command => "cat /proc/loadavg | awk '{print $2}'",
|
51
|
-
:group => "system",
|
52
|
-
:type => 'load'
|
53
|
-
}),
|
54
36
|
ShellMetric.new({
|
55
37
|
:name => "Load Avg (15m)",
|
56
|
-
:
|
38
|
+
:commands => {
|
39
|
+
"1_min" => "cat /proc/loadavg | awk '{print $1}'",
|
40
|
+
"5_min" => "cat /proc/loadavg | awk '{print $2}'",
|
41
|
+
"15_min" => "cat /proc/loadavg | awk '{print $3}'",
|
42
|
+
},
|
57
43
|
:group => "system",
|
58
44
|
:type => 'load'
|
59
45
|
}),
|
60
46
|
ShellMetric.new({
|
61
47
|
:name => "Process Count",
|
62
|
-
:
|
48
|
+
:commands => {:processes => "ps aux | wc -l"},
|
63
49
|
:group => "system",
|
64
50
|
:type => 'process'
|
65
51
|
})
|
@@ -72,11 +58,7 @@ module Neutrino
|
|
72
58
|
get_metrics.each do |m|
|
73
59
|
m.hostname = `hostname`.strip
|
74
60
|
m.base_metadata = Config.metadata
|
75
|
-
|
76
|
-
Reporter.record(m)
|
77
|
-
rescue StandardError => e
|
78
|
-
Log.warn("Error running '#{m.name}': #{e}")
|
79
|
-
end
|
61
|
+
Reporter.record(m)
|
80
62
|
end
|
81
63
|
end
|
82
64
|
end
|
@@ -3,20 +3,28 @@ require 'open3'
|
|
3
3
|
module Neutrino
|
4
4
|
module Client
|
5
5
|
class ShellMetric < Metric
|
6
|
-
property :
|
6
|
+
property :commands
|
7
|
+
|
8
|
+
def initialize(opts={})
|
9
|
+
super(opts)
|
10
|
+
query
|
11
|
+
end
|
7
12
|
|
8
13
|
def self.execute(command)
|
9
14
|
parsed_value = Open3.popen3(command) do |stdin, stdout, stderr, wait_thr|
|
10
15
|
stdout.read.strip
|
11
16
|
end
|
12
|
-
|
17
|
+
Log.debug("'#{command}' outputs '#{parsed_value}'")
|
18
|
+
Log.warn("'#{command}' outputs '#{parsed_value}'") if parsed_value.nil? || parsed_value.empty?
|
13
19
|
return parsed_value
|
14
20
|
end
|
15
21
|
|
16
|
-
def
|
17
|
-
|
18
|
-
|
19
|
-
|
22
|
+
def query
|
23
|
+
values_hash = {}
|
24
|
+
self.commands.each_pair do |name, cmd|
|
25
|
+
values_hash[name] = ShellMetric.execute(cmd)
|
26
|
+
end
|
27
|
+
self.values = values_hash
|
20
28
|
end
|
21
29
|
end
|
22
30
|
end
|
data/lib/neutrino/version.rb
CHANGED
data/test/cli_test.rb
CHANGED
data/test/config_test.rb
CHANGED
data/test/metric_test.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
require "neutrino/client"
|
1
|
+
require "lib/neutrino/client"
|
2
2
|
require "test/unit"
|
3
3
|
require 'mocha'
|
4
4
|
|
@@ -17,7 +17,7 @@ module Neutrino
|
|
17
17
|
def test_metric_attributes
|
18
18
|
attrs = {
|
19
19
|
:name => "Load Avg (15m)",
|
20
|
-
:
|
20
|
+
:values => {:myval => 747},
|
21
21
|
:group => "system",
|
22
22
|
:type => 'load',
|
23
23
|
:display_options => {:width => 100}
|
@@ -26,7 +26,8 @@ module Neutrino
|
|
26
26
|
assert_equal metric.group, attrs[:group]
|
27
27
|
assert_equal metric.type, attrs[:type]
|
28
28
|
assert_equal metric.name, attrs[:name]
|
29
|
-
assert_equal metric.
|
29
|
+
assert_equal metric.values, attrs[:values]
|
30
|
+
assert_equal metric.values[:myval], attrs[:values][:myval]
|
30
31
|
assert_equal metric.display_options, attrs[:display_options]
|
31
32
|
end
|
32
33
|
|
@@ -51,16 +52,6 @@ module Neutrino
|
|
51
52
|
assert_equal metric.metric_id, Digest::MD5.hexdigest("#{name}#{hostname}")
|
52
53
|
end
|
53
54
|
|
54
|
-
def test_metric_id_raises_without_hostname
|
55
|
-
metric = Metric.new(:name => "a_metric")
|
56
|
-
assert_raises(StandardError){ metric.metric_id }
|
57
|
-
end
|
58
|
-
|
59
|
-
def test_metric_id_raises_without_hostname
|
60
|
-
metric = Metric.new(:hostname => "a_metric.com")
|
61
|
-
assert_raises(StandardError){ metric.metric_id }
|
62
|
-
end
|
63
|
-
|
64
55
|
def test_to_json_calls_to_h
|
65
56
|
metric = Metric.new(:hostname => "a_metric.com", :name => "asdf")
|
66
57
|
metric.expects(:to_h)
|
@@ -70,7 +61,7 @@ module Neutrino
|
|
70
61
|
def test_metric_to_h
|
71
62
|
attrs = {
|
72
63
|
:name => "Load Avg (15m)",
|
73
|
-
:
|
64
|
+
:values => {:bval => 0.11},
|
74
65
|
:group => "system",
|
75
66
|
:type => 'load',
|
76
67
|
:display_options => {:width => 100}
|
@@ -84,10 +75,46 @@ module Neutrino
|
|
84
75
|
assert_equal result[:metadata][:name], attrs[:name]
|
85
76
|
assert_equal result[:metadata][:group], attrs[:group]
|
86
77
|
assert_equal result[:metadata][:type], attrs[:type]
|
78
|
+
assert_equal result[:metadata][:hostname], metric.hostname
|
87
79
|
assert_equal result[:display_options], attrs[:display_options]
|
88
|
-
assert_equal result[:
|
80
|
+
assert_equal result[:values][:bval], 0.11
|
89
81
|
assert_equal result[:name], metric.metric_id
|
90
82
|
end
|
83
|
+
|
84
|
+
def test_metric_to_h_raises_without_hostname
|
85
|
+
attrs = {
|
86
|
+
:name => "Load Avg (15m)",
|
87
|
+
:values => {:bval => 0.11},
|
88
|
+
:group => "system",
|
89
|
+
:type => 'load',
|
90
|
+
:display_options => {:width => 100}
|
91
|
+
}
|
92
|
+
metric = Metric.new(attrs)
|
93
|
+
assert_raises(StandardError){ metric.to_h }
|
94
|
+
end
|
95
|
+
|
96
|
+
def test_metric_to_h_raises_without_name
|
97
|
+
attrs = {
|
98
|
+
:values => {:bval => 0.11},
|
99
|
+
:group => "system",
|
100
|
+
:type => 'load',
|
101
|
+
:display_options => {:width => 100}
|
102
|
+
}
|
103
|
+
metric = Metric.new(attrs)
|
104
|
+
assert_raises(StandardError){ metric.to_h }
|
105
|
+
end
|
106
|
+
|
107
|
+
def test_metric_to_h_raises_without_values
|
108
|
+
attrs = {
|
109
|
+
:name => "Load Avg (15m)",
|
110
|
+
:group => "system",
|
111
|
+
:type => 'load',
|
112
|
+
:display_options => {:width => 100}
|
113
|
+
}
|
114
|
+
metric = Metric.new(attrs)
|
115
|
+
assert_raises(StandardError){ metric.to_h }
|
116
|
+
end
|
117
|
+
|
91
118
|
end
|
92
119
|
end
|
93
120
|
end
|
data/test/munin_metric_test.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
require "neutrino/client"
|
1
|
+
require "lib/neutrino/client"
|
2
2
|
require "test/unit"
|
3
3
|
require 'mocha'
|
4
4
|
|
@@ -11,6 +11,7 @@ module Neutrino
|
|
11
11
|
|
12
12
|
def test_properties
|
13
13
|
path = "/path/to/plugin"
|
14
|
+
Open3.stubs(:popen3)
|
14
15
|
m = MuninMetric.new(:munin_plugin_path => path)
|
15
16
|
assert_equal m.munin_plugin_path, path
|
16
17
|
end
|
@@ -42,8 +43,9 @@ module Neutrino
|
|
42
43
|
assert_equal m["load"]["value"], "0.17"
|
43
44
|
end
|
44
45
|
|
45
|
-
def
|
46
|
+
def test_configuring_sets_base_metadata
|
46
47
|
path = "/some_plugin"
|
48
|
+
Open3.stubs(:popen3).with("#{path}")
|
47
49
|
Open3.expects(:popen3).with("#{path} config").returns("graph_title Load average\ngraph_args --base 1000 -l 0\ngraph_vlabel load\ngraph_scale no\ngraph_category system\nload.label load\nload.warning 10\nload.critical 120\ngraph_info The load average of the machine describes how many processes are in the run-queue (scheduled to run \"immediately\").\nload.info Average load for the five minutes.\n")
|
48
50
|
m = MuninMetric.new(:munin_plugin_path => path)
|
49
51
|
assert_equal m.base_metadata["group"], "system"
|
@@ -51,13 +53,48 @@ module Neutrino
|
|
51
53
|
assert_equal m.base_metadata["name"], "Load average"
|
52
54
|
end
|
53
55
|
|
56
|
+
def test_can_handle_memory_output
|
57
|
+
path = "/some_plugin"
|
58
|
+
output = "swap_cache.value 0\nswap.value 0\n"
|
59
|
+
Open3.stubs(:popen3).with("#{path} config").returns("")
|
60
|
+
Open3.stubs(:popen3).with("#{path}").returns(output)
|
61
|
+
m = MuninMetric.new(:munin_plugin_path => path)
|
62
|
+
end
|
63
|
+
|
64
|
+
def test_can_handle_multiple_values
|
65
|
+
path = "/some_plugin"
|
66
|
+
output = "swap_cache.value 33\nswap.value 44\n"
|
67
|
+
Open3.stubs(:popen3).with("#{path} config").returns("")
|
68
|
+
Open3.stubs(:popen3).with("#{path}").returns(output)
|
69
|
+
m = MuninMetric.new(:munin_plugin_path => path)
|
70
|
+
assert_equal m.values["swap_cache"], 33
|
71
|
+
assert_equal m.values["swap"], 44
|
72
|
+
end
|
73
|
+
|
74
|
+
def test_can_handle_no_values
|
75
|
+
path = "/some_plugin"
|
76
|
+
output = "swap_cache.value\nswap.value 44\n"
|
77
|
+
Open3.stubs(:popen3).with("#{path} config").returns("")
|
78
|
+
Open3.stubs(:popen3).with("#{path}").returns(output)
|
79
|
+
m = MuninMetric.new(:munin_plugin_path => path)
|
80
|
+
assert_equal m.values["swap_cache"], nil
|
81
|
+
assert m.values.keys.include? "swap_cache"
|
82
|
+
end
|
83
|
+
|
84
|
+
def test_instanciation_configures_and_queries
|
85
|
+
path = "/some_plugin"
|
86
|
+
Open3.stubs(:popen3).with("#{path}")
|
87
|
+
Open3.expects(:popen3).with("#{path} config")
|
88
|
+
MuninMetric.new(:munin_plugin_path => path)
|
89
|
+
end
|
90
|
+
|
54
91
|
def test_query
|
55
92
|
path = "/some_plugin"
|
56
93
|
Open3.expects(:popen3).with("#{path} config").returns("")
|
57
94
|
Open3.expects(:popen3).with(path).returns("load.value 123\n")
|
58
95
|
m = MuninMetric.new(:munin_plugin_path => path)
|
59
|
-
m.
|
60
|
-
assert_equal m.
|
96
|
+
assert m.values.keys.include? "load"
|
97
|
+
assert_equal m.values["load"], 123
|
61
98
|
end
|
62
99
|
end
|
63
100
|
end
|
data/test/reporter_test.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
require "neutrino/client"
|
1
|
+
require "lib/neutrino/client"
|
2
2
|
require "test/unit"
|
3
3
|
require 'mocha'
|
4
4
|
require 'fakeweb'
|
@@ -12,6 +12,7 @@ module Neutrino
|
|
12
12
|
ShellMetric.stubs(:execute).returns(3.14159)
|
13
13
|
|
14
14
|
FakeWeb.allow_net_connect = false
|
15
|
+
FakeWeb.register_uri(:post, %r|neutrino2\.heroku\.com/|, :body => "{ok:1}")
|
15
16
|
end
|
16
17
|
|
17
18
|
def test_reporter_should_call_record_one_per_metric
|
@@ -20,17 +21,11 @@ module Neutrino
|
|
20
21
|
Reporter.report
|
21
22
|
end
|
22
23
|
|
23
|
-
def test_reporter_swallows_errors_and_logs_warnings
|
24
|
-
Open3.stubs(:popen3).returns('')
|
25
|
-
metrics = Reporter.get_metrics
|
26
|
-
Log.expects(:warn).times(metrics.length)
|
27
|
-
Reporter.report
|
28
|
-
end
|
29
|
-
|
30
24
|
def test_reporter_adds_munin_plugins
|
25
|
+
dummy_metric = Metric.new(:name => "a", :hostname => 'asdf', :values => {:a => 1})
|
31
26
|
Dir.expects(:glob).with("/somedir/*").returns(["/path1", "/path2"])
|
32
|
-
MuninMetric.expects(:new).with(:munin_plugin_path => "/path1").returns(
|
33
|
-
MuninMetric.expects(:new).with(:munin_plugin_path => "/path2").returns(
|
27
|
+
MuninMetric.expects(:new).with(:munin_plugin_path => "/path1").returns(dummy_metric)
|
28
|
+
MuninMetric.expects(:new).with(:munin_plugin_path => "/path2").returns(dummy_metric)
|
34
29
|
Config.munin_plugin_globs "/somedir/*"
|
35
30
|
Reporter.report
|
36
31
|
end
|
data/test/shell_metric_test.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
require "neutrino/client"
|
1
|
+
require "lib/neutrino/client"
|
2
2
|
require "test/unit"
|
3
3
|
require 'mocha'
|
4
4
|
|
@@ -9,22 +9,43 @@ module Neutrino
|
|
9
9
|
Config.defaults!
|
10
10
|
end
|
11
11
|
|
12
|
+
def test_initialization_calls_query
|
13
|
+
ShellMetric.expects(:execute).with("somecmd").returns(100)
|
14
|
+
m = ShellMetric.new(:commands => {:myval => "somecmd"})
|
15
|
+
end
|
16
|
+
|
12
17
|
def test_execute_calculates_value
|
13
18
|
cmd = "ps aux | wc -l"
|
14
|
-
m = ShellMetric.new(:command => cmd)
|
15
19
|
ShellMetric.expects(:execute).with(cmd)
|
16
|
-
m.
|
20
|
+
m = ShellMetric.new(:commands => {:myval => cmd})
|
17
21
|
end
|
18
22
|
|
19
|
-
def
|
23
|
+
def test_creates_values_hash
|
24
|
+
ShellMetric.stubs(:execute).with("somecmd").returns(100)
|
25
|
+
ShellMetric.stubs(:execute).with("othercmd").returns(150)
|
26
|
+
m = ShellMetric.new(:commands => {:myval => "somecmd", :bval => "othercmd"})
|
27
|
+
assert_equal m.values[:myval], 100
|
28
|
+
assert_equal m.values[:bval], 150
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_reporter_logs_warnings_for_empty_output
|
32
|
+
cmd = "ps aux | wc -l"
|
33
|
+
Open3.stubs(:popen3).with(cmd).returns("")
|
34
|
+
Log.expects(:warn)
|
35
|
+
ShellMetric.execute(cmd)
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_reporter_logs_debugs
|
20
39
|
cmd = "ps aux | wc -l"
|
21
|
-
Open3.
|
40
|
+
Open3.stubs(:popen3).with(cmd).returns("100")
|
41
|
+
Log.expects(:debug)
|
22
42
|
ShellMetric.execute(cmd)
|
23
43
|
end
|
24
44
|
|
25
|
-
def
|
26
|
-
|
27
|
-
|
45
|
+
def test_executes_command
|
46
|
+
cmd = "ps aux | wc -l"
|
47
|
+
Open3.expects(:popen3).with(cmd).returns("100")
|
48
|
+
ShellMetric.execute(cmd)
|
28
49
|
end
|
29
50
|
end
|
30
51
|
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: neutrino_client
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 21
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 0
|
9
|
-
-
|
10
|
-
version: 0.0.
|
9
|
+
- 5
|
10
|
+
version: 0.0.5
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Nick Stielau
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-02-
|
18
|
+
date: 2011-02-25 00:00:00 -08:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|