carbon 2.2.3 → 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +15 -0
- data/Gemfile +0 -10
- data/Rakefile +10 -11
- data/carbon.gemspec +18 -6
- data/lib/carbon.rb +9 -61
- data/lib/carbon/query.rb +140 -0
- data/lib/carbon/query_pool.rb +11 -0
- data/lib/carbon/shell/emitter.rb +1 -1
- data/lib/carbon/version.rb +1 -1
- data/spec/carbon/query_spec.rb +106 -0
- data/spec/carbon_spec.rb +237 -0
- data/spec/cassettes/2006_Altima.yml +69 -0
- data/spec/cassettes/2006_Altima_in_2010.yml +230 -0
- data/spec/cassettes/2006_Altima_in_2011.yml +1239 -0
- data/spec/cassettes/Flight.yml +59 -0
- data/spec/cassettes/Flight_and_Automobile.yml +60 -0
- data/spec/cassettes/LAX-_SFO_flight.yml +74 -0
- data/spec/cassettes/Monkey.yml +42 -0
- data/spec/cassettes/carbon_bp_com_flight.yml +58 -0
- data/spec/cassettes/flight_with_key_1.yml +59 -0
- data/spec/cassettes/flight_with_key_2.yml +59 -0
- data/spec/cassettes/timeframed_flight.yml +59 -0
- data/spec/helper.rb +25 -0
- data/spec/support/my_nissan_altima.rb +36 -0
- metadata +200 -13
- data/lib/carbon/future.rb +0 -109
- data/test/carbon_test.rb +0 -302
- data/test/helper.rb +0 -25
data/test/carbon_test.rb
DELETED
@@ -1,302 +0,0 @@
|
|
1
|
-
require File.expand_path("../helper", __FILE__)
|
2
|
-
|
3
|
-
Thread.abort_on_exception = true
|
4
|
-
Carbon.key = 'carbon_test'
|
5
|
-
|
6
|
-
class MyNissan
|
7
|
-
def name
|
8
|
-
'Nissan'
|
9
|
-
end
|
10
|
-
def to_s
|
11
|
-
raise "Not fair!"
|
12
|
-
end
|
13
|
-
alias :inspect :to_s
|
14
|
-
end
|
15
|
-
|
16
|
-
class MyNissanAltima
|
17
|
-
class << self
|
18
|
-
def all(options)
|
19
|
-
raise unless options == { :order => :year }
|
20
|
-
[ new(2000), new(2001), new(2002), new(2003), new(2004) ]
|
21
|
-
end
|
22
|
-
end
|
23
|
-
def initialize(model_year)
|
24
|
-
@model_year = model_year
|
25
|
-
end
|
26
|
-
def make; MyNissan.new end
|
27
|
-
def model; 'Altima' end
|
28
|
-
def model_year; @model_year end # what BP knows as "year"
|
29
|
-
def fuel_type; 'R' end # what BP knows as "automobile_fuel" and keys on "code"
|
30
|
-
def nil_make; nil end
|
31
|
-
def nil_model; nil end
|
32
|
-
include Carbon
|
33
|
-
emit_as 'Automobile' do
|
34
|
-
provide(:make) { |my_nissan_altima| my_nissan_altima.make.try(:name) }
|
35
|
-
provide :model
|
36
|
-
provide :model_year, :as => :year
|
37
|
-
provide :fuel_type, :as => :automobile_fuel, :key => :code
|
38
|
-
provide(:nil_make) { |my_nissan_altima| my_nissan_altima.nil_make.try(:blam!) }
|
39
|
-
provide :nil_model
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
describe Carbon do
|
44
|
-
before do
|
45
|
-
flush_cache!
|
46
|
-
end
|
47
|
-
|
48
|
-
describe :query do
|
49
|
-
describe '(one at a time)' do
|
50
|
-
it "calculates flight impact" do
|
51
|
-
result = Carbon.query('Flight', :origin_airport => 'LAX', :destination_airport => 'SFO', :segments_per_trip => 1, :trips => 1)
|
52
|
-
result.decisions.carbon.object.value.must_be_close_to 200, 50
|
53
|
-
end
|
54
|
-
it "can be used on an object that response to #as_impact_query" do
|
55
|
-
Carbon.query(MyNissanAltima.new(2006)).decisions.must_equal MyNissanAltima.new(2006).impact.decisions
|
56
|
-
end
|
57
|
-
it "gets back characteristics" do
|
58
|
-
result = Carbon.query('Flight', :origin_airport => 'LAX', :destination_airport => 'SFO', :segments_per_trip => 1, :trips => 1)
|
59
|
-
result.characteristics.origin_airport.description.must_match %r{lax}i
|
60
|
-
end
|
61
|
-
it "tells you if the query is successful" do
|
62
|
-
result = Carbon.query('Flight')
|
63
|
-
result.success.must_equal true
|
64
|
-
end
|
65
|
-
it "is gentle about errors" do
|
66
|
-
result = Carbon.query('Monkey')
|
67
|
-
result.success.must_equal false
|
68
|
-
end
|
69
|
-
it "sends timeframe properly" do
|
70
|
-
result = Carbon.query('Flight', :timeframe => Timeframe.new(:year => 2009))
|
71
|
-
result.timeframe.startDate.must_equal '2009-01-01'
|
72
|
-
result.timeframe.endDate.must_equal '2010-01-01'
|
73
|
-
end
|
74
|
-
it "sends key properly" do
|
75
|
-
with_web_mock do
|
76
|
-
WebMock.stub_request(:post, 'http://impact.brighterplanet.com/flights.json').with(:body => hash_including(:key => 'carbon_test')).to_return(:status => 500, :body => 'default')
|
77
|
-
WebMock.stub_request(:post, 'http://impact.brighterplanet.com/flights.json').with(:body => hash_including(:key => 'carbon_test1')).to_return(:status => 500, :body => 'A')
|
78
|
-
WebMock.stub_request(:post, 'http://impact.brighterplanet.com/flights.json').with(:body => hash_including(:key => 'carbon_test2')).to_return(:status => 500, :body => 'B')
|
79
|
-
Carbon.query('Flight', :key => 'carbon_test2').errors.first.must_equal 'B'
|
80
|
-
Carbon.query('Flight').errors.first.must_equal 'default'
|
81
|
-
Carbon.query('Flight', :key => 'carbon_test1').errors.first.must_equal 'A'
|
82
|
-
end
|
83
|
-
end
|
84
|
-
it "allows choosing domain" do
|
85
|
-
with_web_mock do
|
86
|
-
WebMock.stub_request(:post, 'http://impact.brighterplanet.com/flights.json').to_return(:status => 500, :body => 'used impact')
|
87
|
-
WebMock.stub_request(:post, 'http://foo.brighterplanet.com/flights.json').to_return(:status => 500, :body => 'used foo')
|
88
|
-
Carbon.query('Flight', :domain => 'http://foo.brighterplanet.com').errors.first.must_equal 'used foo'
|
89
|
-
Carbon.query('Flight').errors.first.must_equal 'used impact'
|
90
|
-
end
|
91
|
-
end
|
92
|
-
it "raises ArgumentError if args are bad" do
|
93
|
-
lambda {
|
94
|
-
Carbon.query(['Flight'])
|
95
|
-
}.must_raise ArgumentError
|
96
|
-
end
|
97
|
-
end
|
98
|
-
describe '(in parallel)' do
|
99
|
-
before do
|
100
|
-
flunk if ENV['SKIP_MULTI'] == 'true'
|
101
|
-
@queries = []
|
102
|
-
@queries << ['Flight', {:origin_airport => 'LAX', :destination_airport => 'SFO', :segments_per_trip => 1, :trips => 1}]
|
103
|
-
@queries << ['Flight', {:origin_airport => 'MSN', :destination_airport => 'ORD', :segments_per_trip => 1, :trips => 1}]
|
104
|
-
@queries << ['Flight', {:origin_airport => 'IAH', :destination_airport => 'DEN', :segments_per_trip => 1, :trips => 1}]
|
105
|
-
@queries << ['RailTrip', {:distance => 25}]
|
106
|
-
@queries << ['RailTrip', {:rail_class => 'commuter'}]
|
107
|
-
@queries << ['RailTrip', {:rail_traction => 'electric'}]
|
108
|
-
@queries << ['AutomobileTrip', {:make => 'Nissan', :model => 'Altima'}]
|
109
|
-
@queries << ['AutomobileTrip', {:make => 'Toyota', :model => 'Prius'}]
|
110
|
-
@queries << ['AutomobileTrip', {:make => 'Ford', :model => 'Taurus'}]
|
111
|
-
@queries << ['Residence', {:urbanity => 'City'}]
|
112
|
-
@queries << ['Residence', {:zip_code => '53703'}]
|
113
|
-
@queries << ['Residence', {:bathrooms => 4}]
|
114
|
-
@queries << ['Monkey', {:bananas => '1'}]
|
115
|
-
@queries << ['Monkey', {:bananas => '2'}]
|
116
|
-
@queries << ['Monkey', {:bananas => '3'}]
|
117
|
-
@queries = @queries.sort_by { rand }
|
118
|
-
end
|
119
|
-
it "is easy to use" do
|
120
|
-
flight = ['Flight']
|
121
|
-
rail_trip = ['RailTrip']
|
122
|
-
results = Carbon.query([flight, rail_trip])
|
123
|
-
results[flight].decisions.must_equal Carbon.query('Flight').decisions
|
124
|
-
results[rail_trip].decisions.must_equal Carbon.query('RailTrip').decisions
|
125
|
-
end
|
126
|
-
it "doesn't hang up on 0 queries" do
|
127
|
-
Timeout.timeout(0.5) { Carbon.query([]) }.must_equal(Hash.new)
|
128
|
-
end
|
129
|
-
it "raises if you pass it a block directly" do
|
130
|
-
lambda {
|
131
|
-
Carbon.query([]) { }
|
132
|
-
}.must_raise(ArgumentError)
|
133
|
-
end
|
134
|
-
it "can be used on objects that respond to #as_impact_query" do
|
135
|
-
a = MyNissanAltima.new(2001)
|
136
|
-
b = MyNissanAltima.new(2006)
|
137
|
-
ab1 = Carbon.query([a, b])
|
138
|
-
ab2 = Carbon.query([a.as_impact_query, b.as_impact_query])
|
139
|
-
ab1.each do |k, v|
|
140
|
-
ab2[k.as_impact_query].must_equal v
|
141
|
-
end
|
142
|
-
end
|
143
|
-
it "runs multiple queries at once" do
|
144
|
-
reference_results = @queries.inject({}) do |memo, query|
|
145
|
-
memo[query] = Carbon.query(*query)
|
146
|
-
memo
|
147
|
-
end
|
148
|
-
ts = []
|
149
|
-
3.times do
|
150
|
-
ts << Thread.new do
|
151
|
-
flush_cache! # important!
|
152
|
-
multi_results = Carbon.query(@queries)
|
153
|
-
error_count = 0
|
154
|
-
multi_results.each do |query, result|
|
155
|
-
if result.success
|
156
|
-
result.decisions.carbon.object.value.must_be :>, 0
|
157
|
-
result.decisions.carbon.object.value.must_be :<, 10_000
|
158
|
-
else
|
159
|
-
error_count += 1
|
160
|
-
end
|
161
|
-
end
|
162
|
-
error_count.must_equal 3
|
163
|
-
reference_results.each do |query, reference_result|
|
164
|
-
if reference_result.success
|
165
|
-
multi_results[query].decisions.must_equal reference_result.decisions
|
166
|
-
else
|
167
|
-
multi_results[query].must_equal reference_result
|
168
|
-
end
|
169
|
-
end
|
170
|
-
end
|
171
|
-
end
|
172
|
-
ts.each do |t|
|
173
|
-
t.join
|
174
|
-
end
|
175
|
-
end
|
176
|
-
it "is faster than single threaded" do
|
177
|
-
# warm up the cache on the other end
|
178
|
-
@queries.each { |query| Carbon.query(*query) }
|
179
|
-
flush_cache! # important!
|
180
|
-
single_threaded_time = ::Benchmark.realtime do
|
181
|
-
@queries.each { |query| Carbon.query(*query) }
|
182
|
-
end
|
183
|
-
flush_cache! # important!
|
184
|
-
multi_threaded_time = ::Benchmark.realtime do
|
185
|
-
Carbon.query(@queries)
|
186
|
-
end
|
187
|
-
cached_single_threaded_time = ::Benchmark.realtime do
|
188
|
-
@queries.each { |query| Carbon.query(*query) }
|
189
|
-
end
|
190
|
-
cached_multi_threaded_time = ::Benchmark.realtime do
|
191
|
-
Carbon.query(@queries)
|
192
|
-
end
|
193
|
-
multi_threaded_time.must_be :<, single_threaded_time
|
194
|
-
cached_single_threaded_time.must_be :<, multi_threaded_time
|
195
|
-
cached_multi_threaded_time.must_be :<, multi_threaded_time
|
196
|
-
$stderr.puts " Multi-threaded was #{((single_threaded_time - multi_threaded_time) / single_threaded_time * 100).round}% faster than single-threaded"
|
197
|
-
$stderr.puts " Cached single-threaded was #{((multi_threaded_time - cached_single_threaded_time) / multi_threaded_time * 100).round}% faster than uncached multi-threaded"
|
198
|
-
$stderr.puts " Cached multi-threaded was #{((multi_threaded_time - cached_multi_threaded_time) / multi_threaded_time * 100).round}% faster than uncached multi-threaded"
|
199
|
-
end
|
200
|
-
it "safely uniq's and caches queries" do
|
201
|
-
reference_results = @queries.inject({}) do |memo, query|
|
202
|
-
memo[query] = Carbon.query(*query)
|
203
|
-
memo
|
204
|
-
end
|
205
|
-
flush_cache! # important!
|
206
|
-
3.times do
|
207
|
-
multi_results = Carbon.query(@queries)
|
208
|
-
reference_results.each do |query, reference_result|
|
209
|
-
if reference_result.success
|
210
|
-
multi_results[query].decisions.must_equal reference_result.decisions
|
211
|
-
else
|
212
|
-
multi_results[query].must_equal reference_result
|
213
|
-
end
|
214
|
-
end
|
215
|
-
end
|
216
|
-
end
|
217
|
-
end
|
218
|
-
end
|
219
|
-
|
220
|
-
describe :method_signature do
|
221
|
-
it "recognizes emitter_param" do
|
222
|
-
Carbon.method_signature('Flight').must_equal :plain_query
|
223
|
-
Carbon.method_signature('Flight', :origin_airport => 'LAX').must_equal :plain_query
|
224
|
-
Carbon.method_signature(:flight).must_equal :plain_query
|
225
|
-
Carbon.method_signature(:flight, :origin_airport => 'LAX').must_equal :plain_query
|
226
|
-
end
|
227
|
-
it "recognizes obj" do
|
228
|
-
Carbon.method_signature(MyNissanAltima.new(2006)).must_equal :obj
|
229
|
-
end
|
230
|
-
it "recognizes array" do
|
231
|
-
Carbon.method_signature([MyNissanAltima.new(2001)]).must_equal :array
|
232
|
-
Carbon.method_signature([['Flight']]).must_equal :array
|
233
|
-
Carbon.method_signature([['Flight', {:origin_airport => 'LAX'}]]).must_equal :array
|
234
|
-
Carbon.method_signature([['Flight'], ['Flight']]).must_equal :array
|
235
|
-
Carbon.method_signature([['Flight', {:origin_airport => 'LAX'}], ['Flight', {:origin_airport => 'LAX'}]]).must_equal :array
|
236
|
-
[MyNissanAltima.new(2006), ['Flight'], ['Flight', {:origin_airport => 'LAX'}]].permutation.each do |p|
|
237
|
-
Carbon.method_signature(p).must_equal :array
|
238
|
-
end
|
239
|
-
end
|
240
|
-
it "does not want splats for concurrent queries" do
|
241
|
-
Carbon.method_signature(['Flight'], ['Flight']).must_be_nil
|
242
|
-
Carbon.method_signature(MyNissanAltima.new(2001), MyNissanAltima.new(2001)).must_be_nil
|
243
|
-
[MyNissanAltima.new(2006), ['Flight'], ['Flight', {:origin_airport => 'LAX'}]].permutation.each do |p|
|
244
|
-
Carbon.method_signature(*p).must_be_nil
|
245
|
-
end
|
246
|
-
end
|
247
|
-
it "does not like weirdness" do
|
248
|
-
Carbon.method_signature('Flight', 'Flight').must_be_nil
|
249
|
-
Carbon.method_signature('Flight', ['Flight']).must_be_nil
|
250
|
-
Carbon.method_signature(['Flight'], 'Flight').must_be_nil
|
251
|
-
Carbon.method_signature(['Flight', 'Flight']).must_be_nil
|
252
|
-
Carbon.method_signature(['Flight', ['Flight']]).must_be_nil
|
253
|
-
Carbon.method_signature([['Flight'], 'Flight']).must_be_nil
|
254
|
-
Carbon.method_signature(MyNissanAltima.new(2001), [MyNissanAltima.new(2001)]).must_be_nil
|
255
|
-
Carbon.method_signature([MyNissanAltima.new(2001)], MyNissanAltima.new(2001)).must_be_nil
|
256
|
-
Carbon.method_signature([MyNissanAltima.new(2001)], [MyNissanAltima.new(2001)]).must_be_nil
|
257
|
-
Carbon.method_signature([MyNissanAltima.new(2001), [MyNissanAltima.new(2001)]]).must_be_nil
|
258
|
-
Carbon.method_signature([[MyNissanAltima.new(2001)], MyNissanAltima.new(2001)]).must_be_nil
|
259
|
-
Carbon.method_signature([[MyNissanAltima.new(2001)], [MyNissanAltima.new(2001)]]).must_be_nil
|
260
|
-
end
|
261
|
-
end
|
262
|
-
|
263
|
-
describe "mixin" do
|
264
|
-
describe :emit_as do
|
265
|
-
it "overwrites old emit_as blocks" do
|
266
|
-
eval %{class MyFoo; include Carbon; end}
|
267
|
-
MyFoo.emit_as('Automobile') { provide(:make) }
|
268
|
-
Carbon::Registry.instance['MyFoo'].characteristics.keys.must_equal [:make]
|
269
|
-
MyFoo.emit_as('Automobile') { provide(:model) }
|
270
|
-
Carbon::Registry.instance['MyFoo'].characteristics.keys.must_equal [:model]
|
271
|
-
end
|
272
|
-
end
|
273
|
-
describe '#as_impact_query' do
|
274
|
-
it "sets up an query to be run by Carbon.query" do
|
275
|
-
a = MyNissanAltima.new(2006)
|
276
|
-
a.as_impact_query.must_equal ["Automobile", {:make=>"Nissan", :model=>"Altima", :year=>2006, "automobile_fuel[code]"=>"R"}]
|
277
|
-
end
|
278
|
-
it "only includes non-nil params" do
|
279
|
-
a = MyNissanAltima.new(2006)
|
280
|
-
a.as_impact_query[1].keys.must_include :year
|
281
|
-
a.as_impact_query[1].keys.wont_include :nil_model
|
282
|
-
a.as_impact_query[1].keys.wont_include :nil_make
|
283
|
-
end
|
284
|
-
end
|
285
|
-
describe '#impact' do
|
286
|
-
it "works" do
|
287
|
-
impact = MyNissanAltima.new(2006).impact
|
288
|
-
impact.decisions.carbon.object.value.must_be :>, 0
|
289
|
-
impact.characteristics.make.description.must_match %r{Nissan}i
|
290
|
-
impact.characteristics.model.description.must_match %r{Altima}i
|
291
|
-
impact.characteristics.year.description.to_i.must_equal 2006
|
292
|
-
impact.characteristics.automobile_fuel.description.must_match %r{regular gasoline}
|
293
|
-
end
|
294
|
-
it "takes timeframe" do
|
295
|
-
impact_2010 = MyNissanAltima.new(2006).impact(:timeframe => Timeframe.new(:year => 2010))
|
296
|
-
impact_2011 = MyNissanAltima.new(2006).impact(:timeframe => Timeframe.new(:year => 2011))
|
297
|
-
impact_2010.timeframe.startDate.must_equal '2010-01-01'
|
298
|
-
impact_2011.timeframe.startDate.must_equal '2011-01-01'
|
299
|
-
end
|
300
|
-
end
|
301
|
-
end
|
302
|
-
end
|
data/test/helper.rb
DELETED
@@ -1,25 +0,0 @@
|
|
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
|