shipment 0.0.3 → 0.0.4
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/features/shipment_committees.feature +34 -12
- data/features/shipment_emissions.feature +7 -6
- data/features/step_definitions/shipment_steps.rb +4 -0
- data/features/support/env.rb +1 -0
- data/lib/shipment/carbon_model.rb +28 -28
- data/vendor/plugin/mapquest/init.rb +1 -0
- data/vendor/plugin/mapquest/lib/mapquest_directions.rb +51 -0
- data/vendor/plugin/mapquest/spec/lib/mapquest_directions_spec.rb +58 -0
- data/vendor/plugin/mapquest/spec/spec_helper.rb +13 -0
- metadata +20 -18
@@ -24,23 +24,44 @@ Feature: Shipment Committee Calculations
|
|
24
24
|
When the "mode" committee is calculated
|
25
25
|
Then the committee should have used quorum "default"
|
26
26
|
And the conclusion of the committee should be a fallback
|
27
|
+
|
28
|
+
Scenario Outline: Distance from same locality
|
29
|
+
Given a shipment emitter
|
30
|
+
And a characteristic "origin_zip_code.name" of "<origin>"
|
31
|
+
And a characteristic "destination_zip_code.name" of "<destination>"
|
32
|
+
When the "distance" committee is calculated
|
33
|
+
Then the conclusion of the committee should be "<distance>"
|
34
|
+
Examples:
|
35
|
+
| origin | destination | distance |
|
36
|
+
| 05753 | 05753 | 0 |
|
37
|
+
| 05753 | 05401 | |
|
27
38
|
|
28
|
-
Scenario:
|
39
|
+
Scenario Outline: Distance from mapquest
|
29
40
|
Given a shipment emitter
|
30
|
-
|
31
|
-
|
32
|
-
And
|
41
|
+
And a characteristic "origin_zip_code.name" of "<origin>"
|
42
|
+
And a characteristic "destination_zip_code.name" of "<destination>"
|
43
|
+
And a characteristic "mode.name" of "ground"
|
44
|
+
And a characteristic "mapquest_api_key" of "ABC123"
|
45
|
+
And mapquest determines the distance to be "<mapquest_distance>"
|
46
|
+
When the "distance" committee is calculated
|
47
|
+
Then the committee should have used quorum "from mapquest"
|
48
|
+
And the conclusion of the committee should be "<distance>"
|
49
|
+
Examples:
|
50
|
+
| origin | destination | mapquest_distance | distance |
|
51
|
+
| 05753 | 05401 | 53 | 53 |
|
52
|
+
| 05753 | 05401 | 33 | 33 |
|
33
53
|
|
34
|
-
Scenario Outline: Distance from
|
54
|
+
Scenario Outline: Distance from direct path
|
35
55
|
Given a shipment emitter
|
36
56
|
And a characteristic "origin_zip_code.name" of "<origin>"
|
37
57
|
And a characteristic "destination_zip_code.name" of "<destination>"
|
58
|
+
And a characteristic "mode.name" of "air"
|
59
|
+
And a characteristic "mapquest_api_key" of "ABC123"
|
38
60
|
When the "distance" committee is calculated
|
39
|
-
Then the committee should have used quorum "from
|
61
|
+
Then the committee should have used quorum "from direct path"
|
40
62
|
And the conclusion of the committee should be "<distance>"
|
41
63
|
Examples:
|
42
64
|
| origin | destination | distance |
|
43
|
-
| 05753 | 05753 | 0 |
|
44
65
|
| 05753 | 05401 | 53 |
|
45
66
|
|
46
67
|
Scenario Outline: Distance from zip codes not in database or missing lat/lng
|
@@ -73,12 +94,11 @@ Feature: Shipment Committee Calculations
|
|
73
94
|
| ground | 1.0 |
|
74
95
|
| air | 1.1 |
|
75
96
|
|
76
|
-
Scenario: Dogleg factor from
|
97
|
+
Scenario: Dogleg factor from nothing
|
77
98
|
Given a shipment emitter
|
78
|
-
When the "
|
79
|
-
And the "dogleg_factor" committee is calculated
|
99
|
+
When the "dogleg_factor" committee is calculated
|
80
100
|
Then the committee should have used quorum "from segment count"
|
81
|
-
And the conclusion of the committee should be "
|
101
|
+
And the conclusion of the committee should be "1.8"
|
82
102
|
|
83
103
|
Scenario Outline: Dogleg factor from segment count
|
84
104
|
Given a shipment emitter
|
@@ -89,7 +109,9 @@ Feature: Shipment Committee Calculations
|
|
89
109
|
Examples:
|
90
110
|
| segments | factor |
|
91
111
|
| 1 | 1.0 |
|
92
|
-
| 2 | 1.
|
112
|
+
| 2 | 1.8 |
|
113
|
+
| 100 | 1.8 |
|
114
|
+
| -20 | 1.8 |
|
93
115
|
|
94
116
|
Scenario: Adjusted distance from default
|
95
117
|
Given a shipment emitter
|
@@ -6,7 +6,7 @@ Feature: Shipment Emissions Calculations
|
|
6
6
|
When emissions are calculated
|
7
7
|
Then the emission value should be within "0.1" kgs of "8.7"
|
8
8
|
|
9
|
-
Scenario: Calculations from weight, package count
|
9
|
+
Scenario: Calculations from weight, package count and segment count
|
10
10
|
Given a shipment has "weight" of "10"
|
11
11
|
And it has "package_count" of "2"
|
12
12
|
And it has "segment_count" of "1"
|
@@ -16,12 +16,13 @@ Feature: Shipment Emissions Calculations
|
|
16
16
|
Scenario Outline: Calculations from origin/destination
|
17
17
|
Given a shipment has "origin_zip_code.name" of "<origin>"
|
18
18
|
And it has "destination_zip_code.name" of "<destination>"
|
19
|
+
And mapquest determines the distance to be "<distance>"
|
19
20
|
When emissions are calculated
|
20
21
|
Then the emission value should be within "0.1" kgs of "<emission>"
|
21
22
|
Examples:
|
22
|
-
| origin | destination | emission |
|
23
|
-
| 05401 | 05401 | 0.3 |
|
24
|
-
| 05401 | 94128 |
|
23
|
+
| origin | destination | mapquest_distance | emission |
|
24
|
+
| 05401 | 05401 | | 0.3 |
|
25
|
+
| 05401 | 94128 | 30 | 20.8 |
|
25
26
|
|
26
27
|
Scenario: Calculations from carrier
|
27
28
|
Given a shipment has "carrier.name" of "FedEx"
|
@@ -50,5 +51,5 @@ Feature: Shipment Emissions Calculations
|
|
50
51
|
| ground | 05401 | 05401 | 0.3 |
|
51
52
|
| air | 05401 | 05401 | 0.3 |
|
52
53
|
| courier | 05401 | 94128 | 2.3 |
|
53
|
-
| ground | 05401 | 94128 |
|
54
|
-
| air | 05401 | 94128 |
|
54
|
+
| ground | 05401 | 94128 | 25296.2 |
|
55
|
+
| air | 05401 | 94128 | 139127.8 |
|
data/features/support/env.rb
CHANGED
@@ -5,6 +5,7 @@ require 'cucumber'
|
|
5
5
|
require 'cucumber/formatter/unicode'
|
6
6
|
require 'rspec'
|
7
7
|
require 'rspec/expectations'
|
8
|
+
require 'cucumber/rspec/doubles'
|
8
9
|
|
9
10
|
require 'sniff'
|
10
11
|
Sniff.init File.join(File.dirname(__FILE__), '..', '..'), :cucumber => true, :earth => [:locality, :shipping]
|
@@ -2,6 +2,8 @@
|
|
2
2
|
# See LICENSE for details.
|
3
3
|
# Contact Brighter Planet for dual-license arrangements.
|
4
4
|
|
5
|
+
require File.expand_path('../../vendor/plugin/mapquest/lib/mapquest_directions', File.dirname(__FILE__))
|
6
|
+
|
5
7
|
## Shipment carbon model
|
6
8
|
# This model is used by [Brighter Planet](http://brighterplanet.com)'s carbon emission [web service](http://carbon.brighterplanet.com) to estimate the **greenhouse gas emissions of a shipment** (e.g. a FedEx package).
|
7
9
|
#
|
@@ -76,14 +78,14 @@ module BrighterPlanet
|
|
76
78
|
3219
|
77
79
|
end
|
78
80
|
end
|
79
|
-
|
81
|
+
|
80
82
|
committee :dogleg_factor do
|
81
|
-
quorum 'from segment count', :
|
82
|
-
if characteristics[:segment_count]
|
83
|
-
|
84
|
-
1.5 ** (characteristics[:segment_count] - 1)
|
83
|
+
quorum 'from segment count', :appreciates => :segment_count do |characteristics|
|
84
|
+
if characteristics[:segment_count] == 1
|
85
|
+
1.0
|
85
86
|
else
|
86
|
-
|
87
|
+
# based on our sample FedEx tracking numbers
|
88
|
+
1.8
|
87
89
|
end
|
88
90
|
end
|
89
91
|
end
|
@@ -95,34 +97,26 @@ module BrighterPlanet
|
|
95
97
|
end
|
96
98
|
|
97
99
|
committee :distance do
|
98
|
-
quorum 'from
|
99
|
-
|
100
|
-
|
101
|
-
if characteristics[:origin_zip_code] == characteristics[:destination_zip_code]
|
102
|
-
# FIXME TODO
|
103
|
-
# Special calculation to deal with travel within the same zipcode
|
104
|
-
0
|
105
|
-
# Ensure we have the lat/lng for both origin and destination
|
106
|
-
elsif characteristics[:origin_zip_code].latitude and characteristics[:origin_zip_code].longitude and
|
107
|
-
characteristics[:destination_zip_code].latitude and characteristics[:destination_zip_code].longitude
|
108
|
-
characteristics[:origin_zip_code].distance_to(characteristics[:destination_zip_code], :units => :kms)
|
109
|
-
# FIXME TODO: calculate the distance via road using map directions
|
110
|
-
else
|
111
|
-
nil
|
112
|
-
end
|
100
|
+
quorum 'from same locality', :needs => [:origin_zip_code, :destination_zip_code] do |characteristics|
|
101
|
+
if characteristics[:origin_zip_code] == characteristics[:destination_zip_code]
|
102
|
+
0
|
113
103
|
else
|
114
104
|
nil
|
115
105
|
end
|
116
106
|
end
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
107
|
+
quorum 'from mapquest', :needs => [:origin_zip_code, :destination_zip_code, :mode, :mapquest_api_key] do |characteristics|
|
108
|
+
unless characteristics[:mode].name == 'air'
|
109
|
+
mapquest = MapQuestDirections.new characteristics[:origin_zip_code].name,
|
110
|
+
characteristics[:destination_zip_code].name,
|
111
|
+
characteristics[:mapquest_api_key]
|
112
|
+
mapquest.distance_in_miles
|
113
|
+
end
|
114
|
+
end
|
115
|
+
quorum 'from direct path', :needs => [:origin_zip_code, :destination_zip_code, :mode] do |characteristics|
|
116
|
+
characteristics[:origin_zip_code].distance_to(characteristics[:destination_zip_code], :units => :kms)
|
123
117
|
end
|
124
118
|
end
|
125
|
-
|
119
|
+
|
126
120
|
committee :mode do
|
127
121
|
quorum 'default' do
|
128
122
|
ShipmentMode.fallback
|
@@ -148,6 +142,12 @@ module BrighterPlanet
|
|
148
142
|
3.4
|
149
143
|
end
|
150
144
|
end
|
145
|
+
|
146
|
+
committee :mapquest_api_key do
|
147
|
+
quorum 'default' do
|
148
|
+
ENV['MAPQUEST_API_KEY']
|
149
|
+
end
|
150
|
+
end
|
151
151
|
end
|
152
152
|
end
|
153
153
|
end
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'mapquest_directions'
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
require 'nokogiri'
|
3
|
+
|
4
|
+
class MapQuestDirections
|
5
|
+
class Failure < StandardError; end
|
6
|
+
|
7
|
+
attr_accessor :location_1, :location_2, :xml_call, :doc
|
8
|
+
|
9
|
+
def initialize(location_1, location_2, api_key)
|
10
|
+
@base_url = "http://www.mapquestapi.com/directions/v1/route?key=#{api_key}&outFormat=xml&"
|
11
|
+
@location_1 = location_1
|
12
|
+
@location_2 = location_2
|
13
|
+
options = "from=#{transcribe(@location_1)}&to=#{transcribe(@location_2)}"
|
14
|
+
@xml_call = @base_url + options
|
15
|
+
end
|
16
|
+
|
17
|
+
def doc
|
18
|
+
@doc ||= begin
|
19
|
+
xml = get_url(xml_call)
|
20
|
+
noko = Nokogiri::XML(xml)
|
21
|
+
status = noko.css("statusCode").text
|
22
|
+
unless status == '0'
|
23
|
+
errors = noko.css("message").map(&:text).join(', ')
|
24
|
+
raise Failure, "Could not calculate directions between #{location_1} and #{location_2}: #{errors}"
|
25
|
+
end
|
26
|
+
noko
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def drive_time_in_minutes
|
31
|
+
drive_time = doc.css("time").first.text
|
32
|
+
convert_to_minutes(drive_time)
|
33
|
+
end
|
34
|
+
|
35
|
+
def distance_in_miles
|
36
|
+
distance_in_miles = doc.css("distance").first.text.to_i
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
def convert_to_minutes(text)
|
41
|
+
(text.to_i / 60).ceil
|
42
|
+
end
|
43
|
+
|
44
|
+
def transcribe(location)
|
45
|
+
location.gsub(" ", "+")
|
46
|
+
end
|
47
|
+
|
48
|
+
def get_url(url)
|
49
|
+
Net::HTTP.get(::URI.parse(url))
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
context "Mapquest API" do
|
4
|
+
before(:all) do
|
5
|
+
@origin = "816 Meridian St., 37207"
|
6
|
+
@destination = "1963 Canary Dr., 36830"
|
7
|
+
end
|
8
|
+
|
9
|
+
context "API working" do
|
10
|
+
|
11
|
+
describe "directions work" do
|
12
|
+
|
13
|
+
before(:each) do
|
14
|
+
MapQuestDirections.any_instance.stubs(:xml).returns(File.read("spec/lib/mapquest_directions.xml"))
|
15
|
+
@directions = MapQuestDirections.new(@origin, @destination)
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should return distance in miles" do
|
19
|
+
@directions.distance_in_miles.should == 310
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should return drive time in minutes" do
|
23
|
+
@directions.drive_time_in_minutes.should == 303
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should have a status code of 0" do
|
27
|
+
@directions.status.should == "0"
|
28
|
+
end
|
29
|
+
|
30
|
+
end #describe
|
31
|
+
end # API working
|
32
|
+
|
33
|
+
context "API not working" do
|
34
|
+
|
35
|
+
describe "Geocode distance estimation work" do
|
36
|
+
|
37
|
+
before(:each) do
|
38
|
+
MapQuestDirections.any_instance.stubs(:xml).returns(File.read("spec/lib/mapquest_directions_fail.xml"))
|
39
|
+
@directions = MapQuestDirections.new(@origin, @destination)
|
40
|
+
end
|
41
|
+
|
42
|
+
it "should return distance in miles" do
|
43
|
+
@directions.distance_in_miles.should == 0
|
44
|
+
end
|
45
|
+
|
46
|
+
it "should return drive time in minutes" do
|
47
|
+
@directions.drive_time_in_minutes.should == 0
|
48
|
+
end
|
49
|
+
|
50
|
+
it "should have a status code other than 0" do
|
51
|
+
@directions.status.should_not == "0"
|
52
|
+
end
|
53
|
+
|
54
|
+
end #describe
|
55
|
+
end # API not working
|
56
|
+
|
57
|
+
|
58
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'mocha'
|
3
|
+
require 'ruby-debug'
|
4
|
+
|
5
|
+
$:.unshift File.expand_path('../lib', __FILE__)
|
6
|
+
require 'mapquest_directions'
|
7
|
+
|
8
|
+
MAPQUEST_KEY = "replace_me"
|
9
|
+
# http://developer.mapquest.com/
|
10
|
+
|
11
|
+
Spec::Runner.configure do |config|
|
12
|
+
config.mock_with :mocha
|
13
|
+
end
|
metadata
CHANGED
@@ -1,13 +1,12 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: shipment
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash: 25
|
5
4
|
prerelease: false
|
6
5
|
segments:
|
7
6
|
- 0
|
8
7
|
- 0
|
9
|
-
-
|
10
|
-
version: 0.0.
|
8
|
+
- 4
|
9
|
+
version: 0.0.4
|
11
10
|
platform: ruby
|
12
11
|
authors:
|
13
12
|
- Andy Rossmeissl
|
@@ -19,102 +18,96 @@ autorequire:
|
|
19
18
|
bindir: bin
|
20
19
|
cert_chain: []
|
21
20
|
|
22
|
-
date: 2010-12-
|
21
|
+
date: 2010-12-14 00:00:00 -05:00
|
23
22
|
default_executable:
|
24
23
|
dependencies:
|
25
24
|
- !ruby/object:Gem::Dependency
|
26
25
|
name: activerecord
|
27
|
-
prerelease: false
|
28
26
|
requirement: &id001 !ruby/object:Gem::Requirement
|
29
27
|
none: false
|
30
28
|
requirements:
|
31
29
|
- - ~>
|
32
30
|
- !ruby/object:Gem::Version
|
33
|
-
hash: 5
|
34
31
|
segments:
|
35
32
|
- 3
|
36
33
|
- 0
|
37
34
|
- 1
|
38
35
|
version: 3.0.1
|
39
36
|
type: :development
|
37
|
+
prerelease: false
|
40
38
|
version_requirements: *id001
|
41
39
|
- !ruby/object:Gem::Dependency
|
42
40
|
name: bundler
|
43
|
-
prerelease: false
|
44
41
|
requirement: &id002 !ruby/object:Gem::Requirement
|
45
42
|
none: false
|
46
43
|
requirements:
|
47
44
|
- - ~>
|
48
45
|
- !ruby/object:Gem::Version
|
49
|
-
hash: 23
|
50
46
|
segments:
|
51
47
|
- 1
|
52
48
|
- 0
|
53
49
|
- 0
|
54
50
|
version: 1.0.0
|
55
51
|
type: :development
|
52
|
+
prerelease: false
|
56
53
|
version_requirements: *id002
|
57
54
|
- !ruby/object:Gem::Dependency
|
58
55
|
name: rake
|
59
|
-
prerelease: false
|
60
56
|
requirement: &id003 !ruby/object:Gem::Requirement
|
61
57
|
none: false
|
62
58
|
requirements:
|
63
59
|
- - ">="
|
64
60
|
- !ruby/object:Gem::Version
|
65
|
-
hash: 3
|
66
61
|
segments:
|
67
62
|
- 0
|
68
63
|
version: "0"
|
69
64
|
type: :development
|
65
|
+
prerelease: false
|
70
66
|
version_requirements: *id003
|
71
67
|
- !ruby/object:Gem::Dependency
|
72
68
|
name: sniff
|
73
|
-
prerelease: false
|
74
69
|
requirement: &id004 !ruby/object:Gem::Requirement
|
75
70
|
none: false
|
76
71
|
requirements:
|
77
72
|
- - ~>
|
78
73
|
- !ruby/object:Gem::Version
|
79
|
-
hash: 9
|
80
74
|
segments:
|
81
75
|
- 0
|
82
76
|
- 4
|
83
77
|
- 3
|
84
78
|
version: 0.4.3
|
85
79
|
type: :development
|
80
|
+
prerelease: false
|
86
81
|
version_requirements: *id004
|
87
82
|
- !ruby/object:Gem::Dependency
|
88
83
|
name: emitter
|
89
|
-
prerelease: false
|
90
84
|
requirement: &id005 !ruby/object:Gem::Requirement
|
91
85
|
none: false
|
92
86
|
requirements:
|
93
87
|
- - ~>
|
94
88
|
- !ruby/object:Gem::Version
|
95
|
-
hash: 19
|
96
89
|
segments:
|
97
90
|
- 0
|
98
91
|
- 3
|
99
92
|
- 0
|
100
93
|
version: 0.3.0
|
101
94
|
type: :runtime
|
95
|
+
prerelease: false
|
102
96
|
version_requirements: *id005
|
103
97
|
- !ruby/object:Gem::Dependency
|
104
98
|
name: earth
|
105
|
-
prerelease: false
|
106
99
|
requirement: &id006 !ruby/object:Gem::Requirement
|
107
100
|
none: false
|
108
101
|
requirements:
|
109
102
|
- - ~>
|
110
103
|
- !ruby/object:Gem::Version
|
111
|
-
hash: 3
|
112
104
|
segments:
|
113
105
|
- 0
|
114
106
|
- 3
|
115
107
|
- 8
|
116
108
|
version: 0.3.8
|
117
109
|
type: :runtime
|
110
|
+
prerelease: false
|
118
111
|
version_requirements: *id006
|
119
112
|
description: A software model in Ruby for the greenhouse gas emissions of a shipment
|
120
113
|
email: andy@rossmeissl.net
|
@@ -137,8 +130,13 @@ files:
|
|
137
130
|
- lib/shipment/summarization.rb
|
138
131
|
- lib/test_support/shipment_record.rb
|
139
132
|
- features/support/env.rb
|
133
|
+
- features/step_definitions/shipment_steps.rb
|
140
134
|
- features/shipment_committees.feature
|
141
135
|
- features/shipment_emissions.feature
|
136
|
+
- vendor/plugin/mapquest/spec/lib/mapquest_directions_spec.rb
|
137
|
+
- vendor/plugin/mapquest/spec/spec_helper.rb
|
138
|
+
- vendor/plugin/mapquest/init.rb
|
139
|
+
- vendor/plugin/mapquest/lib/mapquest_directions.rb
|
142
140
|
has_rdoc: true
|
143
141
|
homepage: http://brighterplanet.github.com/shipment
|
144
142
|
licenses: []
|
@@ -153,7 +151,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
153
151
|
requirements:
|
154
152
|
- - ">="
|
155
153
|
- !ruby/object:Gem::Version
|
156
|
-
hash:
|
154
|
+
hash: 774422413
|
157
155
|
segments:
|
158
156
|
- 0
|
159
157
|
version: "0"
|
@@ -162,7 +160,6 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
162
160
|
requirements:
|
163
161
|
- - ">="
|
164
162
|
- !ruby/object:Gem::Version
|
165
|
-
hash: 3
|
166
163
|
segments:
|
167
164
|
- 0
|
168
165
|
version: "0"
|
@@ -175,6 +172,11 @@ specification_version: 3
|
|
175
172
|
summary: A carbon model for a shipment
|
176
173
|
test_files:
|
177
174
|
- features/support/env.rb
|
175
|
+
- features/step_definitions/shipment_steps.rb
|
178
176
|
- features/shipment_committees.feature
|
179
177
|
- features/shipment_emissions.feature
|
180
178
|
- lib/test_support/shipment_record.rb
|
179
|
+
- vendor/plugin/mapquest/spec/lib/mapquest_directions_spec.rb
|
180
|
+
- vendor/plugin/mapquest/spec/spec_helper.rb
|
181
|
+
- vendor/plugin/mapquest/init.rb
|
182
|
+
- vendor/plugin/mapquest/lib/mapquest_directions.rb
|