carbon 0.2.4 → 0.2.5
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +37 -6
- data/Rakefile +4 -1
- data/VERSION +1 -1
- data/carbon.gemspec +11 -2
- data/doc/INTEGRATION_GUIDE.rdoc +1002 -0
- data/doc/examining-response-with-jsonview.png +0 -0
- data/doc/timeout-error.png +0 -0
- data/doc/with-committee-reports.png +0 -0
- data/doc/without-committee-reports.png +0 -0
- data/lib/carbon.rb +5 -1
- data/lib/carbon/emission_estimate.rb +45 -15
- data/lib/carbon/emission_estimate/request.rb +5 -2
- data/lib/carbon/emission_estimate/response.rb +15 -10
- data/lib/carbon/emission_estimate/storage.rb +29 -0
- data/spec/lib/carbon_spec.rb +150 -3
- data/spec/spec_helper.rb +0 -22
- metadata +31 -10
data/README.rdoc
CHANGED
@@ -1,13 +1,15 @@
|
|
1
1
|
= Carbon
|
2
2
|
|
3
|
-
Carbon is a Ruby API wrapper for the {Brighter Planet emission estimate web service}[http://carbon.brighterplanet.com], which is located at http://carbon.brighterplanet.com.
|
4
|
-
|
5
|
-
By querying the web service, it can estimate the carbon emissions of many real-life objects, such as cars and houses, based on particular attributes that they may have.
|
3
|
+
Carbon is a Ruby API wrapper for the {Brighter Planet emission estimate web service}[http://carbon.brighterplanet.com], which is located at http://carbon.brighterplanet.com. By querying the web service, it can estimate the carbon emissions of many real-life objects, such as cars and houses, based on particular attributes that they may have.
|
6
4
|
|
7
5
|
== Full documentation
|
8
6
|
|
9
7
|
Give the quick start a try! Once you've exhausted that, read the {carbon gem RDoc}[http://rdoc.info/projects/brighterplanet/carbon] for more.
|
10
8
|
|
9
|
+
== Real-life integration guide
|
10
|
+
|
11
|
+
In addition to the quick start and full documentation, check out the {integration guide}[http://github.com/brighterplanet/carbon/blob/master/doc/INTEGRATION_GUIDE.rdoc]. It has code examples from our real-life migration followed by brief developer commentary.
|
12
|
+
|
11
13
|
== Quick start
|
12
14
|
|
13
15
|
<b>You'll need a Brighter Planet API key. See the "API keys" section below for details.</b>
|
@@ -65,7 +67,7 @@ You should get an API key from http://keys.brighterplanet.com and set it globall
|
|
65
67
|
|
66
68
|
Now all of your queries will use that key.
|
67
69
|
|
68
|
-
== A note on <tt>#to_param</tt>
|
70
|
+
== A note on <tt>#to_characteristic</tt> and <tt>#to_param</tt>
|
69
71
|
|
70
72
|
Once you understand how to map attributes using the DSL, you might still be confused about what the gem actually calls on your objects.
|
71
73
|
|
@@ -75,12 +77,41 @@ Let's say <tt>RentalCar#make</tt> returns a <tt>Make</tt> object. You should def
|
|
75
77
|
|
76
78
|
== A note on asynchronous queries
|
77
79
|
|
78
|
-
To
|
80
|
+
To specify that the result of a query should be POSTed back to you, simply pass an URL as the <tt>:callback</tt> option to <tt>#emission_estimate</tt>:
|
79
81
|
|
80
|
-
> RentalCar.new.emission_estimate :callback => http://example.com/my/callback/handler
|
82
|
+
> RentalCar.new.emission_estimate :callback => 'http://example.com/my/callback/handler'
|
81
83
|
|
82
84
|
A good way to test this is to set up a {PostBin}[http://postbin.org].
|
83
85
|
|
86
|
+
You can specify that the result be stored on S3 so that future identical requests can use the same estimate:
|
87
|
+
|
88
|
+
> RentalCar.new.emission_estimate :guid => 'A_GLOBALLY_UNIQUE_IDENTIFIER_FOR_THIS_EMISSION_ESTIMATE'
|
89
|
+
|
90
|
+
You might think of <tt>:guid</tt> as a hash key or a cache key, but it is not necessarily unique to the emitter object... rather it should identify the particular set of characteristics on that emitter. That way other emitters, if they have the same characteristics, can use the same estimate.
|
91
|
+
|
92
|
+
If you combine <tt>:guid</tt> and <tt>:defer => true</tt>, you have an easy, cheap 2-pass reporting system:
|
93
|
+
|
94
|
+
# pass 1: cron job runs a whole bunch of these
|
95
|
+
> car51.emission_estimate :guid => '[...]', :defer => true
|
96
|
+
> car52.emission_estimate :guid => '[...]', :defer => true
|
97
|
+
> car96.emission_estimate :guid => '[...]', :defer => true
|
98
|
+
|
99
|
+
# pass 2: a while later, cron job runs these
|
100
|
+
> car51.emission_estimate :guid => '[...]'
|
101
|
+
> car52.emission_estimate :guid => '[...]'
|
102
|
+
> car96.emission_estimate :guid => '[...]'
|
103
|
+
|
104
|
+
Most of these will be pre-calculated by the time you run pass #2. If any of them aren't done processing yet, it will revert to a real-time estimate... no big deal!
|
105
|
+
|
106
|
+
== Possible combinations
|
107
|
+
|
108
|
+
* () Runs a normal realtime request.
|
109
|
+
* (timeout) Runs a realtime request but allows timing out the network call. Raises <tt>Timeout::Error</tt> if timeout is exceeded.
|
110
|
+
* (guid) Runs a realtime request, but first checks if there is a result pre-calculated on S3. Stores result to S3 if there isn't.
|
111
|
+
* (callback) Runs an async request (so you don't immediately get the result back). The result will be POSTed to the URL you specify.
|
112
|
+
* (guid,defer) Runs an async request (so you don't immediately get the result back). The result will be stored to S3 as <tt>hxxp://storage.carbon.brighterplanet.com/SHA1-hexdigest-of-key+guid</tt>
|
113
|
+
* (guid,timeout) (NOT IMPLEMENTED) A hybrid "best effort" request that is as cheap as an async request but will try to return the full result data immediately. It keeps trying S3 until your timeout is exceeded, at which point it's just a normal async request.
|
114
|
+
|
84
115
|
== A note on exceptions
|
85
116
|
|
86
117
|
Since this gem connects to a web service, you need to be ready for network problems and latency. For example:
|
data/Rakefile
CHANGED
@@ -13,6 +13,8 @@ begin
|
|
13
13
|
gemspec.add_dependency 'activesupport', '>=2.3.5'
|
14
14
|
gemspec.add_dependency 'nap', '>=0.4'
|
15
15
|
gemspec.add_dependency 'timeframe', '>=0.0.7'
|
16
|
+
# This is still only on Rubyforge
|
17
|
+
gemspec.add_dependency 'SystemTimer', '>=1.2'
|
16
18
|
gemspec.add_dependency 'blockenspiel', '>=0.3.2'
|
17
19
|
|
18
20
|
gemspec.add_development_dependency 'fakeweb', '>=1.2.8'
|
@@ -55,6 +57,7 @@ Rake::RDocTask.new do |rdoc|
|
|
55
57
|
|
56
58
|
rdoc.rdoc_dir = 'rdoc'
|
57
59
|
rdoc.title = "carbon #{version}"
|
58
|
-
rdoc.rdoc_files.include('README
|
60
|
+
rdoc.rdoc_files.include('README.rdoc')
|
61
|
+
rdoc.rdoc_files.include('doc/*.rdoc')
|
59
62
|
rdoc.rdoc_files.include('lib/**/*.rb')
|
60
63
|
end
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.2.
|
1
|
+
0.2.5
|
data/carbon.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{carbon}
|
8
|
-
s.version = "0.2.
|
8
|
+
s.version = "0.2.5"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Derek Kastner", "Seamus Abshere", "Andy Rossmeissl"]
|
12
|
-
s.date = %q{2010-
|
12
|
+
s.date = %q{2010-08-02}
|
13
13
|
s.description = %q{Carbon is a Ruby API wrapper for the Brighter Planet emission estimate web service (http://carbon.brighterplanet.com). By querying the web service, it can estimate the carbon emissions of many real-life objects, such as cars and houses, based on particular attributes that they may have.}
|
14
14
|
s.email = %q{derek.kastner@brighterplanet.com}
|
15
15
|
s.extra_rdoc_files = [
|
@@ -22,11 +22,17 @@ Gem::Specification.new do |s|
|
|
22
22
|
"Rakefile",
|
23
23
|
"VERSION",
|
24
24
|
"carbon.gemspec",
|
25
|
+
"doc/INTEGRATION_GUIDE.rdoc",
|
26
|
+
"doc/examining-response-with-jsonview.png",
|
27
|
+
"doc/timeout-error.png",
|
28
|
+
"doc/with-committee-reports.png",
|
29
|
+
"doc/without-committee-reports.png",
|
25
30
|
"lib/carbon.rb",
|
26
31
|
"lib/carbon/base.rb",
|
27
32
|
"lib/carbon/emission_estimate.rb",
|
28
33
|
"lib/carbon/emission_estimate/request.rb",
|
29
34
|
"lib/carbon/emission_estimate/response.rb",
|
35
|
+
"lib/carbon/emission_estimate/storage.rb",
|
30
36
|
"spec/lib/carbon_spec.rb",
|
31
37
|
"spec/spec_helper.rb",
|
32
38
|
"spec/specwatchr"
|
@@ -49,6 +55,7 @@ Gem::Specification.new do |s|
|
|
49
55
|
s.add_runtime_dependency(%q<activesupport>, [">= 2.3.5"])
|
50
56
|
s.add_runtime_dependency(%q<nap>, [">= 0.4"])
|
51
57
|
s.add_runtime_dependency(%q<timeframe>, [">= 0.0.7"])
|
58
|
+
s.add_runtime_dependency(%q<SystemTimer>, [">= 1.2"])
|
52
59
|
s.add_runtime_dependency(%q<blockenspiel>, [">= 0.3.2"])
|
53
60
|
s.add_development_dependency(%q<fakeweb>, [">= 1.2.8"])
|
54
61
|
s.add_development_dependency(%q<rspec>, [">= 2.0.0.beta.17"])
|
@@ -56,6 +63,7 @@ Gem::Specification.new do |s|
|
|
56
63
|
s.add_dependency(%q<activesupport>, [">= 2.3.5"])
|
57
64
|
s.add_dependency(%q<nap>, [">= 0.4"])
|
58
65
|
s.add_dependency(%q<timeframe>, [">= 0.0.7"])
|
66
|
+
s.add_dependency(%q<SystemTimer>, [">= 1.2"])
|
59
67
|
s.add_dependency(%q<blockenspiel>, [">= 0.3.2"])
|
60
68
|
s.add_dependency(%q<fakeweb>, [">= 1.2.8"])
|
61
69
|
s.add_dependency(%q<rspec>, [">= 2.0.0.beta.17"])
|
@@ -64,6 +72,7 @@ Gem::Specification.new do |s|
|
|
64
72
|
s.add_dependency(%q<activesupport>, [">= 2.3.5"])
|
65
73
|
s.add_dependency(%q<nap>, [">= 0.4"])
|
66
74
|
s.add_dependency(%q<timeframe>, [">= 0.0.7"])
|
75
|
+
s.add_dependency(%q<SystemTimer>, [">= 1.2"])
|
67
76
|
s.add_dependency(%q<blockenspiel>, [">= 0.3.2"])
|
68
77
|
s.add_dependency(%q<fakeweb>, [">= 1.2.8"])
|
69
78
|
s.add_dependency(%q<rspec>, [">= 2.0.0.beta.17"])
|
@@ -0,0 +1,1002 @@
|
|
1
|
+
= Emission estimate integration guide
|
2
|
+
|
3
|
+
Using real examples from the July 2010 integration of http://brighterplanet.com with the carbon middleware emission estimate web service.
|
4
|
+
|
5
|
+
== Step 1: Get an early win
|
6
|
+
|
7
|
+
Convert just one legacy class to use the web service. All you want is a number back, any number!
|
8
|
+
|
9
|
+
Here's what we changed:
|
10
|
+
|
11
|
+
vidalia:~/app1 (practice_migration) $ git diff master..practice_migration
|
12
|
+
diff --git a/Gemfile b/Gemfile
|
13
|
+
index 1d582d4..acccc7e 100644
|
14
|
+
--- a/Gemfile
|
15
|
+
+++ b/Gemfile
|
16
|
+
@@ -15,6 +15,7 @@ gem 'tzinfo', '0.3.20' # otherwise doesn't recognize timezone
|
17
|
+
# gem 'mime-types', '1.16', :require => 'mime/types' # twitter_oauth
|
18
|
+
# --
|
19
|
+
|
20
|
+
+gem 'carbon', '0.2.4'
|
21
|
+
gem 'simple-rss', '1.2.2'
|
22
|
+
gem 'httparty', '0.6.1'
|
23
|
+
gem 'thinking-sphinx', '1.3.16', :require => 'thinking_sphinx'
|
24
|
+
diff --git a/app/models/automobile_fuel_type.rb b/app/models/automobile_fuel_type.rb
|
25
|
+
index 30bb0c7..aaa4f49 100644
|
26
|
+
--- a/app/models/automobile_fuel_type.rb
|
27
|
+
+++ b/app/models/automobile_fuel_type.rb
|
28
|
+
@@ -7,6 +7,10 @@ class AutomobileFuelType < ActiveRecord::Base
|
29
|
+
attributes.slice 'code'
|
30
|
+
end
|
31
|
+
|
32
|
+
+ def to_characteristic
|
33
|
+
+ code
|
34
|
+
+ end
|
35
|
+
+
|
36
|
+
class << self
|
37
|
+
# don't show electricity (plug-in) per Matt https://brighterplanet.sifterapp.com/projects/30/issues/341/comments
|
38
|
+
def for_collection_select(*args)
|
39
|
+
diff --git a/app/models/automobile_make.rb b/app/models/automobile_make.rb
|
40
|
+
index f3e7798..3133406 100644
|
41
|
+
--- a/app/models/automobile_make.rb
|
42
|
+
+++ b/app/models/automobile_make.rb
|
43
|
+
@@ -17,6 +17,10 @@ class AutomobileMake < ActiveRecord::Base
|
44
|
+
def to_s
|
45
|
+
name
|
46
|
+
end
|
47
|
+
+
|
48
|
+
+ def to_characteristic
|
49
|
+
+ name
|
50
|
+
+ end
|
51
|
+
|
52
|
+
# leave this for later if we need it
|
53
|
+
SUBSIDIARIES = {
|
54
|
+
diff --git a/app/models/automobile_model.rb b/app/models/automobile_model.rb
|
55
|
+
index 1620b3a..870a6c5 100644
|
56
|
+
--- a/app/models/automobile_model.rb
|
57
|
+
+++ b/app/models/automobile_model.rb
|
58
|
+
@@ -24,6 +24,10 @@ class AutomobileModel < ActiveRecord::Base
|
59
|
+
name
|
60
|
+
end
|
61
|
+
|
62
|
+
+ def to_characteristic
|
63
|
+
+ "#{make.to_characteristic} #{name}"
|
64
|
+
+ end
|
65
|
+
+
|
66
|
+
def fuel_efficiency(options = {})
|
67
|
+
urbanity = options[:urbanity] || Automobile.fallback.urbanity
|
68
|
+
urbanity * AutomobileVariant.average(:fuel_efficiency_city, :conditions => { :automobile_model_id => id }) +
|
69
|
+
diff --git a/app/models/automobile_model_year.rb b/app/models/automobile_model_year.rb
|
70
|
+
index 36a1714..32b5c1f 100644
|
71
|
+
--- a/app/models/automobile_model_year.rb
|
72
|
+
+++ b/app/models/automobile_model_year.rb
|
73
|
+
@@ -29,4 +29,9 @@ class AutomobileModelYear < ActiveRecord::Base
|
74
|
+
def to_i
|
75
|
+
year.to_i
|
76
|
+
end
|
77
|
+
+
|
78
|
+
+ def to_characteristic
|
79
|
+
+ year
|
80
|
+
+ end
|
81
|
+
+
|
82
|
+
end
|
83
|
+
diff --git a/app/models/automobile_size_class.rb b/app/models/automobile_size_class.rb
|
84
|
+
index e62b80d..5ed1e2a 100644
|
85
|
+
--- a/app/models/automobile_size_class.rb
|
86
|
+
+++ b/app/models/automobile_size_class.rb
|
87
|
+
@@ -7,6 +7,10 @@ class AutomobileSizeClass < ActiveRecord::Base
|
88
|
+
attributes.slice 'name'
|
89
|
+
end
|
90
|
+
|
91
|
+
+ def to_characteristic
|
92
|
+
+ name
|
93
|
+
+ end
|
94
|
+
+
|
95
|
+
class << self
|
96
|
+
def for_collection_select(*args)
|
97
|
+
all :order => :id
|
98
|
+
diff --git a/app/models/emitters/automobile.rb b/app/models/emitters/automobile.rb
|
99
|
+
index d2d852c..e7aa8a6 100644
|
100
|
+
--- a/app/models/emitters/automobile.rb
|
101
|
+
+++ b/app/models/emitters/automobile.rb
|
102
|
+
@@ -1,4 +1,42 @@
|
103
|
+
class Automobile < Emitter
|
104
|
+
+ include Carbon
|
105
|
+
+
|
106
|
+
+ emit_as :automobile do
|
107
|
+
+ provide :make
|
108
|
+
+ provide :model
|
109
|
+
+ provide :model_year_proxy, :as => :model_year
|
110
|
+
+ # provide :variant - what to key on?
|
111
|
+
+ provide :fuel_type
|
112
|
+
+ provide :size_class
|
113
|
+
+ provide :fuel_efficiency
|
114
|
+
+ provide :urbanity
|
115
|
+
+ provide :hybridity
|
116
|
+
+ provide :daily_distance_estimate
|
117
|
+
+ provide :daily_duration
|
118
|
+
+ provide :weekly_distance_estimate
|
119
|
+
+ provide :annual_distance_estimate
|
120
|
+
+ provide :acquisition
|
121
|
+
+ provide :retirement
|
122
|
+
+ end
|
123
|
+
+
|
124
|
+
+ # app1 model years are just years - 1999
|
125
|
+
+ # cm1 model years are composites of year and model - Acura TSX 1999
|
126
|
+
+ # so we have to proxy it
|
127
|
+
+ class ModelYearProxy
|
128
|
+
+ attr_reader :parent
|
129
|
+
+ def initialize(parent)
|
130
|
+
+ @parent = parent
|
131
|
+
+ end
|
132
|
+
+ def to_characteristic
|
133
|
+
+ if parent.model and parent.model_year
|
134
|
+
+ "#{parent.model.to_characteristic} #{parent.model_year.to_characteristic}"
|
135
|
+
+ end
|
136
|
+
+ end
|
137
|
+
+ end
|
138
|
+
+ def model_year_proxy
|
139
|
+
+ @model_year_proxy ||= ModelYearProxy.new self
|
140
|
+
+ end
|
141
|
+
+
|
142
|
+
diff --git a/config/initializers/carbon_middleware.rb b/config/initializers/carbon_middleware.rb
|
143
|
+
new file mode 100644
|
144
|
+
index 0000000..8becc5f
|
145
|
+
--- /dev/null
|
146
|
+
+++ b/config/initializers/carbon_middleware.rb
|
147
|
+
@@ -0,0 +1 @@
|
148
|
+
+::Carbon.key = '[Get your own at http://keys.brighterplanet.com]'
|
149
|
+
|
150
|
+
|
151
|
+
And then we could do...
|
152
|
+
|
153
|
+
>> a = Automobile.find 710
|
154
|
+
=> #<Automobile [...]>
|
155
|
+
>> a.emission(Timeframe.this_year) # legacy call
|
156
|
+
=> 7040.88102017319
|
157
|
+
>> a.emission_estimate(:timeframe => Timeframe.this_year).to_f # outsourced (new) call
|
158
|
+
=> 7040.88102017319
|
159
|
+
|
160
|
+
An early win!
|
161
|
+
|
162
|
+
=== Comments on step 1
|
163
|
+
|
164
|
+
* We're using Ruby on Rails and so we can use the official {carbon gem}[http://rubygems.org/gems/carbon]. If you're not on Ruby on Rails, please contact us for extra support in other languages or frameworks. If we don't have a library for it, we will help shoulder the burden of developing one.
|
165
|
+
|
166
|
+
* We mapped all of the attributes of an Automobile that the web service recognizes.
|
167
|
+
|
168
|
+
* One characteristic causes us trouble: model_year. The web service expects "Acura TSX 1999", but if you just called <tt>Automobile#model_year</tt> in the legacy app, you would get "1999". So, we map the characteristic "model_year" to <tt>Automobile#model_year_proxy</tt>, which responds with a <tt>ModelYearProxy</tt> object, which, in turn, responds to <tt>ModelYearProxy#to_characteristic</tt>.
|
169
|
+
|
170
|
+
* Note the similarity of the legacy call <tt>Automobile#emission</tt> to the outsourced call <tt>Automobile#emission_estimate</tt>. That's because the carbon gem and our website have a lot of shared code history.
|
171
|
+
|
172
|
+
== Step 2: Apply the outsourced method call in interface code
|
173
|
+
|
174
|
+
Rather than getting really deep into replacing the business logic of your legacy emitter classes, try to hit interface problems early.
|
175
|
+
|
176
|
+
Out of all the emitter classes, we've only converted the Automobile class, so for now we have to make sure the interface knows how to render both kinds: outsourced and legacy.
|
177
|
+
|
178
|
+
Here's what we changed:
|
179
|
+
|
180
|
+
vidalia:~/app1 (practice_migration) $ git diff master..practice_migration
|
181
|
+
diff --git a/app/models/emitter.rb b/app/models/emitter.rb
|
182
|
+
index 8603f22..93971b7 100644
|
183
|
+
--- a/app/models/emitter.rb
|
184
|
+
+++ b/app/models/emitter.rb
|
185
|
+
@@ -1,5 +1,10 @@
|
186
|
+
# todo dry emblem
|
187
|
+
class Emitter < ActiveRecord::Base
|
188
|
+
+ # Whether emission estimates for this class have been outsourced to Brighter Planet
|
189
|
+
+ def outsourced?
|
190
|
+
+ respond_to? :emission_estimate
|
191
|
+
+ end
|
192
|
+
+
|
193
|
+
self.abstract_class = true
|
194
|
+
|
195
|
+
extend ActiveSupport::Memoizable if Switches.memoization?
|
196
|
+
@@ -304,7 +313,11 @@ class Emitter < ActiveRecord::Base
|
197
|
+
if respond_to? :emission_date
|
198
|
+
timeframe.include? emission_date
|
199
|
+
elsif self.class.characterization.characteristics.include? :active_subtimeframe
|
200
|
+
- timeframe & committee_reports[:active_subtimeframe]
|
201
|
+
+ if outsourced?
|
202
|
+
+ nil # don't know how to get active_subtimeframe
|
203
|
+
+ else
|
204
|
+
+ timeframe & committee_reports[:active_subtimeframe]
|
205
|
+
+ end
|
206
|
+
end
|
207
|
+
end
|
208
|
+
diff --git a/app/models/component.rb b/app/models/component.rb
|
209
|
+
index 24e359a..b00ba5d 100644
|
210
|
+
--- a/app/models/component.rb
|
211
|
+
+++ b/app/models/component.rb
|
212
|
+
@@ -232,7 +232,13 @@ class Component
|
213
|
+
def emission_from_imperfect_emitters(timeframe, perspective)
|
214
|
+
# unlike preterite components, we have to leave data interpolation up to the emitter, so this is all-or-nothing
|
215
|
+
if emitters_present_during? timeframe
|
216
|
+
- emitters.values.flatten.sum { |emitter| emitter.as_of(perspective).emission(timeframe, perspective).to_f }
|
217
|
+
+ emitters.values.flatten.sum do |emitter|
|
218
|
+
+ if emitter.outsourced?
|
219
|
+
+ emitter.as_of(perspective).emission_estimate(:timeframe => timeframe).to_f # dropping perspective
|
220
|
+
+ else
|
221
|
+
+ emitter.as_of(perspective).emission(timeframe, perspective).to_f
|
222
|
+
+ end
|
223
|
+
+ end
|
224
|
+
else
|
225
|
+
typical_emission_from_emitters(timeframe)
|
226
|
+
end
|
227
|
+
@@ -248,7 +254,13 @@ class Component
|
228
|
+
puts " Looking at subtimeframe #{subtimeframe.from} - #{subtimeframe.to}" if Component::DEBUG
|
229
|
+
if emitters_present_during? subtimeframe # we want to use emissions committee for the period BETWEEN profile creation and the end of last month for which we have emitters
|
230
|
+
puts " --> Emitters present!" if Component::DEBUG
|
231
|
+
- e = preterite_emitters.sum { |emitter| emitter.emission(subtimeframe, perspective).to_f }
|
232
|
+
+ e = preterite_emitters.sum do |emitter|
|
233
|
+
+ if emitter.outsourced?
|
234
|
+
+ emitter.emission_estimate(:timeframe => subtimeframe).to_f # dropping perspective
|
235
|
+
+ else
|
236
|
+
+ emitter.emission(subtimeframe, perspective).to_f
|
237
|
+
+ end
|
238
|
+
+ end
|
239
|
+
puts " --> Adding #{e}" if Component::DEBUG
|
240
|
+
e
|
241
|
+
elsif emitters_present? and profile.created_at.to_date <= subtimeframe.from and subtimeframe.to < Date.new(Time.now.year, Time.now.month, 1) # we want to use 0 for the period BETWEEN profile creation and the end of the last month for which we have no emitters IF there are any emitters at all, ever.
|
242
|
+
@@ -261,7 +273,14 @@ class Component
|
243
|
+
e
|
244
|
+
end
|
245
|
+
end
|
246
|
+
- emission_from_patterns = (patterns.sum { |pattern| pattern.emission(timeframe, perspective).to_f }) || 0
|
247
|
+
+ emission_from_patterns = patterns.sum do |pattern|
|
248
|
+
+ if pattern.outsourced?
|
249
|
+
+ pattern.emission_estimate(:timeframe => timeframe).to_f # dropping perspective
|
250
|
+
+ else
|
251
|
+
+ pattern.emission(timeframe, perspective).to_f
|
252
|
+
+ end
|
253
|
+
+ end
|
254
|
+
+ emission_from_patterns ||= 0
|
255
|
+
if emitters_present_during? timeframe # normally pattern emissions are *added to* preterite emitter emissions
|
256
|
+
emission_during_timeframe += emission_from_patterns
|
257
|
+
elsif emission_from_patterns.nonzero? # if there's no real emitters, but there are patterns established, the patterns *replace* placeholders
|
258
|
+
@@ -270,6 +289,7 @@ class Component
|
259
|
+
emission_during_timeframe
|
260
|
+
end
|
261
|
+
|
262
|
+
+ # Component#emission, not to be confused with Emitter#emission
|
263
|
+
def emission(timeframe, perspective = Time.zone.today)
|
264
|
+
return 0 if disabled?
|
265
|
+
unless @emission and @emission[timeframe.hash] and @emission[timeframe.hash][perspective.hash]
|
266
|
+
diff --git a/app/helpers/emitters_helper.rb b/app/helpers/emitters_helper.rb
|
267
|
+
index c1b75ee..e526ba1 100755
|
268
|
+
--- a/app/helpers/emitters_helper.rb
|
269
|
+
+++ b/app/helpers/emitters_helper.rb
|
270
|
+
@@ -3,7 +3,7 @@
|
271
|
+
|
272
|
+
module EmittersHelper
|
273
|
+
def render_characteristic(emitter, characteristic)
|
274
|
+
- characteristic_value = emitter.characteristics.has_key?(characteristic) ? emitter.characteristics[characteristic] : emitter.committee_reports[characteristic]
|
275
|
+
+ characteristic_value = (emitter.outsourced? or emitter.characteristics.has_key?(characteristic)) ? emitter.characteristics[characteristic] : emitter.committee_reports[characteristic]
|
276
|
+
locals = { :emitter => emitter, :characteristic => characteristic, characteristic => characteristic_value }
|
277
|
+
|
278
|
+
begin
|
279
|
+
@@ -14,7 +14,7 @@ module EmittersHelper
|
280
|
+
end
|
281
|
+
|
282
|
+
def render_edit_characteristic(emitter, characteristic)
|
283
|
+
- characteristic_value = emitter.characteristics.has_key?(characteristic) ? emitter.characteristics[characteristic] : emitter.committee_reports[characteristic]
|
284
|
+
+ characteristic_value = (emitter.outsourced? or emitter.characteristics.has_key?(characteristic)) ? emitter.characteristics[characteristic] : emitter.committee_reports[characteristic]
|
285
|
+
locals = { :emitter => emitter, :characteristic => characteristic, characteristic => characteristic_value }
|
286
|
+
template = pick_edit_partial(emitter, characteristic)
|
287
|
+
if template == 'characteristics/controls/collection_select'
|
288
|
+
@@ -80,7 +80,7 @@ module EmittersHelper
|
289
|
+
end
|
290
|
+
|
291
|
+
def render_placeholder_characteristic(emitter, characteristic)
|
292
|
+
- characteristic_value = emitter.characteristics.has_key?(characteristic) ? emitter.characteristics[characteristic] : emitter.committee_reports[characteristic]
|
293
|
+
+ characteristic_value = (emitter.outsourced? or emitter.characteristics.has_key?(characteristic)) ? emitter.characteristics[characteristic] : emitter.committee_reports[characteristic]
|
294
|
+
locals = { :emitter => emitter, :characteristic => characteristic, characteristic => characteristic_value }
|
295
|
+
render :partial => "#{emitter.common_plural}/#{characteristic}/placeholder", :layout => 'characteristics/layouts/placeholder', :locals => locals
|
296
|
+
rescue ActionView::MissingTemplate
|
297
|
+
diff --git a/app/views/characteristics/_characteristic.html.erb b/app/views/characteristics/_characteristic.html.erb
|
298
|
+
index c08003d..5e5ff1f 100644
|
299
|
+
--- a/app/views/characteristics/_characteristic.html.erb
|
300
|
+
+++ b/app/views/characteristics/_characteristic.html.erb
|
301
|
+
@@ -1,7 +1,7 @@
|
302
|
+
<%
|
303
|
+
known = !(known == false)
|
304
|
+
expanded = (expanded == true)
|
305
|
+
-reported = emitter.committee_reports.keys.include? characteristic # this should never happen if known
|
306
|
+
+reported = !emitter.outsourced? and emitter.committee_reports.keys.include? characteristic # this should never happen if known
|
307
|
+
element_class = [characteristic]
|
308
|
+
element_class << 'reported' if reported
|
309
|
+
element_class << 'next' if expanded
|
310
|
+
diff --git a/app/views/carbon_offsets/_emitter.html.erb b/app/views/carbon_offsets/_emitter.html.erb
|
311
|
+
index 61cd499..b006892 100644
|
312
|
+
--- a/app/views/carbon_offsets/_emitter.html.erb
|
313
|
+
+++ b/app/views/carbon_offsets/_emitter.html.erb
|
314
|
+
@@ -1,5 +1,9 @@
|
315
|
+
<%
|
316
|
+
-emission = emitter.emission timeframe
|
317
|
+
+emission = if emitter.outsourced?
|
318
|
+
+ emitter.emission_estimate(:timeframe => timeframe).to_f
|
319
|
+
+else
|
320
|
+
+ emitter.emission timeframe
|
321
|
+
+end
|
322
|
+
return unless emission.kilograms.to(:tons) > CustomPackage::MINIMUM_CARBON_OFFSET_IN_TONS
|
323
|
+
custom_package = {
|
324
|
+
:carbon_offset => emission,
|
325
|
+
diff --git a/app/views/components/_gaps.html.erb b/app/views/components/_gaps.html.erb
|
326
|
+
index 203d261..6e13b6f 100644
|
327
|
+
--- a/app/views/components/_gaps.html.erb
|
328
|
+
+++ b/app/views/components/_gaps.html.erb
|
329
|
+
@@ -1,5 +1,5 @@
|
330
|
+
<% if component.tense == :imperfect %>
|
331
|
+
- <% covered_timeframes = component.emitters.values.flatten.collect { |e| e.committee_reports(timeframe)[:active_subtimeframe] } %>
|
332
|
+
+ <% covered_timeframes = component.emitters.values.flatten.collect { |e| e.outsourced? ? nil : e.committee_reports(timeframe)[:active_subtimeframe] } %>
|
333
|
+
<% unless timeframe.covered_by? *covered_timeframes %>
|
334
|
+
<% gaps = timeframe.gaps_left_by(*covered_timeframes) %>
|
335
|
+
<p><strong>Note:</strong> you haven't told us about any <%= component.class.component_name %> emissions during <%= gaps.to_sentence %>. If you <%= component.verb[:past] %> <%= component.class.component_name.pluralize %> during these times, please tell us about it.</p>
|
336
|
+
diff --git a/app/views/components/show.html.erb b/app/views/components/show.html.erb
|
337
|
+
index 3a89238..1479f2e 100644
|
338
|
+
--- a/app/views/components/show.html.erb
|
339
|
+
+++ b/app/views/components/show.html.erb
|
340
|
+
@@ -75,7 +75,11 @@
|
341
|
+
<% @component.emitters.values.flatten.partition(&:retired?).reverse.flatten.each do |e| %>
|
342
|
+
<li class="<%= e.emblem %><%= ' retired' if e.retired? %>">
|
343
|
+
<p class="size">
|
344
|
+
- <%= e.emission(@timeframe).kilograms.to(:tons, 2) %> tons
|
345
|
+
+ <% if e.outsourced? %>
|
346
|
+
+ <%= e.emission_estimate(:timeframe => @timeframe).to_f.kilograms.to(:tons, 2) %> tons
|
347
|
+
+ <% else %>
|
348
|
+
+ <%= e.emission(@timeframe).kilograms.to(:tons, 2) %> tons
|
349
|
+
+ <% end %>
|
350
|
+
</p>
|
351
|
+
<h5><%= link_to e.name, e %><%= ' (retired)' if e.retired? %></h5>
|
352
|
+
<%= render :partial => 'carbon_offsets/emitter', :locals => { :emitter => e, :timeframe => @timeframe, :show_purchasing => viewing_self?(@user), :show_granting => false } %>
|
353
|
+
diff --git a/app/views/emitters/update.js.rjs b/app/views/emitters/update.js.rjs
|
354
|
+
index b325e97..5967500 100644
|
355
|
+
--- a/app/views/emitters/update.js.rjs
|
356
|
+
+++ b/app/views/emitters/update.js.rjs
|
357
|
+
@@ -15,7 +15,11 @@ if @wizard
|
358
|
+
page.visual_effect :fade, "#{common_name}_#{@characteristic}"
|
359
|
+
page.visual_effect :appear, "#{common_name}_#{next_characteristic}"
|
360
|
+
else
|
361
|
+
- emission = @emitter.emission Timeframe.new(Time.zone.today, Time.zone.today.tomorrow.tomorrow)
|
362
|
+
+ emission = if @emitter.outsourced?
|
363
|
+
+ @emitter.emission Timeframe.new(Time.zone.today, Time.zone.today.tomorrow.tomorrow)
|
364
|
+
+ else
|
365
|
+
+ @emitter.emission_estimate(:timeframe => Timeframe.new(Time.zone.today, Time.zone.today.tomorrow.tomorrow)).to_f
|
366
|
+
+ end
|
367
|
+
custom_package = {
|
368
|
+
:carbon_offset => emission,
|
369
|
+
:short_title => 'Travel emissions',
|
370
|
+
diff --git a/app/views/emissions/_footprint.html.erb b/app/views/emissions/_footprint.html.erb
|
371
|
+
index 89bcfe5..69c27a4 100644
|
372
|
+
--- a/app/views/emissions/_footprint.html.erb
|
373
|
+
+++ b/app/views/emissions/_footprint.html.erb
|
374
|
+
@@ -5,7 +5,7 @@
|
375
|
+
<%= render :partial => "#{footprintable.common_plural}/footprint", :locals => { :emitter => footprintable, :timeframe => timeframe } %>
|
376
|
+
<% end %>
|
377
|
+
|
378
|
+
- <span class="footprint"><span class="number"><%= footprintable.emission(timeframe).kilograms.to(:tons).adaptive_round %></span> tons CO<sub>2</sub></span>
|
379
|
+
+ <span class="footprint"><span class="number"><%= ((footprintable.is_a?(Emitter) and footprintable.outsourced?) ? footprintable.emission_estimate(:timeframe => timeframe) : footprintable.emission(timeframe)).to_f.kilograms.to(:tons).adaptive_round %></span> tons CO<sub>2</sub></span>
|
380
|
+
|
381
|
+
<%= render :partial => 'emissions/extraneous', :locals => { :timeframe => timeframe } if footprintable.is_a?(Emitter) and !footprintable.emitted_during_timeframe?(timeframe) %>
|
382
|
+
diff --git a/app/views/emitters/_sidebar.html.erb b/app/views/emitters/_sidebar.html.erb
|
383
|
+
index 7f0c8d0..2da2214 100644
|
384
|
+
--- a/app/views/emitters/_sidebar.html.erb
|
385
|
+
+++ b/app/views/emitters/_sidebar.html.erb
|
386
|
+
@@ -4,6 +4,11 @@
|
387
|
+
<%= render :partial => 'emissions/footprint', :locals => { :footprintable => emitter, :timeframe => timeframe } %>
|
388
|
+
<%#= render :partial => 'introduction', :locals => { :emitter => emitter, :component => component } %>
|
389
|
+
<%= render :partial => 'carbon_offsets/emitter', :locals => { :emitter => emitter, :timeframe => timeframe, :show_purchasing => true, :show_granting => true } %>
|
390
|
+
+<% if emitter.outsourced? %>
|
391
|
+
+ <p class="committee_reports">
|
392
|
+
+ <%= link_to 'Show calculation methods', emitter.emission_estimate.methodology %>
|
393
|
+
+ </p>
|
394
|
+
+<% else %>
|
395
|
+
<p class="committee_reports">
|
396
|
+
<%=
|
397
|
+
link_to_function 'Show calculation methods' do |page|
|
398
|
+
@@ -28,6 +33,7 @@ end
|
399
|
+
<% end %>
|
400
|
+
</ol>
|
401
|
+
<%= render :partial => 'emissions/methodology' %>
|
402
|
+
- </div>
|
403
|
+
+<% end %>
|
404
|
+
+</div>
|
405
|
+
<% end %>
|
406
|
+
|
407
|
+
=== Comments on step 2
|
408
|
+
|
409
|
+
* The legacy method <tt>Automobile#committee_reports</tt> is disappearing. We're going to have to look into that.
|
410
|
+
|
411
|
+
* We're don't have any way to pass in "perspective" for the outsourced emitters. Also going to have to deal with that.
|
412
|
+
|
413
|
+
* One big win is to be found in <tt>app/views/emitters/_sidebar.html.erb</tt>. If we're dealing with an outsourced emitter class, we can link to the web service's methodology report instead of trying to explain the calculations locally. If you outsource the hard science to Brighter Planet, it's nice to know that we'll also explain it for you!
|
414
|
+
|
415
|
+
== Step 3: Decide if you will be able to finish the job
|
416
|
+
|
417
|
+
You know you can get a number (step 1) and apply it to the interface (step 2). But does the web service provide everything you need?
|
418
|
+
|
419
|
+
For us, the potential show-stoppers were "committee reports", byproducts of the local calculation process. <b>Once we outsourced calculation, these values weren't being generated locally.</b>
|
420
|
+
|
421
|
+
In step 2, we cheated by ignoring them and showing nothing. We used to exploit them as helpful defaults for interface elements:
|
422
|
+
|
423
|
+
link:../doc/with-committee-reports.png
|
424
|
+
|
425
|
+
After step two, it looked like this:
|
426
|
+
|
427
|
+
link:../doc/without-committee-reports.png
|
428
|
+
|
429
|
+
Let's take a closer look at what the emission estimate web service returns.
|
430
|
+
|
431
|
+
>> a = Automobile.find 710
|
432
|
+
=> #<Automobile id [...] >
|
433
|
+
>> pp a.emission_estimate.response.data
|
434
|
+
{"emission_units"=>"kilograms",
|
435
|
+
"timeframe"=>"2010-01-01/2011-01-01",
|
436
|
+
"acquisition"=>Wed, 01 Jul 2009,
|
437
|
+
"adjusted_fuel_efficiency"=>8.50287,
|
438
|
+
"fuel_efficiency_multiplier"=>1.0,
|
439
|
+
"annual_distance"=>24140.2,
|
440
|
+
"fuel_type"=>
|
441
|
+
{"automobile_fuel_type"=>
|
442
|
+
{"name"=>"regular gasoline",
|
443
|
+
"created_at"=>"2010-05-15T01:31:58Z",
|
444
|
+
"code"=>"R",
|
445
|
+
"annual_distance"=>18161.0,
|
446
|
+
"emission_factor_units"=>"kilograms_per_litre",
|
447
|
+
"updated_at"=>"2010-05-27T01:26:14Z",
|
448
|
+
"annual_distance_units"=>"kilometres",
|
449
|
+
"emission_factor"=>2.48}},
|
450
|
+
"errors"=>[],
|
451
|
+
"nominal_fuel_efficiency"=>7.88765178259689,
|
452
|
+
"retirement"=>Sat, 01 Jan 2011,
|
453
|
+
"methodology"=>
|
454
|
+
"http://carbon.brighterplanet.com/automobiles.html?acquisition=2009-07-01&annual_distance_estimate=24140.2&fuel_efficiency=8.50287&fuel_type=R&key=3fca1403c1a561769a78ba462390ff01&make=Ford&size_class=Midsize+Pickup&timeframe=2010-01-01%2F2011-01-01",
|
455
|
+
"speed"=>50.9438793670604,
|
456
|
+
"emission_factor"=>2.48,
|
457
|
+
"emission"=>7040.88102017319,
|
458
|
+
"active_subtimeframe"=>
|
459
|
+
<Timeframe(-629293078) 365 days starting 2010-01-01 ending 2011-01-01>,
|
460
|
+
"make"=>
|
461
|
+
{"automobile_make"=>
|
462
|
+
{"name"=>"Ford",
|
463
|
+
"created_at"=>nil,
|
464
|
+
"fuel_efficiency_units"=>"kilometres_per_litre",
|
465
|
+
"updated_at"=>"2010-05-27T01:21:08Z",
|
466
|
+
"major"=>true,
|
467
|
+
"fuel_efficiency"=>10.1994}},
|
468
|
+
"fuel_consumed"=>2839.06492748919,
|
469
|
+
"urbanity"=>0.43,
|
470
|
+
"size_class"=>
|
471
|
+
{"automobile_size_class"=>
|
472
|
+
{"name"=>"Midsize Pickup",
|
473
|
+
"created_at"=>"2010-05-14T22:55:43Z",
|
474
|
+
"fuel_efficiency_city"=>6.8,
|
475
|
+
"fuel_efficiency_highway"=>8.97,
|
476
|
+
"annual_distance"=>20918.0,
|
477
|
+
"hybrid_fuel_efficiency_highway_multiplier"=>1.2,
|
478
|
+
"updated_at"=>"2010-05-14T22:55:44Z",
|
479
|
+
"fuel_efficiency_highway_units"=>"kilometres_per_litre",
|
480
|
+
"emblem"=>"",
|
481
|
+
"annual_distance_units"=>"kilometres",
|
482
|
+
"conventional_fuel_efficiency_city_multiplier"=>0.98,
|
483
|
+
"conventional_fuel_efficiency_highway_multiplier"=>0.99,
|
484
|
+
"hybrid_fuel_efficiency_city_multiplier"=>1.57,
|
485
|
+
"fuel_efficiency_city_units"=>"kilometres_per_litre"}},
|
486
|
+
"annual_distance_estimate"=>24140.2,
|
487
|
+
"reports"=>
|
488
|
+
[{"conclusion"=>7040.88102017319,
|
489
|
+
"committee"=>
|
490
|
+
{"name"=>"emission",
|
491
|
+
"quorums"=>
|
492
|
+
[{"name"=>"from fuel",
|
493
|
+
"process"=>{},
|
494
|
+
"supplements"=>["fuel_type"],
|
495
|
+
"compliance"=>[],
|
496
|
+
"requirements"=>["fuel_consumed", "emission_factor"]},
|
497
|
+
{"name"=>"default",
|
498
|
+
"process"=>{},
|
499
|
+
"supplements"=>[],
|
500
|
+
"compliance"=>[],
|
501
|
+
"requirements"=>[]}]},
|
502
|
+
"quorum"=>
|
503
|
+
{"name"=>"from fuel",
|
504
|
+
"process"=>{},
|
505
|
+
"supplements"=>["fuel_type"],
|
506
|
+
"compliance"=>[],
|
507
|
+
"requirements"=>["fuel_consumed", "emission_factor"]}},
|
508
|
+
{"conclusion"=>2.48,
|
509
|
+
"committee"=>
|
510
|
+
{"name"=>"emission_factor",
|
511
|
+
"quorums"=>
|
512
|
+
[{"name"=>"from fuel type",
|
513
|
+
"process"=>{},
|
514
|
+
"supplements"=>[],
|
515
|
+
"compliance"=>[],
|
516
|
+
"requirements"=>["fuel_type"]},
|
517
|
+
{"name"=>"default",
|
518
|
+
"process"=>{},
|
519
|
+
"supplements"=>[],
|
520
|
+
"compliance"=>[],
|
521
|
+
"requirements"=>[]}]},
|
522
|
+
"quorum"=>
|
523
|
+
{"name"=>"from fuel type",
|
524
|
+
"process"=>{},
|
525
|
+
"supplements"=>[],
|
526
|
+
"compliance"=>[],
|
527
|
+
"requirements"=>["fuel_type"]}},
|
528
|
+
{"conclusion"=>2839.06492748919,
|
529
|
+
"committee"=>
|
530
|
+
{"name"=>"fuel_consumed",
|
531
|
+
"quorums"=>
|
532
|
+
[{"name"=>"from adjusted fuel_efficiency and distance",
|
533
|
+
"process"=>{},
|
534
|
+
"supplements"=>[],
|
535
|
+
"compliance"=>[],
|
536
|
+
"requirements"=>["adjusted_fuel_efficiency", "distance"]}]},
|
537
|
+
"quorum"=>
|
538
|
+
{"name"=>"from adjusted fuel_efficiency and distance",
|
539
|
+
"process"=>{},
|
540
|
+
"supplements"=>[],
|
541
|
+
"compliance"=>[],
|
542
|
+
"requirements"=>["adjusted_fuel_efficiency", "distance"]}},
|
543
|
+
{"conclusion"=>24140.2,
|
544
|
+
"committee"=>
|
545
|
+
{"name"=>"distance",
|
546
|
+
"quorums"=>
|
547
|
+
[{"name"=>"from annual distance",
|
548
|
+
"process"=>{},
|
549
|
+
"supplements"=>[],
|
550
|
+
"compliance"=>[],
|
551
|
+
"requirements"=>["annual_distance", "active_subtimeframe"]}]},
|
552
|
+
"quorum"=>
|
553
|
+
{"name"=>"from annual distance",
|
554
|
+
"process"=>{},
|
555
|
+
"supplements"=>[],
|
556
|
+
"compliance"=>[],
|
557
|
+
"requirements"=>["annual_distance", "active_subtimeframe"]}},
|
558
|
+
{"conclusion"=>24140.2,
|
559
|
+
"committee"=>
|
560
|
+
{"name"=>"annual_distance",
|
561
|
+
"quorums"=>
|
562
|
+
[{"name"=>"from annual distance estimate",
|
563
|
+
"process"=>{},
|
564
|
+
"supplements"=>[],
|
565
|
+
"compliance"=>[],
|
566
|
+
"requirements"=>["annual_distance_estimate"]},
|
567
|
+
{"name"=>"from weekly distance estimate",
|
568
|
+
"process"=>{},
|
569
|
+
"supplements"=>[],
|
570
|
+
"compliance"=>[],
|
571
|
+
"requirements"=>["weekly_distance_estimate"]},
|
572
|
+
{"name"=>"from daily distance",
|
573
|
+
"process"=>{},
|
574
|
+
"supplements"=>[],
|
575
|
+
"compliance"=>[],
|
576
|
+
"requirements"=>["daily_distance"]},
|
577
|
+
{"name"=>"from size class",
|
578
|
+
"process"=>{},
|
579
|
+
"supplements"=>[],
|
580
|
+
"compliance"=>[],
|
581
|
+
"requirements"=>["size_class"]},
|
582
|
+
{"name"=>"from fuel type",
|
583
|
+
"process"=>{},
|
584
|
+
"supplements"=>[],
|
585
|
+
"compliance"=>[],
|
586
|
+
"requirements"=>["fuel_type"]},
|
587
|
+
{"name"=>"default",
|
588
|
+
"process"=>{},
|
589
|
+
"supplements"=>[],
|
590
|
+
"compliance"=>[],
|
591
|
+
"requirements"=>[]}]},
|
592
|
+
"quorum"=>
|
593
|
+
{"name"=>"from annual distance estimate",
|
594
|
+
"process"=>{},
|
595
|
+
"supplements"=>[],
|
596
|
+
"compliance"=>[],
|
597
|
+
"requirements"=>["annual_distance_estimate"]}},
|
598
|
+
{"conclusion"=>8.50287,
|
599
|
+
"committee"=>
|
600
|
+
{"name"=>"adjusted_fuel_efficiency",
|
601
|
+
"quorums"=>
|
602
|
+
[{"name"=>"from fuel efficiency",
|
603
|
+
"process"=>{},
|
604
|
+
"supplements"=>[],
|
605
|
+
"compliance"=>[],
|
606
|
+
"requirements"=>["fuel_efficiency"]},
|
607
|
+
{"name"=>"from variant",
|
608
|
+
"process"=>{},
|
609
|
+
"supplements"=>[],
|
610
|
+
"compliance"=>[],
|
611
|
+
"requirements"=>["variant", "urbanity"]},
|
612
|
+
{"name"=>"from nominal fuel efficiency and multiplier",
|
613
|
+
"process"=>{},
|
614
|
+
"supplements"=>[],
|
615
|
+
"compliance"=>[],
|
616
|
+
"requirements"=>
|
617
|
+
["nominal_fuel_efficiency", "fuel_efficiency_multiplier"]}]},
|
618
|
+
"quorum"=>
|
619
|
+
{"name"=>"from fuel efficiency",
|
620
|
+
"process"=>{},
|
621
|
+
"supplements"=>[],
|
622
|
+
"compliance"=>[],
|
623
|
+
"requirements"=>["fuel_efficiency"]}},
|
624
|
+
{"conclusion"=>1.0,
|
625
|
+
"committee"=>
|
626
|
+
{"name"=>"fuel_efficiency_multiplier",
|
627
|
+
"quorums"=>
|
628
|
+
[{"name"=>"from_size_class_and_hybridity",
|
629
|
+
"process"=>{},
|
630
|
+
"supplements"=>[],
|
631
|
+
"compliance"=>[],
|
632
|
+
"requirements"=>["size_class", "hybridity", "urbanity"]},
|
633
|
+
{"name"=>"from hybridity",
|
634
|
+
"process"=>{},
|
635
|
+
"supplements"=>[],
|
636
|
+
"compliance"=>[],
|
637
|
+
"requirements"=>["hybridity", "urbanity"]},
|
638
|
+
{"name"=>"default",
|
639
|
+
"process"=>{},
|
640
|
+
"supplements"=>[],
|
641
|
+
"compliance"=>[],
|
642
|
+
"requirements"=>[]}]},
|
643
|
+
"quorum"=>
|
644
|
+
{"name"=>"default",
|
645
|
+
"process"=>{},
|
646
|
+
"supplements"=>[],
|
647
|
+
"compliance"=>[],
|
648
|
+
"requirements"=>[]}},
|
649
|
+
{"conclusion"=>7.88765178259689,
|
650
|
+
"committee"=>
|
651
|
+
{"name"=>"nominal_fuel_efficiency",
|
652
|
+
"quorums"=>
|
653
|
+
[{"name"=>"from model",
|
654
|
+
"process"=>{},
|
655
|
+
"supplements"=>[],
|
656
|
+
"compliance"=>[],
|
657
|
+
"requirements"=>["model", "urbanity"]},
|
658
|
+
{"name"=>"from make and model year",
|
659
|
+
"process"=>{},
|
660
|
+
"supplements"=>[],
|
661
|
+
"compliance"=>[],
|
662
|
+
"requirements"=>["model_year"]},
|
663
|
+
{"name"=>"from size class",
|
664
|
+
"process"=>{},
|
665
|
+
"supplements"=>[],
|
666
|
+
"compliance"=>[],
|
667
|
+
"requirements"=>["size_class", "urbanity"]},
|
668
|
+
{"name"=>"from model year",
|
669
|
+
"process"=>{},
|
670
|
+
"supplements"=>[],
|
671
|
+
"compliance"=>[],
|
672
|
+
"requirements"=>["model_year"]},
|
673
|
+
{"name"=>"from make",
|
674
|
+
"process"=>{},
|
675
|
+
"supplements"=>[],
|
676
|
+
"compliance"=>[],
|
677
|
+
"requirements"=>["make"]},
|
678
|
+
{"name"=>"default",
|
679
|
+
"process"=>{},
|
680
|
+
"supplements"=>[],
|
681
|
+
"compliance"=>[],
|
682
|
+
"requirements"=>[]}]},
|
683
|
+
"quorum"=>
|
684
|
+
{"name"=>"from size class",
|
685
|
+
"process"=>{},
|
686
|
+
"supplements"=>[],
|
687
|
+
"compliance"=>[],
|
688
|
+
"requirements"=>["size_class", "urbanity"]}},
|
689
|
+
{"conclusion"=>50.9438793670604,
|
690
|
+
"committee"=>
|
691
|
+
{"name"=>"speed",
|
692
|
+
"quorums"=>
|
693
|
+
[{"name"=>"from urbanity",
|
694
|
+
"process"=>{},
|
695
|
+
"supplements"=>[],
|
696
|
+
"compliance"=>[],
|
697
|
+
"requirements"=>["urbanity"]}]},
|
698
|
+
"quorum"=>
|
699
|
+
{"name"=>"from urbanity",
|
700
|
+
"process"=>{},
|
701
|
+
"supplements"=>[],
|
702
|
+
"compliance"=>[],
|
703
|
+
"requirements"=>["urbanity"]}},
|
704
|
+
{"conclusion"=>0.43,
|
705
|
+
"committee"=>
|
706
|
+
{"name"=>"urbanity",
|
707
|
+
"quorums"=>
|
708
|
+
[{"name"=>"default",
|
709
|
+
"process"=>{},
|
710
|
+
"supplements"=>[],
|
711
|
+
"compliance"=>[],
|
712
|
+
"requirements"=>[]}]},
|
713
|
+
"quorum"=>
|
714
|
+
{"name"=>"default",
|
715
|
+
"process"=>{},
|
716
|
+
"supplements"=>[],
|
717
|
+
"compliance"=>[],
|
718
|
+
"requirements"=>[]}},
|
719
|
+
{"conclusion"=>"2010-01-01/2011-01-01",
|
720
|
+
"committee"=>
|
721
|
+
{"name"=>"active_subtimeframe",
|
722
|
+
"quorums"=>
|
723
|
+
[{"name"=>"from acquisition and retirement",
|
724
|
+
"process"=>{},
|
725
|
+
"supplements"=>[],
|
726
|
+
"compliance"=>[],
|
727
|
+
"requirements"=>["acquisition", "retirement"]}]},
|
728
|
+
"quorum"=>
|
729
|
+
{"name"=>"from acquisition and retirement",
|
730
|
+
"process"=>{},
|
731
|
+
"supplements"=>[],
|
732
|
+
"compliance"=>[],
|
733
|
+
"requirements"=>["acquisition", "retirement"]}},
|
734
|
+
{"conclusion"=>Sat, 01 Jan 2011,
|
735
|
+
"committee"=>
|
736
|
+
{"name"=>"retirement",
|
737
|
+
"quorums"=>
|
738
|
+
[{"name"=>"from acquisition",
|
739
|
+
"process"=>{},
|
740
|
+
"supplements"=>["acquisition"],
|
741
|
+
"compliance"=>[],
|
742
|
+
"requirements"=>[]}]},
|
743
|
+
"quorum"=>
|
744
|
+
{"name"=>"from acquisition",
|
745
|
+
"process"=>{},
|
746
|
+
"supplements"=>["acquisition"],
|
747
|
+
"compliance"=>[],
|
748
|
+
"requirements"=>[]}}],
|
749
|
+
"fuel_efficiency"=>8.50287,
|
750
|
+
"distance"=>24140.2}
|
751
|
+
|
752
|
+
An easier way to look is using the {JSONView add-on}[https://addons.mozilla.org/en-US/firefox/addon/10869/] for Firefox. Just take the methodology URL:
|
753
|
+
|
754
|
+
"methodology"=>
|
755
|
+
"http://carbon.brighterplanet.com/automobiles.html?acquisition=2009-07-01&annual_distance_estimate=24140.2&fuel_efficiency=8.50287&fuel_type=R&key=3fca1403c1a561769a78ba462390ff01&make=Ford&size_class=Midsize+Pickup&timeframe=2010-01-01%2F2011-01-01",
|
756
|
+
|
757
|
+
...and say you want JSON instead of HTML...
|
758
|
+
|
759
|
+
http://carbon.brighterplanet.com/automobiles.html?acquisition=2009-07-01&annual_distance_estimate=24140.2&fuel_efficiency=8.50287&fuel_type=R&key=3fca1403c1a561769a78ba462390ff01&make=Ford&size_class=Midsize+Pickup&timeframe=2010-01-01%2F2011-01-01
|
760
|
+
|
|
761
|
+
change this
|
762
|
+
|
|
763
|
+
http://carbon.brighterplanet.com/automobiles.json?acquisition=2009-07-01&annual_distance_estimate=24140.2&fuel_efficiency=8.50287&fuel_type=R&key=3fca1403c1a561769a78ba462390ff01&make=Ford&size_class=Midsize+Pickup&timeframe=2010-01-01%2F2011-01-01
|
764
|
+
|
765
|
+
...and look what we found!
|
766
|
+
|
767
|
+
link:../doc/examining-response-with-jsonview.png
|
768
|
+
|
769
|
+
As you can see, the byproducts (really the internal variables) of the calculation are sent along with the response. Your legacy app may never use these values, but we do! We clarified things with a few helper methods:
|
770
|
+
|
771
|
+
diff --git a/app/models/emitter.rb b/app/models/emitter.rb
|
772
|
+
index 93971b7..c5d5709 100644
|
773
|
+
--- a/app/models/emitter.rb
|
774
|
+
+++ b/app/models/emitter.rb
|
775
|
+
@@ -5,6 +5,35 @@ class Emitter < ActiveRecord::Base
|
776
|
+
respond_to? :emission_estimate
|
777
|
+
end
|
778
|
+
|
779
|
+
+ def real_or_assumed_characteristic_value(key)
|
780
|
+
+ return characteristics[key] if characteristics.has_key? key
|
781
|
+
+ if outsourced?
|
782
|
+
+ emission_estimate.response.data[key.to_s]
|
783
|
+
+ else
|
784
|
+
+ committee_reports[key]
|
785
|
+
+ end
|
786
|
+
+ end
|
787
|
+
+
|
788
|
+
+ def assumed_characteristic_value?(key)
|
789
|
+
+ if outsourced?
|
790
|
+
+ emission_estimate.response.data.keys.include? key.to_s
|
791
|
+
+ else
|
792
|
+
+ committee_reports.keys.include? key
|
793
|
+
+ end
|
794
|
+
+ end
|
795
|
+
+
|
796
|
+
+ def reporting_committee_name(key)
|
797
|
+
+ if outsourced?
|
798
|
+
+ begin
|
799
|
+
+ emission_estimate.response.data['reports'].detect { |i| i['committee']['name'] == key.to_s }['quorum']['name']
|
800
|
+
+ rescue NoMethodError
|
801
|
+
+ # couldn't find it
|
802
|
+
+ end
|
803
|
+
+ else
|
804
|
+
+ self.class.characterization.committees[key].called_quorum.name
|
805
|
+
+ end.to_s.dasherize.downcase
|
806
|
+
+ end
|
807
|
+
+
|
808
|
+
self.abstract_class = true
|
809
|
+
|
810
|
+
extend ActiveSupport::Memoizable if Switches.memoization?
|
811
|
+
@@ -54,6 +83,8 @@ class Emitter < ActiveRecord::Base
|
812
|
+
value = options[:value]
|
813
|
+
elsif characteristics.has_key?(name)
|
814
|
+
value = characteristics[name]
|
815
|
+
+ elsif outsourced? and emission_estimate.response.data.has_key? name.to_s
|
816
|
+
+ value = emission_estimate.response.data[name.to_s]
|
817
|
+
elsif committee_reports.has_key?(name)
|
818
|
+
value = committee_reports[name]
|
819
|
+
else
|
820
|
+
@@ -314,7 +345,7 @@ class Emitter < ActiveRecord::Base
|
821
|
+
timeframe.include? emission_date
|
822
|
+
elsif self.class.characterization.characteristics.include? :active_subtimeframe
|
823
|
+
if outsourced?
|
824
|
+
- timeframe & emission_estimate(:timeframe => timeframe).active_subtimeframe
|
825
|
+
+ timeframe & emission_estimate(:timeframe => timeframe).response.data['active_subtimeframe']
|
826
|
+
else
|
827
|
+
timeframe & committee_reports[:active_subtimeframe]
|
828
|
+
end
|
829
|
+
|
830
|
+
Then we brought the internal variables back to life:
|
831
|
+
|
832
|
+
diff --git a/app/helpers/emitters_helper.rb b/app/helpers/emitters_helper.rb
|
833
|
+
index c1b75ee..b5c3a1c 100755
|
834
|
+
--- a/app/helpers/emitters_helper.rb
|
835
|
+
+++ b/app/helpers/emitters_helper.rb
|
836
|
+
@@ -3,7 +3,7 @@
|
837
|
+
|
838
|
+
module EmittersHelper
|
839
|
+
def render_characteristic(emitter, characteristic)
|
840
|
+
- characteristic_value = (emitter.outsourced? or emitter.characteristics.has_key?(characteristic)) ? emitter.characteristics[characteristic] : emitter.committee_reports[characteristic]
|
841
|
+
+ characteristic_value = emitter.real_or_assumed_characteristic_value(characteristic)
|
842
|
+
locals = { :emitter => emitter, :characteristic => characteristic, characteristic => characteristic_value }
|
843
|
+
|
844
|
+
begin
|
845
|
+
@@ -14,7 +14,7 @@ module EmittersHelper
|
846
|
+
end
|
847
|
+
|
848
|
+
def render_edit_characteristic(emitter, characteristic)
|
849
|
+
- characteristic_value = (emitter.outsourced? or emitter.characteristics.has_key?(characteristic)) ? emitter.characteristics[characteristic] : emitter.committee_reports[characteristic]
|
850
|
+
+ characteristic_value = emitter.real_or_assumed_characteristic_value(characteristic)
|
851
|
+
locals = { :emitter => emitter, :characteristic => characteristic, characteristic => characteristic_value }
|
852
|
+
template = pick_edit_partial(emitter, characteristic)
|
853
|
+
if template == 'characteristics/controls/collection_select'
|
854
|
+
@@ -80,7 +80,7 @@ module EmittersHelper
|
855
|
+
end
|
856
|
+
|
857
|
+
def render_placeholder_characteristic(emitter, characteristic)
|
858
|
+
- characteristic_value = (emitter.outsourced? or emitter.characteristics.has_key?(characteristic)) ? emitter.characteristics[characteristic] : emitter.committee_reports[characteristic]
|
859
|
+
+ characteristic_value = emitter.real_or_assumed_characteristic_value(characteristic)
|
860
|
+
locals = { :emitter => emitter, :characteristic => characteristic, characteristic => characteristic_value }
|
861
|
+
render :partial => "#{emitter.common_plural}/#{characteristic}/placeholder", :layout => 'characteristics/layouts/placeholder', :locals => locals
|
862
|
+
rescue ActionView::MissingTemplate
|
863
|
+
diff --git a/app/views/characteristics/_characteristic.html.erb b/app/views/characteristics/_characteristic.html.erb
|
864
|
+
index c08003d..b9bb073 100644
|
865
|
+
--- a/app/views/characteristics/_characteristic.html.erb
|
866
|
+
+++ b/app/views/characteristics/_characteristic.html.erb
|
867
|
+
@@ -1,7 +1,7 @@
|
868
|
+
<%
|
869
|
+
known = !(known == false)
|
870
|
+
expanded = (expanded == true)
|
871
|
+
-reported = !emitter.outsourced? and emitter.committee_reports.keys.include? characteristic # this should never happen if known
|
872
|
+
+reported = emitter.assumed_characteristic_value? characteristic # this should never happen if known
|
873
|
+
element_class = [characteristic]
|
874
|
+
element_class << 'reported' if reported
|
875
|
+
element_class << 'next' if expanded
|
876
|
+
@@ -16,7 +16,7 @@ element_class = element_class.join ' '
|
877
|
+
<%= render_edit_characteristic emitter, characteristic if expanded %>
|
878
|
+
<%= render_help_for_characteristic(emitter.common_symbol, characteristic) if expanded %>
|
879
|
+
<% if reported %>
|
880
|
+
- <span class="assumption">Assuming <%= render_characteristic emitter, characteristic %><span class="method"> via the <i><%= emitter.class.characterization.committees[characteristic].called_quorum.name.to_s.dasherize %></i> method</span></span>
|
881
|
+
+ <span class="assumption">Assuming <%= render_characteristic emitter, characteristic %><span class="method"> via the <i><%= emitter.reporting_committee_name(characteristic) %></i> method</span></span>
|
882
|
+
<% end %>
|
883
|
+
<% end %>
|
884
|
+
</dd>
|
885
|
+
diff --git a/app/views/components/_gaps.html.erb b/app/views/components/_gaps.html.erb
|
886
|
+
index 203d261..4e0fa04 100644
|
887
|
+
--- a/app/views/components/_gaps.html.erb
|
888
|
+
+++ b/app/views/components/_gaps.html.erb
|
889
|
+
@@ -1,5 +1,5 @@
|
890
|
+
<% if component.tense == :imperfect %>
|
891
|
+
- <% covered_timeframes = component.emitters.values.flatten.collect { |e| e.outsourced? ? nil : e.committee_reports(timeframe)[:active_subtimeframe] } %>
|
892
|
+
+ <% covered_timeframes = component.emitters.values.flatten.collect { |e| e.real_or_assumed_characteristic_value :active_subtimeframe } %>
|
893
|
+
<% unless timeframe.covered_by? *covered_timeframes %>
|
894
|
+
<% gaps = timeframe.gaps_left_by(*covered_timeframes) %>
|
895
|
+
<p><strong>Note:</strong> you haven't told us about any <%= component.class.component_name %> emissions during <%= gaps.to_sentence %>. If you <%= component.verb[:past] %> <%= component.class.component_name.pluralize %> during these times, please tell us about it.</p>
|
896
|
+
|
897
|
+
=== Comments on step 3
|
898
|
+
|
899
|
+
* A lot of data comes back from the emission estimate web service. You can inspect it by grabbing the methodology URL and changing it to JSON.
|
900
|
+
|
901
|
+
* We realized that the "perspective" argument was mostly for caching. We don't need it anymore because the expensive computations are outsourced!
|
902
|
+
|
903
|
+
== Step 4: Prepare for network problems (WORKING DRAFT)
|
904
|
+
|
905
|
+
If you've decided that the data returned by the Brighter Planet emission estimate web service is sufficient for your needs, it's time to deal with network problems.
|
906
|
+
|
907
|
+
link:../doc/timeout-error.png
|
908
|
+
|
909
|
+
You don't want your application to go offline if there is a network problem between carbon middleware and you. Using the carbon gem, that means rescuing from exceptions.
|
910
|
+
|
911
|
+
It's easy to fake a simple problem by adding this to <tt>/etc/hosts</tt>: (remember to take it out later)
|
912
|
+
|
913
|
+
10.0.22.22 carbon.brighterplanet.com
|
914
|
+
|
915
|
+
Now everything will time out:
|
916
|
+
|
917
|
+
>> a = Automobile.find 710
|
918
|
+
=> #<Automobile [...] >
|
919
|
+
>> a.emission_estimate.to_f
|
920
|
+
Errno::ETIMEDOUT: Connection timed out - connect(2)
|
921
|
+
from /usr/lib/ruby/1.8/net/http.rb:560:in `initialize'
|
922
|
+
from /usr/lib/ruby/1.8/net/http.rb:560:in `open'
|
923
|
+
from /usr/lib/ruby/1.8/net/http.rb:560:in `connect'
|
924
|
+
from /usr/lib/ruby/1.8/timeout.rb:53:in `timeout'
|
925
|
+
from /usr/lib/ruby/1.8/timeout.rb:93:in `timeout'
|
926
|
+
from /usr/lib/ruby/1.8/net/http.rb:560:in `connect'
|
927
|
+
from /usr/lib/ruby/1.8/net/http.rb:553:in `do_start'
|
928
|
+
from /usr/lib/ruby/1.8/net/http.rb:542:in `start'
|
929
|
+
from /usr/lib/ruby/gems/1.8/gems/nap-0.4/lib/rest/request.rb:133:in `perform'
|
930
|
+
from /usr/lib/ruby/gems/1.8/gems/carbon-0.2.4/lib/carbon/emission_estimate/response.rb:43:in `perform'
|
931
|
+
from /usr/lib/ruby/gems/1.8/gems/carbon-0.2.4/lib/carbon/emission_estimate/response.rb:16:in `load_realtime_data'
|
932
|
+
from /usr/lib/ruby/gems/1.8/gems/carbon-0.2.4/lib/carbon/emission_estimate/response.rb:11:in `send'
|
933
|
+
from /usr/lib/ruby/gems/1.8/gems/carbon-0.2.4/lib/carbon/emission_estimate/response.rb:11:in `initialize'
|
934
|
+
from /usr/lib/ruby/gems/1.8/gems/carbon-0.2.4/lib/carbon/emission_estimate.rb:66:in `new'
|
935
|
+
from /usr/lib/ruby/gems/1.8/gems/carbon-0.2.4/lib/carbon/emission_estimate.rb:66:in `response'
|
936
|
+
from /usr/lib/ruby/gems/1.8/gems/carbon-0.2.4/lib/carbon/emission_estimate.rb:41:in `method_missing'
|
937
|
+
from (irb):5>>
|
938
|
+
|
939
|
+
Here's an idea:
|
940
|
+
|
941
|
+
diff --git a/app/views/emitters/_sidebar.html.erb b/app/views/emitters/_sidebar.html.erb
|
942
|
+
index 2da2214..9190387 100644
|
943
|
+
--- a/app/views/emitters/_sidebar.html.erb
|
944
|
+
+++ b/app/views/emitters/_sidebar.html.erb
|
945
|
+
@@ -6,7 +6,9 @@
|
946
|
+
<%= render :partial => 'carbon_offsets/emitter', :locals => { :emitter => emitter, :timeframe => timeframe, :show_purchasing => true, :show_granting => true } %>
|
947
|
+
<% if emitter.outsourced? %>
|
948
|
+
<p class="committee_reports">
|
949
|
+
- <%= link_to 'Show calculation methods', emitter.emission_estimate.methodology %>
|
950
|
+
+ <% outsourced_content do %>
|
951
|
+
+ <%= link_to 'Show calculation methods', emitter.emission_estimate.methodology %>
|
952
|
+
+ <% end %>
|
953
|
+
</p>
|
954
|
+
<% else %>
|
955
|
+
<p class="committee_reports">
|
956
|
+
diff --git a/app/helpers/emitters_helper.rb b/app/helpers/emitters_helper.rb
|
957
|
+
index c1b75ee..bd0c78f 100755
|
958
|
+
--- a/app/helpers/emitters_helper.rb
|
959
|
+
+++ b/app/helpers/emitters_helper.rb
|
960
|
+
@@ -2,8 +2,47 @@
|
961
|
+
# doc/partials_that_use_local_variables_named_after_characteristics.rb
|
962
|
+
|
963
|
+
module EmittersHelper
|
964
|
+
+ def outsourced_content(failsafe = '', &block)
|
965
|
+
+ failed = request.instance_variable_get :@outsourced_request_failed
|
966
|
+
+ str = failed ? failsafe : capture(&block)
|
967
|
+
+ if block_called_from_erb? block
|
968
|
+
+ # sabshere 7/28/10 use of #concat is specific to Rails 2, I believe
|
969
|
+
+ concat str
|
970
|
+
+ else
|
971
|
+
+ str
|
972
|
+
+ end
|
973
|
+
+ rescue ::SocketError, ::Timeout::Error, ::Errno::ETIMEDOUT, ::Errno::ENETUNREACH, ::Errno::ECONNRESET, ::Errno::ECONNREFUSED
|
974
|
+
+ # These are general network errors raised by Net::HTTP.
|
975
|
+
+ # Your internet connection might be down, or our servers might be down.
|
976
|
+
+ request.instance_variable_set :@outsourced_request_failed, true
|
977
|
+
+ retry
|
978
|
+
+ rescue ::Carbon::RateLimited
|
979
|
+
+ # Realtime mode only.
|
980
|
+
+ # In order to prevent denial-of-service attacks, our servers rate limit requests.
|
981
|
+
+ # The gem will try up to three times to get an answer back from the server, waiting slightly longer each time.
|
982
|
+
+ # If you still get this exception, please contact us at staff@brighterplanet.com and we'll lift your rate.
|
983
|
+
+ request.instance_variable_set :@outsourced_request_failed, true
|
984
|
+
+ retry
|
985
|
+
+ rescue ::Carbon::RealtimeEstimateFailed
|
986
|
+
+ # Realtime mode only.
|
987
|
+
+ # Our server returned a 4XX or 5XX error.
|
988
|
+
+ # Please contact us at staff@brighterplanet.com if you get these more than a couple times.
|
989
|
+
+ retry
|
990
|
+
+ rescue ::Carbon::QueueingFailed
|
991
|
+
+ # Async mode only.
|
992
|
+
+ # The gem connects directly to Amazon SQS in order to provide maximum throughput. If that service returns anything other than success, you get this exception.
|
993
|
+
+ # Please contact us at staff@brighterplanet.com if you see too many of these.
|
994
|
+
+ request.instance_variable_set :@outsourced_request_failed, true
|
995
|
+
+ retry
|
996
|
+
+ end
|
997
|
+
|
998
|
+
=== Comments on step 4
|
999
|
+
|
1000
|
+
* This is a very Rails-specific solution. It might not be as easy in your language of choice.
|
1001
|
+
|
1002
|
+
* Even if this is easy, it has to go in a lot of places in our app. Maybe we should proxy the response object (::Carbon::EmissionEstimate) and add useful methods there?
|