carbon 0.2.4 → 0.2.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/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
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
data/lib/carbon.rb
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
require 'uri'
|
|
2
2
|
require 'blockenspiel'
|
|
3
|
-
require 'rest' # provided by nap gem
|
|
4
3
|
require 'timeframe'
|
|
4
|
+
require 'digest/sha1'
|
|
5
|
+
require 'rest' # provided by nap gem
|
|
6
|
+
gem 'SystemTimer' # >=1.2, so as not to be confused with system_timer 1.0
|
|
7
|
+
require 'system_timer'
|
|
5
8
|
require 'active_support/version'
|
|
6
9
|
%w{
|
|
7
10
|
active_support/core_ext/module/attribute_accessors
|
|
@@ -44,6 +47,7 @@ module Carbon
|
|
|
44
47
|
|
|
45
48
|
REALTIME_URL = 'http://carbon.brighterplanet.com'
|
|
46
49
|
ASYNC_URL = 'https://queue.amazonaws.com/121562143717/cm1_production_incoming'
|
|
50
|
+
STORAGE_URL = 'http://storage.carbon.brighterplanet.com'
|
|
47
51
|
|
|
48
52
|
class RealtimeEstimateFailed < RuntimeError # :nodoc:
|
|
49
53
|
end
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
require 'carbon/emission_estimate/response'
|
|
2
2
|
require 'carbon/emission_estimate/request'
|
|
3
|
+
require 'carbon/emission_estimate/storage'
|
|
3
4
|
|
|
4
5
|
module Carbon
|
|
5
6
|
# Let's start off by saying that realtime <tt>EmissionEstimate</tt> objects quack like numbers.
|
|
@@ -10,11 +11,18 @@ module Carbon
|
|
|
10
11
|
#
|
|
11
12
|
# At the same time, they contain all the data you get back from the emission estimate web service. For example, you could say <tt>puts my_donut_factor.emission_estimate.oven_count</tt> (see the tests) and you'd get back the oven count used in the calculation, if any.
|
|
12
13
|
class EmissionEstimate
|
|
14
|
+
def self.parse(str)
|
|
15
|
+
data = ::ActiveSupport::JSON.decode str
|
|
16
|
+
data['active_subtimeframe'] = ::Timeframe.interval(data['active_subtimeframe']) if data.has_key? 'active_subtimeframe'
|
|
17
|
+
data['updated_at'] = ::Time.parse(data['updated_at']) if data.has_key? 'updated_at'
|
|
18
|
+
data
|
|
19
|
+
end
|
|
20
|
+
|
|
13
21
|
def initialize(emitter)
|
|
14
22
|
@emitter = emitter
|
|
15
23
|
end
|
|
16
24
|
|
|
17
|
-
VALID_OPTIONS = [:callback_content_type, :key, :callback, :timeframe]
|
|
25
|
+
VALID_OPTIONS = [:callback_content_type, :key, :callback, :timeframe, :guid, :timeout, :defer]
|
|
18
26
|
def take_options(options)
|
|
19
27
|
return if options.blank?
|
|
20
28
|
options.slice(*VALID_OPTIONS).each do |k, v|
|
|
@@ -25,7 +33,7 @@ module Carbon
|
|
|
25
33
|
# I can be compared directly to a number, unless I'm an async request.
|
|
26
34
|
def ==(other)
|
|
27
35
|
if other.is_a? ::Numeric and mode == :realtime
|
|
28
|
-
other ==
|
|
36
|
+
other == number
|
|
29
37
|
else
|
|
30
38
|
super
|
|
31
39
|
end
|
|
@@ -38,23 +46,35 @@ module Carbon
|
|
|
38
46
|
# > my_car.emission_estimate.model
|
|
39
47
|
# => 'Ford Taurus'
|
|
40
48
|
def method_missing(method_id, *args, &blk)
|
|
41
|
-
if !block_given? and args.empty? and
|
|
42
|
-
|
|
49
|
+
if !block_given? and args.empty? and data.has_key? method_id.to_s
|
|
50
|
+
data[method_id.to_s]
|
|
43
51
|
elsif ::Float.method_defined? method_id
|
|
44
52
|
raise TriedToUseAsyncResponseAsNumber if mode == :async
|
|
45
|
-
|
|
53
|
+
number.send method_id, *args, &blk
|
|
46
54
|
else
|
|
47
55
|
super
|
|
48
56
|
end
|
|
49
57
|
end
|
|
50
|
-
|
|
51
58
|
attr_writer :callback_content_type
|
|
52
59
|
attr_writer :key
|
|
53
|
-
|
|
60
|
+
attr_writer :timeout
|
|
61
|
+
attr_writer :defer
|
|
54
62
|
attr_accessor :callback
|
|
55
63
|
attr_accessor :timeframe
|
|
56
|
-
|
|
64
|
+
attr_accessor :guid
|
|
57
65
|
attr_reader :emitter
|
|
66
|
+
def data
|
|
67
|
+
if storage.present?
|
|
68
|
+
storage.data
|
|
69
|
+
else
|
|
70
|
+
response.data
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
def storage
|
|
74
|
+
@storage ||= {}
|
|
75
|
+
return @storage[guid] if @storage.has_key? guid
|
|
76
|
+
@storage[guid] = Storage.new self
|
|
77
|
+
end
|
|
58
78
|
def request
|
|
59
79
|
@request ||= Request.new self
|
|
60
80
|
end
|
|
@@ -65,8 +85,18 @@ module Carbon
|
|
|
65
85
|
return @response[current_params] if @response.has_key? current_params
|
|
66
86
|
@response[current_params] = Response.new self
|
|
67
87
|
end
|
|
88
|
+
def defer?
|
|
89
|
+
@defer == true
|
|
90
|
+
end
|
|
91
|
+
def async?
|
|
92
|
+
callback or defer?
|
|
93
|
+
end
|
|
68
94
|
def mode
|
|
69
|
-
|
|
95
|
+
async? ? :async : :realtime
|
|
96
|
+
end
|
|
97
|
+
# Timeout on realtime requests in seconds, if desired.
|
|
98
|
+
def timeout
|
|
99
|
+
@timeout
|
|
70
100
|
end
|
|
71
101
|
def callback_content_type
|
|
72
102
|
@callback_content_type || 'application/json'
|
|
@@ -76,27 +106,27 @@ module Carbon
|
|
|
76
106
|
end
|
|
77
107
|
# The timeframe being looked at in the emission calculation.
|
|
78
108
|
def active_subtimeframe
|
|
79
|
-
|
|
109
|
+
data['active_subtimeframe']
|
|
80
110
|
end
|
|
81
111
|
# Another way to access the emission value.
|
|
82
112
|
# Useful if you don't like treating <tt>EmissionEstimate</tt> objects like <tt>Numeric</tt> objects (even though they do quack like numbers...)
|
|
83
|
-
def
|
|
84
|
-
|
|
113
|
+
def number
|
|
114
|
+
async? ? nil : data['emission'].to_f.freeze
|
|
85
115
|
end
|
|
86
116
|
# The units of the emission.
|
|
87
117
|
def emission_units
|
|
88
|
-
|
|
118
|
+
data['emission_units']
|
|
89
119
|
end
|
|
90
120
|
# Errors (and warnings) as reported in the response.
|
|
91
121
|
# Note: may contain HTML tags like KBD or A
|
|
92
122
|
def errors
|
|
93
|
-
|
|
123
|
+
data['errors']
|
|
94
124
|
end
|
|
95
125
|
# The URL of the methodology report indicating how this estimate was calculated.
|
|
96
126
|
# > my_car.emission_estimate.methodology
|
|
97
127
|
# => 'http://carbon.brighterplanet.com/automobiles.html?[...]'
|
|
98
128
|
def methodology
|
|
99
|
-
|
|
129
|
+
data['methodology']
|
|
100
130
|
end
|
|
101
131
|
end
|
|
102
132
|
end
|
|
@@ -12,10 +12,13 @@ module Carbon
|
|
|
12
12
|
send "#{parent.mode}_params"
|
|
13
13
|
end
|
|
14
14
|
def async_params # :nodoc:
|
|
15
|
+
raise ::ArgumentError, "When using :callback you cannot specify :defer" if parent.defer? and parent.callback
|
|
16
|
+
raise ::ArgumentError, "When using :defer => true you must specify :guid" if parent.defer? and parent.guid.blank?
|
|
15
17
|
hash = _params
|
|
16
18
|
hash[:emitter] = parent.emitter.class.carbon_base.emitter_common_name
|
|
17
|
-
hash[:callback] = parent.callback
|
|
18
|
-
hash[:callback_content_type] = parent.callback_content_type
|
|
19
|
+
hash[:callback] = parent.callback if parent.callback
|
|
20
|
+
hash[:callback_content_type] = parent.callback_content_type if parent.callback
|
|
21
|
+
hash[:guid] = parent.guid if parent.defer?
|
|
19
22
|
{
|
|
20
23
|
:Action => 'SendMessage',
|
|
21
24
|
:Version => '2009-02-01',
|
|
@@ -3,7 +3,6 @@ module Carbon
|
|
|
3
3
|
class Response
|
|
4
4
|
attr_reader :parent
|
|
5
5
|
attr_reader :data
|
|
6
|
-
attr_reader :number
|
|
7
6
|
attr_reader :raw_request
|
|
8
7
|
attr_reader :raw_response
|
|
9
8
|
def initialize(parent)
|
|
@@ -12,6 +11,7 @@ module Carbon
|
|
|
12
11
|
end
|
|
13
12
|
def load_realtime_data # :nodoc:
|
|
14
13
|
attempts = 0
|
|
14
|
+
response = nil
|
|
15
15
|
begin
|
|
16
16
|
response = perform
|
|
17
17
|
raise ::Carbon::RateLimited if response.status_code == 403 and response.body =~ /Rate Limit/i
|
|
@@ -21,26 +21,31 @@ module Carbon
|
|
|
21
21
|
sleep 0.2 * attempts
|
|
22
22
|
retry
|
|
23
23
|
else
|
|
24
|
-
raise
|
|
24
|
+
raise $!
|
|
25
25
|
end
|
|
26
26
|
end
|
|
27
27
|
raise ::Carbon::RealtimeEstimateFailed unless response.success?
|
|
28
|
-
@data = ::
|
|
29
|
-
instantiate_known_response_objects
|
|
30
|
-
@number = data['emission'].to_f.freeze
|
|
31
|
-
end
|
|
32
|
-
def instantiate_known_response_objects # :nodoc:
|
|
33
|
-
data['active_subtimeframe'] = ::Timeframe.interval(data['active_subtimeframe']) if data.has_key? 'active_subtimeframe'
|
|
28
|
+
@data = ::Carbon::EmissionEstimate.parse response.body
|
|
34
29
|
end
|
|
35
30
|
def load_async_data # :nodoc:
|
|
36
31
|
response = perform
|
|
37
32
|
raise ::Carbon::QueueingFailed unless response.success?
|
|
38
33
|
@data = {}
|
|
39
|
-
@number = nil
|
|
40
34
|
end
|
|
41
35
|
def perform # :nodoc:
|
|
36
|
+
response = nil
|
|
37
|
+
if parent.timeout
|
|
38
|
+
::SystemTimer.timeout_after(parent.timeout) do
|
|
39
|
+
response = _perform
|
|
40
|
+
end
|
|
41
|
+
else
|
|
42
|
+
response = _perform
|
|
43
|
+
end
|
|
44
|
+
response
|
|
45
|
+
end
|
|
46
|
+
def _perform # :nodoc:
|
|
42
47
|
@raw_request = ::REST::Request.new :post, ::URI.parse(parent.request.url), parent.request.body, {'Content-Type' => 'application/x-www-form-urlencoded; charset=utf-8'}
|
|
43
|
-
@raw_response =
|
|
48
|
+
@raw_response = raw_request.perform
|
|
44
49
|
end
|
|
45
50
|
end
|
|
46
51
|
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
module Carbon
|
|
2
|
+
class EmissionEstimate
|
|
3
|
+
class Storage
|
|
4
|
+
attr_accessor :parent
|
|
5
|
+
attr_reader :raw_request
|
|
6
|
+
attr_reader :raw_response
|
|
7
|
+
def initialize(parent)
|
|
8
|
+
@parent = parent
|
|
9
|
+
end
|
|
10
|
+
def url
|
|
11
|
+
"#{::Carbon::STORAGE_URL}/#{::Digest::SHA1.hexdigest(parent.key+parent.guid)}"
|
|
12
|
+
end
|
|
13
|
+
def present?
|
|
14
|
+
parent.guid.present? and data.present?
|
|
15
|
+
end
|
|
16
|
+
def data
|
|
17
|
+
return @data[0] if @data.is_a? ::Array
|
|
18
|
+
@raw_request = ::REST::Request.new :get, ::URI.parse(url)
|
|
19
|
+
@raw_response = raw_request.perform
|
|
20
|
+
if raw_response.success?
|
|
21
|
+
@data = [::Carbon::EmissionEstimate.parse(raw_response.body)]
|
|
22
|
+
else
|
|
23
|
+
@data = []
|
|
24
|
+
end
|
|
25
|
+
@data[0]
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
data/spec/lib/carbon_spec.rb
CHANGED
|
@@ -1,6 +1,85 @@
|
|
|
1
1
|
require 'spec_helper'
|
|
2
|
+
require 'active_support/json/encoding'
|
|
3
|
+
require 'fakeweb'
|
|
2
4
|
|
|
3
5
|
CALLBACK_URL = 'http://www.postbin.org/1dj0146'
|
|
6
|
+
KEY = 'valid'
|
|
7
|
+
EXISTING_UNIQUE_ID = 'oisjoaioijodijaosijdoias'
|
|
8
|
+
MISSING_UNIQUE_ID = 'd09joijdoijaloijdoais'
|
|
9
|
+
OTHER_UNIQUE_ID = '1092fjoid;oijsao;ga'
|
|
10
|
+
|
|
11
|
+
FakeWeb.register_uri :post,
|
|
12
|
+
/carbon.brighterplanet.com.automobiles/,
|
|
13
|
+
:status => ["200", "OK"],
|
|
14
|
+
:body => {
|
|
15
|
+
'emission' => '134.599',
|
|
16
|
+
'emission_units' => 'kilograms',
|
|
17
|
+
'methodology' => 'http://carbon.brighterplanet.com/something',
|
|
18
|
+
'active_subtimeframe' => Timeframe.new(:year => 2008)
|
|
19
|
+
}.to_json
|
|
20
|
+
#
|
|
21
|
+
FakeWeb.register_uri :post,
|
|
22
|
+
/carbon.brighterplanet.com.factories/,
|
|
23
|
+
:status => ["200", "OK"],
|
|
24
|
+
:body => {
|
|
25
|
+
'emission' => 1000.0,
|
|
26
|
+
'emission_units' => 'kilograms',
|
|
27
|
+
'methodology' => 'http://carbon.brighterplanet.com/something',
|
|
28
|
+
'active_subtimeframe' => Timeframe.new(:year => 2008)
|
|
29
|
+
}.to_json
|
|
30
|
+
#
|
|
31
|
+
FakeWeb.register_uri :post,
|
|
32
|
+
/queue.amazonaws.com/,
|
|
33
|
+
:status => ["200", "OK"],
|
|
34
|
+
:body => 'You would see an amazon aws response'
|
|
35
|
+
# yep, it's stored!
|
|
36
|
+
FakeWeb.register_uri :get,
|
|
37
|
+
"http://storage.carbon.brighterplanet.com/#{Digest::SHA1.hexdigest(KEY+EXISTING_UNIQUE_ID)}",
|
|
38
|
+
:status => ["200", "OK"],
|
|
39
|
+
:body => {
|
|
40
|
+
'emission' => 1234,
|
|
41
|
+
'emission_units' => 'kilograms',
|
|
42
|
+
'methodology' => 'http://carbon.brighterplanet.com/something',
|
|
43
|
+
'updated_at' => Time.now.as_json
|
|
44
|
+
}.to_json
|
|
45
|
+
#
|
|
46
|
+
FakeWeb.register_uri :get,
|
|
47
|
+
"http://storage.carbon.brighterplanet.com/#{Digest::SHA1.hexdigest(KEY+OTHER_UNIQUE_ID)}",
|
|
48
|
+
:status => ["200", "OK"],
|
|
49
|
+
:body => {
|
|
50
|
+
'emission' => 99982,
|
|
51
|
+
'emission_units' => 'kilograms',
|
|
52
|
+
'methodology' => 'http://carbon.brighterplanet.com/something',
|
|
53
|
+
'updated_at' => Time.now.as_json
|
|
54
|
+
}.to_json
|
|
55
|
+
#
|
|
56
|
+
FakeWeb.register_uri :get,
|
|
57
|
+
"http://storage.carbon.brighterplanet.com/#{Digest::SHA1.hexdigest(KEY+MISSING_UNIQUE_ID)}",
|
|
58
|
+
[
|
|
59
|
+
{
|
|
60
|
+
:status => ["404", "Not Found"],
|
|
61
|
+
:body => "It's not here, you better ask carbon for it!"
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
:status => ["200", "OK"],
|
|
65
|
+
:body => {
|
|
66
|
+
'emission' => 9876,
|
|
67
|
+
'emission_units' => 'kilograms',
|
|
68
|
+
'methodology' => 'http://carbon.brighterplanet.com/something',
|
|
69
|
+
'updated_at' => Time.now.as_json
|
|
70
|
+
}.to_json
|
|
71
|
+
}
|
|
72
|
+
]
|
|
73
|
+
#
|
|
74
|
+
# FakeWeb.register_uri :post,
|
|
75
|
+
# /carbon.brighterplanet.com.*#{MISSING_UNIQUE_ID}/,
|
|
76
|
+
# :status => ["302", "Moved Permanently"],
|
|
77
|
+
# :body => {
|
|
78
|
+
# 'emission' => 9876,
|
|
79
|
+
# 'emission_units' => 'kilograms',
|
|
80
|
+
# 'methodology' => 'http://carbon.brighterplanet.com/something'
|
|
81
|
+
# }.to_json,
|
|
82
|
+
# :headers => { 'Location' => "http://storage.carbon.brighterplanet.com/#{Digest::SHA1.hexdigest(KEY+MISSING_UNIQUE_ID)}" }
|
|
4
83
|
|
|
5
84
|
class RentalCar
|
|
6
85
|
include Carbon
|
|
@@ -45,9 +124,24 @@ class DonutFactory
|
|
|
45
124
|
end
|
|
46
125
|
end
|
|
47
126
|
|
|
127
|
+
# set up timeouts
|
|
128
|
+
module Carbon
|
|
129
|
+
class EmissionEstimate
|
|
130
|
+
attr_accessor :sleep_before_performing
|
|
131
|
+
VALID_OPTIONS.push :sleep_before_performing
|
|
132
|
+
class Response
|
|
133
|
+
def _perform_with_delay
|
|
134
|
+
sleep parent.sleep_before_performing if parent.sleep_before_performing
|
|
135
|
+
_perform_without_delay
|
|
136
|
+
end
|
|
137
|
+
alias_method_chain :_perform, :delay
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
|
|
48
142
|
describe Carbon do
|
|
49
143
|
before(:each) do
|
|
50
|
-
Carbon.key =
|
|
144
|
+
Carbon.key = KEY
|
|
51
145
|
end
|
|
52
146
|
|
|
53
147
|
it 'should be simple to use' do
|
|
@@ -104,6 +198,52 @@ describe Carbon do
|
|
|
104
198
|
end
|
|
105
199
|
end
|
|
106
200
|
|
|
201
|
+
describe 'requests that can be stored (cached) by guid' do
|
|
202
|
+
it 'should find existing unique ids on S3' do
|
|
203
|
+
d = DonutFactory.new
|
|
204
|
+
d.emission_estimate(:guid => EXISTING_UNIQUE_ID).should == 1234
|
|
205
|
+
d.emission_estimate(:guid => EXISTING_UNIQUE_ID).updated_at.should be_instance_of(Time)
|
|
206
|
+
end
|
|
207
|
+
it "should pass through to realtime if unique id isn't found on S3" do
|
|
208
|
+
d = DonutFactory.new
|
|
209
|
+
d.emission_estimate(:guid => MISSING_UNIQUE_ID).should == 1000
|
|
210
|
+
d.emission_estimate(:guid => MISSING_UNIQUE_ID).response.data.keys.should_not include('updated_at')
|
|
211
|
+
d1 = DonutFactory.new
|
|
212
|
+
d1.emission_estimate(:guid => MISSING_UNIQUE_ID).should == 9876
|
|
213
|
+
d1.emission_estimate(:guid => MISSING_UNIQUE_ID).updated_at.should be_instance_of(Time)
|
|
214
|
+
end
|
|
215
|
+
it "should depend on the user to update the guid if they want a new estimate" do
|
|
216
|
+
d = DonutFactory.new
|
|
217
|
+
d.oven_count = 12_000
|
|
218
|
+
str1 = d.emission_estimate(:guid => EXISTING_UNIQUE_ID).methodology
|
|
219
|
+
str1.should equal(d.emission_estimate(:guid => EXISTING_UNIQUE_ID).methodology)
|
|
220
|
+
d.oven_count = 13_000
|
|
221
|
+
str1.should equal(d.emission_estimate(:guid => EXISTING_UNIQUE_ID).methodology)
|
|
222
|
+
str1.should_not equal(d.emission_estimate(:guid => OTHER_UNIQUE_ID).methodology)
|
|
223
|
+
end
|
|
224
|
+
it 'should be deferrable for use in 2-pass reporting systems' do
|
|
225
|
+
d = DonutFactory.new
|
|
226
|
+
d.emission_estimate(:guid => EXISTING_UNIQUE_ID, :defer => true).number.should be_nil
|
|
227
|
+
d.emission_estimate(:guid => EXISTING_UNIQUE_ID, :defer => true).request.url.should =~ /amazonaws/
|
|
228
|
+
end
|
|
229
|
+
it 'should complain if you provide defer but not guid' do
|
|
230
|
+
d = DonutFactory.new
|
|
231
|
+
lambda {
|
|
232
|
+
d.emission_estimate(:defer => true).request.params
|
|
233
|
+
}.should raise_error(ArgumentError, /defer.*guid/i)
|
|
234
|
+
end
|
|
235
|
+
it 'should complain if you provide guid and callback' do
|
|
236
|
+
d = DonutFactory.new
|
|
237
|
+
lambda {
|
|
238
|
+
d.emission_estimate(:defer => true, :callback => 'foobar').request.params
|
|
239
|
+
}.should raise_error(ArgumentError, /callback.*defer/i)
|
|
240
|
+
end
|
|
241
|
+
it 'should send guid along with other parameters when queueing up deferred request' do
|
|
242
|
+
d = DonutFactory.new
|
|
243
|
+
d.emission_estimate(:guid => EXISTING_UNIQUE_ID, :defer => true).request.params[:MessageBody].should =~ /#{EXISTING_UNIQUE_ID.to_query(:guid)}/
|
|
244
|
+
end
|
|
245
|
+
end
|
|
246
|
+
|
|
107
247
|
describe 'synchronous (realtime) requests' do
|
|
108
248
|
it 'should send simple params' do
|
|
109
249
|
d = DonutFactory.new
|
|
@@ -138,10 +278,17 @@ describe Carbon do
|
|
|
138
278
|
it 'should override defaults' do
|
|
139
279
|
d = DonutFactory.new
|
|
140
280
|
key = 'ADifferentOne'
|
|
141
|
-
d.emission_estimate.key.should ==
|
|
281
|
+
d.emission_estimate.key.should == KEY
|
|
142
282
|
d.emission_estimate.key = key
|
|
143
283
|
d.emission_estimate.key.should == key
|
|
144
284
|
end
|
|
285
|
+
|
|
286
|
+
it 'should accept timeouts' do
|
|
287
|
+
d = DonutFactory.new
|
|
288
|
+
lambda {
|
|
289
|
+
d.emission_estimate(:sleep_before_performing => 2, :timeout => 1).to_f
|
|
290
|
+
}.should raise_error(::Timeout::Error)
|
|
291
|
+
end
|
|
145
292
|
|
|
146
293
|
it 'should accept timeframes' do
|
|
147
294
|
c = RentalCar.new
|
|
@@ -180,7 +327,7 @@ describe Carbon do
|
|
|
180
327
|
it 'should have nil data in its response' do
|
|
181
328
|
c = RentalCar.new
|
|
182
329
|
c.emission_estimate.callback = CALLBACK_URL
|
|
183
|
-
c.emission_estimate.
|
|
330
|
+
c.emission_estimate.number.should be_nil
|
|
184
331
|
c.emission_estimate.emission_units.should be_nil
|
|
185
332
|
c.emission_estimate.methodology.should be_nil
|
|
186
333
|
end
|