carbon 2.2.1 → 2.2.2

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,14 @@
1
+ 2.2.2 / 2012-04-05
2
+
3
+ * Enhancements
4
+
5
+ * Allow choosing domain (API endpoint)
6
+ * Slightly improved method signature explanations: query_array -> plain_query, o -> obj, os -> array
7
+
8
+ * Bug fixes
9
+
10
+ * Actually send keys set with Carbon.key
11
+
1
12
  2.2.1 / 2012-03-21
2
13
 
3
14
  * Enhancements
@@ -4,13 +4,17 @@ require 'carbon/registry'
4
4
  require 'carbon/future'
5
5
 
6
6
  module Carbon
7
- DOMAIN = 'http://impact.brighterplanet.com'
7
+ DOMAIN = 'http://impact.brighterplanet.com'.freeze
8
8
  CONCURRENCY = 16
9
9
 
10
10
  # @private
11
11
  # Make sure there are no warnings about class vars.
12
12
  @@key = nil unless defined?(@@key)
13
13
 
14
+ # @private
15
+ # Make sure there are no warnings about class vars.
16
+ @@domain = nil unless defined?(@@domain)
17
+
14
18
  # Set the Brighter Planet API key that you can get from http://keys.brighterplanet.com
15
19
  #
16
20
  # @param [String] key The alphanumeric key.
@@ -28,6 +32,23 @@ module Carbon
28
32
  @@key
29
33
  end
30
34
 
35
+ # Set an alternate API endpoint. You probably shouldn't do this.
36
+ #
37
+ # @param [String] domain ("http://impact.brighterplanet.com") The API endpoint
38
+ #
39
+ # @return [nil]
40
+ def Carbon.domain=(domain)
41
+ @@domain = domain
42
+ nil
43
+ end
44
+
45
+ # Where we send queries.
46
+ #
47
+ # @return [String] The API endpoint.
48
+ def Carbon.domain
49
+ @@domain || DOMAIN
50
+ end
51
+
31
52
  # Get impact estimates from Brighter Planet CM1; low-level method that does _not_ require you to define {Carbon::ClassMethods#emit_as} blocks; just pass emitter/param or objects that respond to +#as_impact_query+.
32
53
  #
33
54
  # Return values are {http://rdoc.info/github/intridea/hashie/Hashie/Mash Hashie::Mash} objects because they are a simple way to access a deeply nested response.
@@ -50,7 +71,7 @@ module Carbon
50
71
  # timeframe.startDate
51
72
  #
52
73
  # @overload query(emitter, params)
53
- # Simplest form.
74
+ # The simplest form.
54
75
  # @param [String] emitter The {http://impact.brighterplanet.com/emitters.json emitter name}.
55
76
  # @param [optional, Hash] params Characteristics like airline/airport/etc., your API key (if you didn't set it globally), timeframe, compliance, etc.
56
77
  # @option params [Timeframe] :timeframe (Timeframe.this_year) What time period to focus the calculation on. See {https://github.com/rossmeissl/timeframe timeframe} documentation.
@@ -58,18 +79,20 @@ module Carbon
58
79
  # @option params [String, Numeric] <i>characteristic</i> Pieces of data about an emitter. The {http://impact.brighterplanet.com/flights/options Flight characteristics API} lists valid keys like +:aircraft+, +:origin_airport+, etc.
59
80
  # @return [Hashie::Mash] The API response, contained in an easy-to-use +Hashie::Mash+
60
81
  #
61
- # @overload query(o)
82
+ # @overload query(obj)
62
83
  # Pass in a single query-able object.
63
- # @param [#as_impact_query] o An object that responds to +#as_impact_query+, generally because you've declared {Carbon::ClassMethods#emit_as} on its parent class.
84
+ # @param [#as_impact_query] obj An object that responds to +#as_impact_query+, generally because you've declared {Carbon::ClassMethods#emit_as} on its parent class.
64
85
  # @return [Hashie::Mash] The API response, contained in an easy-to-use +Hashie::Mash+
65
86
  #
