carbon 2.0.2 → 2.0.3

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG CHANGED
@@ -1,3 +1,9 @@
1
+ 2.0.3 / 2012-03-13
2
+
3
+ * Enhancements
4
+
5
+ * Automatically skip redundant queries and cache things for an hour (in-process, unless you set up CacheMethod.config.storage = $memcached or something)
6
+
1
7
  2.0.2 / 2012-03-13
2
8
 
3
9
  * Bug fixes
@@ -19,6 +19,7 @@ Gem::Specification.new do |s|
19
19
  s.add_runtime_dependency 'activesupport'
20
20
  s.add_runtime_dependency 'multi_json'
21
21
  s.add_runtime_dependency 'hashie'
22
+ s.add_runtime_dependency 'cache_method'
22
23
 
23
24
  # CLI
24
25
  s.add_runtime_dependency 'bombshell'
@@ -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
- response = ::Hashie::Mash.new
21
- response.status = http.response_header.status
22
- if (200..299).include?(response.status)
23
- response.success = true
24
- response.merge! ::MultiJson.decode(http.response)
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
- response.success = false
27
- response.errors = [http.response]
26
+ result.success = false
27
+ result.errors = [http.response]
28
28
  end
29
- unsorted[query_idx] = response
29
+ unsorted[query_idx] = result
30
30
  end
31
31
  multi.responses[:errback].each do |query_idx, http|
32
- response = ::Hashie::Mash.new
33
- response.status = http.response_header.status
34
- response.success = false
35
- response.errors = ['Timeout or other network error.']
36
- unsorted[query_idx] = response
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 |_, response|
44
- response
43
+ end.map do |_, result|
44
+ result
45
45
  end
46
46
  end
@@ -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 self.key=(key)
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 self.key
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 self.query(emitter, params = {})
47
- params ||= {}
48
- params = params.reverse_merge(:key => key) if key
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 >90% faster than doing them serially (one after the other).
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 Not supported on JRuby because it uses {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+}.
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 self.multi(queries)
84
- return [] if queries.empty?
85
- require 'em-http-request'
86
- unsorted = {}
87
- multi = ::EventMachine::MultiRequest.new
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
- unsorted.sort_by do |query_idx, _|
118
- query_idx
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 self.included(klass)
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
- # What will be sent to Brighter Planet CM1.
185
- # @private
186
- def impact_params
187
- return unless registration = Registry.instance[self.class.name]
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
- return unless registration = Registry.instance[self.class.name]
262
- Carbon.query registration.emitter, impact_params.merge(extra_params)
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
@@ -1,3 +1,3 @@
1
1
  module Carbon
2
- VERSION = "2.0.2"
2
+ VERSION = "2.0.3"
3
3
  end
@@ -1,23 +1,4 @@
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
- $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
- # args could be mmm(:post, 'http://impact.brighterplanet.com/monkeys.json').to_return(:status => 500, :body => 'too many monkeys')
44
+ before do
45
+ flush_cache!
46
+ end
47
+
64
48
  describe :query do
65
49
  it "calculates flight impact" do
66
- response = Carbon.query('Flight', :origin_airport => 'LAX', :destination_airport => 'SFO', :segments_per_trip => 1, :trips => 1)
67
- response.decisions.carbon.object.value.must_be_close_to 200, 50
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
- response = Carbon.query('Flight', :origin_airport => 'LAX', :destination_airport => 'SFO', :segments_per_trip => 1, :trips => 1)
71
- response.characteristics.origin_airport.description.must_match %r{lax}i
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
- response = Carbon.query('Flight')
75
- response.success.must_equal true
58
+ result = Carbon.query('Flight')
59
+ result.success.must_equal true
76
60
  end
77
61
  it "is gentle about errors" do
78
- response = Carbon.query('Monkey')
79
- response.success.must_equal false
62
+ result = Carbon.query('Monkey')
63
+ result.success.must_equal false
80
64
  end
81
65
  it "sends timeframe properly" do
82
- response = Carbon.query('Flight', :timeframe => Timeframe.new(:year => 2009))
83
- response.timeframe.startDate.must_equal '2009-01-01'
84
- response.timeframe.endDate.must_equal '2010-01-01'
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
- response = Carbon.query('Flight')
90
- response.error_body.must_equal 'Good job'
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
- 3.times do
98
- @queries << ['Flight', {:origin_airport => 'LAX', :destination_airport => 'SFO', :segments_per_trip => 1, :trips => 1}]
99
- @queries << ['RailTrip', {:distance => 25}]
100
- @queries << ['AutomobileTrip', {:make => 'Nissan', :model => 'Altima'}]
101
- @queries << ['Residence']
102
- @queries << ['Monkey']
103
- end
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
- responses = Carbon.multi(@queries)
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
- responses.each do |response|
113
- if response.success
114
- response.decisions.carbon.object.value.must_be :>, 0
115
- response.decisions.carbon.object.value.must_be :<, 10_000
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
- @queries.each_with_index do |query, i|
122
- reference_response = Carbon.query(*query)
123
- if reference_response.success
124
- responses[i].decisions.must_equal reference_response.decisions
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 #query over and over" do
129
- # dry run
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
- # Carbon::#multi
139
- # PASS test_0001_runs_multiple_queries_at_once (12.10s)
140
- # Multi-threaded was 95% faster
141
- # PASS test_0002_is_faster_than_just_calling_query_over_and_over (23.73s)
142
- $stderr.puts " Multi-threaded was #{((single_threaded_time - multi_threaded_time) / single_threaded_time * 100).round}% faster"
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 '#impact_params' do
157
- it "only takes non-nil params" do
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.impact_params.keys.wont_include :nil_model
160
- a.impact_params.keys.wont_include :nil_make
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
@@ -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.2
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-13 00:00:00.000000000 Z
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: &2153871340 !ruby/object:Gem::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: *2153871340
24
+ version_requirements: *2165918380
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: activesupport
27
- requirement: &2153870880 !ruby/object:Gem::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: *2153870880
35
+ version_requirements: *2165917960
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: multi_json
38
- requirement: &2153870440 !ruby/object:Gem::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: *2153870440
46
+ version_requirements: *2165917480
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: hashie
49
- requirement: &2153869980 !ruby/object:Gem::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: *2153869980
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: &2153869540 !ruby/object:Gem::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: *2153869540
79
+ version_requirements: *2165941440
69
80
  - !ruby/object:Gem::Dependency
70
81
  name: conversions
71
- requirement: &2153869080 !ruby/object:Gem::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: *2153869080
90
+ version_requirements: *2165941020
80
91
  - !ruby/object:Gem::Dependency
81
92
  name: brighter_planet_metadata
82
- requirement: &2153868640 !ruby/object:Gem::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: *2153868640
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: