carbon 0.1.4 → 0.1.5

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.
@@ -6,17 +6,19 @@ By querying the web service, it can estimate the carbon emissions of many real-l
6
6
 
7
7
  == Quick start
8
8
 
9
- First get the gem!
9
+ *You'll need a Brighter Planet API key. See the "API keys" section below for details.*
10
+
11
+ First get the gem:
10
12
 
11
13
  $ gem install carbon
12
14
 
13
- Carbon works by extending any Ruby class you're using to represent an emission source. For instance, let's say you have a plain Ruby class <tt>RentalCar</tt> that represents a rental car on your lot: (<tt>ActiveRecord</tt> models work fine too!)
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.)
14
16
 
15
17
  class RentalCar
16
18
  attr_accessor :year, :make, :model, :fuel_efficiency, :daily_distance_average, :purchase_date, :retirement_date
17
19
  end
18
20
 
19
- In order to calculate carbon emissions, we need to map the car's relevant attributes to correctly-named characteristics that the {web service}[http://carbon.brighterplanet.com] will recognize:
21
+ 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:
20
22
 
21
23
  class RentalCar
22
24
  include Carbon
@@ -32,7 +34,7 @@ In order to calculate carbon emissions, we need to map the car's relevant attrib
32
34
  end
33
35
  end
34
36
 
35
- When you want to calculate emissions, simply call <tt>RentalCar</tt>#<tt>emission</tt>... (and <b>store the result to a local variable!</b> Otherwise it will make a web service call every time.)
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.
36
38
 
37
39
  > my_car = RentalCar.new([...])
38
40
  => #<RentalCar [...]>
@@ -44,10 +46,20 @@ When you want to calculate emissions, simply call <tt>RentalCar</tt>#<tt>emissio
44
46
  => "kilograms"
45
47
  > my_emission.methodology
46
48
  => "http://carbon.brighterplanet.com/automobiles.html?[...]"
