carbon 2.0.2 → 2.0.3
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/CHANGELOG +6 -0
- data/carbon.gemspec +1 -0
- data/developer_notes/REDUCE_HTTP_CONNECTIONS.markdown +15 -15
- data/lib/carbon.rb +25 -72
- data/lib/carbon/future.rb +116 -0
- data/lib/carbon/version.rb +1 -1
- data/test/carbon_test.rb +89 -62
- data/test/helper.rb +25 -0
- metadata +30 -16
data/CHANGELOG
CHANGED
data/carbon.gemspec
CHANGED
@@ -17,30 +17,30 @@ One way to reduce the number of connections by a constant... but it makes it slo
|
|
17
17
|
end
|
18
18
|
multi.callback do
|
19
19
|
multi.responses[:callback].each do |query_idx, http|
|
20
|
-
|
21
|
-
|
22
|
-
if (200..299).include?(
|
23
|
-
|
24
|
-
|
20
|
+
result = ::Hashie::Mash.new
|
21
|
+
result.status = http.response_header.status
|
22
|
+
if (200..299).include?(result.status)
|
23
|
+
result.success = true
|
24
|
+
result.merge! ::MultiJson.decode(http.response)
|
25
25
|
else
|
26
|
-
|
27
|
-
|
26
|
+
result.success = false
|
27
|
+
result.errors = [http.response]
|
28
28
|
end
|
29
|
-
unsorted[query_idx] =
|
29
|
+
unsorted[query_idx] = result
|
30
30
|
end
|
31
31
|
multi.responses[:errback].each do |query_idx, http|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
unsorted[query_idx] =
|
32
|
+
result = ::Hashie::Mash.new
|
33
|
+
result.status = http.response_header.status
|
34
|
+
result.success = false
|
35
|
+
result.errors = ['Timeout or other network error.']
|
36
|
+
unsorted[query_idx] = result
|
37
37
|
end
|
38
38
|
::EventMachine.stop
|
39
39
|
end
|
40
40
|
end
|
41
41
|
unsorted.sort_by do |query_idx, _|
|
42
42
|
query_idx
|
43
|
-
end.map do |_,
|
44
|
-
|
43
|
+
end.map do |_, result|
|
44
|
+
result
|
45
45
|
end
|
46
46
|
end
|
data/lib/carbon.rb
CHANGED
@@ -1,9 +1,7 @@
|
|
1
|
-
require 'net/http'
|
2
|
-
require 'hashie/mash'
|
3
|
-
require 'multi_json'
|
4
1
|
require 'active_support/core_ext'
|
5
2
|
|
6
3
|
require 'carbon/registry'
|
4
|
+
require 'carbon/future'
|
7
5
|
|
8
6
|
module Carbon
|
9
7
|
DOMAIN = 'http://impact.brighterplanet.com'
|
@@ -17,14 +15,14 @@ module Carbon
|
|
17
15
|
# @param [String] key The alphanumeric key.
|
18
16
|
#
|
19
17
|
# @return [nil]
|
20
|
-
def
|
18
|
+
def Carbon.key=(key)
|
21
19
|
@@key = key
|
22
20
|
end
|
23
21
|
|
24
22
|
# Get the key you've set.
|
25
23
|
#
|
26
24
|
# @return [String] The key you set.
|
27
|
-
def
|
25
|
+
def Carbon.key
|
28
26
|
@@key
|
29
27
|
end
|
30
28
|
|
@@ -39,39 +37,24 @@ module Carbon
|
|
39
37
|
# @option params [Array<Symbol>] :comply ([]) What {http://impact.brighterplanet.com/protocols.json calculation protocols} to require.
|
40
38
|
# @option params [String, Numeric] _characteristic_ Pieces of data about an emitter. The {http://impact.brighterplanet.com/flights/options Flight characteristics API} lists valid keys like +:aircraft+, +:origin_airport+, etc.
|
41
39
|
#
|
42
|
-
# @return [Hashie::Mash] An {file:README.html#API_response API response as documented in the README}
|
40
|
+
# @return [Hashie::Mash, Carbon::Future] An {file:README.html#API_response API response as documented in the README}
|
43
41
|
#
|
44
42
|
# @example A flight taken in 2009
|
45
43
|
# Carbon.query('Flight', :origin_airport => 'MSN', :destination_airport => 'ORD', :date => '2009-01-01', :timeframe => Timeframe.new(:year => 2009), :comply => [:tcr])
|
46
|
-
def
|
47
|
-
|
48
|
-
|
49
|
-
uri = ::URI.parse("#{DOMAIN}/#{emitter.underscore.pluralize}.json")
|
50
|
-
raw_response = ::Net::HTTP.post_form(uri, params)
|
51
|
-
response = ::Hashie::Mash.new
|
52
|
-
case raw_response
|
53
|
-
when ::Net::HTTPSuccess
|
54
|
-
response.status = raw_response.code.to_i
|
55
|
-
response.success = true
|
56
|
-
response.merge! ::MultiJson.decode(raw_response.body)
|
57
|
-
else
|
58
|
-
response.status = raw_response.code.to_i
|
59
|
-
response.success = false
|
60
|
-
response.error_body = raw_response.respond_to?(:body) ? raw_response.body : ''
|
61
|
-
response.errors = [raw_response.class.name]
|
62
|
-
end
|
63
|
-
response
|
44
|
+
def Carbon.query(emitter, params = {})
|
45
|
+
future = Future.new emitter, params
|
46
|
+
future.result
|
64
47
|
end
|
65
48
|
|
66
|
-
# Perform many queries in parallel. Can be
|
49
|
+
# Perform many queries in parallel. Can be *more than 90% faster* than doing them serially (one after the other).
|
67
50
|
#
|
68
51
|
# See the {file:README.html#API_response section about API responses} for an explanation of +Hashie::Mash+.
|
69
52
|
#
|
70
53
|
# @param [Array<Array>] queries Multiple queries like you would pass to {Carbon.query}
|
71
54
|
#
|
72
|
-
# @return [Array<Hashie::Mash>] An array of {file:README.html#API_response API responses} in the same order as the queries.
|
55
|
+
# @return [Array<Hashie::Mash>] An array of {file:README.html#API_response API responses}, each a +Hashie::Mash+, in the same order as the queries.
|
73
56
|
#
|
74
|
-
# @note
|
57
|
+
# @note You may get errors like +SOCKET: SET COMM INACTIVITY UNIMPLEMENTED 10+ on JRuby because under the hood we're using {https://github.com/igrigorik/em-http-request em-http-request}, which suffers from {https://github.com/eventmachine/eventmachine/issues/155 an issue with +pending_connect_timeout+}.
|
75
58
|
#
|
76
59
|
# @example Two flights and an automobile trip
|
77
60
|
# queries = [
|
@@ -80,50 +63,20 @@ module Carbon
|
|
80
63
|
# ['AutomobileTrip', :make => 'Nissan', :model => 'Altima', :timeframe => Timeframe.new(:year => 2008), :comply => [:tcr]]
|
81
64
|
# ]
|
82
65
|
# Carbon.multi(queries)
|
83
|
-
def
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
::EventMachine.run do
|
89
|
-
queries.each_with_index do |(emitter, params), query_idx|
|
90
|
-
params ||= {}
|
91
|
-
params = params.reverse_merge(:key => key) if key
|
92
|
-
multi.add query_idx, ::EventMachine::HttpRequest.new(DOMAIN).post(:path => "/#{emitter.underscore.pluralize}.json", :body => params)
|
93
|
-
end
|
94
|
-
multi.callback do
|
95
|
-
multi.responses[:callback].each do |query_idx, http|
|
96
|
-
response = ::Hashie::Mash.new
|
97
|
-
response.status = http.response_header.status
|
98
|
-
if (200..299).include?(response.status)
|
99
|
-
response.success = true
|
100
|
-
response.merge! ::MultiJson.decode(http.response)
|
101
|
-
else
|
102
|
-
response.success = false
|
103
|
-
response.errors = [http.response]
|
104
|
-
end
|
105
|
-
unsorted[query_idx] = response
|
106
|
-
end
|
107
|
-
multi.responses[:errback].each do |query_idx, http|
|
108
|
-
response = ::Hashie::Mash.new
|
109
|
-
response.status = http.response_header.status
|
110
|
-
response.success = false
|
111
|
-
response.errors = ['Timeout or other network error.']
|
112
|
-
unsorted[query_idx] = response
|
113
|
-
end
|
114
|
-
::EventMachine.stop
|
115
|
-
end
|
66
|
+
def Carbon.multi(queries)
|
67
|
+
futures = queries.map do |emitter, params|
|
68
|
+
future = Future.new emitter, params
|
69
|
+
future.multi!
|
70
|
+
future
|
116
71
|
end
|
117
|
-
|
118
|
-
|
119
|
-
end.map do |_, response|
|
120
|
-
response
|
72
|
+
Future.multi(futures).map do |future|
|
73
|
+
future.result
|
121
74
|
end
|
122
75
|
end
|
123
76
|
|
124
77
|
# Called when you +include Carbon+ and adds the class method +emit_as+.
|
125
78
|
# @private
|
126
|
-
def
|
79
|
+
def Carbon.included(klass)
|
127
80
|
klass.extend ClassMethods
|
128
81
|
end
|
129
82
|
|
@@ -181,11 +134,10 @@ module Carbon
|
|
181
134
|
end
|
182
135
|
end
|
183
136
|
|
184
|
-
#
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
registration.characteristics.inject({}) do |memo, (method_id, translation_options)|
|
137
|
+
# A query like what you could pass into +Carbon.query+.
|
138
|
+
def as_impact_query(extra_params = {})
|
139
|
+
registration = Registry.instance[self.class.name]
|
140
|
+
params = registration.characteristics.inject({}) do |memo, (method_id, translation_options)|
|
189
141
|
k = translation_options.has_key?(:as) ? translation_options[:as] : method_id
|
190
142
|
if translation_options.has_key?(:key)
|
191
143
|
k = "#{k}[#{translation_options[:key]}]"
|
@@ -200,6 +152,7 @@ module Carbon
|
|
200
152
|
end
|
201
153
|
memo
|
202
154
|
end
|
155
|
+
[ registration.emitter, params.merge(extra_params) ]
|
203
156
|
end
|
204
157
|
|
205
158
|
# Get an impact estimate from Brighter Planet CM1.
|
@@ -258,7 +211,7 @@ module Carbon
|
|
258
211
|
# my_impact.characteristics.airline.description
|
259
212
|
# my_impact.equivalents.lightbulbs_for_a_week
|
260
213
|
def impact(extra_params = {})
|
261
|
-
|
262
|
-
|
214
|
+
future = Future.new(*as_impact_query(extra_params))
|
215
|
+
future.result
|
263
216
|
end
|
264
217
|
end
|
@@ -0,0 +1,116 @@
|
|
1
|
+
require 'uri'
|
2
|
+
require 'net/http'
|
3
|
+
require 'cache_method'
|
4
|
+
require 'hashie/mash'
|
5
|
+
require 'multi_json'
|
6
|
+
|
7
|
+
module Carbon
|
8
|
+
# @private
|
9
|
+
class Future
|
10
|
+
class << self
|
11
|
+
def single(future)
|
12
|
+
uri = ::URI.parse("#{Carbon::DOMAIN}/#{future.emitter.underscore.pluralize}.json")
|
13
|
+
raw_result = ::Net::HTTP.post_form(uri, future.params)
|
14
|
+
result = ::Hashie::Mash.new
|
15
|
+
case raw_result
|
16
|
+
when ::Net::HTTPSuccess
|
17
|
+
result.status = raw_result.code.to_i
|
18
|
+
result.success = true
|
19
|
+
result.merge! ::MultiJson.decode(raw_result.body)
|
20
|
+
else
|
21
|
+
result.status = raw_result.code.to_i
|
22
|
+
result.success = false
|
23
|
+
result.errors = [raw_result.body]
|
24
|
+
end
|
25
|
+
result
|
26
|
+
end
|
27
|
+
|
28
|
+
def multi(futures)
|
29
|
+
uniq_pending_futures = futures.uniq.select do |future|
|
30
|
+
future.pending?
|
31
|
+
end
|
32
|
+
return futures if uniq_pending_futures.empty?
|
33
|
+
require 'em-http-request'
|
34
|
+
multi = ::EventMachine::MultiRequest.new
|
35
|
+
::EventMachine.run do
|
36
|
+
uniq_pending_futures.each do |future|
|
37
|
+
multi.add future, ::EventMachine::HttpRequest.new(Carbon::DOMAIN).post(:path => "/#{future.emitter.underscore.pluralize}.json", :body => future.params)
|
38
|
+
end
|
39
|
+
multi.callback do
|
40
|
+
multi.responses[:callback].each do |future, http|
|
41
|
+
result = ::Hashie::Mash.new
|
42
|
+
result.status = http.response_header.status
|
43
|
+
if (200..299).include?(result.status)
|
44
|
+
result.success = true
|
45
|
+
result.merge! ::MultiJson.decode(http.response)
|
46
|
+
else
|
47
|
+
result.success = false
|
48
|
+
result.errors = [http.response]
|
49
|
+
end
|
50
|
+
future.result = result
|
51
|
+
end
|
52
|
+
multi.responses[:errback].each do |future, http|
|
53
|
+
result = ::Hashie::Mash.new
|
54
|
+
result.status = http.response_header.status
|
55
|
+
result.success = false
|
56
|
+
result.errors = ['Timeout or other network error.']
|
57
|
+
future.result = result
|
58
|
+
end
|
59
|
+
::EventMachine.stop
|
60
|
+
end
|
61
|
+
end
|
62
|
+
futures
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
attr_reader :emitter
|
67
|
+
attr_reader :params
|
68
|
+
|
69
|
+
def initialize(emitter, params = {})
|
70
|
+
@result = nil
|
71
|
+
@emitter = emitter
|
72
|
+
params = params || {}
|
73
|
+
params.reverse_merge(:key => Carbon.key) if Carbon.key
|
74
|
+
@params = params
|
75
|
+
end
|
76
|
+
|
77
|
+
def multi!
|
78
|
+
@multi = true
|
79
|
+
end
|
80
|
+
|
81
|
+
def multi?
|
82
|
+
@multi == true
|
83
|
+
end
|
84
|
+
|
85
|
+
def pending?
|
86
|
+
@result.nil? and !cache_method_cached?(:result)
|
87
|
+
end
|
88
|
+
|
89
|
+
def result=(result)
|
90
|
+
@result = result
|
91
|
+
self.result # force this to be cached
|
92
|
+
end
|
93
|
+
|
94
|
+
def result
|
95
|
+
if @result
|
96
|
+
@result
|
97
|
+
elsif not multi?
|
98
|
+
@result = Future.single(self)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
cache_method :result, 3_600 # one hour
|
102
|
+
|
103
|
+
def as_cache_key
|
104
|
+
[ @emitter, @params ]
|
105
|
+
end
|
106
|
+
|
107
|
+
def hash
|
108
|
+
as_cache_key.hash
|
109
|
+
end
|
110
|
+
|
111
|
+
def eql?(other)
|
112
|
+
as_cache_key == other.as_cache_key
|
113
|
+
end
|
114
|
+
alias :== :eql?
|
115
|
+
end
|
116
|
+
end
|
data/lib/carbon/version.rb
CHANGED
data/test/carbon_test.rb
CHANGED
@@ -1,23 +1,4 @@
|
|
1
|
-
require
|
2
|
-
require 'bundler/setup'
|
3
|
-
require 'benchmark'
|
4
|
-
require 'webmock/minitest'
|
5
|
-
WebMock.disable!
|
6
|
-
def with_web_mock
|
7
|
-
WebMock.enable!
|
8
|
-
WebMock.disable_net_connect!
|
9
|
-
yield
|
10
|
-
ensure
|
11
|
-
WebMock.disable!
|
12
|
-
end
|
13
|
-
require 'minitest/spec'
|
14
|
-
require 'minitest/autorun'
|
15
|
-
require 'minitest/reporters'
|
16
|
-
MiniTest::Unit.runner = MiniTest::SuiteRunner.new
|
17
|
-
MiniTest::Unit.runner.reporters << MiniTest::Reporters::SpecReporter.new
|
18
|
-
require 'timeframe'
|
19
|
-
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
20
|
-
require 'carbon'
|
1
|
+
require File.expand_path("../helper", __FILE__)
|
21
2
|
|
22
3
|
Carbon.key = 'carbon_test'
|
23
4
|
|
@@ -60,89 +41,130 @@ class MyNissanAltima
|
|
60
41
|
end
|
61
42
|
|
62
43
|
describe Carbon do
|
63
|
-
|
44
|
+
before do
|
45
|
+
flush_cache!
|
46
|
+
end
|
47
|
+
|
64
48
|
describe :query do
|
65
49
|
it "calculates flight impact" do
|
66
|
-
|
67
|
-
|
50
|
+
result = Carbon.query('Flight', :origin_airport => 'LAX', :destination_airport => 'SFO', :segments_per_trip => 1, :trips => 1)
|
51
|
+
result.decisions.carbon.object.value.must_be_close_to 200, 50
|
68
52
|
end
|
69
53
|
it "gets back characteristics" do
|
70
|
-
|
71
|
-
|
54
|
+
result = Carbon.query('Flight', :origin_airport => 'LAX', :destination_airport => 'SFO', :segments_per_trip => 1, :trips => 1)
|
55
|
+
result.characteristics.origin_airport.description.must_match %r{lax}i
|
72
56
|
end
|
73
57
|
it "tells you if the query is successful" do
|
74
|
-
|
75
|
-
|
58
|
+
result = Carbon.query('Flight')
|
59
|
+
result.success.must_equal true
|
76
60
|
end
|
77
61
|
it "is gentle about errors" do
|
78
|
-
|
79
|
-
|
62
|
+
result = Carbon.query('Monkey')
|
63
|
+
result.success.must_equal false
|
80
64
|
end
|
81
65
|
it "sends timeframe properly" do
|
82
|
-
|
83
|
-
|
84
|
-
|
66
|
+
result = Carbon.query('Flight', :timeframe => Timeframe.new(:year => 2009))
|
67
|
+
result.timeframe.startDate.must_equal '2009-01-01'
|
68
|
+
result.timeframe.endDate.must_equal '2010-01-01'
|
85
69
|
end
|
86
70
|
it "sends key properly" do
|
87
71
|
with_web_mock do
|
88
72
|
WebMock.stub_request(:post, 'http://impact.brighterplanet.com/flights.json').with(:key => 'carbon_test').to_return(:status => 500, :body => 'Good job')
|
89
|
-
|
90
|
-
|
73
|
+
result = Carbon.query('Flight')
|
74
|
+
result.errors.first.must_equal 'Good job'
|
91
75
|
end
|
92
76
|
end
|
93
77
|
end
|
78
|
+
|
94
79
|
describe :multi do
|
95
80
|
before do
|
96
81
|
@queries = []
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
82
|
+
@queries << ['Flight', {:origin_airport => 'LAX', :destination_airport => 'SFO', :segments_per_trip => 1, :trips => 1}]
|
83
|
+
@queries << ['Flight', {:origin_airport => 'MSN', :destination_airport => 'ORD', :segments_per_trip => 1, :trips => 1}]
|
84
|
+
@queries << ['Flight', {:origin_airport => 'IAH', :destination_airport => 'DEN', :segments_per_trip => 1, :trips => 1}]
|
85
|
+
@queries << ['RailTrip', {:distance => 25}]
|
86
|
+
@queries << ['RailTrip', {:rail_class => 'commuter'}]
|
87
|
+
@queries << ['RailTrip', {:rail_traction => 'electric'}]
|
88
|
+
@queries << ['AutomobileTrip', {:make => 'Nissan', :model => 'Altima'}]
|
89
|
+
@queries << ['AutomobileTrip', {:make => 'Toyota', :model => 'Prius'}]
|
90
|
+
@queries << ['AutomobileTrip', {:make => 'Ford', :model => 'Taurus'}]
|
91
|
+
@queries << ['Residence', {:urbanity => 'City'}]
|
92
|
+
@queries << ['Residence', {:zip_code => '53703'}]
|
93
|
+
@queries << ['Residence', {:bathrooms => 4}]
|
94
|
+
@queries << ['Monkey', {:bananas => '1'}]
|
95
|
+
@queries << ['Monkey', {:bananas => '2'}]
|
96
|
+
@queries << ['Monkey', {:bananas => '3'}]
|
104
97
|
@queries = @queries.sort_by { rand }
|
105
98
|
end
|
106
99
|
it "doesn't hang up on 0 queries" do
|
107
100
|
Timeout.timeout(0.5) { Carbon.multi([]) }.must_equal []
|
108
101
|
end
|
109
102
|
it "runs multiple queries at once" do
|
110
|
-
|
103
|
+
reference_results = @queries.map do |query|
|
104
|
+
Carbon.query(*query)
|
105
|
+
end
|
106
|
+
flush_cache! # important!
|
107
|
+
multi_results = Carbon.multi(@queries)
|
111
108
|
error_count = 0
|
112
|
-
|
113
|
-
if
|
114
|
-
|
115
|
-
|
109
|
+
multi_results.each do |result|
|
110
|
+
if result.success
|
111
|
+
result.decisions.carbon.object.value.must_be :>, 0
|
112
|
+
result.decisions.carbon.object.value.must_be :<, 10_000
|
116
113
|
else
|
117
114
|
error_count += 1
|
118
115
|
end
|
119
116
|
end
|
120
117
|
error_count.must_equal 3
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
118
|
+
reference_results.each_with_index do |reference_result, idx|
|
119
|
+
if reference_result.success
|
120
|
+
multi_results[idx].decisions.must_equal reference_result.decisions
|
121
|
+
else
|
122
|
+
multi_results[idx].must_equal reference_result
|
125
123
|
end
|
126
124
|
end
|
127
125
|
end
|
128
|
-
it "is faster than just calling
|
129
|
-
#
|
126
|
+
it "is faster than just calling .query over and over" do
|
127
|
+
# warm up the cache on the other end
|
130
128
|
@queries.each { |query| Carbon.query(*query) }
|
131
|
-
#
|
129
|
+
flush_cache! # important!
|
132
130
|
single_threaded_time = ::Benchmark.realtime do
|
133
131
|
@queries.each { |query| Carbon.query(*query) }
|
134
132
|
end
|
133
|
+
flush_cache! # important!
|
135
134
|
multi_threaded_time = ::Benchmark.realtime do
|
136
135
|
Carbon.multi(@queries)
|
137
136
|
end
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
137
|
+
cached_single_threaded_time = ::Benchmark.realtime do
|
138
|
+
@queries.each { |query| Carbon.query(*query) }
|
139
|
+
end
|
140
|
+
cached_multi_threaded_time = ::Benchmark.realtime do
|
141
|
+
Carbon.multi(@queries)
|
142
|
+
end
|
143
143
|
multi_threaded_time.must_be :<, single_threaded_time
|
144
|
+
cached_single_threaded_time.must_be :<, multi_threaded_time
|
145
|
+
cached_multi_threaded_time.must_be :<, multi_threaded_time
|
146
|
+
$stderr.puts " Multi-threaded was #{((single_threaded_time - multi_threaded_time) / single_threaded_time * 100).round}% faster than single-threaded"
|
147
|
+
$stderr.puts " Cached single-threaded was #{((multi_threaded_time - cached_single_threaded_time) / multi_threaded_time * 100).round}% faster than uncached multi-threaded"
|
148
|
+
$stderr.puts " Cached multi-threaded was #{((multi_threaded_time - cached_multi_threaded_time) / multi_threaded_time * 100).round}% faster than uncached multi-threaded"
|
149
|
+
end
|
150
|
+
it "safely uniq's and caches queries" do
|
151
|
+
reference_results = @queries.map do |query|
|
152
|
+
Carbon.query(*query)
|
153
|
+
end
|
154
|
+
flush_cache! # important!
|
155
|
+
3.times do
|
156
|
+
multi_results = Carbon.multi(@queries)
|
157
|
+
reference_results.each_with_index do |reference_result, idx|
|
158
|
+
if reference_result.success
|
159
|
+
multi_results[idx].decisions.must_equal reference_result.decisions
|
160
|
+
else
|
161
|
+
multi_results[idx].must_equal reference_result
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
144
165
|
end
|
145
166
|
end
|
167
|
+
|
146
168
|
describe "mixin" do
|
147
169
|
describe :emit_as do
|
148
170
|
it "overwrites old emit_as blocks" do
|
@@ -153,11 +175,16 @@ describe Carbon do
|
|
153
175
|
Carbon::Registry.instance['MyFoo'].characteristics.keys.must_equal [:model]
|
154
176
|
end
|
155
177
|
end
|
156
|
-
describe '#
|
157
|
-
it "
|
178
|
+
describe '#as_impact_query' do
|
179
|
+
it "sets up an query to be run by Carbon.multi" do
|
180
|
+
a = MyNissanAltima.new(2006)
|
181
|
+
a.as_impact_query.must_equal ["Automobile", {:make=>"Nissan", :model=>"Altima", :year=>2006, "automobile_fuel[code]"=>"R"}]
|
182
|
+
end
|
183
|
+
it "only includes non-nil params" do
|
158
184
|
a = MyNissanAltima.new(2006)
|
159
|
-
a.
|
160
|
-
a.
|
185
|
+
a.as_impact_query[1].keys.must_include :year
|
186
|
+
a.as_impact_query[1].keys.wont_include :nil_model
|
187
|
+
a.as_impact_query[1].keys.wont_include :nil_make
|
161
188
|
end
|
162
189
|
end
|
163
190
|
describe '#impact' do
|
data/test/helper.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler/setup'
|
3
|
+
require 'benchmark'
|
4
|
+
require 'webmock/minitest'
|
5
|
+
WebMock.disable!
|
6
|
+
def with_web_mock
|
7
|
+
WebMock.enable!
|
8
|
+
WebMock.disable_net_connect!
|
9
|
+
yield
|
10
|
+
ensure
|
11
|
+
WebMock.disable!
|
12
|
+
end
|
13
|
+
require 'minitest/spec'
|
14
|
+
require 'minitest/autorun'
|
15
|
+
require 'minitest/reporters'
|
16
|
+
MiniTest::Unit.runner = MiniTest::SuiteRunner.new
|
17
|
+
MiniTest::Unit.runner.reporters << MiniTest::Reporters::SpecReporter.new
|
18
|
+
require 'timeframe'
|
19
|
+
require 'carbon'
|
20
|
+
|
21
|
+
class MiniTest::Spec
|
22
|
+
def flush_cache!
|
23
|
+
CacheMethod.config.storage.flush
|
24
|
+
end
|
25
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: carbon
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0.
|
4
|
+
version: 2.0.3
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-03-
|
12
|
+
date: 2012-03-14 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: em-http-request
|
16
|
-
requirement: &
|
16
|
+
requirement: &2165918380 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: '0'
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *2165918380
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: activesupport
|
27
|
-
requirement: &
|
27
|
+
requirement: &2165917960 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ! '>='
|
@@ -32,10 +32,10 @@ dependencies:
|
|
32
32
|
version: '0'
|
33
33
|
type: :runtime
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *2165917960
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: multi_json
|
38
|
-
requirement: &
|
38
|
+
requirement: &2165917480 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
40
40
|
requirements:
|
41
41
|
- - ! '>='
|
@@ -43,10 +43,10 @@ dependencies:
|
|
43
43
|
version: '0'
|
44
44
|
type: :runtime
|
45
45
|
prerelease: false
|
46
|
-
version_requirements: *
|
46
|
+
version_requirements: *2165917480
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: hashie
|
49
|
-
requirement: &
|
49
|
+
requirement: &2165917040 !ruby/object:Gem::Requirement
|
50
50
|
none: false
|
51
51
|
requirements:
|
52
52
|
- - ! '>='
|
@@ -54,10 +54,21 @@ dependencies:
|
|
54
54
|
version: '0'
|
55
55
|
type: :runtime
|
56
56
|
prerelease: false
|
57
|
-
version_requirements: *
|
57
|
+
version_requirements: *2165917040
|
58
|
+
- !ruby/object:Gem::Dependency
|
59
|
+
name: cache_method
|
60
|
+
requirement: &2165941860 !ruby/object:Gem::Requirement
|
61
|
+
none: false
|
62
|
+
requirements:
|
63
|
+
- - ! '>='
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: '0'
|
66
|
+
type: :runtime
|
67
|
+
prerelease: false
|
68
|
+
version_requirements: *2165941860
|
58
69
|
- !ruby/object:Gem::Dependency
|
59
70
|
name: bombshell
|
60
|
-
requirement: &
|
71
|
+
requirement: &2165941440 !ruby/object:Gem::Requirement
|
61
72
|
none: false
|
62
73
|
requirements:
|
63
74
|
- - ! '>='
|
@@ -65,10 +76,10 @@ dependencies:
|
|
65
76
|
version: '0'
|
66
77
|
type: :runtime
|
67
78
|
prerelease: false
|
68
|
-
version_requirements: *
|
79
|
+
version_requirements: *2165941440
|
69
80
|
- !ruby/object:Gem::Dependency
|
70
81
|
name: conversions
|
71
|
-
requirement: &
|
82
|
+
requirement: &2165941020 !ruby/object:Gem::Requirement
|
72
83
|
none: false
|
73
84
|
requirements:
|
74
85
|
- - ! '>='
|
@@ -76,10 +87,10 @@ dependencies:
|
|
76
87
|
version: '0'
|
77
88
|
type: :runtime
|
78
89
|
prerelease: false
|
79
|
-
version_requirements: *
|
90
|
+
version_requirements: *2165941020
|
80
91
|
- !ruby/object:Gem::Dependency
|
81
92
|
name: brighter_planet_metadata
|
82
|
-
requirement: &
|
93
|
+
requirement: &2165940600 !ruby/object:Gem::Requirement
|
83
94
|
none: false
|
84
95
|
requirements:
|
85
96
|
- - ! '>='
|
@@ -87,7 +98,7 @@ dependencies:
|
|
87
98
|
version: '0'
|
88
99
|
type: :runtime
|
89
100
|
prerelease: false
|
90
|
-
version_requirements: *
|
101
|
+
version_requirements: *2165940600
|
91
102
|
description: Brighter Planet API client for Ruby
|
92
103
|
email:
|
93
104
|
- seamus@abshere.net
|
@@ -110,11 +121,13 @@ files:
|
|
110
121
|
- features/shell.feature
|
111
122
|
- features/support/env.rb
|
112
123
|
- lib/carbon.rb
|
124
|
+
- lib/carbon/future.rb
|
113
125
|
- lib/carbon/registry.rb
|
114
126
|
- lib/carbon/shell.rb
|
115
127
|
- lib/carbon/shell/emitter.rb
|
116
128
|
- lib/carbon/version.rb
|
117
129
|
- test/carbon_test.rb
|
130
|
+
- test/helper.rb
|
118
131
|
homepage: https://github.com/brighterplanet/carbon
|
119
132
|
licenses: []
|
120
133
|
post_install_message:
|
@@ -143,4 +156,5 @@ test_files:
|
|
143
156
|
- features/shell.feature
|
144
157
|
- features/support/env.rb
|
145
158
|
- test/carbon_test.rb
|
159
|
+
- test/helper.rb
|
146
160
|
has_rdoc:
|