carbon 0.1.6 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -6,35 +6,41 @@ By querying the web service, it can estimate the carbon emissions of many real-l
6
6
 
7
7
  == Quick start
8
8
 
9
- *You'll need a Brighter Planet API key. See the "API keys" section below for details.*
9
+ <b>You'll need a Brighter Planet API key. See the "API keys" section below for details.</b>
10
10
 
11
11
  First get the gem:
12
12
 
13
13
  $ gem install carbon
14
14
 
15
- Carbon works by extending any Ruby class you're using to represent an emission source. For instance, let's say you have a Ruby class <tt>RentalCar</tt> that represents a rental car on your lot. (Note that ActiveRecord models work great with carbon.)
15
+ Carbon works by extending any Ruby class you're using to represent an emission source. For instance, let's say you have a Ruby class <tt>RentalCar</tt> that represents a rental car on your lot. (Note that ActiveRecord models work great with this gem.)
16
16
 
17
17
  class RentalCar
18
- attr_accessor :year, :make, :model, :fuel_efficiency, :daily_distance_average, :purchase_date, :retirement_date
18
+ attr_accessor :model, :model_year, :fuel_economy
19
+ class Make
20
+ attr_accessor :name
21
+ def to_param
22
+ name
23
+ end
24
+ end
25
+ def make
26
+ @make ||= Make.new
27
+ end
19
28
  end
20
29
 
21
30
  In order to calculate carbon emissions, we need to map the car's relevant attributes to characteristics that the {web service}[http://carbon.brighterplanet.com] will recognize. In this case, a review of the available characteristics for Automobile[http://carbon.brighterplanet.com/automobiles/options] yields the following map:
22
31
 
23
32
  class RentalCar
33
+ # [...]
24
34
  include Carbon
25
- [...]
26
35
  emit_as :automobile do
27
- provide :model_year, :as => :year # you say tomayto, I say tomahto
28
36
  provide :make
29
37
  provide :model
30
- provide :fuel_efficiency
31
- provide :daily_distance_estimate, :as => daily_distance_average
32
- provide :acquisition, :as => :purchase_date
33
- provide :retirement, :as => :retirement_date
38
+ provide :model_year
39
+ provide :fuel_economy, :as => :fuel_efficiency
34
40
  end
35
41
  end
36
42
 
37
- When you want to calculate emissions, simply call <tt>RentalCar</tt>#<tt>emission</tt>. Memoize this method on your class or store the result; <tt>#emision</tt> makes a web service call every time it is invoked.
43
+ When you want to calculate emissions, simply call <tt>RentalCar#emission</tt>.
38
44
 
39
45
  > my_car = RentalCar.new([...])
40
46
  => #<RentalCar [...]>
@@ -49,7 +55,7 @@ When you want to calculate emissions, simply call <tt>RentalCar</tt>#<tt>emissio
49
55
 
50
56
  === Asynchronous queries
51
57
 
52
- To request an emission estimate asynchronously, simply pass an URL as the +:callback+ option to +#emission+:
58
+ To request an emission estimate asynchronously, simply pass an URL as the <tt>:callback</tt> option to <tt>#emission</tt>:
53
59
 
54
60
  > RentalCar.new.emission :callback => http://example.com/my/callback/handler
55
61
 
data/Rakefile CHANGED
@@ -5,14 +5,15 @@ begin
5
5
  require 'jeweler'
6
6
  Jeweler::Tasks.new do |gemspec|
7
7
  gemspec.name = 'carbon'