66
- # @overload query(os)
67
- # Get multiple impact estimates for arrays and/or query-able objects concurrently.
68
- # @param [Array<Array, #as_impact_query>] os An array of arrays in +[emitter, params]+ format and/or objects that respond to +#as_impact_query+.
87
+ # @overload query(array)
88
+ # Get impact estimates for multiple query-able objects concurrently.
89
+ # @param [Array<Array, #as_impact_query>] array An array of plain queries and/or objects that respond to +#as_impact_query+.
69
90
  # @return [Hash{Object => Hashie::Mash}] A +Hash+ of +Hashie::Mash+ objects, keyed on the original query object.
70
91
  #
71
92
  # @note We make up to 16 requests concurrently (hardcoded, per the Brighter Planet Terms of Service) and it can be more than 90% faster than running queries serially!
72
93
  #
94
+ # @note +[emitter, params]+ is called a "plain query."
95
+ #
73
96
  # @raise [ArgumentError] If your arguments don't match any of the method signatures.
74
97
  #
75
98
  # @example A flight taken in 2009
@@ -105,29 +128,23 @@ module Carbon
105
128
  # Carbon.query(queries)
106
129
  #
107
130
  # @example Flights and cars (concurrently, as query-able objects)
108
- # Carbon.query(MyFlight.all+MyCar.all)
109
- #
110
- # @example Cars month-by-month (note that you won't get MyCar objects back, you'll get Arrays back. This will be fixed soon.)
111
- # cars_by_month = MyCar.all.inject([]) do |memo, my_car|
112
- # months.each do |first_day_of_the_month|
113
- # my_car.as_impact_query(:date => first_day_of_the_month)
114
- # end
131
+ # Carbon.query(MyFlight.all+MyCar.all).each do |car_or_flight, impact|
132
+ # puts "Carbon emitter by #{car_or_flight} was #{impact.decisions.carbon.object.value.round(1)}"
115
133
  # end
116
- # Carbon.query(cars_by_month)
117
134
  def Carbon.query(*args)
118
135
  case Carbon.method_signature(*args)
119
- when :query_array
120
- query_array = args
121
- future = Future.wrap query_array
136
+ when :plain_query
137
+ plain_query = args
138
+ future = Future.wrap plain_query
122
139
  future.result
123
- when :o
124
- o = args.first
125
- future = Future.wrap o
140
+ when :obj
141
+ obj = args.first
142
+ future = Future.wrap obj
126
143
  future.result
127
- when :os
128
- os = args.first
129
- futures = os.map do |o|
130
- future = Future.wrap o
144
+ when :array
145
+ array = args.first
146
+ futures = array.map do |obj|
147
+ future = Future.wrap obj
131
148
  future.multi!
132
149
  future
133
150
  end
@@ -136,13 +153,13 @@ module Carbon
136
153
  memo
137
154
  end
138
155
  else
139
- raise ::ArgumentError, "Didn't match any of the method signatures. If you want multiple queries, make sure to pass an unsplatted Array."
156
+ raise ::ArgumentError, "You must pass one plain query, or one object that responds to #as_impact_query, or an array of such objects. Please check the docs!"
140
157
  end
141
158
  end
142
159
 
143
160
  # Determine if a variable is a +[emitter, param]+ style "query"
144
161
  # @private
145
- def Carbon.is_query_array?(query)
162
+ def Carbon.is_plain_query?(query)
146
163
  return false unless query.is_a?(::Array)
147
164
  return false unless query.first.is_a?(::String) or query.first.is_a?(::Symbol)
148
165
  return true if query.length == 1
@@ -156,20 +173,20 @@ module Carbon
156
173
  first_arg = args.first
157
174
  case args.length
158
175
  when 1
159
- if is_query_array?(args)
176
+ if is_plain_query?(args)
160
177
  # query('Flight')
161
- :query_array
178
+ :plain_query
162
179
  elsif first_arg.respond_to?(:as_impact_query)
163
180
  # query(my_flight)
164
- :o
165
- elsif first_arg.is_a?(::Array) and first_arg.all? { |o| o.respond_to?(:as_impact_query) or is_query_array?(o) }
181
+ :obj
182
+ elsif first_arg.is_a?(::Array) and first_arg.all? { |obj| obj.respond_to?(:as_impact_query) or is_plain_query?(obj) }
166
183
  # query([my_flight, my_flight])
167
- :os
184
+ :array
168
185
  end