49
+
50
+ === Asynchronous queries
51
+
52
+ To request an emission estimate asynchronously, simply pass an URL as the +:callback+ option to +#emission+:
53
+
54
+ > RentalCar.new.emission :callback => http://example.com/my/callback/handler
55
+
56
+ A good way to test this is to set up a {PostBin}[http://postbin.org]
47
57
 
48
- Read the {carbon gem RDoc}[http://rdoc.info/projects/brighterplanet/carbon] for more!
58
+ == Documentation
49
59
 
50
- == Exceptions to watch out for
60
+ Read the {carbon gem RDoc}[http://rdoc.info/projects/brighterplanet/carbon] for more.
61
+
62
+ == Exceptions
51
63
 
52
64
  Since this gem connects to a web service, you need to be ready for network problems and latency. For example:
53
65
 
@@ -71,7 +83,7 @@ Since this gem connects to a web service, you need to be ready for network probl
71
83
  # Please contact us at staff@brighterplanet.com if you see too many of these.
72
84
  end
73
85
 
74
- == A note on API keys
86
+ == API keys
75
87
 
76
88
  You should get an API key from http://keys.brighterplanet.com and set it globally:
77
89
 
@@ -79,27 +91,6 @@ You should get an API key from http://keys.brighterplanet.com and set it globall
79
91
 
80
92
  Now all of your queries will use that key.
81
93
 
82
- == A note on modes
83
-
84
- When you send in a query, you have two options for how you want the result back:
85
-
86
- * realtime - you get the answer back immediately. More expensive.
87
- * async - the answer is POSTed back to a URL that you specify. You must have a server waiting for it! Cheaper.
88
-
89
- The default is realtime:
90
-
91
- > my_emission = RentalCar.new.emission
92
- => #<Carbon::EmissionEstimate [...]>
93
-
94
- A good way to test the "async" mode is to set up a {PostBin}[http://postbin.org]
95
-
96
- > RentalCar.new.emission :mode => :async, :callback => 'http://postbin.org/1dj0145'
97
- => true # useless, but go check out http://postbin.org/1dj0145
98
-
99
- You can set the mode globally with
100
-
101
- Carbon.mode = :async
102
-
103
94
  == Copyright
104
95
 
105
96
  Copyright (c) 2010 Brighter Planet.
data/Rakefile CHANGED
@@ -10,12 +10,13 @@ begin
10
10
  gemspec.email = 'derek.kastner@brighterplanet.com'
11
11
  gemspec.homepage = 'http://carbon.brighterplanet.com/libraries'
12
12
  gemspec.authors = ['Derek Kastner', 'Seamus Abshere']
13
- gemspec.add_dependency 'activesupport', '>=3.0.0.beta2'
13
+ gemspec.add_dependency 'activesupport', '>=2.3.5'
14
14
  gemspec.add_dependency 'nap', '>=0.4'
15
- gemspec.add_dependency 'timeframe', '>=0.0.6'
15
+ gemspec.add_dependency 'timeframe', '>=0.0.7'
16
16
 
17
17
  gemspec.add_development_dependency 'fakeweb', '>=1.2.8'
18
18
  # sabshere 7/16/10 if you're having trouble running specs, try "rspec spec" and/or "sudo gem install rspec --pre"
19
+ # sabshere 7/20/10 this might not work with activesupport 2
19
20
  gemspec.add_development_dependency 'rspec', '>=2.0.0.beta.17'
20
21
  end
21
22
  Jeweler::GemcutterTasks.new
@@ -52,7 +53,7 @@ Rake::RDocTask.new do |rdoc|
52
53
  version = File.exist?('VERSION') ? File.read('VERSION') : ""
53
54
 
54
55
  rdoc.rdoc_dir = 'rdoc'
55
- rdoc.title = "decider #{version}"
56
+ rdoc.title = "carbon #{version}"
56
57
  rdoc.rdoc_files.include('README*')
57
58
  rdoc.rdoc_files.include('lib/**/*.rb')
58
59
  end
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.4
1
+ 0.1.5
@@ -5,7 +5,7 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{carbon}
8
- s.version = "0.1.4"
8
+ s.version = "0.1.5"
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"]
@@ -44,22 +44,22 @@ Gem::Specification.new do |s|
44
44
  s.specification_version = 3
45
45
 
46
46
  if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
47
- s.add_runtime_dependency(%q<activesupport>, [">= 3.0.0.beta2"])
47
+ s.add_runtime_dependency(%q<activesupport>, [">= 2.3.5"])
48
48
  s.add_runtime_dependency(%q<nap>, [">= 0.4"])
49
- s.add_runtime_dependency(%q<timeframe>, [">= 0.0.6"])
49
+ s.add_runtime_dependency(%q<timeframe>, [">= 0.0.7"])
50
50
  s.add_development_dependency(%q<fakeweb>, [">= 1.2.8"])
51
51
  s.add_development_dependency(%q<rspec>, [">= 2.0.0.beta.17"])
52
52
  else
53
- s.add_dependency(%q<activesupport>, [">= 3.0.0.beta2"])
53
+ s.add_dependency(%q<activesupport>, [">= 2.3.5"])
54
54
  s.add_dependency(%q<nap>, [">= 0.4"])
55
- s.add_dependency(%q<timeframe>, [">= 0.0.6"])
55
+ s.add_dependency(%q<timeframe>, [">= 0.0.7"])
56
56
  s.add_dependency(%q<fakeweb>, [">= 1.2.8"])
57
57
  s.add_dependency(%q<rspec>, [">= 2.0.0.beta.17"])
58
58
  end
59
59
  else
60
- s.add_dependency(%q<activesupport>, [">= 3.0.0.beta2"])
60
+ s.add_dependency(%q<activesupport>, [">= 2.3.5"])
61
61
  s.add_dependency(%q<nap>, [">= 0.4"])
62
- s.add_dependency(%q<timeframe>, [">= 0.0.6"])
62
+ s.add_dependency(%q<timeframe>, [">= 0.0.7"])
63
63
  s.add_dependency(%q<fakeweb>, [">= 1.2.8"])
64
64
  s.add_dependency(%q<rspec>, [">= 2.0.0.beta.17"])
65
65
  end
@@ -2,6 +2,7 @@ require 'uri'
2
2
  require 'blockenspiel'
3
3
  require 'rest' # provided by nap gem
4
4
  require 'timeframe'
5
+ require 'active_support/version'
5
6
  %w{
6
7
  active_support/core_ext/module/attribute_accessors
7
8
  active_support/core_ext/class/attribute_accessors
@@ -13,7 +14,7 @@ require 'timeframe'
13
14
  active_support/json/decoding
14
15
  }.each do |active_support_3_requirement|
15
16
  require active_support_3_requirement
16
- end
17
+ end if ActiveSupport::VERSION::MAJOR == 3
17
18
  require 'carbon/base'
18
19
  require 'carbon/emission_estimate'
19
20
 
@@ -42,12 +43,9 @@ module Carbon
42
43
  klass.extend ClassMethods
43
44
  end
44
45
 
45
- MODES = [ :realtime, :async ]
46
46
  REALTIME_URL = 'http://carbon.brighterplanet.com'
47
47
  ASYNC_URL = 'https://queue.amazonaws.com/121562143717/cm1_production_incoming'
48
48
 
49
- class UnrecognizedMode < ArgumentError # :nodoc:
50
- end
51
49
  class BlankCallback < ArgumentError # :nodoc:
52
50
  end
53
51
  class RealtimeEstimateFailed < RuntimeError # :nodoc:
@@ -59,30 +57,15 @@ module Carbon
59
57
 
60
58
  # The api key obtained from http://keys.brighterplanet.com
61
59
  mattr_accessor :key
62
-
63
- mattr_accessor :_mode
64
- # Return the current mode. Defaults to <tt>:realtime</tt>.
65
- def self.mode
66
- _mode || :realtime
67
- end
68
- # Set the current mode.
69
- # * Realtime mode (<tt>:realtime</tt>) means you get the answer back immediately.
70
- # * Async mode (<tt>:async</tt>) means the answer will be POSTed back to you at a URL you specify. You must have a server waiting to receive it!
71
- def self.mode=(str)
72
- self._mode = str.to_sym
73
- raise UnrecognizedMode unless MODES.include? mode
74
- end
75
-
76
- def self.default_options # :nodoc:
77
- {
78
- :key => key,
79
- :mode => mode
80
- }
60
+
61
+ def self.prepare_options(options) # :nodoc:
62
+ options[:key] ||= key
63
+ options[:mode] ||= options.has_key?(:callback) ? :async : :realtime
81
64
  end
82
-
83
- # You will probably never access this module directly. Instead, you'll use it through the DSL.
84
- #
85
- # It's mixed into any class that includes <tt>Carbon</tt>.
65
+
66
+ # You will probably never access this module directly. Instead, you'll use it through the DSL.
67
+ #
68
+ # It's mixed into any class that includes <tt>Carbon</tt>.
86
69
  module ClassMethods
87
70
  # Indicate that this class "emits as" an <tt>:automobile</tt>, <tt>:flight</tt>, or another of the Brighter Planet emitter classes.
88
71
  #
@@ -108,7 +91,7 @@ module Carbon
108
91
  # > my_car._carbon_request_url
109
92
  # => 'http://carbon.brighterplanet.com/automobiles.json'
110
93
  def _carbon_request_url(options = {})
111
- options.reverse_merge! ::Carbon.default_options
94
+ ::Carbon.prepare_options options
112
95
  send "_#{options[:mode]}_carbon_request_url"
113
96
  end
114
97
 
@@ -128,7 +111,7 @@ module Carbon
128
111
  # > my_car._carbon_request_body
129
112
  # => 'fuel_efficiency=41&model=Ford+Taurus'
130
113
  def _carbon_request_body(options = {})
131
- options.reverse_merge! ::Carbon.default_options
114
+ ::Carbon.prepare_options options
132
115
  send "_#{options[:mode]}_carbon_request_body", options
133
116
  end
134
117
 
@@ -153,7 +136,7 @@ module Carbon
153
136
  #
154
137
  # Returns the params hash that will be send to the emission estimate server.
155
138
  def _carbon_request_params(options)
156
- options.reverse_merge! ::Carbon.default_options
139
+ ::Carbon.prepare_options options
157
140
  params = self.class.carbon_base.translation_table.inject(Hash.new) do |memo, translation|
158
141
  characteristic, as = translation
159
142
  current_value = send as
@@ -233,12 +216,11 @@ module Carbon
233
216
  # === Options:
234
217
  #
235
218
  # * <tt>:timeframe</tt> (optional) pass an instance of Timeframe[http://github.com/rossmeissl/timeframe] to request an emission for a specific time period.
236
- # * <tt>:callback</tt> (required in <tt>:async</tt> mode, ignored otherwise) where to POST the result when it's been calculated. You need a server waiting for it!
237
- # * <tt>:callback_content_type</tt> (optional in <tt>:async</tt> mode, ignored otherwise) pass a MIME type like 'text/yaml' so we know how to format the result when we send it to your waiting server. Defaults to 'application/json'.
238
- # * <tt>:mode</tt> (optional, overrides general <tt>Carbon</tt>.<tt>mode</tt> setting just for this query) If some of your queries are realtime and some are asynchronous, you can override the setting here.
219
+ # * <tt>:callback</tt> (optional) where to POST the result when it's been calculated. You need a server waiting for it!
220
+ # * <tt>:callback_content_type</tt> (optional if <tt>:callback</tt> is specified, ignored otherwise) pass a MIME type like 'text/yaml' so we know how to format the result when we send it to your waiting server. Defaults to 'application/json'.
239
221
  # * <tt>:key</tt> (optional, overrides general <tt>Carbon</tt>.<tt>key</tt> setting just for this query) If you want to use different API keys for different queries.
240
222
  def emission(options = {})
241
- options.reverse_merge! ::Carbon.default_options
223
+ ::Carbon.prepare_options options
242
224
  send "_#{options[:mode]}_emission", options
243
225
  end
244
226
  end
@@ -39,10 +39,6 @@ describe Carbon do
39
39
  end
40
40
 
41
41
  describe 'synchronous (realtime) requests' do
42
- before(:each) do
43
- Carbon.mode = :realtime
44
- end
45
-
46
42
  it 'should handle complex attributes like mixer[size]' do
47
43
  d = DonutFactory.new
48
44
  d.mixer_size = 20
@@ -80,20 +76,9 @@ describe Carbon do
80
76
  end
81
77
 
82
78
  describe 'asynchronous (queued) requests' do
83
- before(:each) do
84
- Carbon.mode = :async
85
- end
86
-
87
- it 'should raise an exception if no callback is provided' do
88
- c = RentalCar.new
89
- lambda {
90
- c.emission :timeframe => Timeframe.new(:year => 2009)
91
- }.should raise_error(Carbon::BlankCallback)
92
- end
93
-
94
79
  it 'should post a message to SQS' do
95
80
  c = RentalCar.new
96
- c._carbon_request_url.should =~ /queue.amazonaws.com/
81
+ c._carbon_request_url(:callback => 'http://www.postbin.org/1dj0146').should =~ /queue.amazonaws.com/
97
82
  c.emission :timeframe => Timeframe.new(:year => 2009), :callback => 'http://www.postbin.org/1dj0146'
98
83
  end
99
84
  end
@@ -5,6 +5,8 @@ begin
5
5
  rescue
6
6
  end
7
7
 
8
+ require 'active_support/json/encoding'
9
+
8
10
  require 'carbon'
9
11
 
10
12
  require 'fakeweb'
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: 19
4
+ hash: 17
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
8
  - 1
9
- - 4
10
- version: 0.1.4
9
+ - 5
10
+ version: 0.1.5
11
11
  platform: ruby
12
12
  authors:
13
13
  - Derek Kastner
@@ -27,13 +27,12 @@ dependencies:
27
27
  requirements:
28
28
  - - ">="
29
29
  - !ruby/object:Gem::Version
30
- hash: 299253626
30
+ hash: 9
31
31
  segments:
32
+ - 2
32
33
  - 3
33
- - 0
34
- - 0
35
- - beta2
36
- version: 3.0.0.beta2
34
+ - 5
35
+ version: 2.3.5
37
36
  type: :runtime
38
37
  version_requirements: *id001
39
38
  - !ruby/object:Gem::Dependency
@@ -59,12 +58,12 @@ dependencies:
59
58
  requirements:
60
59
  - - ">="
61
60
  - !ruby/object:Gem::Version
62
- hash: 19
61
+ hash: 17
63
62
  segments:
64
63
  - 0
65
64
  - 0
66
- - 6
67
- version: 0.0.6
65
+ - 7
66
+ version: 0.0.7
68
67
  type: :runtime
69
68
  version_requirements: *id003
70
69
  - !ruby/object:Gem::Dependency