8
- gemspec.summary = %q{A gem for calculating carbon footprints using Brighter Planet's Carbon Middleware service}
9
- gemspec.description = %q{Carbon allows you to easily calculate the carbon footprint of various activities. This is an API for the Brighter Planet Carbon Middleware service.}
8
+ gemspec.summary = %q{Carbon is a Ruby API wrapper for the Brighter Planet emission estimate web service (http://carbon.brighterplanet.com).}
9
+ gemspec.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.}
10
10
  gemspec.email = 'derek.kastner@brighterplanet.com'
11
11
  gemspec.homepage = 'http://carbon.brighterplanet.com/libraries'
12
- gemspec.authors = ['Derek Kastner', 'Seamus Abshere']
12
+ gemspec.authors = ['Derek Kastner', 'Seamus Abshere', 'Andy Rossmeissl']
13
13
  gemspec.add_dependency 'activesupport', '>=2.3.5'
14
14
  gemspec.add_dependency 'nap', '>=0.4'
15
15
  gemspec.add_dependency 'timeframe', '>=0.0.7'
16
+ gemspec.add_dependency 'blockenspiel', '>=0.3.2'
16
17
 
17
18
  gemspec.add_development_dependency 'fakeweb', '>=1.2.8'
18
19
  # sabshere 7/16/10 if you're having trouble running specs, try "rspec spec" and/or "sudo gem install rspec --pre"
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.6
1
+ 0.2.0
@@ -5,12 +5,12 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{carbon}
8
- s.version = "0.1.6"
8
+ s.version = "0.2.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
- s.authors = ["Derek Kastner", "Seamus Abshere"]
12
- s.date = %q{2010-07-20}
13
- s.description = %q{Carbon allows you to easily calculate the carbon footprint of various activities. This is an API for the Brighter Planet Carbon Middleware service.}
11
+ s.authors = ["Derek Kastner", "Seamus Abshere", "Andy Rossmeissl"]
12
+ s.date = %q{2010-07-21}
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 = [
16
16
  "README.rdoc"
@@ -35,7 +35,7 @@ Gem::Specification.new do |s|
35
35
  s.rdoc_options = ["--charset=UTF-8"]
36
36
  s.require_paths = ["lib"]
37
37
  s.rubygems_version = %q{1.3.7}
38
- s.summary = %q{A gem for calculating carbon footprints using Brighter Planet's Carbon Middleware service}
38
+ s.summary = %q{Carbon is a Ruby API wrapper for the Brighter Planet emission estimate web service (http://carbon.brighterplanet.com).}
39
39
  s.test_files = [
40
40
  "spec/lib/carbon_spec.rb",
41
41
  "spec/spec_helper.rb"
@@ -49,12 +49,14 @@ Gem::Specification.new do |s|
49
49
  s.add_runtime_dependency(%q<activesupport>, [">= 2.3.5"])
50
50
  s.add_runtime_dependency(%q<nap>, [">= 0.4"])
51
51
  s.add_runtime_dependency(%q<timeframe>, [">= 0.0.7"])
52
+ s.add_runtime_dependency(%q<blockenspiel>, [">= 0.3.2"])
52
53
  s.add_development_dependency(%q<fakeweb>, [">= 1.2.8"])
53
54
  s.add_development_dependency(%q<rspec>, [">= 2.0.0.beta.17"])
54
55
  else
55
56
  s.add_dependency(%q<activesupport>, [">= 2.3.5"])
56
57
  s.add_dependency(%q<nap>, [">= 0.4"])
57
58
  s.add_dependency(%q<timeframe>, [">= 0.0.7"])
59
+ s.add_dependency(%q<blockenspiel>, [">= 0.3.2"])
58
60
  s.add_dependency(%q<fakeweb>, [">= 1.2.8"])
59
61
  s.add_dependency(%q<rspec>, [">= 2.0.0.beta.17"])
60
62
  end
@@ -62,6 +64,7 @@ Gem::Specification.new do |s|
62
64
  s.add_dependency(%q<activesupport>, [">= 2.3.5"])
63
65
  s.add_dependency(%q<nap>, [">= 0.4"])
64
66
  s.add_dependency(%q<timeframe>, [">= 0.0.7"])
67
+ s.add_dependency(%q<blockenspiel>, [">= 0.3.2"])
65
68
  s.add_dependency(%q<fakeweb>, [">= 1.2.8"])
66
69
  s.add_dependency(%q<rspec>, [">= 2.0.0.beta.17"])
67
70
  end
@@ -9,7 +9,6 @@ require 'active_support/version'
9
9
  active_support/core_ext/hash/keys
10
10
  active_support/core_ext/hash/reverse_merge
11
11
  active_support/core_ext/object/to_query
12
- active_support/core_ext/array/wrap
13
12
  active_support/inflector/inflections
14
13
  active_support/json/decoding
15
14
  }.each do |active_support_3_requirement|
@@ -78,9 +77,7 @@ module Carbon
78
77
 
79
78
  # Returns an emission estimate.
80
79
  #
81
- # Note: <b>You need to take care of storing the return value to a local variable!</b> Every call to <tt>emission</tt> runs a query.
82
- #
83
- # Note also: please see the README about exceptions that you should watch out for.
80
+ # Note: please see the README about <b>exceptions that you should watch out for</b>.
84
81
  #
85
82
  # You can use it like a number...
86
83
  # > my_car.emission + 5.1
@@ -21,30 +21,34 @@ module Carbon
21
21
  end
22
22
  # Indicate that you will send in a piece of data about the emitter.
23
23
  #
24
- # If you don't use the <tt>:as</tt> option, the name of the getter method will be guessed.
24
+ # Two general rules:
25
+ # * Take note of what Brighter Planet expects to receive. If you send <tt>fuel_economy</tt> and we're expecting <tt>fuel_efficiency</tt>, we won't understand! (Hint: use the <tt>:as</tt> option.)
26
+ # * Make sure <tt>#to_param</tt> is set up. The gem always calls <tt>#to_param</tt> before sending, so that's your change to key things by "EPA code" (fictional) or whatever else you want. (Hint: use the <tt>:key</tt> option.)
25
27
  #
26
28
  # There are two optional parameters:
27
- # * <tt>:of</tt> - the owner of a nested characteristic. So to send <tt>model[name]</tt> you write <tt>provide :name, :of => :model</tt>
28
- # * <tt>:as</tt> - the local getter name. So if Brighter Planet expects <tt>fuel_efficiency</tt>, and you only have <tt>fuel_economy</tt>, you can write <tt>provide :fuel_efficiency, :as => :fuel_economy</tt>.
29
+ # * <tt>:as</tt> - if Brighter Planet expects <tt>fuel_efficiency</tt>, and you say <tt>mpg</tt>, you can write <tt>provide :mpg, :as => :fuel_efficiency</tt>. This will result in a query like <tt>?fuel_efficiency=XYZ</tt>.
30
+ # * <tt>:key</tt> - if Brighter Planet expects a make's name ("Nissan") and you want to look things up by (fictional) "EPA code", you could say <tt>provide :make, :key => :epa_code</tt>. This will result in a query like <tt>?make[epa_code]=ABC</tt>.
29
31
  #
30
- # For example:
31
- #
32
- # emit_as :automobile do
33
- # # Official Brighter Planet characteristic name Your name for it
34
- # provide :model, :as => :carline_class # model carline_class
35
- # provide :name, :of => :make, :as => :mfr_name # make[name] mfr_name
32
+ # # What's sent to Brighter Planet
33
+ # emit_as :automobile do
34
+ # provide :mpg, :as => :fuel_efficiency # fuel_efficiency=my_car.mpg.to_param
35
+ # provide :make, :key => :epa_code # make[epa_code]=my_car.make.to_param
36
+ # # or really shaking things up...
37
+ # provide :manufacturer, :as => :make, :key => :epa_code # make[epa_code]=my_car.manufacturer.to_param
36
38
  # end
39
+ #
40
+ # Note that no matter what you send to us, the gem always calls <b>to_param</b> on the emitter. In this example, it's up to you to make sure my_car.manufacturer.to_param returns an epa_code.
37
41
  def provide(attr_name, options = {})
38
42
  options = options.symbolize_keys
39
- characteristic = if options.has_key? :of
40
- # [ :mixer, :size ]
41
- [options[:of], attr_name]
43
+ characteristic = if options.has_key? :as
44
+ # [ :mpg, :fuel_efficiency ]
45
+ [attr_name, options[:as]]
42
46
  else
43
- # :oven_count
47
+ # :make
44
48
  attr_name
45
49
  end
46
- # translation_table[[:mixer,:size]] = 'mixer_size'
47
- translation_table[characteristic] = options[:as] || Array.wrap(characteristic).join('_')
50
+ # translation_table[:make] = 'epa_code'
51
+ translation_table[characteristic] = options[:key]
48
52
  end
49
53
  # japanese-style preferred
50
54
  alias :provides :provide
@@ -27,20 +27,27 @@ module Carbon
27
27
  # Returns the params hash that will be send to the emission estimate server.
28
28
  def params
29
29
  params = parent.emitter.class.carbon_base.translation_table.inject({}) do |memo, translation|
30
- characteristic, as = translation
31
- current_value = parent.emitter.send as
30
+ characteristic, key = translation
31
+ if characteristic.is_a? ::Array
32
+ current_value = parent.emitter.send characteristic[0]
33
+ as = characteristic[1]
34
+ else
35
+ current_value = parent.emitter.send characteristic
36
+ as = characteristic
37
+ end
38
+ current_value = current_value.to_param
32
39
  if current_value.present?
33
- if characteristic.is_a? Array # [:mixer, :size]
34
- memo[characteristic[0]] ||= {} # { :mixer => Hash.new }
35
- memo[characteristic[0]][characteristic[1]] = current_value # { :mixer => { :size => 'foo' }}
36
- else # :oven_count
37
- memo[characteristic] = current_value # { :oven_count => 'bar' }
40
+ if key
41
+ memo[as] ||= {}
42
+ memo[as][key] = current_value
43
+ else
44
+ memo[as] = current_value
38
45
  end
39
46
  end
40
47
  memo
41
48
  end
42
- params[:timeframe] = parent.timeframe
43
- params[:key] = parent.key
49
+ params[:timeframe] = parent.timeframe if parent.timeframe
50
+ params[:key] = parent.key if parent.key
44
51
  params
45
52
  end
46
53
  def realtime_url # :nodoc:
@@ -2,24 +2,41 @@ require 'spec_helper'
2
2
 
3
3
  class RentalCar
4
4
  include Carbon
5
- attr_accessor :make, :model, :model_year, :fuel_economy
5
+ attr_accessor :model, :model_year, :fuel_economy
6
+ class Make
7
+ attr_accessor :name
8
+ def to_param
9
+ name
10
+ end
11
+ end
12
+ def make
13
+ @make ||= Make.new
14
+ end
6
15
  emit_as :automobile do
7
16
  provide :make
8
17
  provide :model
9
18
  provide :model_year
10
- provide :fuel_efficiency, :as => :fuel_economy
19
+ provide :fuel_economy, :as => :fuel_efficiency
11
20
  end
12
21
  end
13
22
 
14
23
  class DonutFactory
15
24
  include Carbon
16
- attr_accessor :smokestack_size, :oven_count, :mixer_size, :mixer_wattage, :employees
25
+ attr_accessor :smokestack_size, :oven_count, :employees
26
+ class Mixer
27
+ attr_accessor :upc
28
+ def to_param
29
+ upc
30
+ end
31
+ end
32
+ def mixer
33
+ @mixer ||= Mixer.new
34
+ end
17
35
  emit_as :factory do
18
36
  provide :smokestack_size
19
37
  provide :oven_count
20
- provide :size, :of => :mixer
21
- provide :wattage, :of => :mixer
22
- provide :personnel, :as => :employees
38
+ provide :employees, :as => :personnel
39
+ provide :mixer, :key => :upc
23
40
  end
24
41
  end
25
42
 
@@ -60,19 +77,37 @@ describe Carbon do
60
77
  c.emission.should == 134.599
61
78
  c.emission.response.raw_request.object_id.should_not == first_raw_request.object_id
62
79
  end
80
+
81
+ it "should recalculate if parameters change (though the options hash)" do
82
+ c = RentalCar.new
83
+ c.model = 'Acura'
84
+ c.model_year = 2003
85
+ c.fuel_economy = 32
86
+ c.emission.should == 134.599
87
+ first_raw_request = c.emission.response.raw_request
88
+ c.emission(:timeframe => Timeframe.new(:year => 2009)).should == 134.599
89
+ c.emission.response.raw_request.object_id.should_not == first_raw_request.object_id
90
+ end
63
91
  end
64
92
 
65
93
  describe 'synchronous (realtime) requests' do
66
- it 'should handle complex attributes like mixer[size]' do
94
+ it 'should send simple params' do
95
+ d = DonutFactory.new
96
+ d.oven_count = 12_000
97
+ d.emission.request.body.should =~ /oven_count=12000/
98
+ end
99
+
100
+ it 'send complex params' do
67
101
  d = DonutFactory.new
68
- d.mixer_size = 20
69
- d.emission.request.body.should =~ /mixer\[size\]=20/
102
+ d.mixer.upc = 123
103
+ d.emission.request.body.should =~ /mixer\[upc\]=123/
70
104
  end
71
105
 
72
106
  it 'should not send attributes that are blank' do
73
107
  d = DonutFactory.new
74
- d.mixer_size = 20
108
+ d.mixer.upc = 123
75
109
  d.emission.request.body.should_not =~ /oven_count/
110
+ d.emission.request.body.should_not =~ /timeframe/
76
111
  end
77
112
 
78
113
  it 'should send the key' do
metadata CHANGED
@@ -5,18 +5,19 @@ version: !ruby/object:Gem::Version
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
- - 1
9
- - 6
10
- version: 0.1.6
8
+ - 2
9
+ - 0
10
+ version: 0.2.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Derek Kastner
14
14
  - Seamus Abshere
15
+ - Andy Rossmeissl
15
16
  autorequire:
16
17
  bindir: bin
17
18
  cert_chain: []
18
19
 
19
- date: 2010-07-20 00:00:00 -05:00
20
+ date: 2010-07-21 00:00:00 -05:00
20
21
  default_executable:
21
22
  dependencies:
22
23
  - !ruby/object:Gem::Dependency
@@ -67,9 +68,25 @@ dependencies:
67
68
  type: :runtime
68
69
  version_requirements: *id003
69
70
  - !ruby/object:Gem::Dependency
70
- name: fakeweb
71
+ name: blockenspiel
71
72
  prerelease: false
72
73
  requirement: &id004 !ruby/object:Gem::Requirement
74
+ none: false
75
+ requirements:
76
+ - - ">="
77
+ - !ruby/object:Gem::Version
78
+ hash: 23
79
+ segments:
80
+ - 0
81
+ - 3
82
+ - 2
83
+ version: 0.3.2
84
+ type: :runtime
85
+ version_requirements: *id004
86
+ - !ruby/object:Gem::Dependency
87
+ name: fakeweb
88
+ prerelease: false
89
+ requirement: &id005 !ruby/object:Gem::Requirement
73
90
  none: false
74
91
  requirements:
75
92
  - - ">="
@@ -81,11 +98,11 @@ dependencies:
81
98
  - 8
82
99
  version: 1.2.8
83
100
  type: :development
84
- version_requirements: *id004
101
+ version_requirements: *id005
85
102
  - !ruby/object:Gem::Dependency
86
103
  name: rspec
87
104
  prerelease: false
88
- requirement: &id005 !ruby/object:Gem::Requirement
105
+ requirement: &id006 !ruby/object:Gem::Requirement
89
106
  none: false
90
107
  requirements:
91
108
  - - ">="
@@ -99,8 +116,8 @@ dependencies:
99
116
  - 17
100
117
  version: 2.0.0.beta.17
101
118
  type: :development
102
- version_requirements: *id005
103
- description: Carbon allows you to easily calculate the carbon footprint of various activities. This is an API for the Brighter Planet Carbon Middleware service.
119
+ version_requirements: *id006
120
+ description: 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.
104
121
  email: derek.kastner@brighterplanet.com
105
122
  executables: []
106
123
 
@@ -156,7 +173,7 @@ rubyforge_project:
156
173
  rubygems_version: 1.3.7
157
174
  signing_key:
158
175
  specification_version: 3
159
- summary: A gem for calculating carbon footprints using Brighter Planet's Carbon Middleware service
176
+ summary: Carbon is a Ruby API wrapper for the Brighter Planet emission estimate web service (http://carbon.brighterplanet.com).
160
177
  test_files:
161
178
  - spec/lib/carbon_spec.rb
162
179
  - spec/spec_helper.rb