169
186
  when 2
170
- if is_query_array?(args)
187
+ if is_plain_query?(args)
171
188
  # query('Flight', :origin_airport => 'LAX')
172
- :query_array
189
+ :plain_query
173
190
  end
174
191
  end
175
192
  end
@@ -287,8 +304,8 @@ module Carbon
287
304
  # ?> my_impact.methodology
288
305
  # => "http://impact.brighterplanet.com/flights?[...]"
289
306
  def impact(extra_params = {})
290
- query_array = as_impact_query extra_params
291
- future = Future.wrap query_array
307
+ plain_query = as_impact_query extra_params
308
+ future = Future.wrap plain_query
292
309
  future.result
293
310
  end
294
311
  end
@@ -8,18 +8,18 @@ module Carbon
8
8
  # @private
9
9
  class Future
10
10
  class << self
11
- def wrap(query_array_or_o)
12
- future = if query_array_or_o.is_a?(::Array)
13
- new(*query_array_or_o)
11
+ def wrap(plain_query_or_o)
12
+ future = if plain_query_or_o.is_a?(::Array)
13
+ new(*plain_query_or_o)
14
14
  else
15
- new(*query_array_or_o.as_impact_query)
15
+ new(*plain_query_or_o.as_impact_query)
16
16
  end
17
- future.object = query_array_or_o
17
+ future.object = plain_query_or_o
18
18
  future
19
19
  end
20
20
 
21
21
  def single(future)
22
- uri = ::URI.parse("#{Carbon::DOMAIN}/#{future.emitter.underscore.pluralize}.json")
22
+ uri = ::URI.parse("#{future.domain}/#{future.emitter.underscore.pluralize}.json")
23
23
  raw_result = ::Net::HTTP.post_form(uri, future.params)
24
24
  future.finalize raw_result.code.to_i, raw_result.body
25
25
  future
@@ -41,14 +41,18 @@ module Carbon
41
41
 
42
42
  attr_reader :emitter
43
43
  attr_reader :params
44
+ attr_reader :domain
44
45
 
45
46
  attr_accessor :object
46
47
 
47
48
  def initialize(emitter, params = {})
48
49
  @result = nil
49
50
  @emitter = emitter
50
- params = params || {}
51
- params.reverse_merge(:key => Carbon.key) if Carbon.key
51
+ params = params.dup || {}
52
+ @domain = params.delete(:domain) || Carbon.domain
53
+ if Carbon.key and not params.has_key?(:key)
54
+ params[:key] = Carbon.key
55
+ end
52
56
  @params = params
53
57
  end
54
58
 
@@ -90,7 +94,7 @@ module Carbon
90
94
  cache_method :result, 3_600 # one hour
91
95
 
92
96
  def as_cache_key
93
- [ @emitter, @params ]
97
+ [ @domain, @emitter, @params ]
94
98
  end
95
99
 
96
100
  def hash
@@ -1,3 +1,3 @@
1
1
  module Carbon
2
- VERSION = "2.2.1"
2
+ VERSION = "2.2.2"
3
3
  end
@@ -73,9 +73,20 @@ describe Carbon do
73
73
  end
74
74
  it "sends key properly" do
75
75
  with_web_mock do
76
- WebMock.stub_request(:post, 'http://impact.brighterplanet.com/flights.json').with(:key => 'carbon_test').to_return(:status => 500, :body => 'Good job')
77
- result = Carbon.query('Flight')
78
- result.errors.first.must_equal 'Good job'
76
+ WebMock.stub_request(:post, 'http://impact.brighterplanet.com/flights.json').with(:body => hash_including(:key => 'carbon_test')).to_return(:status => 500, :body => 'default')
77
+ WebMock.stub_request(:post, 'http://impact.brighterplanet.com/flights.json').with(:body => hash_including(:key => 'carbon_test1')).to_return(:status => 500, :body => 'A')
78
+ WebMock.stub_request(:post, 'http://impact.brighterplanet.com/flights.json').with(:body => hash_including(:key => 'carbon_test2')).to_return(:status => 500, :body => 'B')
79
+ Carbon.query('Flight', :key => 'carbon_test2').errors.first.must_equal 'B'
80
+ Carbon.query('Flight').errors.first.must_equal 'default'
81
+ Carbon.query('Flight', :key => 'carbon_test1').errors.first.must_equal 'A'
82
+ end
83
+ end
84
+ it "allows choosing domain" do
85
+ with_web_mock do
86
+ WebMock.stub_request(:post, 'http://impact.brighterplanet.com/flights.json').to_return(:status => 500, :body => 'used impact')
87
+ WebMock.stub_request(:post, 'http://foo.brighterplanet.com/flights.json').to_return(:status => 500, :body => 'used foo')
88
+ Carbon.query('Flight', :domain => 'http://foo.brighterplanet.com').errors.first.must_equal 'used foo'
89
+ Carbon.query('Flight').errors.first.must_equal 'used impact'
79
90
  end
