carbon 0.2.5 → 0.2.6

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/VERSION CHANGED
@@ -1 +1 @@
1
- 0.2.5
1
+ 0.2.6
data/carbon.gemspec CHANGED
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{carbon}
8
- s.version = "0.2.5"
8
+ s.version = "0.2.6"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Derek Kastner", "Seamus Abshere", "Andy Rossmeissl"]
12
- s.date = %q{2010-08-02}
12
+ s.date = %q{2010-08-18}
13
13
  s.description = %q{Carbon is a Ruby API wrapper for the Brighter Planet emission estimate web service (http://carbon.brighterplanet.com). By querying the web service, it can estimate the carbon emissions of many real-life objects, such as cars and houses, based on particular attributes that they may have.}
14
14
  s.email = %q{derek.kastner@brighterplanet.com}
15
15
  s.extra_rdoc_files = [
@@ -33,6 +33,7 @@ Gem::Specification.new do |s|
33
33
  "lib/carbon/emission_estimate/request.rb",
34
34
  "lib/carbon/emission_estimate/response.rb",
35
35
  "lib/carbon/emission_estimate/storage.rb",
36
+ "spec/lib/carbon/emission_estimate/response_spec.rb",
36
37
  "spec/lib/carbon_spec.rb",
37
38
  "spec/spec_helper.rb",
38
39
  "spec/specwatchr"
@@ -43,7 +44,8 @@ Gem::Specification.new do |s|
43
44
  s.rubygems_version = %q{1.3.7}
44
45
  s.summary = %q{Carbon is a Ruby API wrapper for the Brighter Planet emission estimate web service (http://carbon.brighterplanet.com).}
45
46
  s.test_files = [
46
- "spec/lib/carbon_spec.rb",
47
+ "spec/lib/carbon/emission_estimate/response_spec.rb",
48
+ "spec/lib/carbon_spec.rb",
47
49
  "spec/spec_helper.rb"
48
50
  ]
49
51
 
data/lib/carbon.rb CHANGED
@@ -5,6 +5,7 @@ require 'digest/sha1'
5
5
  require 'rest' # provided by nap gem
6
6
  gem 'SystemTimer' # >=1.2, so as not to be confused with system_timer 1.0
7
7
  require 'system_timer'
8
+ require 'active_support'
8
9
  require 'active_support/version'
9
10
  %w{
10
11
  active_support/core_ext/module/attribute_accessors
data/lib/carbon/base.rb CHANGED
@@ -10,6 +10,7 @@ module Carbon
10
10
  @klass = klass
11
11
  @emitter_common_name = emitter_common_name.to_s
12
12
  end
13
+
13
14
  # A completed translation table will look like:
14
15
  # {[:mixer, :size]=>"mixer_size",
15
16
  # :personnel=>:employees,
@@ -19,6 +20,7 @@ module Carbon
19
20
  def translation_table # :nodoc:
20
21
  @translation_table ||= Hash.new
21
22
  end
23
+
22
24
  # Indicate that you will send in a piece of data about the emitter.
23
25
  #
24
26
  # Two general rules:
@@ -50,6 +52,7 @@ module Carbon
50
52
  # translation_table[:make] = 'epa_code'
51
53
  translation_table[characteristic] = options[:key]
52
54
  end
55
+
53
56
  # Third-person singular preferred.
54
57
  alias :provides :provide
55
58
  end
@@ -17,6 +17,15 @@ module Carbon
17
17
  data['updated_at'] = ::Time.parse(data['updated_at']) if data.has_key? 'updated_at'
18
18
  data
19
19
  end
20
+
21
+ attr_writer :callback_content_type
22
+ attr_writer :key
23
+ attr_writer :timeout
24
+ attr_writer :defer
25
+ attr_accessor :callback
26
+ attr_accessor :timeframe
27
+ attr_accessor :guid
28
+ attr_reader :emitter
20
29
 
21
30
  def initialize(emitter)
22
31
  @emitter = emitter
@@ -55,14 +64,7 @@ module Carbon
55
64
  super
56
65
  end
57
66
  end
58
- attr_writer :callback_content_type
59
- attr_writer :key
60
- attr_writer :timeout
61
- attr_writer :defer
62
- attr_accessor :callback
63
- attr_accessor :timeframe
64
- attr_accessor :guid
65
- attr_reader :emitter
67
+
66
68
  def data
67
69
  if storage.present?
68
70
  storage.data
@@ -70,58 +72,74 @@ module Carbon
70
72
  response.data
71
73
  end
72
74
  end
75
+
73
76
  def storage
74
77
  @storage ||= {}
75
78
  return @storage[guid] if @storage.has_key? guid
76
79
  @storage[guid] = Storage.new self
77
80
  end
81
+
78
82
  def request
79
83
  @request ||= Request.new self
80
84
  end
85
+
81
86
  # Here's where caching takes place.
82
87
  def response
83
88
  current_params = request.params
84
89
  @response ||= {}
85
90
  return @response[current_params] if @response.has_key? current_params
86
- @response[current_params] = Response.new self
91
+ response_object = Response.new self
92
+ response_object.load_data
93
+ @response[current_params] = response_object
87
94
  end
95
+
88
96
  def defer?
89
97
  @defer == true
90
98
  end
99
+
91
100
  def async?
92
101
  callback or defer?
93
102
  end
103
+
94
104
  def mode
95
105
  async? ? :async : :realtime
96
106
  end
107
+
97
108
  # Timeout on realtime requests in seconds, if desired.
98
109
  def timeout
99
110
  @timeout
100
111
  end
112
+
101
113
  def callback_content_type
102
114
  @callback_content_type || 'application/json'
103
115
  end
116
+
104
117
  def key
105
118
  @key || ::Carbon.key
106
119
  end
120
+
107
121
  # The timeframe being looked at in the emission calculation.
108
122
  def active_subtimeframe
109
123
  data['active_subtimeframe']
110
124
  end
125
+
111
126
  # Another way to access the emission value.
112
127
  # Useful if you don't like treating <tt>EmissionEstimate</tt> objects like <tt>Numeric</tt> objects (even though they do quack like numbers...)
113
128
  def number
114
129
  async? ? nil : data['emission'].to_f.freeze
115
130
  end
131
+
116
132
  # The units of the emission.
117
133
  def emission_units
118
134
  data['emission_units']
119
135
  end
136
+
120
137
  # Errors (and warnings) as reported in the response.
121
138
  # Note: may contain HTML tags like KBD or A
122
139
  def errors
123
140
  data['errors']
124
141
  end
142
+
125
143
  # The URL of the methodology report indicating how this estimate was calculated.
126
144
  # > my_car.emission_estimate.methodology
127
145
  # => 'http://carbon.brighterplanet.com/automobiles.html?[...]'
@@ -2,15 +2,19 @@ module Carbon
2
2
  class EmissionEstimate
3
3
  class Request
4
4
  attr_reader :parent
5
+
5
6
  def initialize(parent)
6
7
  @parent = parent
7
8
  end
9
+
8
10
  def body
9
11
  params.to_query
10
12
  end
13
+
11
14
  def params
12
15
  send "#{parent.mode}_params"
13
16
  end
17
+
14
18
  def async_params # :nodoc:
15
19
  raise ::ArgumentError, "When using :callback you cannot specify :defer" if parent.defer? and parent.callback
16
20
  raise ::ArgumentError, "When using :defer => true you must specify :guid" if parent.defer? and parent.guid.blank?
@@ -25,9 +29,11 @@ module Carbon
25
29
  :MessageBody => hash.to_query
26
30
  }
27
31
  end
32
+
28
33
  def realtime_params # :nodoc:
29
34
  _params
30
35
  end
36
+
31
37
  # Used internally, but you can look if you want.
32
38
  #
33
39
  # Returns the params hash that will be send to the emission estimate server.
@@ -60,12 +66,15 @@ module Carbon
60
66
  hash[:key] = parent.key if parent.key
61
67
  hash
62
68
  end
69
+
63
70
  def realtime_url # :nodoc:
64
71
  "#{::Carbon::REALTIME_URL}/#{parent.emitter.class.carbon_base.emitter_common_name.pluralize}.json"
65
72
  end
73
+
66
74
  def async_url # :nodoc:
67
75
  ::Carbon::ASYNC_URL
68
76
  end
77
+
69
78
  def url
70
79
  send "#{parent.mode}_url"
71
80
  end
@@ -5,17 +5,23 @@ module Carbon
5
5
  attr_reader :data
6
6
  attr_reader :raw_request
7
7
  attr_reader :raw_response
8
+
8
9
  def initialize(parent)
9
10
  @parent = parent
11
+ end
12
+
13
+ def load_data
10
14
  send "load_#{parent.mode}_data"
11
15
  end
16
+
17
+ private
12
18
  def load_realtime_data # :nodoc:
13
19
  attempts = 0
14
20
  response = nil
15
21
  begin
16
22
  response = perform
17
- raise ::Carbon::RateLimited if response.status_code == 403 and response.body =~ /Rate Limit/i
18
- rescue ::Carbon::RateLimited
23
+ raise ::Carbon::RateLimited if response.status_code == 403 and response.body =~ /Rate Limit/i #TODO: Should we expect an HTTP 402: payment required, instead?
24
+ rescue ::Carbon::RateLimited, EOFError
19
25
  if attempts < 4
20
26
  attempts += 1
21
27
  sleep 0.2 * attempts
@@ -24,26 +30,29 @@ module Carbon
24
30
  raise $!
25
31
  end
26
32
  end
27
- raise ::Carbon::RealtimeEstimateFailed unless response.success?
33
+ raise ::Carbon::RealtimeEstimateFailed unless response.success? #TODO: should we expect 300s as well as 200s? Also, we may want to include response code and body in our exception.
28
34
  @data = ::Carbon::EmissionEstimate.parse response.body
29
35
  end
36
+
30
37
  def load_async_data # :nodoc:
31
38
  response = perform
32
- raise ::Carbon::QueueingFailed unless response.success?
39
+ raise ::Carbon::QueueingFailed unless response.success? #TODO: should we expect 300s as well as 200s? Also, we may want to include response code and body in our exception.
33
40
  @data = {}
34
41
  end
42
+
35
43
  def perform # :nodoc:
36
44
  response = nil
37
45
  if parent.timeout
38
46
  ::SystemTimer.timeout_after(parent.timeout) do
39
- response = _perform
47
+ response = perform_request
40
48
  end
41
49
  else
42
- response = _perform
50
+ response = perform_request
43
51
  end
44
52
  response
45
53
  end
46
- def _perform # :nodoc:
54
+
55
+ def perform_request # :nodoc:
47
56
  @raw_request = ::REST::Request.new :post, ::URI.parse(parent.request.url), parent.request.body, {'Content-Type' => 'application/x-www-form-urlencoded; charset=utf-8'}
48
57
  @raw_response = raw_request.perform
49
58
  end
@@ -4,15 +4,19 @@ module Carbon
4
4
  attr_accessor :parent
5
5
  attr_reader :raw_request
6
6
  attr_reader :raw_response
7
+
7
8
  def initialize(parent)
8
9
  @parent = parent
9
10
  end
11
+
10
12
  def url
11
13
  "#{::Carbon::STORAGE_URL}/#{::Digest::SHA1.hexdigest(parent.key+parent.guid)}"
12
14
  end
15
+
13
16
  def present?
14
17
  parent.guid.present? and data.present?
15
18
  end
19
+
16
20
  def data
17
21
  return @data[0] if @data.is_a? ::Array
18
22
  @raw_request = ::REST::Request.new :get, ::URI.parse(url)
@@ -0,0 +1,34 @@
1
+ require 'spec_helper'
2
+
3
+ describe Carbon::EmissionEstimate::Response do
4
+ let(:parent) { mock(Object, :mode => :realtime) }
5
+ let(:response) { Carbon::EmissionEstimate::Response.new parent }
6
+ let(:rest_response) { mock(Object, :success? => true, :status_code => 200,
7
+ :body => 'OK') }
8
+
9
+ describe '#load_realtime_data' do
10
+ before do
11
+ ::Carbon::EmissionEstimate.stub! :parse
12
+ response.stub! :sleep
13
+ end
14
+
15
+ it 'should retry a request that is rate limited' do
16
+ response.should_receive(:perform).once.ordered.
17
+ and_raise ::Carbon::RateLimited
18
+ response.should_receive(:perform).once.ordered.
19
+ and_return rest_response
20
+
21
+ response.send :load_realtime_data
22
+ end
23
+
24
+ it 'should retry a request that gets cut off (server disappears mid-request)' do
25
+ response.should_receive(:perform).once.ordered.
26
+ and_raise EOFError
27
+ response.should_receive(:perform).once.ordered.
28
+ and_return rest_response
29
+
30
+ response.send :load_realtime_data
31
+ end
32
+ end
33
+ end
34
+
@@ -130,11 +130,11 @@ module Carbon
130
130
  attr_accessor :sleep_before_performing
131
131
  VALID_OPTIONS.push :sleep_before_performing
132
132
  class Response
133
- def _perform_with_delay
133
+ def perform_request_with_delay
134
134
  sleep parent.sleep_before_performing if parent.sleep_before_performing
135
- _perform_without_delay
135
+ perform_request_without_delay
136
136
  end
137
- alias_method_chain :_perform, :delay
137
+ alias_method_chain :perform_request, :delay
138
138
  end
139
139
  end
140
140
  end
data/spec/spec_helper.rb CHANGED
@@ -1,8 +1,8 @@
1
1
  require 'rubygems'
2
2
  require 'rspec'
3
- begin
4
- require 'ruby-debug'
5
- rescue
6
- end
3
+ #begin
4
+ # require 'ruby-debug'
5
+ #rescue
6
+ #end
7
7
 
8
8
  require 'carbon'
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: carbon
3
3
  version: !ruby/object:Gem::Version
4
- hash: 29
4
+ hash: 27
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
8
  - 2
9
- - 5
10
- version: 0.2.5
9
+ - 6
10
+ version: 0.2.6
11
11
  platform: ruby
12
12
  authors:
13
13
  - Derek Kastner
@@ -17,7 +17,7 @@ autorequire:
17
17
  bindir: bin
18
18
  cert_chain: []
19
19
 
20
- date: 2010-08-02 00:00:00 -04:00
20
+ date: 2010-08-18 00:00:00 -04:00
21
21
  default_executable:
22
22
  dependencies:
23
23
  - !ruby/object:Gem::Dependency
@@ -158,6 +158,7 @@ files:
158
158
  - lib/carbon/emission_estimate/request.rb
159
159
  - lib/carbon/emission_estimate/response.rb
160
160
  - lib/carbon/emission_estimate/storage.rb
161
+ - spec/lib/carbon/emission_estimate/response_spec.rb
161
162
  - spec/lib/carbon_spec.rb
162
163
  - spec/spec_helper.rb
163
164
  - spec/specwatchr
@@ -196,5 +197,6 @@ signing_key:
196
197
  specification_version: 3
197
198
  summary: Carbon is a Ruby API wrapper for the Brighter Planet emission estimate web service (http://carbon.brighterplanet.com).
198
199
  test_files:
200
+ - spec/lib/carbon/emission_estimate/response_spec.rb
199
201
  - spec/lib/carbon_spec.rb
200
202
  - spec/spec_helper.rb