carbon 1.0.4 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -20,3 +20,4 @@ pkg
20
20
 
21
21
  ## PROJECT::SPECIFIC
22
22
  Gemfile.lock
23
+ *.gem
data/README.rdoc CHANGED
@@ -154,7 +154,7 @@ It's telling you that a flight in 2009 did not result in any 2011 emissions (the
154
154
 
155
155
  So, 850 kilograms emitted in 2009.
156
156
 
157
- == Attribute serialization
157
+ == Association serialization
158
158
 
159
159
  Your objects' attributes are serialized via <tt>#to_characteristic</tt> or <tt>#to_param</tt> (in that order of preference) before being submitted to the web service.
160
160
 
@@ -180,6 +180,12 @@ Without <tt>AutomobileMake#to_characteristic</tt>, the library would have no way
180
180
 
181
181
  Runs a realtime request but allows timing out the network call. Raises <tt>Timeout::Error</tt> if timeout is exceeded.
182
182
 
183
+ == Certified calculations
184
+
185
+ You can run {certified calculations}[http://brighterplanet.com/certified] by setting <tt>certified</tt> to true.
186
+
187
+ > RentalCar.new.emission_estimate :certified => true
188
+
183
189
  == Persisted queries
184
190
 
185
191
  You can specify that the result be persisted in low-latency storage so that future identical requests can use the same estimate:
@@ -241,8 +247,12 @@ This library includes a special console for performing calculations interactivel
241
247
 
242
248
  === Emitter mode
243
249
 
250
+ In Emitter mode, the prompt displays the emitter type in use. If a timeframe has been set, the timeframe is also included in the prompt.
251
+
244
252
  [+help+] Displays a list of characteristics for this emitter type.
245
253
  [<tt><i>characteristic value</i></tt>] (e.g. <tt>origin_airport 'lax'</tt>) Provide a characteristic. Remember, this is Ruby we're dealing with, so strings must be quoted.
254
+ [+timeframe+] Display the current timeframe in effect on the emission estimate.
255
+ [<tt>timeframe <i>timeframe</i></tt>] (e.g. <tt>timeframe '2009-01-01/2010-01-01'</tt> or just <tt>timeframe '2009'</tt>) Set a timeframe on the emission estimate.
246
256
  [+emission+] Displays the current emission in kilograms CO2e for this emitter.
247
257
  [+lbs+, +pounds+, or +tons+] Display the emission using different units.
248
258
  [+characteristics+] Lists the characteristics you have provided so far.
data/Rakefile CHANGED
@@ -8,7 +8,8 @@ RSpec::Core::RakeTask.new('examples') do |c|
8
8
  c.rspec_opts = '-Ispec'
9
9
  end
10
10
 
11
- task :default => :examples
11
+ task :test => [:examples, :cucumber]
12
+ task :default => :test
12
13
 
13
14
  desc "Run specs with RCov"
14
15
  RSpec::Core::RakeTask.new(:examples_with_coverage) do |t|
@@ -26,3 +27,7 @@ Rake::RDocTask.new do |rdoc|
26
27
  rdoc.rdoc_files.include('README*')
27
28
  rdoc.rdoc_files.include('lib/**/*.rb')
28
29
  end
30
+
31
+ require 'cucumber/rake/task'
32
+ Cucumber::Rake::Task.new
33
+
data/bin/carbon CHANGED
@@ -3,15 +3,5 @@ $:.unshift(File.dirname(__FILE__) + '/../lib') unless $:.include?(File.dirname(_
3
3
 
4
4
  require 'rubygems'
5
5
  require 'carbon'
6
- require 'carbon/cli'
7
- begin
8
- # The dup is to keep ARGV intact, so that tools like ruby-debug can respawn.
9
- failure = Carbon::Cli.execute(ARGV.dup)
10
- Kernel.exit(failure ? 1 : 0)
11
- rescue SystemExit => e
12
- Kernel.exit(e.status)
13
- rescue Exception => e
14
- STDERR.puts("#{e.message} (#{e.class})")
15
- STDERR.puts(e.backtrace.join("\n"))
16
- Kernel.exit(1)
17
- end
6
+ require 'carbon/shell'
7
+ Bombshell.launch(Carbon::Shell)
data/carbon.gemspec CHANGED
@@ -25,6 +25,9 @@ Gem::Specification.new do |s|
25
25
  s.add_dependency 'timeframe'
26
26
  s.add_dependency 'blockenspiel'
27
27
  s.add_dependency 'conversions'
28
+ s.add_dependency 'brighter_planet_metadata'
29
+ s.add_dependency 'bombshell'
28
30
  s.add_development_dependency 'fakeweb'
29
31
  s.add_development_dependency 'rspec'
32
+ s.add_development_dependency 'aruba'
30
33
  end
@@ -0,0 +1,186 @@
1
+ Feature: Shell
2
+
3
+ In order to explore the CM1 API
4
+ As a potential client
5
+ I want to make simple calculations from an interactive console
6
+
7
+ Scenario: Running the shell
8
+ When I run `carbon` interactively
9
+ And I type "exit"
10
+ Then the output should contain:
11
+ """
12
+ carbon->
13
+ """
14
+
15
+ Scenario: Setting a key
16
+ When I run `carbon` interactively
17
+ And I type "key 'abc'"
18
+ And I type "exit"
19
+ Then the output should contain:
20
+ """
21
+ Using key abc
22
+ """
23
+
24
+ Scenario: Seeing a list of emitters
25
+ When I run `carbon` interactively
26
+ And I type "help"
27
+ And I type "exit"
28
+ Then the output should contain:
29
+ """
30
+ Computation
31
+ """
32
+
33
+ Scenario: Getting a calculation
34
+ When I run `carbon` interactively
35
+ And I type "computation"
36
+ And I type "done"
37
+ And I type "exit"
38
+ Then the output should contain:
39
+ """
40
+ kg CO2e
41
+ """
42
+
43
+ Scenario: Seeing a list of characteristics
44
+ When I run `carbon` interactively
45
+ And I type "computation"
46
+ And I type "help"
47
+ And I type "done"
48
+ And I type "exit"
49
+ Then the output should contain:
50
+ """
51
+ duration
52
+ """
53
+
54
+ Scenario: Setting a characteristic
55
+ When I run `carbon` interactively
56
+ And I type "computation"
57
+ And I type "duration 10"
58
+ And I type "done"
59
+ And I type "exit"
60
+ Then the output should contain:
61
+ """
62
+ kg CO2e
63
+ """
64
+
65
+ Scenario: Retrieving the default timeframe
66
+ When I run `carbon` interactively
67
+ And I type "computation"
68
+ And I type "timeframe"
69
+ And I type "done"
70
+ And I type "exit"
71
+ Then the output should contain:
72
+ """
73
+ (defaults to current year)
74
+ """
75
+
76
+ Scenario: Setting the timeframe
77
+ When I run `carbon` interactively
78
+ And I type "computation"
79
+ And I type "timeframe '2009'"
80
+ And I type "timeframe"
81
+ And I type "done"
82
+ And I type "exit"
83
+ Then the output should contain:
84
+ """
85
+ => 2009
86
+ """
87
+
88
+ Scenario: Getting the current emission
89
+ When I run `carbon` interactively
90
+ And I type "computation"
91
+ And I type "emission"
92
+ And I type "done"
93
+ And I type "exit"
94
+ Then the output should contain:
95
+ """
96
+ kg CO2e
97
+ """
98
+
99
+ Scenario: Using a different unit
100
+ When I run `carbon` interactively
101
+ And I type "computation"
102
+ And I type "lbs"
103
+ And I type "done"
104
+ And I type "exit"
105
+ Then the output should contain:
106
+ """
107
+ lbs CO2e
108
+ """
109
+
110
+ Scenario: Retrieving default characteristics
111
+ When I run `carbon` interactively
112
+ And I type "computation"
113
+ And I type "characteristics"
114
+ And I type "done"
115
+ And I type "exit"
116
+ Then the output should contain:
117
+ """
118
+ (none)
119
+ """
120
+
121
+ Scenario: Retrieving set characteristics
122
+ When I run `carbon` interactively
123
+ And I type "computation"
124
+ And I type "duration 10; characteristics; done"
125
+ And I type "exit"
126
+ Then the output should contain:
127
+ """
128
+ duration: 10
129
+ """
130
+
131
+ Scenario: Retrieving default methodology
132
+ When I run `carbon` interactively
133
+ And I type "computation"
134
+ And I type "methodology"
135
+ And I type "done"
136
+ And I type "exit"
137
+ Then the output should contain:
138
+ """
139
+ duration: default
140
+ """
141
+
142
+ Scenario: Retrieving customized methodology
143
+ When I run `carbon` interactively
144
+ And I type "computation"
145
+ And I type "duration 10; methodology; done"
146
+ And I type "exit"
147
+ Then the output should not contain:
148
+ """
149
+ duration:
150
+ """
151
+
152
+ Scenario: Retrieving reports
153
+ When I run `carbon` interactively
154
+ And I type "computation"
155
+ And I type "reports"
156
+ And I type "done"
157
+ And I type "exit"
158
+ Then the output should contain:
159
+ """
160
+ power_usage_effectiveness: 1.5
161
+ """
162
+
163
+ Scenario: Retrieving methodology URL
164
+ When I run `carbon` interactively
165
+ And I type "computation"
166
+ And I type "duration 10"
167
+ And I type "url"
168
+ And I type "done"
169
+ And I type "exit"
170
+ Then the output should contain:
171
+ """
172
+ http://carbon.brighterplanet.com/computations.json?duration=10
173
+ """
174
+
175
+ Scenario: Retrieving stored emitter
176
+ When I run `carbon` interactively
177
+ And I type "computation"
178
+ And I type "duration 10; done"
179
+ And I type "computation 0; characteristics; done"
180
+ And I type "exit"
181
+ Then the output should not contain:
182
+ """
183
+ duration: 10
184
+ """
185
+
186
+
@@ -0,0 +1,12 @@
1
+ $LOAD_PATH.unshift(File.dirname(__FILE__) + '/../../lib')
2
+ require 'aruba/cucumber'
3
+ require 'fileutils'
4
+ require 'rspec/expectations'
5
+ require 'carbon'
6
+ require 'conversions'
7
+
8
+ Before do
9
+ @aruba_io_wait_seconds = 2
10
+ @aruba_timeout_seconds = 5
11
+ @dirs = [File.join(ENV['HOME'], 'carbon_features')]
12
+ end
data/lib/carbon.rb CHANGED
@@ -11,13 +11,16 @@ require 'active_support/version'
11
11
  active_support/core_ext/hash/keys
12
12
  active_support/core_ext/hash/reverse_merge
13
13
  active_support/core_ext/object/to_query
14
+ active_support/inflector
14
15
  active_support/inflector/inflections
15
16
  active_support/json/decoding
16
17
  }.each do |active_support_3_requirement|
17
18
  require active_support_3_requirement
18
19
  end if ActiveSupport::VERSION::MAJOR == 3
20
+
19
21
  require 'carbon/base'
20
22
  require 'carbon/emission_estimate'
23
+ require 'logger'
21
24
 
22
25
  # A module (aka mixin) that lets you estimate carbon emissions by querying the {Brighter Planet carbon middleware emission estimate web service}[http://carbon.brighterplanet.com].
23
26
  #
@@ -44,10 +47,6 @@ module Carbon
44
47
  klass.extend ClassMethods
45
48
  end
46
49
 
47
- REALTIME_URL = 'http://carbon.brighterplanet.com'
48
- ASYNC_URL = 'https://queue.amazonaws.com/121562143717/cm1_production_incoming'
49
- STORAGE_URL = 'http://storage.carbon.brighterplanet.com'
50
-
51
50
  class RealtimeEstimateFailed < RuntimeError # :nodoc:
52
51
  end
53
52
  class QueueingFailed < RuntimeError # :nodoc:
@@ -59,6 +58,16 @@ module Carbon
59
58
 
60
59
  # The api key obtained from http://keys.brighterplanet.com
61
60
  mattr_accessor :key
61
+
62
+ mattr_accessor :log
63
+
64
+ def self.log #:nodoc:
65
+ @log ||= Logger.new STDOUT
66
+ end
67
+
68
+ def self.warn(msg) #:nodoc:
69
+ log.warn msg
70
+ end
62
71
 
63
72
  # You will probably never access this module directly. Instead, you'll use it through the DSL.
64
73
  #
data/lib/carbon/base.rb CHANGED
@@ -6,6 +6,7 @@ module Carbon
6
6
  include Blockenspiel::DSL
7
7
  attr_reader :klass
8
8
  attr_reader :emitter_common_name
9
+
9
10
  def initialize(klass, emitter_common_name)
10
11
  @klass = klass
11
12
  @emitter_common_name = emitter_common_name.to_s
@@ -21,7 +22,7 @@ module Carbon
21
22
  @translation_table ||= Hash.new
22
23
  end
23
24
 
24
- def reset_translation_table!
25
+ def reset_translation_table! #:nodoc:
25
26
  @translation_table = Hash.new
26
27
  end
27
28
 
@@ -11,10 +11,10 @@ module Carbon
11
11
  #
12
12
  # At the same time, they contain all the data you get back from the emission estimate web service. For example, you could say <tt>puts my_donut_factor.emission_estimate.oven_count</tt> (see the tests) and you'd get back the oven count used in the calculation, if any.
13
13
  class EmissionEstimate
14
- def self.parse(str)
14
+ def self.parse(str) #:nodoc:
15
15
  data = ::ActiveSupport::JSON.decode str
16
16
  data['active_subtimeframe'] = ::Timeframe.interval(data['active_subtimeframe']) if data.has_key? 'active_subtimeframe'
17
- data['updated_at'] = ::Time.parse(data['updated_at']) if data.has_key? 'updated_at'
17
+ data['updated_at'] = ::Time.parse(data['updated_at']) if data.has_key?('updated_at') and data['updated_at'].is_a?(::String)
18
18
  data
19
19
  end
20
20
 
@@ -24,6 +24,7 @@ module Carbon
24
24
  attr_writer :defer
25
25
  attr_accessor :callback
26
26
  attr_accessor :timeframe
27
+ attr_accessor :certified
27
28
  attr_accessor :guid
28
29
  attr_reader :emitter
29
30
 
@@ -32,8 +33,9 @@ module Carbon
32
33
  take_options options unless options.empty?
33
34
  end
34
35
 
35
- VALID_OPTIONS = [:callback_content_type, :key, :callback, :timeframe, :guid, :timeout, :defer]
36
- def take_options(options)
36
+ VALID_OPTIONS = [:callback_content_type, :key, :callback, :timeframe, :guid, :timeout, :defer, :certified]
37
+
38
+ def take_options(options) #:nodoc:
37
39
  return if options.blank?
38
40
  options.slice(*VALID_OPTIONS).each do |k, v|
39
41
  instance_variable_set "@#{k}", v
@@ -66,7 +68,7 @@ module Carbon
66
68
  end
67
69
  end
68
70
 
69
- def data
71
+ def data #:nodoc:
70
72
  if storage.present?
71
73
  storage.data
72
74
  else
@@ -74,18 +76,18 @@ module Carbon
74
76
  end
75
77
  end
76
78
 
77
- def storage
79
+ def storage #:nodoc:
78
80
  @storage ||= {}
79
81
  return @storage[guid] if @storage.has_key? guid
80
82
  @storage[guid] = Storage.new self
81
83
  end
82
84
 
83
- def request
85
+ def request #:nodoc:
84
86
  @request ||= Request.new self
85
87
  end
86
88
 
87
89
  # Here's where caching takes place.
88
- def response
90
+ def response #:nodoc:
89
91
  current_params = request.params
90
92
  @response ||= {}
91
93
  return @response[current_params] if @response.has_key? current_params
@@ -94,15 +96,19 @@ module Carbon
94
96
  @response[current_params] = response_object
95
97
  end
96
98
 
97
- def defer?
99
+ def certified? #:nodoc:
100
+ !!certified
101
+ end
102
+
103
+ def defer? #:nodoc:
98
104
  @defer == true
99
105
  end
100
106
 
101
- def async?
107
+ def async? #:nodoc:
102
108
  callback or defer?
103
109
  end
104
110
 
105
- def mode
111
+ def mode #:nodoc:
106
112
  async? ? :async : :realtime
107
113
  end
108
114
 
@@ -1,6 +1,6 @@
1
1
  module Carbon
2
2
  class EmissionEstimate
3
- class Request
3
+ class Request #:nodoc:all
4
4
  attr_reader :parent
5
5
 
6
6
  def initialize(parent)
@@ -12,10 +12,18 @@ module Carbon
12
12
  end
13
13
 
14
14
  def params
15
- send "#{parent.mode}_params"
15
+ params = send "#{parent.mode}_params"
16
+ validate params
17
+ params
16
18
  end
17
19
 
18
- def async_params # :nodoc:
20
+ def validate(params_hash)
21
+ unless params_hash.key? :key
22
+ Carbon.warn 'You have not specified an API key. Please obtain a key from http://keys.brighterplanet.com.'
23
+ end
24
+ end
25
+
26
+ def async_params
19
27
  raise ::ArgumentError, "When using :callback you cannot specify :defer" if parent.defer? and parent.callback
20
28
  raise ::ArgumentError, "When using :defer => true you must specify :guid" if parent.defer? and parent.guid.blank?
21
29
  hash = _params
@@ -30,7 +38,7 @@ module Carbon
30
38
  }
31
39
  end
32
40
 
33
- def realtime_params # :nodoc:
41
+ def realtime_params
34
42
  _params
35
43
  end
36
44
 
@@ -67,12 +75,20 @@ module Carbon
67
75
  hash
68
76
  end
69
77
 
70
- def realtime_url # :nodoc:
71
- "#{::Carbon::REALTIME_URL}/#{parent.emitter.class.carbon_base.emitter_common_name.pluralize}.json"
78
+ def realtime_url
79
+ uri = ::URI.parse ''
80
+ uri.scheme = 'http'
81
+ uri.host = parent.certified? ? 'certified.carbon.brighterplanet.com' : 'carbon.brighterplanet.com'
82
+ uri.path = "/#{parent.emitter.class.carbon_base.emitter_common_name.pluralize}.json"
83
+ uri.to_s
72
84
  end
73
85
 
74
- def async_url # :nodoc:
75
- ::Carbon::ASYNC_URL
86
+ def async_url
87
+ uri = ::URI.parse ''
88
+ uri.scheme = 'https'
89
+ uri.host = 'queue.amazonaws.com'
90
+ uri.path = parent.certified? ? '/121562143717/cm1_production_incoming_certified' : '/121562143717/cm1_production_incoming'
91
+ uri.to_s
76
92
  end
77
93
 
78
94
  def url
@@ -1,6 +1,6 @@
1
1
  module Carbon
2
2
  class EmissionEstimate
3
- class Response
3
+ class Response #:nodoc:all
4
4
  attr_reader :parent
5
5
  attr_reader :data
6
6
  attr_reader :raw_request
@@ -15,7 +15,7 @@ module Carbon
15
15
  end
16
16
 
17
17
  private
18
- def load_realtime_data # :nodoc:
18
+ def load_realtime_data
19
19
  attempts = 0
20
20
  response = nil
21
21
  begin
@@ -34,13 +34,13 @@ module Carbon
34
34
  @data = ::Carbon::EmissionEstimate.parse response.body
35
35
  end
36
36
 
37
- def load_async_data # :nodoc:
37
+ def load_async_data
38
38
  response = perform
39
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.
40
40
  @data = {}
41
41
  end
42
42
 
43
- def perform # :nodoc:
43
+ def perform
44
44
  response = nil
45
45
  if parent.timeout
46
46
  Timeout.timeout(parent.timeout) do
@@ -52,7 +52,7 @@ module Carbon
52
52
  response
53
53
  end
54
54
 
55
- def perform_request # :nodoc:
55
+ def perform_request
56
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'}
57
57
  @raw_response = raw_request.perform
58
58
  end
@@ -1,6 +1,6 @@
1
1
  module Carbon
2
2
  class EmissionEstimate
3
- class Storage
3
+ class Storage #:nodoc:all
4
4
  attr_accessor :parent
5
5
  attr_reader :raw_request
6
6
  attr_reader :raw_response
@@ -10,7 +10,7 @@ module Carbon
10
10
  end
11
11
 
12
12
  def url
13
- "#{::Carbon::STORAGE_URL}/#{::Digest::SHA1.hexdigest(parent.key+parent.guid)}"
13
+ "http://storage.carbon.brighterplanet.com/#{::Digest::SHA1.hexdigest(parent.key+parent.guid)}"
14
14
  end
15
15
 
16
16
  def present?
@@ -0,0 +1,51 @@
1
+ require 'brighter_planet_metadata'
2
+ require 'bombshell'
3
+ require 'conversions'
4
+ module Carbon
5
+ class Shell < Bombshell::Environment
6
+ include Bombshell::Shell
7
+
8
+ before_launch do
9
+ $emitters = {}
10
+ emitters.map(&:underscore).each do |e|
11
+ define_method e.to_sym do |*args|
12
+ if args.any? and num = args.first and saved = $emitters[e.to_sym][num]
13
+ emitter e.to_sym, saved
14
+ else
15
+ emitter e.to_sym
16
+ end
17
+ end
18
+ end
19
+ end
20
+
21
+ prompt_with 'carbon-'
22
+
23
+ def help
24
+ puts " => #{self.class.emitters.join ', '}"
25
+ end
26
+
27
+ def key(k)
28
+ ::Carbon.key = k
29
+ puts " => Using key #{::Carbon.key}"
30
+ end
31
+
32
+ def emitter(e, saved = {})
33
+ Emitter.launch e, saved
34
+ end
35
+
36
+ class << self
37
+ def emitters
38
+ ::BrighterPlanet.metadata.emitters
39
+ end
40
+ end
41
+ end
42
+ end
43
+
44
+ if File.exist?(dotfile = File.join(ENV['HOME'], '.brighter_planet'))
45
+ if (key = File.read(dotfile).strip).present?
46
+ ::Carbon.key = key
47
+ end
48
+ end
49
+
50
+ require 'carbon/shell/emitter'
51
+
@@ -1,7 +1,9 @@
1
1
  module Carbon
2
- module Cli
3
- class Emitter < Environment
2
+ class Shell
3
+ class Emitter < Bombshell::Environment
4
+ include Bombshell::Shell
4
5
  include Carbon
6
+
5
7
  def initialize(name, input = {})
6
8
  @emitter = name
7
9
  @input = input
@@ -38,8 +40,10 @@ module Carbon
38
40
  if t
39
41
  @timeframe = t
40
42
  emission
43
+ elsif @timeframe
44
+ puts ' => ' + @timeframe
41
45
  else
42
- @timeframe
46
+ puts ' => (defaults to current year)'
43
47
  end
44
48
  end
45
49
 
@@ -116,8 +120,20 @@ module Carbon
116
120
  puts " => #{@characteristics.keys.join ', '}"
117
121
  end
118
122
 
119
- def to_s
120
- "#{@emitter}*"
123
+ prompt_with do |emitter|
124
+ if emitter._timeframe
125
+ "#{emitter._name}[#{emitter._timeframe}]*"
126
+ else
127
+ "#{emitter._name}*"
128
+ end
129
+ end
130
+
131
+ def _name
132
+ @emitter
133
+ end
134
+
135
+ def _timeframe
136
+ @timeframe
121
137
  end
122
138
 
123
139
  def inspect
@@ -128,7 +144,13 @@ module Carbon
128
144
  $emitters[@emitter] ||= []
129
145
  $emitters[@emitter] << @input
130
146
  puts " => Saved as #{@emitter} ##{$emitters[@emitter].length - 1}"
131
- throw :IRB_EXIT
147
+ quit
148
+ end
149
+
150
+ class << self
151
+ def emitter_name
152
+ @name
153
+ end
132
154
  end
133
155
  end
134
156
  end
@@ -1,3 +1,3 @@
1
1
  module Carbon
2
- VERSION = '1.0.4'
2
+ VERSION = '1.1.0'
3
3
  end
@@ -0,0 +1,37 @@
1
+ require 'spec_helper'
2
+
3
+ describe Carbon::EmissionEstimate::Request do
4
+ let(:emitter) do
5
+ mock Object,
6
+ :class => mock(Object,
7
+ :carbon_base => mock(Object,
8
+ :emitter_common_name => 'dirigible',
9
+ :translation_table => []))
10
+ end
11
+ let(:emission_estimate) { Carbon::EmissionEstimate.new emitter }
12
+ let(:request) { Carbon::EmissionEstimate::Request.new emission_estimate }
13
+
14
+ describe '#params' do
15
+ it 'returns a hash of params' do
16
+ request.params.should be_a_kind_of(Hash)
17
+ end
18
+ it 'validates the params' do
19
+ request.should_receive :validate
20
+ request.params
21
+ end
22
+ end
23
+
24
+ describe '#validate' do
25
+ it 'warns the user if no key is given' do
26
+ Carbon.should_receive :warn
27
+ request.validate({})
28
+ end
29
+ it 'does nothing if all parameters are OK' do
30
+ Carbon.should_not_receive :warn
31
+ request.validate(
32
+ :key => 'ABC123'
33
+ )
34
+ end
35
+ end
36
+ end
37
+
@@ -7,7 +7,7 @@ MISSING_UNIQUE_ID = 'd09joijdoijaloijdoais'
7
7
  OTHER_UNIQUE_ID = '1092fjoid;oijsao;ga'
8
8
 
9
9
  FakeWeb.register_uri :post,
10
- /carbon.brighterplanet.com.automobiles/,
10
+ %r{http://carbon.brighterplanet.com/automobile_trips},
11
11
  :status => ["200", "OK"],
12
12
  :body => {
13
13
  'emission' => '134.599',
@@ -16,6 +16,16 @@ FakeWeb.register_uri :post,
16
16
  'active_subtimeframe' => Timeframe.new(:year => 2008)
17
17
  }.to_json
18
18
  #
19
+ FakeWeb.register_uri :post,
20
+ %r{http://certified.carbon.brighterplanet.com/automobile_trips},
21
+ :status => ["200", "OK"],
22
+ :body => {
23
+ 'emission' => '54321',
24
+ 'emission_units' => 'kilograms',
25
+ 'methodology' => 'http://certified.carbon.brighterplanet.com/something',
26
+ 'active_subtimeframe' => Timeframe.new(:year => 2008)
27
+ }.to_json
28
+ #
19
29
  FakeWeb.register_uri :post,
20
30
  /carbon.brighterplanet.com.factories/,
21
31
  :status => ["200", "OK"],
@@ -91,7 +101,7 @@ class RentalCar
91
101
  def make
92
102
  @make ||= Make.new
93
103
  end
94
- emit_as :automobile do
104
+ emit_as :automobile_trip do
95
105
  provide :make
96
106
  provide :model
97
107
  provide :model_year
@@ -313,6 +323,17 @@ describe Carbon do
313
323
  c.emission_estimate.request.body.should_not include('&&')
314
324
  c.emission_estimate.request.body.should_not =~ /=[^a-z0-9]/i
315
325
  end
326
+
327
+ it 'should do certified calculations' do
328
+ c = RentalCar.new
329
+ c.emission_estimate.certified = true
330
+ c.emission_estimate.should == 54321
331
+ end
332
+
333
+ it 'should do certified calculations (inline)' do
334
+ c = RentalCar.new
335
+ c.emission_estimate(:certified => true).should == 54321
336
+ end
316
337
  end
317
338
 
318
339
  describe 'asynchronous (queued) requests' do
@@ -322,6 +343,19 @@ describe Carbon do
322
343
  c.emission_estimate.request.url.should =~ /queue.amazonaws.com/
323
344
  end
324
345
 
346
+ it 'should default to non-certified' do
347
+ c = RentalCar.new
348
+ c.emission_estimate.callback = CALLBACK_URL
349
+ c.emission_estimate.request.url.should_not =~ /certified/
350
+ end
351
+
352
+ it 'should accept certified' do
353
+ c = RentalCar.new
354
+ c.emission_estimate.callback = CALLBACK_URL
355
+ c.emission_estimate.certified = true
356
+ c.emission_estimate.request.url.should =~ /certified/
357
+ end
358
+
325
359
  it 'should have nil data in its response' do
326
360
  c = RentalCar.new
327
361
  c.emission_estimate.callback = CALLBACK_URL
data/spec/spec_helper.rb CHANGED
@@ -7,3 +7,5 @@ require 'fakeweb'
7
7
  $LOAD_PATH.unshift(File.dirname(__FILE__))
8
8
  $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
9
9
  require 'carbon'
10
+
11
+ Carbon.log = Logger.new nil
metadata CHANGED
@@ -1,13 +1,8 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: carbon
3
3
  version: !ruby/object:Gem::Version
4
- hash: 31
5
- prerelease: false
6
- segments:
7
- - 1
8
- - 0
9
- - 4
10
- version: 1.0.4
4
+ prerelease:
5
+ version: 1.1.0
11
6
  platform: ruby
12
7
  authors:
13
8
  - Derek Kastner
@@ -17,7 +12,7 @@ autorequire:
17
12
  bindir: bin
18
13
  cert_chain: []
19
14
 
20
- date: 2011-02-03 00:00:00 -06:00
15
+ date: 2011-04-04 00:00:00 -05:00
21
16
  default_executable:
22
17
  dependencies:
23
18
  - !ruby/object:Gem::Dependency
@@ -28,11 +23,6 @@ dependencies:
28
23
  requirements:
29
24
  - - ">="
30
25
  - !ruby/object:Gem::Version
31
- hash: 9
32
- segments:
33
- - 2
34
- - 3
35
- - 5
36
26
  version: 2.3.5
37
27
  type: :runtime
38
28
  version_requirements: *id001
@@ -44,9 +34,6 @@ dependencies:
44
34
  requirements:
45
35
  - - ">="
46
36
  - !ruby/object:Gem::Version
47
- hash: 3
48
- segments:
49
- - 0
50
37
  version: "0"
51
38
  type: :runtime
52
39
  version_requirements: *id002
@@ -58,9 +45,6 @@ dependencies:
58
45
  requirements:
59
46
  - - ">="
60
47
  - !ruby/object:Gem::Version
61
- hash: 3
62
- segments:
63
- - 0
64
48
  version: "0"
65
49
  type: :runtime
66
50
  version_requirements: *id003
@@ -72,9 +56,6 @@ dependencies:
72
56
  requirements:
73
57
  - - ">="
74
58
  - !ruby/object:Gem::Version
75
- hash: 3
76
- segments:
77
- - 0
78
59
  version: "0"
79
60
  type: :runtime
80
61
  version_requirements: *id004
@@ -86,9 +67,6 @@ dependencies:
86
67
  requirements:
87
68
  - - ">="
88
69
  - !ruby/object:Gem::Version
89
- hash: 3
90
- segments:
91
- - 0
92
70
  version: "0"
93
71
  type: :runtime
94
72
  version_requirements: *id005
@@ -100,40 +78,64 @@ dependencies:
100
78
  requirements:
101
79
  - - ">="
102
80
  - !ruby/object:Gem::Version
103
- hash: 3
104
- segments:
105
- - 0
106
81
  version: "0"
107
82
  type: :runtime
108
83
  version_requirements: *id006
109
84
  - !ruby/object:Gem::Dependency
110
- name: fakeweb
85
+ name: brighter_planet_metadata
111
86
  prerelease: false
112
87
  requirement: &id007 !ruby/object:Gem::Requirement
113
88
  none: false
114
89
  requirements:
115
90
  - - ">="
116
91
  - !ruby/object:Gem::Version
117
- hash: 3
118
- segments:
119
- - 0
120
92
  version: "0"
121
- type: :development
93
+ type: :runtime
122
94
  version_requirements: *id007
123
95
  - !ruby/object:Gem::Dependency
124
- name: rspec
96
+ name: bombshell
125
97
  prerelease: false
126
98
  requirement: &id008 !ruby/object:Gem::Requirement
127
99
  none: false
128
100
  requirements:
129
101
  - - ">="
130
102
  - !ruby/object:Gem::Version
131
- hash: 3
132
- segments:
133
- - 0
134
103
  version: "0"
135
- type: :development
104
+ type: :runtime
136
105
  version_requirements: *id008
106
+ - !ruby/object:Gem::Dependency
107
+ name: fakeweb
108
+ prerelease: false
109
+ requirement: &id009 !ruby/object:Gem::Requirement
110
+ none: false
111
+ requirements:
112
+ - - ">="
113
+ - !ruby/object:Gem::Version
114
+ version: "0"
115
+ type: :development
116
+ version_requirements: *id009
117
+ - !ruby/object:Gem::Dependency
118
+ name: rspec
119
+ prerelease: false
120
+ requirement: &id010 !ruby/object:Gem::Requirement
121
+ none: false
122
+ requirements:
123
+ - - ">="
124
+ - !ruby/object:Gem::Version
125
+ version: "0"
126
+ type: :development
127
+ version_requirements: *id010
128
+ - !ruby/object:Gem::Dependency
129
+ name: aruba
130
+ prerelease: false
131
+ requirement: &id011 !ruby/object:Gem::Requirement
132
+ none: false
133
+ requirements:
134
+ - - ">="
135
+ - !ruby/object:Gem::Version
136
+ version: "0"
137
+ type: :development
138
+ version_requirements: *id011
137
139
  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.
138
140
  email:
139
141
  - derek.kastner@brighterplanet.com
@@ -157,19 +159,18 @@ files:
157
159
  - doc/timeout-error.png
158
160
  - doc/with-committee-reports.png
159
161
  - doc/without-committee-reports.png
162
+ - features/shell.feature
163
+ - features/support/env.rb
160
164
  - lib/carbon.rb
161
165
  - lib/carbon/base.rb
162
- - lib/carbon/cli.rb
163
- - lib/carbon/cli/emitter.rb
164
- - lib/carbon/cli/environment.rb
165
- - lib/carbon/cli/irb.rb
166
- - lib/carbon/cli/shell.rb
167
166
  - lib/carbon/emission_estimate.rb
168
167
  - lib/carbon/emission_estimate/request.rb
169
168
  - lib/carbon/emission_estimate/response.rb
170
169
  - lib/carbon/emission_estimate/storage.rb
170
+ - lib/carbon/shell.rb
171
+ - lib/carbon/shell/emitter.rb
171
172
  - lib/carbon/version.rb
172
- - spec/lib/carbon/cli/shell_spec.rb
173
+ - spec/lib/carbon/emission_estimate/request_spec.rb
173
174
  - spec/lib/carbon/emission_estimate/response_spec.rb
174
175
  - spec/lib/carbon_spec.rb
175
176
  - spec/spec_helper.rb
@@ -188,28 +189,24 @@ required_ruby_version: !ruby/object:Gem::Requirement
188
189
  requirements:
189
190
  - - ">="
190
191
  - !ruby/object:Gem::Version
191
- hash: 3
192
- segments:
193
- - 0
194
192
  version: "0"
195
193
  required_rubygems_version: !ruby/object:Gem::Requirement
196
194
  none: false
197
195
  requirements:
198
196
  - - ">="
199
197
  - !ruby/object:Gem::Version
200
- hash: 3
201
- segments:
202
- - 0
203
198
  version: "0"
204
199
  requirements: []
205
200
 
206
201
  rubyforge_project: carbon
207
- rubygems_version: 1.3.7
202
+ rubygems_version: 1.6.2
208
203
  signing_key:
209
204
  specification_version: 3
210
205
  summary: Carbon is a Ruby API wrapper for the Brighter Planet emission estimate web service (http://carbon.brighterplanet.com).
211
206
  test_files:
212
- - spec/lib/carbon/cli/shell_spec.rb
207
+ - features/shell.feature
208
+ - features/support/env.rb
209
+ - spec/lib/carbon/emission_estimate/request_spec.rb
213
210
  - spec/lib/carbon/emission_estimate/response_spec.rb
214
211
  - spec/lib/carbon_spec.rb
215
212
  - spec/spec_helper.rb
data/lib/carbon/cli.rb DELETED
@@ -1,22 +0,0 @@
1
- module Carbon
2
- module Cli
3
- def execute(*)
4
- Shell.init
5
- $emitters = {}
6
- IRB.start_session(Shell.new.get_binding)
7
- end
8
- module_function :execute
9
- end
10
- end
11
-
12
- require 'carbon/cli/environment'
13
- require 'carbon/cli/shell'
14
- require 'carbon/cli/emitter'
15
- require 'carbon/cli/irb'
16
- require 'conversions'
17
-
18
- if File.exist?(dotfile = File.join(ENV['HOME'], '.carbon_middleware'))
19
- if (key = File.read(dotfile).strip).present?
20
- ::Carbon.key = key
21
- end
22
- end
@@ -1,16 +0,0 @@
1
- module Carbon
2
- module Cli
3
- class Environment
4
- instance_methods.each do |m|
5
- undef_method(m) if m.to_s !~ /(?:^__|^nil\?$|^send$|^instance_eval$|^define_method$|^class$|^object_id$)/
6
- end
7
-
8
- def get_binding() binding end
9
-
10
- def method_missing(*args)
11
- return if [:extend, :respond_to?].include? args.first
12
- puts "Unknown command #{args.first}"
13
- end
14
- end
15
- end
16
- end
@@ -1,34 +0,0 @@
1
- # encoding: utf-8
2
-
3
- require 'irb'
4
-
5
- module IRB # :nodoc:
6
- def self.start_session(binding)
7
- unless @__initialized
8
- args = ARGV
9
- ARGV.replace(ARGV.dup)
10
- IRB.setup(nil)
11
- ARGV.replace(args)
12
- @__initialized = true
13
- end
14
-
15
- workspace = WorkSpace.new(binding)
16
-
17
- @CONF[:PROMPT][:CARBON] = {
18
- :PROMPT_I => "%m> ",
19
- :PROMPT_S => "%m\"> ",
20
- :PROMPT_C => "%m…>",
21
- :PROMPT_N => "%m→>",
22
- :RETURN => ''
23
- }
24
- @CONF[:PROMPT_MODE] = :CARBON
25
-
26
- irb = Irb.new(workspace)
27
-
28
- @CONF[:IRB_RC].call(irb.context) if @CONF[:IRB_RC]
29
- @CONF[:MAIN_CONTEXT] = irb.context
30
- catch(:IRB_EXIT) do
31
- irb.eval_input
32
- end
33
- end
34
- end
@@ -1,46 +0,0 @@
1
- require 'carbon/cli/environment'
2
-
3
- module Carbon
4
- module Cli
5
- class Shell < Environment
6
- cattr_accessor :emitters
7
-
8
- def self.init
9
- emitters_url = "http://carbon.brighterplanet.com/models.json"
10
- response = REST.get(emitters_url)
11
- if true || response.ok?
12
- self.emitters = ActiveSupport::JSON.decode response.body
13
- emitters.map(&:underscore).each do |e|
14
- define_method e.to_sym do |*args|
15
- if args.any? and num = args.first and saved = $emitters[e.to_sym][num]
16
- emitter e.to_sym, saved
17
- else
18
- emitter e.to_sym
19
- end
20
- end
21
- end
22
- else
23
- puts " => Sorry, emitter types couldn't be retrieved (via #{emitters_url})"
24
- done
25
- end
26
- end
27
-
28
- def help
29
- puts " => #{self.class.emitters.join ', '}"
30
- end
31
-
32
- def to_s
33
- 'carbon-'
34
- end
35
-
36
- def key(k)
37
- ::Carbon.key = k
38
- puts " => Using key #{::Carbon.key}"
39
- end
40
-
41
- def emitter(e, saved = {})
42
- ::IRB.start_session(Emitter.new(e, saved).get_binding)
43
- end
44
- end
45
- end
46
- end
@@ -1,30 +0,0 @@
1
- require 'spec_helper'
2
- require 'carbon/cli/shell'
3
-
4
- describe Carbon::Cli::Shell do
5
- let(:json) { %{
6
- ["Automobile","AutomobileTrip","BusTrip","Computation","Diet","Flight","FuelPurchase","Lodging","Meeting","Motorcycle","Pet","Purchase","RailTrip","Residence"]
7
- } }
8
- let(:mock_response) { mock(REST, :ok? => true, :body => json) }
9
- let(:shell) { Carbon::Cli::Shell.new }
10
-
11
-
12
- before(:each) do
13
- REST.stub!(:get).and_return mock_response
14
- end
15
-
16
- describe '.init' do
17
- it 'should create methods for each model' do
18
- Carbon::Cli::Shell.init
19
- Carbon::Cli::Shell.instance_methods.should include('automobile')
20
- end
21
- it 'should exit if the models cannot be fetched' do
22
- pending
23
-
24
- mock_response.stub!(:ok?).and_return false
25
- Carbon::Cli::Shell.should_receive :done
26
- Carbon::Cli::Shell.init
27
- end
28
- end
29
- end
30
-