tronprint 0.0.16 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +21 -7
- data/lib/tronprint/aggregator.rb +91 -11
- data/lib/tronprint/app.rb +13 -0
- data/lib/tronprint/rails/tronprint_helper.rb +33 -6
- data/lib/tronprint/rails.rb +9 -1
- data/lib/tronprint/rake_tasks/active_record.rb +1 -3
- data/lib/tronprint/statistics.rb +49 -0
- data/lib/tronprint/statistics_formatter.rb +11 -0
- data/lib/tronprint/traffic_monitor.rb +29 -0
- data/lib/tronprint/version.rb +1 -1
- data/lib/tronprint.rb +10 -12
- data/spec/tronprint/aggregator_spec.rb +86 -2
- data/spec/tronprint/application_spec.rb +3 -4
- data/spec/tronprint/cpu_monitor_spec.rb +7 -7
- data/spec/tronprint/rails/tronprint_helper_spec.rb +2 -2
- data/spec/tronprint/statistics_formatter_spec.rb +28 -0
- data/spec/tronprint/statistics_spec.rb +45 -0
- data/spec/tronprint/traffic_monitor_spec.rb +38 -0
- data/spec/tronprint_spec.rb +12 -34
- data/tronprint.gemspec +6 -3
- metadata +119 -113
- data/spec/tronprint/computer_spec.rb +0 -9
data/README.rdoc
CHANGED
@@ -43,6 +43,20 @@ In order to display your application's footprint, you can use Tronprint's
|
|
43
43
|
built-in view helper: TronprintHelper. Feel free to cache your footprint
|
44
44
|
to minimize the number of API requests made to CM1.
|
45
45
|
|
46
|
+
In whichever controller(s) that will use TronprintHelper (or in `ApplicationController`), simply require the helper:
|
47
|
+
|
48
|
+
class FoosController
|
49
|
+
helper TronprintHelper
|
50
|
+
end
|
51
|
+
|
52
|
+
==== Helper Methods
|
53
|
+
|
54
|
+
TronprintHelper comes with a few helper methods:
|
55
|
+
|
56
|
+
* footprint_badge - A badge that displays total footprint and current rate of emissions for your app.
|
57
|
+
* cm1_badge - Displays a CM1 badge
|
58
|
+
* footprint_methodology - A URL for a live methodology statement reporting how your total footprint was calculated. {Example}[http://carbon.brighterplanet.com/computations?duration=128372]
|
59
|
+
|
46
60
|
==== Heroku
|
47
61
|
|
48
62
|
Tronprint is available as a Heroku add-on. Add tronprint to your app, and
|
@@ -72,14 +86,14 @@ config/initializers/tronprint.rb:
|
|
72
86
|
|
73
87
|
Tronprint.aggregator_options = { :adapter => :active_record }
|
74
88
|
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
your Rakefile:
|
89
|
+
Tronprint automatically creates a storage table, `moneta_store` the next time your app
|
90
|
+
is run.
|
91
|
+
|
92
|
+
If you need to create the table manually, add to your Rakefile:
|
79
93
|
|
80
94
|
require 'tronprint/rake_tasks/active_record'
|
81
95
|
|
82
|
-
|
96
|
+
And run `rake tronprint:moneta`
|
83
97
|
|
84
98
|
=== Other Ruby Apps
|
85
99
|
|
@@ -89,7 +103,7 @@ When your application has started, all you have to do is make a call to
|
|
89
103
|
Tronprint.run. This starts up a thread that collects statistics at a
|
90
104
|
certain interval and stores the results in a key/value store.
|
91
105
|
|
92
|
-
To retrieve the footprint, make a call to Tronprint.emission_estimate. This
|
106
|
+
To retrieve the footprint, make a call to Tronprint.statistics.emission_estimate. This
|
93
107
|
returns an instance of {Carbon::EmissionEstimate}[http://rubydoc.info/gems/carbon/Carbon/EmissionEstimate].
|
94
108
|
It can be converted to a float for the amount in kilograms or other
|
95
109
|
methods, such as EmissionEstimate#methodology can provide a link to the
|
@@ -120,7 +134,7 @@ the options you would normally set in config/tronprint.yml.
|
|
120
134
|
== Examples
|
121
135
|
|
122
136
|
You can see an example Rails app using tronprint at http://github.com/brighterplanet/yaktrak.
|
123
|
-
Files of note: config/initializers/tronprint.rb
|
137
|
+
Files of note: `config/initializers/tronprint.rb`, `Gemfile`, `app/views/trackings/_form.html.rb`.
|
124
138
|
The live example is at http://yaktrak.org
|
125
139
|
|
126
140
|
== Note on Patches/Pull Requests
|
data/lib/tronprint/aggregator.rb
CHANGED
@@ -9,6 +9,8 @@ module Tronprint
|
|
9
9
|
# {moneta}[http://github.com/wycats/moneta] will work.
|
10
10
|
class Aggregator < Delegator
|
11
11
|
|
12
|
+
attr_accessor :adapter
|
13
|
+
|
12
14
|
# Initialize the Aggregator with the following options:
|
13
15
|
# +adapter+:: The underscore-ized name of the moneta class to use.
|
14
16
|
#
|
@@ -16,17 +18,17 @@ module Tronprint
|
|
16
18
|
# You'll have to read {moneda's source code}[https://github.com/wycats/moneta/tree/master/lib/moneta/adapters]
|
17
19
|
# for options needed by your desired adapter.
|
18
20
|
def initialize(options = {})
|
19
|
-
|
20
|
-
|
21
|
-
|
21
|
+
self.adapter = options.delete :adapter
|
22
|
+
self.adapter ||= 'pstore'
|
23
|
+
self.adapter = self.adapter.to_s.downcase
|
22
24
|
begin
|
23
|
-
require "moneta/#{
|
24
|
-
klass = Moneta.const_get adapter_constant
|
25
|
+
require "moneta/#{self.adapter}"
|
26
|
+
klass = Moneta.const_get adapter_constant
|
25
27
|
rescue LoadError # Bundler hack
|
26
|
-
require "moneta/adapters/#{
|
27
|
-
klass = Moneta::Adapters.const_get adapter_constant
|
28
|
+
require "moneta/adapters/#{self.adapter}"
|
29
|
+
klass = Moneta::Adapters.const_get adapter_constant
|
28
30
|
end
|
29
|
-
args =
|
31
|
+
args = self.adapter == 'memory' ? [] : [options]
|
30
32
|
instance = klass.new(*args)
|
31
33
|
__setobj__ instance # required in Ruby 1.8.7
|
32
34
|
super instance
|
@@ -40,19 +42,97 @@ module Tronprint
|
|
40
42
|
end
|
41
43
|
|
42
44
|
# The class name of the desired moneta adapter
|
43
|
-
def adapter_constant
|
44
|
-
case
|
45
|
+
def adapter_constant
|
46
|
+
case self.adapter
|
45
47
|
when 'pstore' then 'PStore'
|
46
48
|
when 'yaml' then 'YAML'
|
47
49
|
when 'mongodb' then 'MongoDB'
|
48
50
|
else
|
49
|
-
|
51
|
+
self.adapter.split('_').map(&:capitalize).join('')
|
50
52
|
end
|
51
53
|
end
|
52
54
|
|
53
55
|
# Increment the total statistic by the given +value+,
|
54
56
|
# specified by the given +key+.
|
55
57
|
def update(key, value)
|
58
|
+
update_total(key, value)
|
59
|
+
update_yearly(key, value)
|
60
|
+
update_monthly(key, value)
|
61
|
+
update_daily(key, value)
|
62
|
+
update_hourly(key, value)
|
63
|
+
end
|
64
|
+
|
65
|
+
def path(*args)
|
66
|
+
args.join('/')
|
67
|
+
end
|
68
|
+
|
69
|
+
def range_total(key, from, to)
|
70
|
+
raise "Invalid range" if from > to
|
71
|
+
total = 0
|
72
|
+
current = from
|
73
|
+
while current <= to
|
74
|
+
hourly_key = hourly_path(key, year(current), month(current), day(current), hour(current))
|
75
|
+
total += self[hourly_key].to_f
|
76
|
+
current = current + 3600
|
77
|
+
end
|
78
|
+
|
79
|
+
total
|
80
|
+
end
|
81
|
+
|
82
|
+
private
|
83
|
+
|
84
|
+
def year(time)
|
85
|
+
time.year.to_s
|
86
|
+
end
|
87
|
+
def current_year
|
88
|
+
year(Time.now)
|
89
|
+
end
|
90
|
+
def month(time)
|
91
|
+
sprintf('%02d', time.month)
|
92
|
+
end
|
93
|
+
def current_month
|
94
|
+
month(Time.now)
|
95
|
+
end
|
96
|
+
def day(time)
|
97
|
+
sprintf('%02d', time.day)
|
98
|
+
end
|
99
|
+
def current_day
|
100
|
+
day(Time.now)
|
101
|
+
end
|
102
|
+
def hour(time)
|
103
|
+
sprintf('%02d', time.hour)
|
104
|
+
end
|
105
|
+
def current_hour
|
106
|
+
hour(Time.now)
|
107
|
+
end
|
108
|
+
|
109
|
+
def update_total(key, value)
|
110
|
+
update_entry key, value
|
111
|
+
end
|
112
|
+
|
113
|
+
def update_yearly(key, value)
|
114
|
+
update_entry path(key, 'by_date', current_year), value
|
115
|
+
end
|
116
|
+
|
117
|
+
def update_monthly(key, value)
|
118
|
+
update_entry path(key, 'by_date', current_year, current_month), value
|
119
|
+
end
|
120
|
+
|
121
|
+
def update_daily(key, value)
|
122
|
+
update_entry path(key, 'by_date', current_year, current_month, current_day), value
|
123
|
+
end
|
124
|
+
|
125
|
+
def hourly_path(key, year, month, day, hour)
|
126
|
+
path(key, 'by_date', year, month, day, hour)
|
127
|
+
end
|
128
|
+
def update_hourly(key, value)
|
129
|
+
update_entry hourly_path(key, current_year, current_month,
|
130
|
+
current_day, current_hour),
|
131
|
+
value
|
132
|
+
update_entry path(key, 'hourly', current_hour), value
|
133
|
+
end
|
134
|
+
|
135
|
+
def update_entry(key, value)
|
56
136
|
old_value = self[key]
|
57
137
|
new_value = old_value ? old_value + value : value
|
58
138
|
self[key] = new_value
|
@@ -1,19 +1,42 @@
|
|
1
|
+
require 'tronprint/statistics_formatter'
|
2
|
+
|
1
3
|
# Rails helper for displaying footprint data.
|
2
4
|
module TronprintHelper
|
5
|
+
include Tronprint::StatisticsFormatter
|
3
6
|
|
4
7
|
# The total amount of CO2e generated by the application.
|
5
8
|
def total_footprint
|
6
|
-
|
9
|
+
total_estimate.to_f
|
10
|
+
end
|
11
|
+
|
12
|
+
# The total amount of electricity used by the application.
|
13
|
+
def total_electricity
|
14
|
+
total_estimate.electricity_use.to_f
|
7
15
|
end
|
16
|
+
|
8
17
|
# A URL for the methodology statement of the emissions calculation.
|
9
18
|
def footprint_methodology
|
10
|
-
|
19
|
+
Tronprint.statistics.total_footprint_methodology
|
11
20
|
end
|
12
21
|
|
13
|
-
#
|
14
|
-
|
15
|
-
|
16
|
-
|
22
|
+
# An informational badge displaying total energy, footprint, CO2/minute
|
23
|
+
def footprint_badge
|
24
|
+
footprint = pounds_with_precision total_estimate
|
25
|
+
|
26
|
+
two_hr_emissions = Tronprint.statistics.
|
27
|
+
emission_estimate(Time.now - 7200, Time.now).to_f
|
28
|
+
rate = two_hr_emissions / 120 # kgs CO2 per minute over last 2 hours
|
29
|
+
rate = rate < 0.0001 ? "< 0.0001" : pounds_with_precision(rate)
|
30
|
+
|
31
|
+
text = <<-HTML
|
32
|
+
<p class="cm1-footprint">
|
33
|
+
<span class="cm1-total-footprint">Total footprint: #{total_electricity.to_i}W, #{footprint}lbs CO<sub>2</sub>e</span>
|
34
|
+
|
|
35
|
+
<span class="cm1-current-footprint">Current footprint: #{rate}lbs CO<sub>2</sub>e/min</span>
|
36
|
+
</p>
|
37
|
+
HTML
|
38
|
+
|
39
|
+
text.html_safe
|
17
40
|
end
|
18
41
|
|
19
42
|
# Let the world know that your app is powered by CM1
|
@@ -21,4 +44,8 @@ module TronprintHelper
|
|
21
44
|
%q{<script type="text/javascript" src="http://carbon.brighterplanet.com/badge.js"></script>}.
|
22
45
|
html_safe
|
23
46
|
end
|
47
|
+
|
48
|
+
def total_estimate
|
49
|
+
@total_estimate ||= Tronprint.statistics.emission_estimate
|
50
|
+
end
|
24
51
|
end
|
data/lib/tronprint/rails.rb
CHANGED
@@ -1,12 +1,20 @@
|
|
1
1
|
require 'rails'
|
2
2
|
require 'tronprint/rails/tronprint_helper'
|
3
|
+
require 'tronprint/app'
|
3
4
|
|
4
5
|
module Tronprint
|
5
6
|
|
6
7
|
# Rails plugin class.
|
7
8
|
class Railtie < Rails::Railtie
|
9
|
+
initializer 'tronprint.configure' do |app|
|
10
|
+
app.config.middleware.use Tronprint::App
|
11
|
+
end
|
12
|
+
|
8
13
|
config.after_initialize do
|
9
|
-
Tronprint.
|
14
|
+
if Tronprint.aggregator.adapter == 'active_record' && !Moneta::Adapters::ActiveRecord::Store.table_exists?
|
15
|
+
Tronprint.aggregator.migrate
|
16
|
+
end
|
17
|
+
Tronprint.run
|
10
18
|
end
|
11
19
|
|
12
20
|
generators do
|
@@ -1,5 +1,5 @@
|
|
1
1
|
namespace :tronprint do
|
2
|
-
desc '
|
2
|
+
desc 'Manually set up ActiveRecord datastore for Tronprint'
|
3
3
|
task :moneta => :environment do
|
4
4
|
adapter_options = Tronprint.aggregator_options
|
5
5
|
ar = Moneta::Adapters::ActiveRecord.new
|
@@ -7,5 +7,3 @@ namespace :tronprint do
|
|
7
7
|
puts 'Ensured that Moneta::Adapters::ActiveRecord::Store exists'
|
8
8
|
end
|
9
9
|
end
|
10
|
-
|
11
|
-
task 'db:migrate' => 'tronprint:moneta'
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module Tronprint
|
2
|
+
# The Statistics class is your gateway to fetching statistics about
|
3
|
+
# the energy usage and footprint of your app.
|
4
|
+
class Statistics
|
5
|
+
|
6
|
+
attr_accessor :aggregator, :cpu_monitor
|
7
|
+
|
8
|
+
def initialize(aggregator, cpu_monitor)
|
9
|
+
self.aggregator = aggregator
|
10
|
+
self.cpu_monitor = cpu_monitor
|
11
|
+
end
|
12
|
+
|
13
|
+
# Fetch the total amount of CPU time (in hours) used by the application.
|
14
|
+
def total_duration
|
15
|
+
aggregator[cpu_monitor.key] / 3600
|
16
|
+
end
|
17
|
+
|
18
|
+
# Fetch total CPU time for a given range
|
19
|
+
def range_duration(from, to)
|
20
|
+
aggregator.range_total cpu_monitor.key, from, to
|
21
|
+
end
|
22
|
+
|
23
|
+
# Calculate emissions using aggregated data. A call is made to
|
24
|
+
# Brighter Planet's CM1 emission estimate service. Specifically,
|
25
|
+
# the call is made to the {computation emitter}[http://carbon.brighterplanet.com/models/computation]
|
26
|
+
def emission_estimate(from = nil, to = nil)
|
27
|
+
duration = from.nil? ? total_duration : range_duration(from, to)
|
28
|
+
|
29
|
+
app = Application.new :zip_code => Tronprint.zip_code, :duration => duration,
|
30
|
+
:brighter_planet_key => Tronprint.brighter_planet_key
|
31
|
+
app.emission_estimate
|
32
|
+
end
|
33
|
+
|
34
|
+
# The total amount of CO2e generated by the application.
|
35
|
+
def total_footprint
|
36
|
+
emission_estimate.to_f
|
37
|
+
end
|
38
|
+
|
39
|
+
# The total amount of electricity used by the application.
|
40
|
+
def total_electricity
|
41
|
+
emission_estimate.electricity_use.to_f
|
42
|
+
end
|
43
|
+
|
44
|
+
# A URL for the methodology statement of the total_footprint calculation.
|
45
|
+
def total_footprint_methodology
|
46
|
+
emission_estimate.methodology
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Tronprint
|
2
|
+
|
3
|
+
# Tronprint::CPUMonitor is a thread that monitors aggregate CPU usage.
|
4
|
+
class TrafficMonitor
|
5
|
+
attr_accessor :aggregator, :application_name
|
6
|
+
|
7
|
+
# Parameters:
|
8
|
+
# +aggregator+:: A Tronprint::Aggregator instance.
|
9
|
+
# +application_name+:: A unique application name.
|
10
|
+
def initialize(aggregator, application_name)
|
11
|
+
self.aggregator = aggregator
|
12
|
+
self.application_name = application_name
|
13
|
+
end
|
14
|
+
|
15
|
+
# The key used to store number of requests in the Aggregator.
|
16
|
+
def key
|
17
|
+
[application_name, 'requests'].join('/')
|
18
|
+
end
|
19
|
+
|
20
|
+
# Increment the total number of requests
|
21
|
+
def increment
|
22
|
+
aggregator.update key, 1
|
23
|
+
end
|
24
|
+
|
25
|
+
def requests
|
26
|
+
aggregator[key] || 0
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
data/lib/tronprint/version.rb
CHANGED
data/lib/tronprint.rb
CHANGED
@@ -2,6 +2,8 @@ require 'yaml'
|
|
2
2
|
require 'tronprint/aggregator'
|
3
3
|
require 'tronprint/application'
|
4
4
|
require 'tronprint/cpu_monitor'
|
5
|
+
require 'tronprint/traffic_monitor'
|
6
|
+
require 'tronprint/statistics'
|
5
7
|
|
6
8
|
if defined?(Rails)
|
7
9
|
require 'tronprint/rails'
|
@@ -72,9 +74,14 @@ module Tronprint
|
|
72
74
|
@cpu_monitor ||= CPUMonitor.new aggregator, application_name
|
73
75
|
end
|
74
76
|
|
75
|
-
#
|
76
|
-
def
|
77
|
-
|
77
|
+
# The Tronprint::TrafficMonitor instance
|
78
|
+
def traffic_monitor
|
79
|
+
@traffic_monitor ||= TrafficMonitor.new aggregator, application_name
|
80
|
+
end
|
81
|
+
|
82
|
+
# The Tronprint::Statistics interface
|
83
|
+
def statistics
|
84
|
+
@statistics ||= Statistics.new aggregator, cpu_monitor
|
78
85
|
end
|
79
86
|
|
80
87
|
# The current configuration.
|
@@ -117,13 +124,4 @@ module Tronprint
|
|
117
124
|
}
|
118
125
|
@default_config
|
119
126
|
end
|
120
|
-
|
121
|
-
# Calculate emissions using aggregated data. A call is made to
|
122
|
-
# Brighter Planet's CM1 emission estimate service. Specifically,
|
123
|
-
# the call is made to the {computation emitter}[http://carbon.brighterplanet.com/models/computation]
|
124
|
-
def emission_estimate
|
125
|
-
app = Application.new :zip_code => zip_code, :duration => total_duration,
|
126
|
-
:brighter_planet_key => brighter_planet_key
|
127
|
-
app.emission_estimate
|
128
|
-
end
|
129
127
|
end
|
@@ -1,18 +1,102 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
require 'sandbox'
|
3
|
+
require 'time'
|
4
|
+
require 'timecop'
|
3
5
|
|
4
6
|
describe Tronprint::Aggregator do
|
5
7
|
let(:aggregator) { Tronprint::Aggregator.new :adapter => :memory }
|
6
8
|
|
7
9
|
describe '#update' do
|
8
|
-
|
10
|
+
let(:now) { Time.parse('2011-06-02 13:45:12') }
|
11
|
+
before do
|
12
|
+
Timecop.freeze now
|
13
|
+
end
|
14
|
+
after do
|
15
|
+
Timecop.return
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'writes statistics to an uninitailzed key' do
|
9
19
|
aggregator.update('foo/bar', 22.1)
|
10
20
|
aggregator['foo/bar'].should == 22.1
|
11
21
|
end
|
12
|
-
it '
|
22
|
+
it 'cumulatively updates statistics' do
|
13
23
|
aggregator.update('foo/bar', 22.1)
|
14
24
|
aggregator.update('foo/bar', 44.2)
|
15
25
|
aggregator['foo/bar'].should be_within(0.01).of(66.3)
|
26
|
+
aggregator['foo/bar/by_date/2011'].should be_within(0.01).of(66.3)
|
27
|
+
aggregator['foo/bar/by_date/2011/06'].should be_within(0.01).of(66.3)
|
28
|
+
aggregator['foo/bar/by_date/2011/06/02'].should be_within(0.01).of(66.3)
|
29
|
+
aggregator['foo/bar/by_date/2011/06/02/13'].should be_within(0.01).of(66.3)
|
30
|
+
aggregator['foo/bar/hourly/13'].should be_within(0.01).of(66.3)
|
31
|
+
end
|
32
|
+
it 'stores by_date statistics in separate entries for each day, month, and year' do
|
33
|
+
aggregator.update('foo/bar', 22.1)
|
34
|
+
aggregator.update('foo/bar', 23.1)
|
35
|
+
aggregator['foo/bar/by_date/2011'].should be_within(0.01).of(45.2)
|
36
|
+
aggregator['foo/bar/by_date/2011/06'].should be_within(0.01).of(45.2)
|
37
|
+
aggregator['foo/bar/by_date/2011/06/02'].should be_within(0.01).of(45.2)
|
38
|
+
aggregator['foo/bar/by_date/2011/06/02/13'].should be_within(0.01).of(45.2)
|
39
|
+
aggregator['foo/bar/hourly/13'].should be_within(0.01).of(45.2)
|
40
|
+
|
41
|
+
Timecop.freeze Time.parse('2011-06-03 11:45:12')
|
42
|
+
aggregator.update('foo/bar', 33.1)
|
43
|
+
aggregator['foo/bar/by_date/2011'].should be_within(0.01).of(78.3)
|
44
|
+
aggregator['foo/bar/by_date/2011/06'].should be_within(0.01).of(78.3)
|
45
|
+
aggregator['foo/bar/by_date/2011/06/03'].should be_within(0.01).of(33.1)
|
46
|
+
aggregator['foo/bar/by_date/2011/06/03/11'].should be_within(0.01).of(33.1)
|
47
|
+
aggregator['foo/bar/hourly/11'].should be_within(0.01).of(33.1)
|
48
|
+
|
49
|
+
Timecop.freeze Time.parse('2011-05-03 11:45:12')
|
50
|
+
aggregator.update('foo/bar', 44.1)
|
51
|
+
aggregator['foo/bar/by_date/2011'].should be_within(0.01).of(122.4)
|
52
|
+
aggregator['foo/bar/by_date/2011/05'].should be_within(0.01).of(44.1)
|
53
|
+
aggregator['foo/bar/by_date/2011/06'].should be_within(0.01).of(78.3)
|
54
|
+
aggregator['foo/bar/by_date/2011/05/03'].should be_within(0.01).of(44.1)
|
55
|
+
aggregator['foo/bar/by_date/2011/05/03/11'].should be_within(0.01).of(44.1)
|
56
|
+
aggregator['foo/bar/hourly/11'].should be_within(0.01).of(77.2)
|
57
|
+
|
58
|
+
Timecop.freeze Time.parse('2012-05-03 00:45:12')
|
59
|
+
aggregator.update('foo/bar', 55.1)
|
60
|
+
aggregator['foo/bar/by_date/2012'].should be_within(0.01).of(55.1)
|
61
|
+
aggregator['foo/bar/by_date/2012/05'].should be_within(0.01).of(55.1)
|
62
|
+
aggregator['foo/bar/by_date/2012/05/03'].should be_within(0.01).of(55.1)
|
63
|
+
aggregator['foo/bar/by_date/2012/05/03/00'].should be_within(0.01).of(55.1)
|
64
|
+
aggregator['foo/bar/hourly/00'].should be_within(0.01).of(55.1)
|
65
|
+
|
66
|
+
Timecop.freeze Time.parse('2012-05-03 00:57:02')
|
67
|
+
aggregator.update('foo/bar', 55.1)
|
68
|
+
aggregator['foo/bar/by_date/2012'].should be_within(0.01).of(110.2)
|
69
|
+
aggregator['foo/bar/by_date/2012/05'].should be_within(0.01).of(110.2)
|
70
|
+
aggregator['foo/bar/by_date/2012/05/03'].should be_within(0.01).of(110.2)
|
71
|
+
aggregator['foo/bar/by_date/2012/05/03/00'].should be_within(0.01).of(110.2)
|
72
|
+
aggregator['foo/bar/hourly/00'].should be_within(0.01).of(110.2)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
describe '#range_total' do
|
77
|
+
before :each do
|
78
|
+
[
|
79
|
+
'2011-06-02 13:01:00','2011-06-02 14:01:00','2011-06-02 15:01:00',
|
80
|
+
'2011-06-02 16:01:00','2011-06-02 18:01:00','2011-06-02 19:01:00',
|
81
|
+
'2011-06-02 19:01:00','2011-06-02 20:01:00','2011-06-02 21:01:00',
|
82
|
+
].each do |time|
|
83
|
+
Timecop.freeze Time.parse(time)
|
84
|
+
aggregator.update('foozle', 1)
|
85
|
+
end
|
86
|
+
Timecop.return
|
87
|
+
end
|
88
|
+
|
89
|
+
it 'returns a total for a given range' do
|
90
|
+
result = aggregator.range_total('foozle', Time.parse('2011-06-02 18:01:00'), Time.parse('2011-06-02 20:01:00'))
|
91
|
+
result.should == 4
|
92
|
+
end
|
93
|
+
it 'counts missing hours as 0' do
|
94
|
+
result = aggregator.range_total('foozle', Time.parse('2011-06-02 01:01:00'), Time.parse('2011-06-02 04:01:00'))
|
95
|
+
result.should == 0
|
96
|
+
end
|
97
|
+
it 'counts missing hours as 0 when a range has partial data' do
|
98
|
+
result = aggregator.range_total('foozle', Time.parse('2011-06-02 16:01:00'), Time.parse('2011-06-02 18:01:00'))
|
99
|
+
result.should == 2
|
16
100
|
end
|
17
101
|
end
|
18
102
|
end
|
@@ -1,10 +1,9 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe Tronprint::Application do
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
4
|
+
it 'reports emission esimates for application-related activity' do
|
5
|
+
app = Tronprint::Application.new :duration => 72831, :zip_code => 48915
|
6
|
+
app.should respond_to(:emission_estimate)
|
8
7
|
end
|
9
8
|
end
|
10
9
|
|
@@ -8,11 +8,11 @@ describe Tronprint::CPUMonitor do
|
|
8
8
|
before :each do
|
9
9
|
cpu_monitor.stub!(:elapsed_cpu_time).and_return 23.87
|
10
10
|
end
|
11
|
-
it '
|
11
|
+
it 'writes the elapsed time to the aggregate statistics' do
|
12
12
|
cpu_monitor.monitor
|
13
13
|
aggregator['my_app/application/cpu_time'].should == 23.87
|
14
14
|
end
|
15
|
-
it '
|
15
|
+
it 'increments the toal recorded cpu time' do
|
16
16
|
cpu_monitor.stub!(:elapsed_cpu_time).and_return 9.0
|
17
17
|
cpu_monitor.monitor
|
18
18
|
cpu_monitor.total_recorded_cpu_time.should == 9.0
|
@@ -23,12 +23,12 @@ describe Tronprint::CPUMonitor do
|
|
23
23
|
end
|
24
24
|
|
25
25
|
describe '#elapsed_cpu_time' do
|
26
|
-
it '
|
26
|
+
it 'returns the total CPU time on the first run' do
|
27
27
|
cpu_monitor.stub!(:total_recorded_cpu_time).and_return 0
|
28
28
|
cpu_monitor.stub!(:total_cpu_time).and_return 9.0
|
29
29
|
cpu_monitor.elapsed_cpu_time.should == 9.0
|
30
30
|
end
|
31
|
-
it '
|
31
|
+
it 'returns the amount of CPU time used since the last check' do
|
32
32
|
cpu_monitor.stub!(:total_recorded_cpu_time).and_return 23.0
|
33
33
|
cpu_monitor.stub!(:total_cpu_time).and_return 36.0
|
34
34
|
cpu_monitor.elapsed_cpu_time.should == 13.0
|
@@ -36,17 +36,17 @@ describe Tronprint::CPUMonitor do
|
|
36
36
|
end
|
37
37
|
|
38
38
|
describe '#total_cpu_time' do
|
39
|
-
it '
|
39
|
+
it 'returns the total user and system time of the process' do
|
40
40
|
Process.stub!(:times).and_return [10.1, 12.3]
|
41
41
|
cpu_monitor.total_cpu_time.should == 22.4
|
42
42
|
end
|
43
43
|
end
|
44
44
|
|
45
45
|
describe '#total_recorded_cpu_time' do
|
46
|
-
it '
|
46
|
+
it 'returns 0 by default' do
|
47
47
|
cpu_monitor.total_recorded_cpu_time.should == 0
|
48
48
|
end
|
49
|
-
it '
|
49
|
+
it 'returns total recorded time' do
|
50
50
|
cpu_monitor.total_recorded_cpu_time = 3
|
51
51
|
cpu_monitor.total_recorded_cpu_time.should == 3
|
52
52
|
end
|
@@ -9,8 +9,8 @@ describe TronprintHelper do
|
|
9
9
|
end
|
10
10
|
|
11
11
|
describe '#total_footprint' do
|
12
|
-
it '
|
13
|
-
|
12
|
+
it 'returns the total footprint' do
|
13
|
+
Tronprint.statistics.stub!(:emission_estimate).and_return mock(Object, :to_f => 89.4)
|
14
14
|
helper.total_footprint.should == 89.4
|
15
15
|
end
|
16
16
|
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'tronprint/statistics_formatter'
|
3
|
+
require 'action_view'
|
4
|
+
|
5
|
+
class StatisticsFormatterHarness
|
6
|
+
include ActionView::Helpers
|
7
|
+
include Tronprint::StatisticsFormatter
|
8
|
+
end
|
9
|
+
|
10
|
+
describe Tronprint::StatisticsFormatter do
|
11
|
+
let(:formatter) { StatisticsFormatterHarness.new }
|
12
|
+
|
13
|
+
describe '#pounds_with_precision' do
|
14
|
+
it 'converts kilograms to pounds' do
|
15
|
+
formatter.pounds_with_precision(1).should == '2.2046'
|
16
|
+
end
|
17
|
+
it 'uses a precision of 4 if the number is less than 100' do
|
18
|
+
formatter.pounds_with_precision(8).should == '17.6368'
|
19
|
+
end
|
20
|
+
it 'uses a precision of 4 if the number is 0' do
|
21
|
+
formatter.pounds_with_precision(0).should == '0.0000'
|
22
|
+
end
|
23
|
+
it 'uses a precision of 0 if the number is at least 100' do
|
24
|
+
formatter.pounds_with_precision(60).should == '132.2760'
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Tronprint::Statistics do
|
4
|
+
let(:aggregator) { Tronprint::Aggregator.new :adapter => :memory }
|
5
|
+
let(:cpu_monitor) { mock Tronprint::CPUMonitor, :total_recorded_cpu_time => 27.2,
|
6
|
+
:key => 'myapp' }
|
7
|
+
let(:statistics) { Tronprint::Statistics.new aggregator, cpu_monitor }
|
8
|
+
|
9
|
+
before do
|
10
|
+
Tronprint.zip_code = 48915
|
11
|
+
Tronprint.brighter_planet_key = 'ABC123'
|
12
|
+
Tronprint.application_name = 'groove'
|
13
|
+
end
|
14
|
+
|
15
|
+
after do
|
16
|
+
aggregator.clear
|
17
|
+
end
|
18
|
+
|
19
|
+
describe '#emission_estimate' do
|
20
|
+
it 'sends uses total duration if no range is given' do
|
21
|
+
statistics.stub!(:total_duration).and_return 28.7
|
22
|
+
Tronprint::Application.should_receive(:new).
|
23
|
+
with(:zip_code => 48915, :duration => 28.7, :brighter_planet_key => 'ABC123').
|
24
|
+
and_return mock(Object, :emission_estimate => nil)
|
25
|
+
statistics.emission_estimate
|
26
|
+
end
|
27
|
+
it 'sends a duration range if given' do
|
28
|
+
statistics.stub!(:range_duration).and_return 18.7
|
29
|
+
Tronprint::Application.should_receive(:new).
|
30
|
+
with(:zip_code => 48915, :duration => 18.7, :brighter_planet_key => 'ABC123').
|
31
|
+
and_return mock(Object, :emission_estimate => nil)
|
32
|
+
statistics.emission_estimate(Time.now - 7200, Time.now)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
describe '#total_duration' do
|
37
|
+
it 'looks up the total for the application and return number of hours' do
|
38
|
+
mock_cpu = mock Tronprint::CPUMonitor, :key => 'groove/application/cpu_time'
|
39
|
+
statistics.instance_variable_set :@cpu_monitor, mock_cpu
|
40
|
+
statistics.aggregator.update 'groove/application/cpu_time', 5.0
|
41
|
+
statistics.total_duration.should be_within(0.00001).of(0.00138)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'timecop'
|
3
|
+
|
4
|
+
describe Tronprint::TrafficMonitor do
|
5
|
+
let(:aggregator) { Tronprint::Aggregator.new :adapter => :memory }
|
6
|
+
let(:traffic_monitor) { Tronprint::TrafficMonitor.new aggregator, 'my_app' }
|
7
|
+
|
8
|
+
describe '#increment' do
|
9
|
+
it 'increments the user count for each time slice' do
|
10
|
+
Timecop.freeze Time.parse('2011-06-02 13:23:01')
|
11
|
+
2.times { traffic_monitor.increment }
|
12
|
+
aggregator['my_app/requests'].should == 2
|
13
|
+
aggregator['my_app/requests/by_date/2011'].should == 2
|
14
|
+
aggregator['my_app/requests/by_date/2011/06'].should == 2
|
15
|
+
aggregator['my_app/requests/by_date/2011/06/02'].should == 2
|
16
|
+
aggregator['my_app/requests/by_date/2011/06/02/13'].should == 2
|
17
|
+
aggregator['my_app/requests/hourly/13'].should == 2
|
18
|
+
Timecop.return
|
19
|
+
end
|
20
|
+
it 'increments the toal recorded requests' do
|
21
|
+
traffic_monitor.increment
|
22
|
+
traffic_monitor.requests.should == 1
|
23
|
+
traffic_monitor.increment
|
24
|
+
traffic_monitor.requests.should == 2
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
describe '#requests' do
|
29
|
+
it 'returns 0 on the first run' do
|
30
|
+
traffic_monitor.requests.should == 0
|
31
|
+
end
|
32
|
+
it 'returns the total number of requests' do
|
33
|
+
aggregator['my_app/requests'] = 13
|
34
|
+
traffic_monitor.requests.should == 13
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
data/spec/tronprint_spec.rb
CHANGED
@@ -8,39 +8,27 @@ describe Tronprint do
|
|
8
8
|
end
|
9
9
|
|
10
10
|
describe '.run' do
|
11
|
-
it '
|
11
|
+
it 'starts up each monitor' do
|
12
12
|
Tronprint.should_receive :cpu_monitor
|
13
13
|
Tronprint.run
|
14
14
|
end
|
15
15
|
end
|
16
16
|
|
17
17
|
describe '.cpu_monitor' do
|
18
|
-
it '
|
18
|
+
it 'starts the CPU monitor' do
|
19
|
+
Tronprint.instance_variable_set :@cpu_monitor, nil
|
19
20
|
Tronprint::CPUMonitor.should_receive(:new).and_return mock_cpu
|
20
21
|
Tronprint.cpu_monitor
|
21
22
|
end
|
22
|
-
it '
|
23
|
+
it 'returns the CPU monitor instance' do
|
23
24
|
Tronprint.instance_variable_set :@cpu_monitor, nil
|
24
25
|
Tronprint::CPUMonitor.stub!(:new).and_return mock_cpu
|
25
26
|
Tronprint.cpu_monitor.should == mock_cpu
|
26
27
|
end
|
27
28
|
end
|
28
29
|
|
29
|
-
describe '.emission_estimate' do
|
30
|
-
it 'should send the zip code and total duration to the application' do
|
31
|
-
Tronprint.instance_variable_set(:@emission_estimate, nil)
|
32
|
-
Tronprint.zip_code = 48915
|
33
|
-
Tronprint.brighter_planet_key = 'ABC123'
|
34
|
-
Tronprint.stub!(:total_duration).and_return 28.7
|
35
|
-
Tronprint::Application.should_receive(:new).
|
36
|
-
with(:zip_code => 48915, :duration => 28.7, :brighter_planet_key => 'ABC123').
|
37
|
-
and_return mock(Object, :emission_estimate => nil)
|
38
|
-
Tronprint.emission_estimate
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
30
|
describe '.brighter_planet_key' do
|
43
|
-
it '
|
31
|
+
it 'returns the brighter_planet_key config option' do
|
44
32
|
Tronprint.instance_variable_set :@brighter_planet_key, nil
|
45
33
|
Tronprint.stub!(:config).and_return({ :brighter_planet_key => 'aaa' })
|
46
34
|
Tronprint.brighter_planet_key.should == 'aaa'
|
@@ -48,11 +36,11 @@ describe Tronprint do
|
|
48
36
|
end
|
49
37
|
|
50
38
|
describe '.config' do
|
51
|
-
it '
|
39
|
+
it 'returns a configuration loaded from disk' do
|
52
40
|
Tronprint.stub!(:load_config).and_return :foo => :bar
|
53
41
|
Tronprint.config.should include(:foo => :bar)
|
54
42
|
end
|
55
|
-
it '
|
43
|
+
it 'returns a default configuration if no config file exists' do
|
56
44
|
Tronprint.stub!(:default_config).and_return :foo => :bar
|
57
45
|
Tronprint.config.should include(:foo => :bar)
|
58
46
|
end
|
@@ -62,14 +50,14 @@ describe Tronprint do
|
|
62
50
|
before :each do
|
63
51
|
Tronprint.instance_variable_set :@loaded_config, nil
|
64
52
|
end
|
65
|
-
it '
|
53
|
+
it 'loads a config file from cwd/config/tronprint.yml if it exists' do
|
66
54
|
Dir.stub!(:pwd).and_return '/some/dir'
|
67
55
|
File.stub!(:exist?).and_return true
|
68
56
|
YAML.should_receive(:load_file).with('/some/dir/config/tronprint.yml').
|
69
57
|
and_return :my => :config
|
70
58
|
Tronprint.load_config.should == { :my => :config }
|
71
59
|
end
|
72
|
-
it '
|
60
|
+
it 'returns nil if no config file exists' do
|
73
61
|
Tronprint.instance_variable_set :@loaded_config, nil
|
74
62
|
Dir.stub!(:pwd).and_return '/some/dir'
|
75
63
|
File.stub!(:exist?).and_return false
|
@@ -85,27 +73,17 @@ describe Tronprint do
|
|
85
73
|
ENV['TRONPRINT_API_KEY'] = nil
|
86
74
|
ENV['MONGOHQ_URL'] = nil
|
87
75
|
end
|
88
|
-
it '
|
76
|
+
it 'returns a default configuration' do
|
89
77
|
Tronprint.default_config.should be_an_instance_of(Hash)
|
90
78
|
end
|
91
|
-
it '
|
79
|
+
it 'sets the brighter_planet_key if ENV["TRONPRINT_API_KEY"] is set' do
|
92
80
|
ENV['TRONPRINT_API_KEY'] = 'abc123'
|
93
81
|
Tronprint.default_config[:brighter_planet_key].should == 'abc123'
|
94
82
|
end
|
95
|
-
it '
|
83
|
+
it 'uses MongoHQ if ENV["MONGOHQ_URL"] is set' do
|
96
84
|
ENV['MONGOHQ_URL'] = 'mongodb://foo.com/bar'
|
97
85
|
Tronprint.default_config[:aggregator_options][:adapter].should == :mongodb
|
98
86
|
Tronprint.default_config[:aggregator_options][:uri].should == 'mongodb://foo.com/bar'
|
99
87
|
end
|
100
88
|
end
|
101
|
-
|
102
|
-
describe '.total_duration' do
|
103
|
-
it 'should look up the total for the application and return number of hours' do
|
104
|
-
mock_cpu = mock Tronprint::CPUMonitor, :key => 'groove/application/cpu_time'
|
105
|
-
Tronprint.instance_variable_set :@cpu_monitor, mock_cpu
|
106
|
-
Tronprint.application_name = 'groove'
|
107
|
-
Tronprint.aggregator.update 'groove/application/cpu_time', 5.0
|
108
|
-
Tronprint.total_duration.should be_within(0.00001).of(0.00138)
|
109
|
-
end
|
110
|
-
end
|
111
89
|
end
|
data/tronprint.gemspec
CHANGED
@@ -7,7 +7,7 @@ Gem::Specification.new do |s|
|
|
7
7
|
s.version = Tronprint::VERSION
|
8
8
|
|
9
9
|
s.authors = ['Derek Kastner']
|
10
|
-
s.date = "2011-
|
10
|
+
s.date = "2011-06-15"
|
11
11
|
s.description = %q{A gem for monitoring the carbon footprint of your ruby app}
|
12
12
|
s.email = %q{dkastner@gmail.com}
|
13
13
|
s.homepage = %q{http://github.com/brighterplanet/tronprint}
|
@@ -30,13 +30,16 @@ Gem::Specification.new do |s|
|
|
30
30
|
s.rubygems_version = %q{1.3.7}
|
31
31
|
s.summary = %q{Ruby process carbon footprinter}
|
32
32
|
|
33
|
+
s.add_development_dependency 'actionpack', '~> 3'
|
34
|
+
s.add_development_dependency 'activesupport', '~> 3'
|
33
35
|
s.add_development_dependency 'cucumber'
|
34
36
|
s.add_development_dependency 'bueller', '~> 0.0.2'
|
35
37
|
s.add_development_dependency 'rake'
|
36
38
|
s.add_development_dependency 'rspec', '~> 2.0'
|
37
|
-
s.add_development_dependency
|
39
|
+
s.add_development_dependency 'sandbox'
|
40
|
+
s.add_development_dependency 'timecop'
|
38
41
|
s.add_runtime_dependency 'carbon', '~> 1.0.3'
|
39
42
|
s.add_runtime_dependency 'i18n'
|
40
|
-
s.add_runtime_dependency 'dkastner-moneta', '~> 1.0.
|
43
|
+
s.add_runtime_dependency 'dkastner-moneta', '~> 1.0.5'
|
41
44
|
end
|
42
45
|
|
metadata
CHANGED
@@ -1,150 +1,156 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: tronprint
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
|
5
|
-
|
6
|
-
- 0
|
7
|
-
- 0
|
8
|
-
- 16
|
9
|
-
version: 0.0.16
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
prerelease:
|
10
6
|
platform: ruby
|
11
|
-
authors:
|
7
|
+
authors:
|
12
8
|
- Derek Kastner
|
13
9
|
autorequire:
|
14
10
|
bindir: bin
|
15
11
|
cert_chain: []
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
12
|
+
date: 2011-06-15 00:00:00.000000000Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: actionpack
|
16
|
+
requirement: &2157410400 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '3'
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *2157410400
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: activesupport
|
27
|
+
requirement: &2157409500 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ~>
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '3'
|
33
|
+
type: :development
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *2157409500
|
36
|
+
- !ruby/object:Gem::Dependency
|
21
37
|
name: cucumber
|
22
|
-
requirement: &
|
38
|
+
requirement: &2157409100 !ruby/object:Gem::Requirement
|
23
39
|
none: false
|
24
|
-
requirements:
|
25
|
-
- -
|
26
|
-
- !ruby/object:Gem::Version
|
27
|
-
|
28
|
-
- 0
|
29
|
-
version: "0"
|
40
|
+
requirements:
|
41
|
+
- - ! '>='
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '0'
|
30
44
|
type: :development
|
31
45
|
prerelease: false
|
32
|
-
version_requirements: *
|
33
|
-
- !ruby/object:Gem::Dependency
|
46
|
+
version_requirements: *2157409100
|
47
|
+
- !ruby/object:Gem::Dependency
|
34
48
|
name: bueller
|
35
|
-
requirement: &
|
49
|
+
requirement: &2157408560 !ruby/object:Gem::Requirement
|
36
50
|
none: false
|
37
|
-
requirements:
|
51
|
+
requirements:
|
38
52
|
- - ~>
|
39
|
-
- !ruby/object:Gem::Version
|
40
|
-
segments:
|
41
|
-
- 0
|
42
|
-
- 0
|
43
|
-
- 2
|
53
|
+
- !ruby/object:Gem::Version
|
44
54
|
version: 0.0.2
|
45
55
|
type: :development
|
46
56
|
prerelease: false
|
47
|
-
version_requirements: *
|
48
|
-
- !ruby/object:Gem::Dependency
|
57
|
+
version_requirements: *2157408560
|
58
|
+
- !ruby/object:Gem::Dependency
|
49
59
|
name: rake
|
50
|
-
requirement: &
|
60
|
+
requirement: &2157408040 !ruby/object:Gem::Requirement
|
51
61
|
none: false
|
52
|
-
requirements:
|
53
|
-
- -
|
54
|
-
- !ruby/object:Gem::Version
|
55
|
-
|
56
|
-
- 0
|
57
|
-
version: "0"
|
62
|
+
requirements:
|
63
|
+
- - ! '>='
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: '0'
|
58
66
|
type: :development
|
59
67
|
prerelease: false
|
60
|
-
version_requirements: *
|
61
|
-
- !ruby/object:Gem::Dependency
|
68
|
+
version_requirements: *2157408040
|
69
|
+
- !ruby/object:Gem::Dependency
|
62
70
|
name: rspec
|
63
|
-
requirement: &
|
71
|
+
requirement: &2157407300 !ruby/object:Gem::Requirement
|
64
72
|
none: false
|
65
|
-
requirements:
|
73
|
+
requirements:
|
66
74
|
- - ~>
|
67
|
-
- !ruby/object:Gem::Version
|
68
|
-
|
69
|
-
- 2
|
70
|
-
- 0
|
71
|
-
version: "2.0"
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: '2.0'
|
72
77
|
type: :development
|
73
78
|
prerelease: false
|
74
|
-
version_requirements: *
|
75
|
-
- !ruby/object:Gem::Dependency
|
79
|
+
version_requirements: *2157407300
|
80
|
+
- !ruby/object:Gem::Dependency
|
76
81
|
name: sandbox
|
77
|
-
requirement: &
|
82
|
+
requirement: &2157406680 !ruby/object:Gem::Requirement
|
83
|
+
none: false
|
84
|
+
requirements:
|
85
|
+
- - ! '>='
|
86
|
+
- !ruby/object:Gem::Version
|
87
|
+
version: '0'
|
88
|
+
type: :development
|
89
|
+
prerelease: false
|
90
|
+
version_requirements: *2157406680
|
91
|
+
- !ruby/object:Gem::Dependency
|
92
|
+
name: timecop
|
93
|
+
requirement: &2157400260 !ruby/object:Gem::Requirement
|
78
94
|
none: false
|
79
|
-
requirements:
|
80
|
-
- -
|
81
|
-
- !ruby/object:Gem::Version
|
82
|
-
|
83
|
-
- 0
|
84
|
-
version: "0"
|
95
|
+
requirements:
|
96
|
+
- - ! '>='
|
97
|
+
- !ruby/object:Gem::Version
|
98
|
+
version: '0'
|
85
99
|
type: :development
|
86
100
|
prerelease: false
|
87
|
-
version_requirements: *
|
88
|
-
- !ruby/object:Gem::Dependency
|
101
|
+
version_requirements: *2157400260
|
102
|
+
- !ruby/object:Gem::Dependency
|
89
103
|
name: carbon
|
90
|
-
requirement: &
|
104
|
+
requirement: &2157399320 !ruby/object:Gem::Requirement
|
91
105
|
none: false
|
92
|
-
requirements:
|
106
|
+
requirements:
|
93
107
|
- - ~>
|
94
|
-
- !ruby/object:Gem::Version
|
95
|
-
segments:
|
96
|
-
- 1
|
97
|
-
- 0
|
98
|
-
- 3
|
108
|
+
- !ruby/object:Gem::Version
|
99
109
|
version: 1.0.3
|
100
110
|
type: :runtime
|
101
111
|
prerelease: false
|
102
|
-
version_requirements: *
|
103
|
-
- !ruby/object:Gem::Dependency
|
112
|
+
version_requirements: *2157399320
|
113
|
+
- !ruby/object:Gem::Dependency
|
104
114
|
name: i18n
|
105
|
-
requirement: &
|
115
|
+
requirement: &2157397400 !ruby/object:Gem::Requirement
|
106
116
|
none: false
|
107
|
-
requirements:
|
108
|
-
- -
|
109
|
-
- !ruby/object:Gem::Version
|
110
|
-
|
111
|
-
- 0
|
112
|
-
version: "0"
|
117
|
+
requirements:
|
118
|
+
- - ! '>='
|
119
|
+
- !ruby/object:Gem::Version
|
120
|
+
version: '0'
|
113
121
|
type: :runtime
|
114
122
|
prerelease: false
|
115
|
-
version_requirements: *
|
116
|
-
- !ruby/object:Gem::Dependency
|
123
|
+
version_requirements: *2157397400
|
124
|
+
- !ruby/object:Gem::Dependency
|
117
125
|
name: dkastner-moneta
|
118
|
-
requirement: &
|
126
|
+
requirement: &2157366380 !ruby/object:Gem::Requirement
|
119
127
|
none: false
|
120
|
-
requirements:
|
128
|
+
requirements:
|
121
129
|
- - ~>
|
122
|
-
- !ruby/object:Gem::Version
|
123
|
-
|
124
|
-
- 1
|
125
|
-
- 0
|
126
|
-
- 3
|
127
|
-
version: 1.0.3
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: 1.0.5
|
128
132
|
type: :runtime
|
129
133
|
prerelease: false
|
130
|
-
version_requirements: *
|
134
|
+
version_requirements: *2157366380
|
131
135
|
description: A gem for monitoring the carbon footprint of your ruby app
|
132
136
|
email: dkastner@gmail.com
|
133
137
|
executables: []
|
134
|
-
|
135
138
|
extensions: []
|
136
|
-
|
137
|
-
extra_rdoc_files:
|
139
|
+
extra_rdoc_files:
|
138
140
|
- LICENSE
|
139
141
|
- README.rdoc
|
140
|
-
files:
|
142
|
+
files:
|
141
143
|
- lib/tronprint/aggregator.rb
|
144
|
+
- lib/tronprint/app.rb
|
142
145
|
- lib/tronprint/application.rb
|
143
146
|
- lib/tronprint/cpu_monitor.rb
|
144
147
|
- lib/tronprint/rails/generator.rb
|
145
148
|
- lib/tronprint/rails/tronprint_helper.rb
|
146
149
|
- lib/tronprint/rails.rb
|
147
150
|
- lib/tronprint/rake_tasks/active_record.rb
|
151
|
+
- lib/tronprint/statistics.rb
|
152
|
+
- lib/tronprint/statistics_formatter.rb
|
153
|
+
- lib/tronprint/traffic_monitor.rb
|
148
154
|
- lib/tronprint/version.rb
|
149
155
|
- lib/tronprint.rb
|
150
156
|
- .document
|
@@ -159,55 +165,55 @@ files:
|
|
159
165
|
- spec/spec_helper.rb
|
160
166
|
- spec/tronprint/aggregator_spec.rb
|
161
167
|
- spec/tronprint/application_spec.rb
|
162
|
-
- spec/tronprint/computer_spec.rb
|
163
168
|
- spec/tronprint/cpu_monitor_spec.rb
|
164
169
|
- spec/tronprint/rails/tronprint_helper_spec.rb
|
170
|
+
- spec/tronprint/statistics_formatter_spec.rb
|
171
|
+
- spec/tronprint/statistics_spec.rb
|
172
|
+
- spec/tronprint/traffic_monitor_spec.rb
|
165
173
|
- spec/tronprint_spec.rb
|
166
174
|
- features/step_definitions/tronprint_steps.rb
|
167
175
|
- features/support/env.rb
|
168
176
|
- features/tronprint.feature
|
169
|
-
has_rdoc: true
|
170
177
|
homepage: http://github.com/brighterplanet/tronprint
|
171
178
|
licenses: []
|
172
|
-
|
173
179
|
post_install_message:
|
174
180
|
rdoc_options: []
|
175
|
-
|
176
|
-
require_paths:
|
181
|
+
require_paths:
|
177
182
|
- lib
|
178
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
183
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
179
184
|
none: false
|
180
|
-
requirements:
|
181
|
-
- -
|
182
|
-
- !ruby/object:Gem::Version
|
183
|
-
|
184
|
-
segments:
|
185
|
+
requirements:
|
186
|
+
- - ! '>='
|
187
|
+
- !ruby/object:Gem::Version
|
188
|
+
version: '0'
|
189
|
+
segments:
|
185
190
|
- 0
|
186
|
-
|
187
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
191
|
+
hash: -3534616707855240394
|
192
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
188
193
|
none: false
|
189
|
-
requirements:
|
190
|
-
- -
|
191
|
-
- !ruby/object:Gem::Version
|
192
|
-
|
193
|
-
segments:
|
194
|
+
requirements:
|
195
|
+
- - ! '>='
|
196
|
+
- !ruby/object:Gem::Version
|
197
|
+
version: '0'
|
198
|
+
segments:
|
194
199
|
- 0
|
195
|
-
|
200
|
+
hash: -3534616707855240394
|
196
201
|
requirements: []
|
197
|
-
|
198
202
|
rubyforge_project:
|
199
|
-
rubygems_version: 1.
|
203
|
+
rubygems_version: 1.8.5
|
200
204
|
signing_key:
|
201
205
|
specification_version: 3
|
202
206
|
summary: Ruby process carbon footprinter
|
203
|
-
test_files:
|
207
|
+
test_files:
|
204
208
|
- spec/spec.opts
|
205
209
|
- spec/spec_helper.rb
|
206
210
|
- spec/tronprint/aggregator_spec.rb
|
207
211
|
- spec/tronprint/application_spec.rb
|
208
|
-
- spec/tronprint/computer_spec.rb
|
209
212
|
- spec/tronprint/cpu_monitor_spec.rb
|
210
213
|
- spec/tronprint/rails/tronprint_helper_spec.rb
|
214
|
+
- spec/tronprint/statistics_formatter_spec.rb
|
215
|
+
- spec/tronprint/statistics_spec.rb
|
216
|
+
- spec/tronprint/traffic_monitor_spec.rb
|
211
217
|
- spec/tronprint_spec.rb
|
212
218
|
- features/step_definitions/tronprint_steps.rb
|
213
219
|
- features/support/env.rb
|
@@ -1,9 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe Tronprint::Application do
|
4
|
-
it 'should report emission esimates for application-related activity' do
|
5
|
-
app = Tronprint::Application.new :duration => 72831, :zip_code => 48915
|
6
|
-
app.should respond_to(:emission_estimate)
|
7
|
-
end
|
8
|
-
end
|
9
|
-
|