80
91
  end
81
92
  it "raises ArgumentError if args are bad" do
@@ -116,7 +127,13 @@ describe Carbon do
116
127
  Timeout.timeout(0.5) { Carbon.query([]) }.must_equal(Hash.new)
117
128
  end
118
129
  it "can be used on objects that respond to #as_impact_query" do
119
- Carbon.query([MyNissanAltima.new(2001), MyNissanAltima.new(2006)]).values.map(&:decisions).map(&:carbon).map(&:object).map(&:value).must_equal Carbon.query([MyNissanAltima.new(2001).as_impact_query, MyNissanAltima.new(2006).as_impact_query]).values.map(&:decisions).map(&:carbon).map(&:object).map(&:value)
130
+ a = MyNissanAltima.new(2001)
131
+ b = MyNissanAltima.new(2006)
132
+ ab1 = Carbon.query([a, b])
133
+ ab2 = Carbon.query([a.as_impact_query, b.as_impact_query])
134
+ ab1.each do |k, v|
135
+ ab2[k.as_impact_query].must_equal v
136
+ end
120
137
  end
121
138
  it "runs multiple queries at once" do
122
139
  reference_results = @queries.inject({}) do |memo, query|
@@ -197,22 +214,22 @@ describe Carbon do
197
214
 
198
215
  describe :method_signature do
199
216
  it "recognizes emitter_param" do
200
- Carbon.method_signature('Flight').must_equal :query_array
201
- Carbon.method_signature('Flight', :origin_airport => 'LAX').must_equal :query_array
202
- Carbon.method_signature(:flight).must_equal :query_array
203
- Carbon.method_signature(:flight, :origin_airport => 'LAX').must_equal :query_array
217
+ Carbon.method_signature('Flight').must_equal :plain_query
218
+ Carbon.method_signature('Flight', :origin_airport => 'LAX').must_equal :plain_query
219
+ Carbon.method_signature(:flight).must_equal :plain_query
220
+ Carbon.method_signature(:flight, :origin_airport => 'LAX').must_equal :plain_query
204
221
  end
205
- it "recognizes o" do
206
- Carbon.method_signature(MyNissanAltima.new(2006)).must_equal :o
222
+ it "recognizes obj" do
223
+ Carbon.method_signature(MyNissanAltima.new(2006)).must_equal :obj
207
224
  end
208
- it "recognizes os" do
209
- Carbon.method_signature([MyNissanAltima.new(2001)]).must_equal :os
210
- Carbon.method_signature([['Flight']]).must_equal :os
211
- Carbon.method_signature([['Flight', {:origin_airport => 'LAX'}]]).must_equal :os
212
- Carbon.method_signature([['Flight'], ['Flight']]).must_equal :os
213
- Carbon.method_signature([['Flight', {:origin_airport => 'LAX'}], ['Flight', {:origin_airport => 'LAX'}]]).must_equal :os
225
+ it "recognizes array" do
226
+ Carbon.method_signature([MyNissanAltima.new(2001)]).must_equal :array
227
+ Carbon.method_signature([['Flight']]).must_equal :array
228
+ Carbon.method_signature([['Flight', {:origin_airport => 'LAX'}]]).must_equal :array
229
+ Carbon.method_signature([['Flight'], ['Flight']]).must_equal :array
230
+ Carbon.method_signature([['Flight', {:origin_airport => 'LAX'}], ['Flight', {:origin_airport => 'LAX'}]]).must_equal :array
214
231
  [MyNissanAltima.new(2006), ['Flight'], ['Flight', {:origin_airport => 'LAX'}]].permutation.each do |p|
