toll_booth 0.1.0
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/.document +5 -0
- data/.gitignore +7 -0
- data/LICENSE +20 -0
- data/README.rdoc +42 -0
- data/Rakefile +109 -0
- data/VERSION +1 -0
- data/features/get_directions.feature +25 -0
- data/features/step_definitions/direction_steps.rb +22 -0
- data/features/step_definitions/location_steps.rb +9 -0
- data/features/step_definitions/toll_booth_steps.rb +0 -0
- data/features/support/env.rb +6 -0
- data/lib/toll_booth/location.rb +37 -0
- data/lib/toll_booth/route.rb +62 -0
- data/lib/toll_booth/route_collection.rb +18 -0
- data/lib/toll_booth/route_step.rb +38 -0
- data/lib/toll_booth.rb +10 -0
- data/test/test_helper.rb +10 -0
- metadata +91 -0
data/.document
ADDED
data/.gitignore
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 Dan Pickett
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
= toll_booth
|
2
|
+
@origin = TollBooth::Location.new("4 Yawkey Way, Boston, MA")
|
3
|
+
@destination = TollBooth::Location.new("1 Fleetcenter Place, Boston, MA")
|
4
|
+
@routes = @origin.drive_to(@destination)
|
5
|
+
if @routes.found?
|
6
|
+
@routes[0].distance #distance in miles
|
7
|
+
@routes[0].drive_time #drive time in seconds
|
8
|
+
@routes[0].name #name of route (usually specified when multiple routes are returned)
|
9
|
+
@routes[0].steps #array of TollBooth::Steps to take
|
10
|
+
@routes[0].steps[0].distance #distance of step in miles
|
11
|
+
@routes[0].steps[0].description #summary of step
|
12
|
+
else
|
13
|
+
puts @routes.errors.join(",")
|
14
|
+
end
|
15
|
+
|
16
|
+
== Install
|
17
|
+
sudo gem install dpickett-toll_booth
|
18
|
+
|
19
|
+
== Links of Interest
|
20
|
+
* {Issue Tracker}[http://github.com/dpickett/toll_booth/issues]
|
21
|
+
* {RDoc}[http://rdoc.info/projects/dpickett/toll_booth]
|
22
|
+
* {WWR Profile (please recommend me if you find this software useful)}[http://workingwithrails.com/person/8076-dan-pickett]
|
23
|
+
|
24
|
+
== TODO
|
25
|
+
* Allow Configuration for Key
|
26
|
+
* Some unit testing with FakeWeb for 100% coverage
|
27
|
+
* Fix distance parsing for when distance is expressed in ft
|
28
|
+
* public transit directions
|
29
|
+
* Walking directions
|
30
|
+
|
31
|
+
== Note on Patches/Pull Requests
|
32
|
+
|
33
|
+
* Fork the project.
|
34
|
+
* Make your feature addition or bug fix.
|
35
|
+
* Add tests for it. This is important so I don't break it in a
|
36
|
+
future version unintentionally.
|
37
|
+
* Commit, do not mess with rakefile, version, or history.
|
38
|
+
* Send me a pull request. Bonus points for topic branches.
|
39
|
+
|
40
|
+
== Copyright
|
41
|
+
|
42
|
+
Copyright (c) 2009 Dan Pickett. See LICENSE for details.
|
data/Rakefile
ADDED
@@ -0,0 +1,109 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'jeweler'
|
6
|
+
Jeweler::Tasks.new do |gem|
|
7
|
+
gem.name = "toll_booth"
|
8
|
+
gem.summary = %Q{API Wrapper for Google Directions}
|
9
|
+
gem.description = %Q{API Wrapper for Google Directions}
|
10
|
+
gem.email = "dpickett@enlightsolutions.com"
|
11
|
+
gem.homepage = "http://github.com/dpickett/toll_booth"
|
12
|
+
gem.authors = ["Dan Pickett"]
|
13
|
+
gem.add_dependency("jnunemaker-httparty", ">= 0.4.4")
|
14
|
+
gem.add_dependency("hpoydar-chronic_duration", ">= 0.7.4")
|
15
|
+
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
16
|
+
end
|
17
|
+
|
18
|
+
rescue LoadError
|
19
|
+
puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
|
20
|
+
end
|
21
|
+
|
22
|
+
require 'rake/testtask'
|
23
|
+
Rake::TestTask.new(:test) do |test|
|
24
|
+
test.libs << 'lib' << 'test'
|
25
|
+
test.pattern = 'test/**/*_test.rb'
|
26
|
+
test.verbose = true
|
27
|
+
end
|
28
|
+
|
29
|
+
namespace :rcov do
|
30
|
+
require 'rcov/rcovtask'
|
31
|
+
Rcov::RcovTask.new(:tests) do |test|
|
32
|
+
test.libs << 'test'
|
33
|
+
test.pattern = 'test/**/*_test.rb'
|
34
|
+
test.rcov_opts = %w{--aggregate coverage.data --exclude osx\/objc,gems\/,spec\/}
|
35
|
+
test.verbose = true
|
36
|
+
end
|
37
|
+
|
38
|
+
require 'cucumber/rake/task'
|
39
|
+
Cucumber::Rake::Task.new(:cucumber) do |t|
|
40
|
+
t.rcov = true
|
41
|
+
t.rcov_opts = %w{--aggregate coverage.data --exclude osx\/objc,gems\/,features\/,spec\/ -o "features_rcov"}
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
begin
|
46
|
+
require 'rcov/rcovtask'
|
47
|
+
desc "Run both specs and features to generate aggregated coverage"
|
48
|
+
task :rcov do |t|
|
49
|
+
rm "coverage.data" if File.exist?("coverage.data")
|
50
|
+
Rake::Task["rcov:cucumber"].invoke
|
51
|
+
Rake::Task["rcov:tests"].invoke
|
52
|
+
end
|
53
|
+
rescue LoadError
|
54
|
+
task :rcov do
|
55
|
+
abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
begin
|
60
|
+
require 'cucumber/rake/task'
|
61
|
+
Cucumber::Rake::Task.new(:features)
|
62
|
+
rescue LoadError
|
63
|
+
task :features do
|
64
|
+
abort "Cucumber is not available. In order to run features, you must: sudo gem install cucumber"
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
begin
|
69
|
+
require 'reek/rake_task'
|
70
|
+
Reek::RakeTask.new do |t|
|
71
|
+
t.fail_on_error = true
|
72
|
+
t.verbose = false
|
73
|
+
t.source_files = 'lib/**/*.rb'
|
74
|
+
end
|
75
|
+
rescue LoadError
|
76
|
+
task :reek do
|
77
|
+
abort "Reek is not available. In order to run reek, you must: sudo gem install reek"
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
begin
|
82
|
+
require 'roodi'
|
83
|
+
require 'roodi_task'
|
84
|
+
RoodiTask.new do |t|
|
85
|
+
t.verbose = false
|
86
|
+
end
|
87
|
+
rescue LoadError
|
88
|
+
task :roodi do
|
89
|
+
abort "Roodi is not available. In order to run roodi, you must: sudo gem install roodi"
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
task :default => :test
|
94
|
+
|
95
|
+
require 'rake/rdoctask'
|
96
|
+
Rake::RDocTask.new do |rdoc|
|
97
|
+
if File.exist?('VERSION.yml')
|
98
|
+
config = YAML.load(File.read('VERSION.yml'))
|
99
|
+
version = "#{config[:major]}.#{config[:minor]}.#{config[:patch]}"
|
100
|
+
else
|
101
|
+
version = ""
|
102
|
+
end
|
103
|
+
|
104
|
+
rdoc.rdoc_dir = 'rdoc'
|
105
|
+
rdoc.title = "toll_booth #{version}"
|
106
|
+
rdoc.rdoc_files.include('README*')
|
107
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
108
|
+
end
|
109
|
+
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.1.0
|
@@ -0,0 +1,25 @@
|
|
1
|
+
Feature: As a user of the toll_booth library
|
2
|
+
I want to retrieve direction data
|
3
|
+
So that I can interact with it
|
4
|
+
|
5
|
+
Scenario: Get Routes From a Simple Trip
|
6
|
+
Given I'm starting at "4 Yawkey Way, Boston, MA"
|
7
|
+
And I want to go to "1 Fleetcenter Place, Boston, MA"
|
8
|
+
When I get driving directions
|
9
|
+
Then I should get a list of possible routes
|
10
|
+
And the first route should have a "distance"
|
11
|
+
And the first route should have "travel_time"
|
12
|
+
And the first route should have a list of "steps"
|
13
|
+
|
14
|
+
Scenario: Invalid Destination
|
15
|
+
Given I'm starting at "4 Yawkey Way, Boston, MA"
|
16
|
+
And I want to go to "Foobar"
|
17
|
+
When I get driving directions
|
18
|
+
Then I should get "1" routing error
|
19
|
+
|
20
|
+
Scenario: Invalid Origin
|
21
|
+
Given I'm starting at "Foobar"
|
22
|
+
And I want to go to "1 Fleetcenter Place, Boston, MA"
|
23
|
+
When I get driving directions
|
24
|
+
Then I should get "1" routing error
|
25
|
+
|
@@ -0,0 +1,22 @@
|
|
1
|
+
When /^I get driving directions$/ do
|
2
|
+
@routes = @origin.drive_to(@destinations)
|
3
|
+
end
|
4
|
+
|
5
|
+
Then /^I should get a list of possible routes$/ do
|
6
|
+
assert !@routes.found?
|
7
|
+
end
|
8
|
+
|
9
|
+
Then /^the first route should have (a\s)?"(.*)"$/ do |a, attribute|
|
10
|
+
assert_not_nil @routes[0].send(attribute)
|
11
|
+
end
|
12
|
+
|
13
|
+
Then /^the first route should have a list of "([^\"]*)"$/ do |set|
|
14
|
+
assert_instance_of Array, @routes[0].send(set)
|
15
|
+
assert !@routes[0].send(set).empty?
|
16
|
+
end
|
17
|
+
|
18
|
+
|
19
|
+
Then /^I should get "([^\"]*)" routing error$/ do |error_qty|
|
20
|
+
assert_equal error_qty.to_i, @routes.errors.size
|
21
|
+
end
|
22
|
+
|
File without changes
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module TollBooth
|
2
|
+
# Represents a location that you would want directions from or to
|
3
|
+
# A location has the following attributes:
|
4
|
+
# * description
|
5
|
+
class Location
|
6
|
+
attr_accessor :description
|
7
|
+
|
8
|
+
# create a new location
|
9
|
+
# @param description [String] address or zipcode of the location
|
10
|
+
def initialize(description)
|
11
|
+
@description = description
|
12
|
+
end
|
13
|
+
|
14
|
+
# get driving routes to the destinations specified
|
15
|
+
# @example
|
16
|
+
# @origin = TollBooth::Location.new("4 Yawkey Way, Boston, MA")
|
17
|
+
# @destination = TollBooth::Location.new("1 Fleetcenter Place, Boston, MA")
|
18
|
+
# @routes = @origin.drive_to(@destination)
|
19
|
+
# if @routes.found?
|
20
|
+
# @routes[0].distance #distance in miles
|
21
|
+
# @routes[0].drive_time #drive time in seconds
|
22
|
+
# @routes[0].name #name of route (usually specified when multiple routes are returned)
|
23
|
+
# @routes[0].steps #array of TollBooth::Steps to take
|
24
|
+
# @routes[0].steps[0].distance #distance of step in miles
|
25
|
+
# @routes[0].steps[0].description #summary of step
|
26
|
+
# else
|
27
|
+
# puts @routes.errors.join(",")
|
28
|
+
# end
|
29
|
+
# @param destinations [TollBooth::Location, Array] a single location or list of locations to drive to
|
30
|
+
# @return [TollBooth::RouteCollection] a collection of potential routes to specified destination(s)
|
31
|
+
def drive_to(destinations)
|
32
|
+
destinations = [destinations] if !destinations.is_a?(Array)
|
33
|
+
|
34
|
+
TollBooth::Route.find(self, destinations)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
module TollBooth
|
2
|
+
class Route
|
3
|
+
include HTTParty
|
4
|
+
attr_accessor :name, :steps, :distance, :travel_time
|
5
|
+
|
6
|
+
default_params(
|
7
|
+
:output => "json"
|
8
|
+
)
|
9
|
+
base_uri "http://maps.google.com/maps/nav"
|
10
|
+
|
11
|
+
class << self
|
12
|
+
# get driving directions from the origin to the specified destination(s)
|
13
|
+
# @param origin [TollBooth::Location] the starting point for the trip
|
14
|
+
# @param destinations [Array] a list of destinations to drive to
|
15
|
+
# @return [TollBooth::RouteCollection] a list of potential routes for the trip
|
16
|
+
def find(origin, destinations)
|
17
|
+
response = get("",
|
18
|
+
:query => {:q => "from: #{origin.description} " +
|
19
|
+
destinations.collect{|d| " to: #{d.description}"}.join("")})
|
20
|
+
routes = parse(response)
|
21
|
+
|
22
|
+
routes
|
23
|
+
end
|
24
|
+
|
25
|
+
# parses response from google
|
26
|
+
# @param the response received from google
|
27
|
+
# @return [TollBooth::RouteCollection] returns a route collection based on the request
|
28
|
+
def parse(response)
|
29
|
+
resp = JSON.parse(response.body)
|
30
|
+
|
31
|
+
code = response["Status"]["code"]
|
32
|
+
routes = TollBooth::RouteCollection.new
|
33
|
+
if code == 200
|
34
|
+
resp["Directions"]["Routes"].each do |r|
|
35
|
+
route = new
|
36
|
+
route.distance = r["Distance"]["html"].gsub(" mi", "").to_f
|
37
|
+
route.travel_time = ChronicDuration.parse(r["Duration"]["html"])
|
38
|
+
route.steps = TollBooth::RouteStep.parse(r["Steps"])
|
39
|
+
|
40
|
+
routes << route
|
41
|
+
end
|
42
|
+
|
43
|
+
else
|
44
|
+
routes.errors = [error_for(code)]
|
45
|
+
end
|
46
|
+
routes
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
# get a friently error message for the status code specified
|
51
|
+
# @param code [Integer] code to translate
|
52
|
+
# @return [String] a friendly error message
|
53
|
+
def error_for(code)
|
54
|
+
if code == 602
|
55
|
+
"Bad Address Specified"
|
56
|
+
elsif code == 500
|
57
|
+
"Server Error"
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module TollBooth
|
2
|
+
# a collection of routes received from google after requesting directions
|
3
|
+
# if an error occurs, the collection will be empty and the errors attribute will
|
4
|
+
# be populated
|
5
|
+
class RouteCollection < Array
|
6
|
+
attr_accessor :errors
|
7
|
+
def initialize(size = 0, obj = nil)
|
8
|
+
super
|
9
|
+
@errors = []
|
10
|
+
end
|
11
|
+
|
12
|
+
# where routes found?
|
13
|
+
# @return [Boolean] whether routes were found or not
|
14
|
+
def found?
|
15
|
+
empty?
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module TollBooth
|
2
|
+
#a direction to take for a given route
|
3
|
+
#direction steps have the following attributes
|
4
|
+
# * distance (in miles)
|
5
|
+
# * travel_time (in seconds)
|
6
|
+
# * latitude
|
7
|
+
# * longitude
|
8
|
+
# * html_description
|
9
|
+
# * description (html stripped)
|
10
|
+
class RouteStep
|
11
|
+
attr_accessor :distance, :travel_time, :latitude, :longitude, :html_description
|
12
|
+
|
13
|
+
# strips any html from the html_description_attribute
|
14
|
+
# @return [String]
|
15
|
+
def description
|
16
|
+
@html_description.gsub(/<\/?[^>]*>/, "")
|
17
|
+
end
|
18
|
+
|
19
|
+
class << self
|
20
|
+
# parses the step from the json supplied
|
21
|
+
def parse(json)
|
22
|
+
route_steps = []
|
23
|
+
json.each do |s|
|
24
|
+
route_step = new
|
25
|
+
route_step.html_description = s["descriptionHtml"]
|
26
|
+
route_step.travel_time = s["Duration"]["seconds"]
|
27
|
+
route_step.distance = s["Distance"]["html"]
|
28
|
+
route_step.latitude = s["Point"]["coordinates"][0]
|
29
|
+
route_step.longitude = s["Point"]["coordinates"][1]
|
30
|
+
|
31
|
+
route_steps << route_step
|
32
|
+
end
|
33
|
+
|
34
|
+
route_steps
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
data/lib/toll_booth.rb
ADDED
data/test/test_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,91 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: toll_booth
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Dan Pickett
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-08-06 00:00:00 -04:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: jnunemaker-httparty
|
17
|
+
type: :runtime
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 0.4.4
|
24
|
+
version:
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: hpoydar-chronic_duration
|
27
|
+
type: :runtime
|
28
|
+
version_requirement:
|
29
|
+
version_requirements: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 0.7.4
|
34
|
+
version:
|
35
|
+
description: API Wrapper for Google Directions
|
36
|
+
email: dpickett@enlightsolutions.com
|
37
|
+
executables: []
|
38
|
+
|
39
|
+
extensions: []
|
40
|
+
|
41
|
+
extra_rdoc_files:
|
42
|
+
- LICENSE
|
43
|
+
- README.rdoc
|
44
|
+
files:
|
45
|
+
- .document
|
46
|
+
- .gitignore
|
47
|
+
- LICENSE
|
48
|
+
- README.rdoc
|
49
|
+
- Rakefile
|
50
|
+
- VERSION
|
51
|
+
- features/get_directions.feature
|
52
|
+
- features/step_definitions/direction_steps.rb
|
53
|
+
- features/step_definitions/location_steps.rb
|
54
|
+
- features/step_definitions/toll_booth_steps.rb
|
55
|
+
- features/support/env.rb
|
56
|
+
- lib/toll_booth.rb
|
57
|
+
- lib/toll_booth/location.rb
|
58
|
+
- lib/toll_booth/route.rb
|
59
|
+
- lib/toll_booth/route_collection.rb
|
60
|
+
- lib/toll_booth/route_step.rb
|
61
|
+
- test/test_helper.rb
|
62
|
+
has_rdoc: true
|
63
|
+
homepage: http://github.com/dpickett/toll_booth
|
64
|
+
licenses: []
|
65
|
+
|
66
|
+
post_install_message:
|
67
|
+
rdoc_options:
|
68
|
+
- --charset=UTF-8
|
69
|
+
require_paths:
|
70
|
+
- lib
|
71
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: "0"
|
76
|
+
version:
|
77
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
78
|
+
requirements:
|
79
|
+
- - ">="
|
80
|
+
- !ruby/object:Gem::Version
|
81
|
+
version: "0"
|
82
|
+
version:
|
83
|
+
requirements: []
|
84
|
+
|
85
|
+
rubyforge_project:
|
86
|
+
rubygems_version: 1.3.5
|
87
|
+
signing_key:
|
88
|
+
specification_version: 3
|
89
|
+
summary: API Wrapper for Google Directions
|
90
|
+
test_files:
|
91
|
+
- test/test_helper.rb
|