carbon 2.2.1 → 2.2.2

Sign up to get free protection for your applications and to get access to all the features.
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