215
- Carbon.method_signature(p).must_equal :os
232
+ Carbon.method_signature(p).must_equal :array
216
233
  end
217
234
  end
218
235
  it "does not want splats for concurrent queries" do
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.2.1
4
+ version: 2.2.2
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-21 00:00:00.000000000 Z
12
+ date: 2012-04-06 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activesupport
16
- requirement: &2169272660 !ruby/object:Gem::Requirement
16
+ requirement: !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,10 +21,15 @@ dependencies:
21
21
  version: '0'
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *2169272660
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
25
30
  - !ruby/object:Gem::Dependency
26
31
  name: multi_json
27
- requirement: &2169272200 !ruby/object:Gem::Requirement
32
+ requirement: !ruby/object:Gem::Requirement
28
33
  none: false
29
34
  requirements:
30
35
  - - ! '>='
@@ -32,10 +37,15 @@ dependencies:
32
37
  version: '0'
33
38
  type: :runtime
34
39
  prerelease: false
35
- version_requirements: *2169272200
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
36
46
  - !ruby/object:Gem::Dependency
37
47
  name: hashie
38
- requirement: &2169271780 !ruby/object:Gem::Requirement
48
+ requirement: !ruby/object:Gem::Requirement
39
49
  none: false
40
50
  requirements:
41
51
  - - ! '>='
@@ -43,10 +53,15 @@ dependencies:
43
53
  version: '0'
44
54
  type: :runtime
45
55
  prerelease: false
46
- version_requirements: *2169271780
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
47
62
  - !ruby/object:Gem::Dependency
48
63
  name: cache_method
49
- requirement: &2169271220 !ruby/object:Gem::Requirement
64
+ requirement: !ruby/object:Gem::Requirement
50
65
  none: false
51
66
  requirements:
52
67
  - - ! '>='
@@ -54,10 +69,15 @@ dependencies:
54
69
  version: '0'
55
70
  type: :runtime
56
71
  prerelease: false
57
- version_requirements: *2169271220
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
58
78
  - !ruby/object:Gem::Dependency
59
79
  name: bombshell
60
- requirement: &2169270600 !ruby/object:Gem::Requirement
80
+ requirement: !ruby/object:Gem::Requirement
61
81
  none: false
62
82
  requirements:
63
83
  - - ! '>='
@@ -65,10 +85,15 @@ dependencies:
65
85
  version: '0'
66
86
  type: :runtime
67
87
  prerelease: false
68
- version_requirements: *2169270600
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ! '>='
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
69
94
  - !ruby/object:Gem::Dependency
70
95
  name: conversions
71
- requirement: &2169269920 !ruby/object:Gem::Requirement
96
+ requirement: !ruby/object:Gem::Requirement
72
97
  none: false
73
98
  requirements:
74
99
  - - ! '>='
@@ -76,10 +101,15 @@ dependencies:
76
101
  version: '0'
77
102
  type: :runtime
78
103
  prerelease: false
79
- version_requirements: *2169269920
104
+ version_requirements: !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ! '>='
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
80
110
  - !ruby/object:Gem::Dependency
81
111
  name: brighter_planet_metadata
82
- requirement: &2169269500 !ruby/object:Gem::Requirement
112
+ requirement: !ruby/object:Gem::Requirement
83
113
  none: false
84
114
  requirements:
85
115
  - - ! '>='
@@ -87,7 +117,12 @@ dependencies:
87
117
  version: '0'
88
118
  type: :runtime
89
119
  prerelease: false
90
- version_requirements: *2169269500
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ none: false
122
+ requirements:
123
+ - - ! '>='
124
+ - !ruby/object:Gem::Version
125
+ version: '0'
91
126
  description: Brighter Planet API client for Ruby
92
127
  email:
93
128
  - seamus@abshere.net
@@ -139,7 +174,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
139
174
  version: '0'
140
175
  requirements: []
141
176
  rubyforge_project:
142
- rubygems_version: 1.8.15
177
+ rubygems_version: 1.8.21
143
178
  signing_key:
144
179
  specification_version: 3
145
180
  summary: Brighter Planet API client for Ruby