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 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: